You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/kexi/core/kexipart.cpp

453 lines
14 KiB

/* This file is part of the KDE project
Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
Copyright (C) 2003-2005 Jaroslaw Staniek <js@iidea.pl>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "kexipart.h"
#include "kexipartinfo.h"
#include "kexipartitem.h"
#include "kexistaticpart.h"
#include "kexidialogbase.h"
#include "kexiviewbase.h"
#include "kexipartguiclient.h"
#include "keximainwindow.h"
//#include "kexipartdatasource.h"
#include "kexi.h"
#include <kexidb/connection.h>
#include <kexiutils/identifier.h>
#include <kexiutils/utils.h>
#include <tqwidgetstack.h>
#include <kiconloader.h>
#include <kdebug.h>
#include <kmessagebox.h>
namespace KexiPart {
//! @internal
class PartPrivate
{
public:
PartPrivate()
: instanceActionsInitialized(false)
{
}
//! Helper, used in Part::openInstance()
tristate askForOpeningInTextMode(KexiDialogBase *dlg, KexiPart::Item &item,
int supportedViewModes, int viewMode)
{
if (viewMode != Kexi::TextViewMode
&& supportedViewModes & Kexi::TextViewMode
&& dlg->tempData()->proposeOpeningInTextViewModeBecauseOfProblems)
{
//ask
KexiUtils::WaitCursorRemover remover;
//! @todo use message handler for this to enable non-gui apps
TQString singleStatusString( dlg->singleStatusString() );
if (!singleStatusString.isEmpty())
singleStatusString.prepend(TQString("\n\n")+i18n("Details:")+" ");
if (KMessageBox::No==KMessageBox::questionYesNo(0,
((viewMode == Kexi::DesignViewMode)
? i18n("Object \"%1\" could not be opened in Design View.").tqarg(item.name())
: i18n("Object could not be opened in Data View."))+"\n"
+ i18n("Do you want to open it in Text View?") + singleStatusString, 0,
KStdGuiItem::open(), KStdGuiItem::cancel()))
{
// dlg->close(); //this will destroy dlg
return false;
}
return true;
}
return cancelled;
}
bool instanceActionsInitialized : 1;
};
}
//----------------------------------------------------------------
using namespace KexiPart;
Part::Part(TQObject *tqparent, const char *name, const TQStringList &)
: TQObject(tqparent, name)
, m_guiClient(0)
, m_registeredPartID(-1) //no registered ID by default
, d(new PartPrivate())
{
m_info = 0;
m_supportedViewModes = Kexi::DataViewMode | Kexi::DesignViewMode;
m_supportedUserViewModes = Kexi::DataViewMode;
m_mainWin = 0;
m_newObjectsAreDirty = false;
}
Part::Part(TQObject* tqparent, StaticInfo *info)
: TQObject(tqparent, "StaticPart")
, m_guiClient(0)
, m_registeredPartID(-1) //no registered ID by default
, d(new PartPrivate())
{
m_info = info;
m_supportedViewModes = Kexi::DesignViewMode;
m_supportedUserViewModes = 0;
m_mainWin = 0;
m_newObjectsAreDirty = false;
}
Part::~Part()
{
delete d;
}
void Part::createGUIClients(KexiMainWindow *win)
{
m_mainWin = win;
if (!m_guiClient) {
//create part's gui client
m_guiClient = new GUIClient(m_mainWin, this, false, "part");
//default actions for part's gui client:
KAction *act = new KAction(m_names["instanceCaption"]+"...", info()->createItemIcon(), 0, this,
TQT_SLOT(slotCreate()), m_mainWin->actionCollection(),
KexiPart::nameForCreateAction(*info()));
act->plug( m_mainWin->findPopupMenu("insert") );
// new KAction(m_names["instance"]+"...", info()->itemIcon(), 0, this,
// TQT_SLOT(create()), m_guiClient->actionCollection(), (info()->objectName()+"part_create").latin1());
//let init specific actions for parts
// initPartActions( m_guiClient->actionCollection() );
m_mainWin->guiFactory()->addClient(m_guiClient); //this client is added permanently
//create part instance's gui client
// m_instanceGuiClient = new GUIClient(win, this, true);
//default actions for part instance's gui client:
//NONE
//let init specific actions for part instances
for (int mode = 1; mode <= 0x01000; mode <<= 1) {
if (m_supportedViewModes & mode) {
GUIClient *instanceGuiClient = new GUIClient(m_mainWin,
this, true, Kexi::nameForViewMode(mode).latin1());
m_instanceGuiClients.insert(mode, instanceGuiClient);
// initInstanceActions( mode, instanceGuiClient->actionCollection() );
}
}
// also add an instance common for all modes (mode==0)
GUIClient *instanceGuiClient = new GUIClient(m_mainWin, this, true, "allViews");
m_instanceGuiClients.insert(Kexi::AllViewModes, instanceGuiClient);
// initInstanceActions( Kexi::AllViewModes , instanceGuiClient->actionCollection() );
//todo
initPartActions();
// initActions();
}
}
KActionCollection* Part::actionCollectionForMode(int viewMode) const
{
KXMLGUIClient *cli = m_instanceGuiClients[viewMode];
return cli ? cli->actionCollection() : 0;
}
KAction* Part::createSharedAction(int mode, const TQString &text,
const TQString &pix_name, const KShortcut &cut, const char *name,
const char *subclassName)
{
GUIClient *instanceGuiClient = m_instanceGuiClients[mode];
if (!instanceGuiClient) {
kdDebug() << "KexiPart::createSharedAction(): no gui client for mode " << mode << "!" << endl;
return 0;
}
return m_mainWin->createSharedAction(text, pix_name, cut, name,
instanceGuiClient->actionCollection(), subclassName);
}
KAction* Part::createSharedPartAction(const TQString &text,
const TQString &pix_name, const KShortcut &cut, const char *name,
const char *subclassName)
{
if (!m_guiClient)
return 0;
return m_mainWin->createSharedAction(text, pix_name, cut, name,
m_guiClient->actionCollection(), subclassName);
}
KAction* Part::createSharedToggleAction(int mode, const TQString &text,
const TQString &pix_name, const KShortcut &cut, const char *name)
{
return createSharedAction(mode, text, pix_name, cut, name, "KToggleAction");
}
KAction* Part::createSharedPartToggleAction(const TQString &text,
const TQString &pix_name, const KShortcut &cut, const char *name)
{
return createSharedPartAction(text, pix_name, cut, name, "KToggleAction");
}
/*KAction* Part::sharedAction(int mode, const char* name, const char *classname)
{
GUIClient *instanceGuiClient = m_instanceGuiClients[mode];
if (!instanceGuiClient) {
kdDebug() << "KexiPart::createSharedAction(): no gui client for mode " << mode << "!" << endl;
return 0;
}
return instanceGuiClient->actionCollection()->action(name, classname);
}
KAction* Part::sharedPartAction(int mode, const char* name, const char *classname)
{
if (!m_guiClient)
return 0;
return m_guiClient->actionCollection()->action(name, classname);
}*/
void Part::setActionAvailable(const char *action_name, bool avail)
{
TQIntDictIterator<GUIClient> it( m_instanceGuiClients );
for (;it.current();++it) {
KAction *act = it.current()->actionCollection()->action(action_name);
if (act) {
act->setEnabled(avail);
return;
}
}
m_mainWin->setActionAvailable(action_name, avail);
}
KexiDialogBase* Part::openInstance(KexiMainWindow *win, KexiPart::Item &item, int viewMode,
TQMap<TQString,TQString>* staticObjectArgs)
{
//now it's the time for creating instance actions
if (!d->instanceActionsInitialized) {
initInstanceActions();
d->instanceActionsInitialized = true;
}
m_status.cleartqStatus();
// KexiDialogBase *dlg = createInstance(win,item,viewMode);
// if (!dlg)
// return 0;
// TQString capt = TQString("%1 : %2").tqarg(item.name()).tqarg(instanceName());
KexiDialogBase *dlg = new KexiDialogBase(win);
dlg->m_supportedViewModes = m_supportedViewModes;
// dlg->m_neverSaved = item.neverSaved();
// dlg->m_currentViewMode = viewMode;
dlg->m_part = this;
dlg->m_item = &item;
dlg->updateCaption();
KexiDB::SchemaData sdata(m_info->projectPartID());
sdata.setName( item.name() );
sdata.setCaption( item.caption() );
sdata.setDescription( item.description() );
/*! @todo js: apply settings for caption displaying method; there can be option for
- displaying item.caption() as caption, if not empty, without instanceName
- displaying the same as above in tabCaption (or not) */
// dlg->setCaption( capt );
// dlg->setTabCaption( item.name() );
dlg->setId(item.identifier()); //not needed, but we did it
//moved down dlg->registerDialog();
dlg->setIcon( SmallIcon( dlg->itemIcon() ) );
if (dlg->mdiParent())
dlg->mdiParent()->setIcon( *dlg->icon() );
// if (dlg->mainWidget())
// dlg->mainWidget()->setIcon( *dlg->icon() );
dlg->stack()->setIcon( *dlg->icon() );
dlg->m_tempData = createTempData(dlg);
if (!item.neverSaved()) {
//we have to load schema data for this dialog
dlg->m_schemaData = loadSchemaData(dlg, sdata, viewMode);
if (!dlg->m_schemaData) {
//last chance:
if (false == d->askForOpeningInTextMode(dlg, item, dlg->m_supportedViewModes, viewMode)) {
delete dlg;
return 0;
}
viewMode = Kexi::TextViewMode;
dlg->m_schemaData = loadSchemaData(dlg, sdata, viewMode);
}
if (!dlg->m_schemaData) {
if (!m_status.error())
m_status = Kexi::ObjecttqStatus( dlg->mainWin()->project()->dbConnection(),
i18n("Could not load object's definition."), i18n("Object design may be corrupted."));
m_status.append(
Kexi::ObjecttqStatus(i18n("You can delete \"%1\" object and create it again.")
.tqarg(item.name()), TQString()) );
dlg->close();
delete dlg;
return 0;
}
}
bool switchingFailed = false;
bool dummy;
tristate res = dlg->switchToViewMode( viewMode, staticObjectArgs, dummy );
if (!res) {
tristate askForOpeningInTextModeRes
= d->askForOpeningInTextMode(dlg, item, dlg->m_supportedViewModes, viewMode);
// if (viewMode==Kexi::DesignViewMode && dlg->isDesignModePreloadedForTextModeHackUsed(Kexi::TextViewMode))
// askForOpeningInTextModeRes = cancelled; //do not try
// else
if (true == askForOpeningInTextModeRes) {
delete dlg->m_schemaData; //old one
dlg->close();
delete dlg;
//try in text mode
return openInstance(win, item, Kexi::TextViewMode, staticObjectArgs);
}
else if (false == askForOpeningInTextModeRes) {
delete dlg->m_schemaData; //old one
dlg->close();
delete dlg;
return 0;
}
//dlg has an error info
switchingFailed = true;
}
if (~res)
switchingFailed = true;
if (switchingFailed) {
m_status = dlg->status();
dlg->close();
delete dlg;
return 0;
}
dlg->registerDialog(); //ok?
dlg->show();
if (dlg->mdiParent() && dlg->mdiParent()->state()==KMdiChildFrm::Normal) //only resize dialog if it is in normal state
dlg->resize(dlg->tqsizeHint());
dlg->setMinimumSize(dlg->tqminimumSizeHint().width(),dlg->tqminimumSizeHint().height());
//dirty only if it's a new object
if (dlg->selectedView())
dlg->selectedView()->setDirty( m_newObjectsAreDirty ? item.neverSaved() : false );
return dlg;
}
void Part::slotCreate()
{
emit newObjectRequest( m_info );
}
KexiDB::SchemaData* Part::loadSchemaData(KexiDialogBase * /*dlg*/, const KexiDB::SchemaData& sdata,
int /*viewMode*/)
{
KexiDB::SchemaData *new_schema = new KexiDB::SchemaData();
*new_schema = sdata;
return new_schema;
}
bool Part::loadDataBlock( KexiDialogBase *dlg, TQString &dataString, const TQString& dataID)
{
if (!dlg->mainWin()->project()->dbConnection()->loadDataBlock( dlg->id(), dataString, dataID )) {
m_status = Kexi::ObjecttqStatus( dlg->mainWin()->project()->dbConnection(),
i18n("Could not load object's data."), i18n("Data identifier: \"%1\".").tqarg(dataID) );
m_status.append( *dlg );
return false;
}
return true;
}
void Part::initPartActions()
{
}
void Part::initInstanceActions()
{
}
bool Part::remove(KexiMainWindow *win, KexiPart::Item &item)
{
if (!win || !win->project() || !win->project()->dbConnection())
return false;
KexiDB::Connection *conn = win->project()->dbConnection();
return conn->removeObject( item.identifier() );
}
KexiDialogTempData* Part::createTempData(KexiDialogBase* dialog)
{
return new KexiDialogTempData(TQT_TQOBJECT(dialog));
}
TQString Part::i18nMessage(const TQCString& englishMessage, KexiDialogBase* dlg) const
{
Q_UNUSED(dlg);
return TQString(englishMessage).startsWith(":") ? TQString() : englishMessage;
}
void Part::setupCustomPropertyPanelTabs(KTabWidget *, KexiMainWindow*)
{
}
TQCString Part::instanceName() const
{
// "instanceName" should be already valid identifier but we're using
// KexiUtils::string2Identifier() to be sure translators did it right.
return KexiUtils::string2Identifier(m_names["instanceName"]).lower().latin1();
}
TQString Part::instanceCaption() const
{
return m_names["instanceCaption"];
}
tristate Part::rename(KexiMainWindow *win, KexiPart::Item &item, const TQString& newName)
{
Q_UNUSED(win);
Q_UNUSED(item);
Q_UNUSED(newName);
return true;
}
//-------------------------------------------------------------------------
GUIClient::GUIClient(KexiMainWindow *win, Part* part, bool partInstanceClient, const char* nameSuffix)
: TQObject(part,
(part->info()->objectName()
+ (nameSuffix ? TQString(":%1").tqarg(nameSuffix) : TQString())).latin1() )
, KXMLGUIClient(win)
{
if(!win->project()->data()->userMode())
setXMLFile(TQString::tqfromLatin1("kexi")+part->info()->objectName()
+"part"+(partInstanceClient?"inst":"")+"ui.rc");
// new KAction(part->m_names["new"], part->info()->itemIcon(), 0, this,
// TQT_SLOT(create()), actionCollection(), (part->info()->objectName()+"part_create").latin1());
// new KAction(i18nInstanceName+"...", part->info()->itemIcon(), 0, this,
// TQT_SLOT(create()), actionCollection(), (part->info()->objectName()+"part_create").latin1());
// win->guiFactory()->addClient(this);
}
#include "kexipart.moc"