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