kexi

kexidialogbase.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
00003    Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "kexidialogbase.h"
00022 
00023 #include "keximainwindow.h"
00024 #include "kexiviewbase.h"
00025 #include "kexicontexthelp_p.h"
00026 #include "kexipart.h"
00027 #include "kexistaticpart.h"
00028 #include "kexipartitem.h"
00029 #include "kexipartinfo.h"
00030 #include "kexiproject.h"
00031 
00032 #include <kexidb/connection.h>
00033 #include <kexidb/utils.h>
00034 #include <kexiutils/utils.h>
00035 
00036 #include <qwidgetstack.h>
00037 #include <qobjectlist.h>
00038 
00039 #include <kdebug.h>
00040 #include <kapplication.h>
00041 #include <kiconloader.h>
00042 
00043 KexiDialogBase::KexiDialogBase(KexiMainWindow *parent, const QString &caption)
00044  : KMdiChildView(caption, parent, "KexiDialogBase")
00045  , KexiActionProxy(this, parent)
00046  , m_isRegistered(false)
00047  , m_origCaption(caption)
00048  , m_schemaData(0)
00049  , m_destroying(false)
00050  , m_disableDirtyChanged(false)
00051 // , m_neverSaved(false)
00052 {
00053     m_supportedViewModes = 0; //will be set by KexiPart
00054     m_openedViewModes = 0;
00055     m_currentViewMode = Kexi::NoViewMode; //no view available yet
00056     m_parentWindow = parent;
00057     m_creatingViewsMode = -1;
00058 
00059     QVBoxLayout *lyr = new QVBoxLayout(this);
00060     m_stack = new QWidgetStack(this, "stack");
00061     lyr->addWidget(m_stack);
00062 
00063 #ifdef KEXI_NO_CTXT_HELP
00064     m_contextHelpInfo=new KexiContextHelpInfo();
00065 #endif
00066 //  m_instance=parent->instance();
00067     m_id = -1;
00068     m_item = 0;
00069 
00070     hide(); //will be shown later
00071 }
00072 
00073 KexiDialogBase::~KexiDialogBase()
00074 {
00075     m_destroying = true;
00076 }
00077 
00078 KexiViewBase *KexiDialogBase::selectedView() const
00079 {
00080     if (m_destroying)
00081         return 0;
00082 //  return static_cast<KexiViewBase*>(m_stack->visibleWidget());
00083     return static_cast<KexiViewBase*>( m_stack->widget(m_currentViewMode) );
00084 }
00085 
00086 KexiViewBase *KexiDialogBase::viewForMode(int mode) const
00087 {
00088     return static_cast<KexiViewBase*>( m_stack->widget(mode) );
00089 }
00090 
00091 void KexiDialogBase::addView(KexiViewBase *view)
00092 {
00093     addView(view,0);
00094 }
00095 
00096 void KexiDialogBase::addView(KexiViewBase *view, int mode)
00097 {
00098     m_stack->addWidget(view, mode);
00099 //  addActionProxyChild( view );
00100 
00101     //set focus proxy inside this view
00102     QWidget *ch = static_cast<QWidget*>(view->child( 0, "QWidget", false ));
00103     if (ch)
00104         view->setFocusProxy(ch);
00105 
00106     m_openedViewModes |= mode;
00107 }
00108 
00109 QSize KexiDialogBase::minimumSizeHint() const
00110 {
00111     KexiViewBase *v = selectedView();
00112     if (!v)
00113         return KMdiChildView::minimumSizeHint();
00114     return v->minimumSizeHint() + QSize(0, mdiParent() ? mdiParent()->captionHeight() : 0);
00115 }
00116 
00117 QSize KexiDialogBase::sizeHint() const
00118 {
00119     KexiViewBase *v = selectedView();
00120     if (!v)
00121         return KMdiChildView::sizeHint();
00122     return v->preferredSizeHint( v->sizeHint() );
00123 }
00124 
00125 /*
00126 KInstance *KexiDialogBase::instance() {
00127     return m_instance;
00128 }*/
00129 
00130 void KexiDialogBase::registerDialog() {
00131     if (m_isRegistered)
00132         return;
00133     m_parentWindow->registerChild(this);
00134     m_isRegistered=true;
00135     if ( m_parentWindow->mdiMode() == KMdi::ToplevelMode ) {
00136         m_parentWindow->addWindow( (KMdiChildView *)this, KMdi::Detach );
00137         m_parentWindow->detachWindow((KMdiChildView *)this, true);
00138     }
00139     else
00140         m_parentWindow->addWindow((KMdiChildView *)this);
00141 //later show();
00142 //  m_parentWindow->activeWindowChanged(this);
00143 }
00144 
00145 bool KexiDialogBase::isRegistered(){
00146     return m_isRegistered;
00147 }
00148 
00149 void KexiDialogBase::attachToGUIClient() {
00150     if (!guiClient())
00151         return;
00152 
00153 }
00154 
00155 void KexiDialogBase::detachFromGUIClient() {
00156     if (!guiClient())
00157         return;
00158     //TODO
00159 }
00160 
00161 int KexiDialogBase::id() const
00162 {
00163     return (partItem() && partItem()->identifier()>0) ? partItem()->identifier() : m_id;
00164 }
00165 
00166 void KexiDialogBase::setContextHelp(const QString& caption, const QString& text, const QString& iconName) {
00167 #ifdef KEXI_NO_CTXT_HELP
00168     m_contextHelpInfo->caption=caption;
00169     m_contextHelpInfo->text=text;
00170     m_contextHelpInfo->text=iconName;
00171     updateContextHelp();
00172 #endif
00173 }
00174 
00175 void KexiDialogBase::closeEvent( QCloseEvent * e )
00176 {
00177     m_parentWindow->acceptPropertySetEditing();
00178 
00179     //let any view send "closing" signal
00180     QObjectList *list = m_stack->queryList( "KexiViewBase", 0, false, false);
00181     KexiViewBase *view;
00182     QObjectListIt it( *list );
00183     for ( ;(view = static_cast<KexiViewBase*>(it.current()) ) != 0; ++it ) {
00184         bool cancel = false;
00185         emit view->closing(cancel);
00186         if (cancel) {
00187             e->ignore();
00188             return;
00189         }
00190     }
00191     delete list;
00192     emit closing();
00193     KMdiChildView::closeEvent(e);
00194 }
00195 
00196 #if 0
00197 //js removed
00198 bool KexiDialogBase::tryClose(bool dontSaveChanges)
00199 {
00200     if (!dontSaveChanges && dirty()) {
00201 /*TODO      if (KMessageBox::questionYesNo(this, "<b>"+i18n("Do you want save:")
00202         +"<p>"+typeName+" \""+ item->name() + "\"?</b>",
00203         0, KStdGuiItem::yes(), KStdGuiItem::no(), ???????)==KMessageBox::No)
00204         return false;*/
00205         //js TODO: save data using saveChanges()
00206     }
00207     close(true);
00208     return true;
00209 }
00210 #endif
00211 
00212 bool KexiDialogBase::dirty() const
00213 {
00214     //look for "dirty" flag
00215     int m = m_openedViewModes, mode = 1;
00216     while (m>0) {
00217         if (m & 1) {
00218             if (static_cast<KexiViewBase*>(m_stack->widget(mode))->dirty())
00219                 return true;
00220         }
00221         m >>= 1;
00222         mode <<= 1;
00223     }
00224     return false;
00225 /*  KexiViewBase *v = m_newlySelectedView ? m_newlySelectedView : selectedView();
00226     return v ? v->dirty() : false;*/
00227 }
00228 
00229 void KexiDialogBase::setDirty(bool dirty)
00230 {
00231     m_disableDirtyChanged = true;
00232     int m = m_openedViewModes, mode = 1;
00233     while (m>0) {
00234         if (m & 1) {
00235             static_cast<KexiViewBase*>(m_stack->widget(mode))->setDirty(dirty);
00236         }
00237         m >>= 1;
00238         mode <<= 1;
00239     }
00240     m_disableDirtyChanged = false;
00241     dirtyChanged(m_viewThatRecentlySetDirtyFlag); //update
00242 }
00243 
00244 QString KexiDialogBase::itemIcon()
00245 {
00246     if (!m_part || !m_part->info()) {
00247         KexiViewBase *v = selectedView();
00248         if (v) {//m_stack->visibleWidget() && m_stack->visibleWidget()->inherits("KexiViewBase")) {
00249             return v->m_defaultIconName;
00250         }
00251         return QString::null;
00252     }
00253     return m_part->info()->itemIcon();
00254 }
00255 
00256 KexiPart::GUIClient* KexiDialogBase::guiClient() const
00257 {
00258     if (!m_part || m_currentViewMode<1)
00259         return 0;
00260     return m_part->instanceGuiClient(m_currentViewMode);
00261 }
00262 
00263 KexiPart::GUIClient* KexiDialogBase::commonGUIClient() const
00264 {
00265     if (!m_part)
00266         return 0;
00267     return m_part->instanceGuiClient(0);
00268 }
00269 
00270 tristate KexiDialogBase::switchToViewMode( int newViewMode, QMap<QString,QString>* staticObjectArgs )
00271 {
00272     m_parentWindow->acceptPropertySetEditing();
00273 
00274     const bool designModePreloadedForTextModeHack = 
00275         newViewMode==Kexi::TextViewMode 
00276         && !viewForMode(Kexi::DesignViewMode) 
00277         && supportsViewMode(Kexi::DesignViewMode);
00278 
00279     tristate res = true;
00280     if (designModePreloadedForTextModeHack) {
00281         /* A HACK: open design BEFORE text mode: otherwise Query schema becames crazy */
00282         res = switchToViewMode( Kexi::DesignViewMode, staticObjectArgs );
00283         if (!res || ~res)
00284             return res;
00285     }
00286 
00287     kdDebug() << "KexiDialogBase::switchToViewMode()" << endl;
00288     bool dontStore = false;
00289     KexiViewBase *view = selectedView();
00290 
00291     if (m_currentViewMode == newViewMode)
00292         return true;
00293     if (!supportsViewMode(newViewMode))
00294         return false;
00295 
00296     if (view) {
00297         res = true;
00298         if (!designModePreloadedForTextModeHack) {
00299             res = view->beforeSwitchTo(newViewMode, dontStore);
00300         }
00301         if (~res || !res)
00302             return res;
00303         if (!dontStore && view->dirty()) {
00304             res = m_parentWindow->saveObject(this, i18n("Design has been changed. "
00305                 "You must save it before switching to other view."));
00306             if (~res || !res)
00307                 return res;
00308 //          KMessageBox::questionYesNo(0, i18n("Design has been changed. You must save it before switching to other view."))
00309 //              ==KMessageBox::No
00310         }
00311     }
00312 
00313     //get view for viewMode
00314     KexiViewBase *newView 
00315         = (m_stack->widget(newViewMode) && m_stack->widget(newViewMode)->inherits("KexiViewBase"))
00316         ? static_cast<KexiViewBase*>(m_stack->widget(newViewMode)) : 0;
00317     if (!newView) {
00318         KexiUtils::setWaitCursor();
00319         //ask the part to create view for the new mode
00320         m_creatingViewsMode = newViewMode;
00321         KexiPart::StaticPart *staticPart = dynamic_cast<KexiPart::StaticPart*>((KexiPart::Part*)m_part);
00322         if (staticPart)
00323             newView = staticPart->createView(m_stack, this, *m_item, newViewMode, staticObjectArgs);
00324         else
00325             newView = m_part->createView(m_stack, this, *m_item, newViewMode, staticObjectArgs);
00326         KexiUtils::removeWaitCursor();
00327         if (!newView) {
00328             //js TODO error?
00329             kdDebug() << "Switching to mode " << newViewMode << " failed. Previous mode "
00330                 << m_currentViewMode << " restored." << endl;
00331             return false;
00332         }
00333         m_creatingViewsMode = -1;
00334         addView(newView, newViewMode);
00335     }
00336     const int prevViewMode = m_currentViewMode;
00337     res = true;
00338     if (designModePreloadedForTextModeHack) {
00339         m_currentViewMode = Kexi::NoViewMode; //SAFE?
00340     }
00341     res = newView->beforeSwitchTo(newViewMode, dontStore);
00342     if (!res) {
00343         kdDebug() << "Switching to mode " << newViewMode << " failed. Previous mode "
00344             << m_currentViewMode << " restored." << endl;
00345         return false;
00346     }
00347     m_currentViewMode = newViewMode;
00348     m_newlySelectedView = newView;
00349     if (prevViewMode==Kexi::NoViewMode)
00350         m_newlySelectedView->setDirty(false);
00351 
00352     res = newView->afterSwitchFrom(
00353             designModePreloadedForTextModeHack ? Kexi::NoViewMode : prevViewMode);
00354     if (!res) {
00355         kdDebug() << "Switching to mode " << newViewMode << " failed. Previous mode "
00356             << prevViewMode << " restored." << endl;
00357         setStatus(mainWin()->project()->dbConnection(), 
00358             i18n("Switching to other view failed (%1).").arg(Kexi::nameForViewMode(newViewMode)),"");
00359         m_currentViewMode = prevViewMode;
00360         return false;
00361     }
00362     m_newlySelectedView = 0;
00363     if (~res) {
00364         m_currentViewMode = prevViewMode;
00365         return cancelled;
00366     }
00367     if (view)
00368         takeActionProxyChild( view ); //take current proxy child
00369     addActionProxyChild( newView ); //new proxy child
00370     m_stack->raiseWidget( newView );
00371     newView->propertySetSwitched();
00372     m_parentWindow->invalidateSharedActions( newView );
00373 //  setFocus();
00374     return true;
00375 }
00376 
00377 tristate KexiDialogBase::switchToViewMode( int newViewMode )
00378 {
00379     return switchToViewMode( newViewMode, 0 );
00380 }
00381 
00382 void KexiDialogBase::setFocus()
00383 {
00384     if (m_stack->visibleWidget()) {
00385         if (m_stack->visibleWidget()->inherits("KexiViewBase"))
00386             static_cast<KexiViewBase*>( m_stack->visibleWidget() )->setFocus();
00387         else
00388             m_stack->visibleWidget()->setFocus();
00389     }
00390     else {
00391         KMdiChildView::setFocus();
00392     }
00393     activate();
00394 }
00395 
00396 KoProperty::Set*
00397 KexiDialogBase::propertySet()
00398 {
00399     KexiViewBase *v = selectedView();
00400     if (!v)
00401         return 0;
00402     return v->propertySet();
00403 }
00404 
00405 bool KexiDialogBase::eventFilter(QObject *obj, QEvent *e)
00406 {
00407     if (KMdiChildView::eventFilter(obj, e))
00408         return true;
00409 /*  if (e->type()==QEvent::FocusIn) {
00410         QWidget *w = m_parentWindow->activeWindow();
00411         w=0;
00412     }*/
00413     if ((e->type()==QEvent::FocusIn && m_parentWindow->activeWindow()==this)
00414         || e->type()==QEvent::MouseButtonPress) {
00415         if (m_stack->visibleWidget() && KexiUtils::hasParent(m_stack->visibleWidget(), obj)) {
00416             //pass the activation
00417             activate();
00418         }
00419     }
00420     return false;
00421 }
00422 
00423 void KexiDialogBase::dirtyChanged(KexiViewBase* view)
00424 {
00425     if (m_disableDirtyChanged)
00426         return;
00427     m_viewThatRecentlySetDirtyFlag = dirty() ? view : 0;
00428 /*  if (!dirty()) {
00429         if (caption()!=m_origCaption)
00430             KMdiChildView::setCaption(m_origCaption);
00431     }
00432     else {
00433         if (caption()!=(m_origCaption+"*"))
00434             KMdiChildView::setCaption(m_origCaption+"*");
00435     }*/
00436     updateCaption();
00437     emit dirtyChanged(this);
00438 }
00439 
00440 /*QString KexiDialogBase::caption() const
00441 {
00442     return m_origCaption;
00443     if (dirty())
00444         return KMdiChildView::caption()+;
00445 
00446     return KMdiChildView::caption();
00447 }*/
00448 
00449 void KexiDialogBase::updateCaption()
00450 {
00451     if (!m_item || !m_part || !m_origCaption.isEmpty())
00452         return;
00453 //  m_origCaption = c;
00454     QString capt = m_item->name();
00455     QString fullCapt = capt;
00456     if (m_part)
00457         fullCapt += (" : " + m_part->instanceCaption());
00458     if (dirty()) {
00459         KMdiChildView::setCaption(fullCapt+"*");
00460         KMdiChildView::setTabCaption(capt+"*");
00461     }
00462     else {
00463         KMdiChildView::setCaption(fullCapt);
00464         KMdiChildView::setTabCaption(capt);
00465     }
00466 }
00467 
00468 bool KexiDialogBase::neverSaved() const
00469 {
00470     return m_item ? m_item->neverSaved() : true;
00471 }
00472 
00473 tristate KexiDialogBase::storeNewData()
00474 {
00475     if (!neverSaved())
00476         return false;
00477     KexiViewBase *v = selectedView();
00478     if (m_schemaData)
00479         return false; //schema must not exist
00480     if (!v)
00481         return false;
00482     //create schema object and assign information
00483     KexiDB::SchemaData sdata(m_part->info()->projectPartID());
00484     sdata.setName( m_item->name() );
00485     sdata.setCaption( m_item->caption() );
00486     sdata.setDescription( m_item->description() );
00487 
00488     bool cancel = false;
00489     m_schemaData = v->storeNewData(sdata, cancel);
00490     if (cancel)
00491         return cancelled;
00492     if (!m_schemaData) {
00493         setStatus(m_parentWindow->project()->dbConnection(), i18n("Saving object's definition failed."),"");
00494         return false;
00495     }
00496 
00497     if (!part()->info()->isIdStoredInPartDatabase()) {
00498         //this part's ID is not stored within kexi__parts:
00499         KexiDB::TableSchema *ts = m_parentWindow->project()->dbConnection()->tableSchema("kexi__parts");
00500         kdDebug() << "KexiMainWindowImpl::newObject(): schema: " << ts << endl;
00501         if (!ts)
00502             return false;
00503 
00504         //temp. hack: avoid problems with autonumber
00505         // see http://bugs.kde.org/show_bug.cgi?id=89381
00506         int p_id = part()->info()->projectPartID();
00507 
00508         if (p_id<0) {
00509             // Find first available custom part ID by taking the greatest
00510             // existing custom ID (if it exists) and adding 1.
00511             p_id = (int)KexiPart::UserObjectType;
00512             tristate success = m_parentWindow->project()->dbConnection()->querySingleNumber(
00513                 "SELECT max(p_id) FROM kexi__parts", p_id);
00514             if (!success) {
00515                     // Couldn't read part id's from the kexi__parts table
00516                 return false;
00517             } else {
00518                     // Got a maximum part ID, or there were no parts
00519                 p_id = p_id + 1;
00520                 p_id = QMAX(p_id, (int)KexiPart::UserObjectType);
00521             }
00522         }
00523 
00524         KexiDB::FieldList *fl = ts->subList("p_id", "p_name", "p_mime", "p_url");
00525         kexidbg << "KexiMainWindowImpl::newObject(): fieldlist: " 
00526             << (fl ? fl->debugString() : QString::null) << endl;
00527         if (!fl)
00528             return false;
00529 
00530         kexidbg << part()->info()->ptr()->untranslatedGenericName() << endl;
00531 //      QStringList sl = part()->info()->ptr()->propertyNames();
00532 //      for (QStringList::ConstIterator it=sl.constBegin();it!=sl.constEnd();++it)
00533 //          kexidbg << *it << " " << part()->info()->ptr()->property(*it).toString() <<  endl;
00534         if (!m_parentWindow->project()->dbConnection()->insertRecord(
00535                 *fl,
00536                 QVariant(p_id),
00537                 QVariant(part()->info()->ptr()->untranslatedGenericName()),
00538                 QVariant(part()->info()->mimeType()), QVariant("http://www.koffice.org/kexi/" /*always ok?*/)))
00539             return false;
00540 
00541         kdDebug() << "KexiMainWindowImpl::newObject(): insert success!" << endl;
00542         part()->info()->setProjectPartID( p_id );
00543             //(int) project()->dbConnection()->lastInsertedAutoIncValue("p_id", "kexi__parts"));
00544         kdDebug() << "KexiMainWindowImpl::newObject(): new id is: " 
00545             << part()->info()->projectPartID()  << endl;
00546 
00547         part()->info()->setIdStoredInPartDatabase(true);
00548     }
00549 
00550     /* Sets 'dirty' flag on every dialog's view. */
00551     setDirty(false);
00552 //  v->setDirty(false);
00553     //new schema data has now ID updated to a unique value
00554     //-assign that to item's identifier
00555     m_item->setIdentifier( m_schemaData->id() );
00556     m_parentWindow->project()->addStoredItem( part()->info(), m_item );
00557 
00558     return true;
00559 }
00560 
00561 tristate KexiDialogBase::storeData(bool dontAsk)
00562 {
00563     if (neverSaved())
00564         return false;
00565     KexiViewBase *v = selectedView();
00566     if (!v)
00567         return false;
00568 
00569 #define storeData_ERR \
00570     setStatus(m_parentWindow->project()->dbConnection(), i18n("Saving object's data failed."),"");
00571 
00572     //save changes using transaction
00573     KexiDB::Transaction transaction = m_parentWindow->project()->dbConnection()->beginTransaction();
00574     if (transaction.isNull()) {
00575         storeData_ERR;
00576         return false;
00577     }
00578     KexiDB::TransactionGuard tg(transaction);
00579 
00580     const tristate res = v->storeData(dontAsk);
00581     if (~res) //trans. will be cancelled
00582         return res;
00583     if (!res) {
00584         storeData_ERR;
00585         return res;
00586     }
00587     if (!tg.commit()) {
00588         storeData_ERR;
00589         return false;
00590     }
00591     /* Sets 'dirty' flag on every dialog's view. */
00592     setDirty(false);
00593 //  v->setDirty(false);
00594     return true;
00595 }
00596 
00597 void KexiDialogBase::activate()
00598 {
00599     KexiViewBase *v = selectedView();
00600     //kdDebug() << "focusWidget(): " << focusWidget()->name() << endl;
00601     if (KexiUtils::hasParent( v, KMdiChildView::focusedChildWidget()))//focusWidget()))
00602         KMdiChildView::activate();
00603     else {//ah, focused widget is not in this view, move focus:
00604         if (v)
00605             v->setFocus();
00606     }
00607     if (v)
00608         v->updateActions(true);
00609 //js: not neeed??   m_parentWindow->invalidateSharedActions(this);
00610 }
00611 
00612 void KexiDialogBase::deactivate()
00613 {
00614     KexiViewBase *v = selectedView();
00615     if (v)
00616         v->updateActions(false);
00617 }
00618 
00619 void KexiDialogBase::sendDetachedStateToCurrentView()
00620 {
00621     KexiViewBase *v = selectedView();
00622     if (v)
00623         v->parentDialogDetached();
00624 }
00625 
00626 void KexiDialogBase::sendAttachedStateToCurrentView()
00627 {
00628     KexiViewBase *v = selectedView();
00629     if (v)
00630         v->parentDialogAttached();
00631 }
00632 
00633 #include "kexidialogbase.moc"
00634 
KDE Home | KDE Accessibility Home | Description of Access Keys