• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDEUI

kmainwindow.cpp
Go to the documentation of this file.
00001  /* This file is part of the KDE libraries
00002      Copyright
00003      (C) 2000 Reginald Stadlbauer (reggie@kde.org)
00004      (C) 1997 Stephan Kulow (coolo@kde.org)
00005      (C) 1997-2000 Sven Radej (radej@kde.org)
00006      (C) 1997-2000 Matthias Ettrich (ettrich@kde.org)
00007      (C) 1999 Chris Schlaeger (cs@kde.org)
00008      (C) 2002 Joseph Wenninger (jowenn@kde.org)
00009      (C) 2005-2006 Hamish Rodda (rodda@kde.org)
00010      (C) 2000-2008 David Faure (faure@kde.org)
00011 
00012      This library is free software; you can redistribute it and/or
00013      modify it under the terms of the GNU Library General Public
00014      License version 2 as published by the Free Software Foundation.
00015 
00016      This library is distributed in the hope that it will be useful,
00017      but WITHOUT ANY WARRANTY; without even the implied warranty of
00018      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019      Library General Public License for more details.
00020 
00021      You should have received a copy of the GNU Library General Public License
00022      along with this library; see the file COPYING.LIB.  If not, write to
00023      the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00024      Boston, MA 02110-1301, USA.
00025  */
00026 
00027 #include "kmainwindow.h"
00028 #include "kmainwindow_p.h"
00029 #include "kmainwindowiface_p.h"
00030 #include "ktoolbarhandler_p.h"
00031 #include "kcmdlineargs.h"
00032 #include "ktoggleaction.h"
00033 #include "ksessionmanager.h"
00034 #include "kstandardaction.h"
00035 
00036 #include <QtCore/QList>
00037 #include <QtCore/QObject>
00038 #include <QtCore/QTimer>
00039 #include <QtGui/QCloseEvent>
00040 #include <QtGui/QDesktopWidget>
00041 #include <QtGui/QDockWidget>
00042 #include <QtGui/QLayout>
00043 #include <QtGui/QSessionManager>
00044 #include <QtGui/QStyle>
00045 #include <QtGui/QWidget>
00046 
00047 #include <kaction.h>
00048 #include <kapplication.h>
00049 #include <kauthorized.h>
00050 #include <kconfig.h>
00051 #include <kdebug.h>
00052 #include <kdialog.h>
00053 #include <khelpmenu.h>
00054 #include <klocale.h>
00055 #include <kmenubar.h>
00056 #include <kstandarddirs.h>
00057 #include <kstatusbar.h>
00058 #include <ktoolbar.h>
00059 #include <kwindowsystem.h>
00060 #include <kconfiggroup.h>
00061 #include <kglobalsettings.h>
00062 
00063 #if defined Q_WS_X11
00064 #include <qx11info_x11.h>
00065 #include <netwm.h>
00066 #endif
00067 
00068 #include <stdlib.h>
00069 #include <ctype.h>
00070 #include <assert.h>
00071 
00072 #include <config.h>
00073 
00074 static bool no_query_exit = false;
00075 
00076 static KMenuBar *internalMenuBar(KMainWindow *mw)
00077 {
00078     return KGlobal::findDirectChild<KMenuBar *>(mw);
00079 }
00080 
00081 static KStatusBar *internalStatusBar(KMainWindow *mw)
00082 {
00083     // Don't use qFindChild here, it's recursive!
00084     // (== slow, but also finds konqueror's per-view statusbars)
00085     return KGlobal::findDirectChild<KStatusBar *>(mw);
00086 }
00087 
00095 class DockResizeListener : public QObject
00096 {
00097 public:
00098     DockResizeListener(KMainWindow *win);
00099     virtual ~DockResizeListener();
00100     virtual bool eventFilter(QObject *watched, QEvent *event);
00101 
00102 private:
00103     KMainWindow *m_win;
00104 };
00105 
00106 DockResizeListener::DockResizeListener(KMainWindow *win) :
00107     QObject(win),
00108     m_win(win)
00109 {
00110 }
00111 
00112 DockResizeListener::~DockResizeListener()
00113 {
00114 }
00115 
00116 bool DockResizeListener::eventFilter(QObject *watched, QEvent *event)
00117 {
00118     switch( event->type() ) {
00119     case QEvent::Resize:
00120     case QEvent::Move:
00121     case QEvent::Hide:
00122         m_win->k_ptr->setSettingsDirty(KMainWindowPrivate::CompressCalls);
00123         break;
00124 
00125     default:
00126         break;
00127     }
00128 
00129     return QObject::eventFilter(watched, event);
00130 }
00131 
00132 class KMWSessionManager : public KSessionManager
00133 {
00134 public:
00135     KMWSessionManager()
00136     {
00137     }
00138     ~KMWSessionManager()
00139     {
00140     }
00141     bool dummyInit() { return true; }
00142     bool saveState( QSessionManager& )
00143     {
00144         KConfig* config = KApplication::kApplication()->sessionConfig();
00145         if ( KMainWindow::memberList().count() ){
00146             // According to Jochen Wilhelmy <digisnap@cs.tu-berlin.de>, this
00147             // hook is useful for better document orientation
00148             KMainWindow::memberList().first()->saveGlobalProperties(config);
00149         }
00150 
00151         int n = 0;
00152         foreach (KMainWindow* mw, KMainWindow::memberList()) {
00153             n++;
00154             mw->savePropertiesInternal(config, n);
00155         }
00156 
00157         KConfigGroup group( config, "Number" );
00158         group.writeEntry("NumberOfWindows", n );
00159         return true;
00160     }
00161 
00162     bool commitData( QSessionManager& sm )
00163     {
00164         // not really a fast method but the only compatible one
00165         if ( sm.allowsInteraction() ) {
00166             bool canceled = false;
00167             ::no_query_exit = true;
00168 
00169             foreach (KMainWindow *window, KMainWindow::memberList()) {
00170                 if ( !window->testAttribute( Qt::WA_WState_Hidden ) ) {
00171                     QCloseEvent e;
00172                     QApplication::sendEvent( window, &e );
00173                     canceled = !e.isAccepted();
00174                     if (canceled)
00175                         break;
00176                     /* Don't even think_about deleting widgets with
00177                        Qt::WDestructiveClose flag set at this point. We
00178                        are faking a close event, but we are *not*_
00179                        closing the window. The purpose of the faked
00180                        close event is to prepare the application so it
00181                        can safely be quit without the user losing data
00182                        (possibly showing a message box "do you want to
00183                        save this or that?"). It is possible that the
00184                        session manager quits the application later
00185                        (emitting QApplication::aboutToQuit() when this
00186                        happens), but it is also possible that the user
00187                        cancels the shutdown, so the application will
00188                        continue to run.
00189                     */
00190                 }
00191             }
00192             ::no_query_exit = false;
00193             if (canceled)
00194                return false;
00195 
00196             KMainWindow* last = 0;
00197             foreach (KMainWindow *window, KMainWindow::memberList()) {
00198                 if ( !window->testAttribute( Qt::WA_WState_Hidden ) ) {
00199                     last = window;
00200                 }
00201             }
00202             if ( last )
00203                 return last->queryExit();
00204             // else
00205             return true;
00206         }
00207 
00208         // the user wants it, the user gets it
00209         return true;
00210     }
00211 };
00212 
00213 K_GLOBAL_STATIC(KMWSessionManager, ksm)
00214 K_GLOBAL_STATIC(QList<KMainWindow*>, sMemberList)
00215 static bool being_first = true;
00216 
00217 KMainWindow::KMainWindow( QWidget* parent, Qt::WFlags f )
00218     : QMainWindow(parent, f), k_ptr(new KMainWindowPrivate)
00219 {
00220     k_ptr->init(this);
00221 }
00222 
00223 KMainWindow::KMainWindow(KMainWindowPrivate &dd, QWidget *parent, Qt::WFlags f)
00224     : QMainWindow(parent, f), k_ptr(&dd)
00225 {
00226     k_ptr->init(this);
00227 }
00228 
00229 void KMainWindowPrivate::init(KMainWindow *_q)
00230 {
00231     KGlobal::ref();
00232 
00233     // We set allow quit to true when the first mainwindow is created, so that when the refcounting
00234     // reaches 0 the application can quit. We don't want this to happen before the first mainwindow
00235     // is created, otherwise running a job in main would exit the app too early.
00236     KGlobal::setAllowQuit(true);
00237 
00238     q = _q;
00239 
00240     q->setAnimated(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects);
00241 
00242     q->setAttribute( Qt::WA_DeleteOnClose );
00243 
00244     // We handle this functionality (quitting the app) ourselves, with KGlobal::ref/deref.
00245     // This makes apps stay alive even if they only have a systray icon visible, or
00246     // a progress widget with "keep open" checked, for instance.
00247     // So don't let the default Qt mechanism allow any toplevel widget to just quit the app on us.
00248     // Setting WA_QuitOnClose to false for all KMainWindows is not enough, any progress widget
00249     // or dialog box would still quit the app...
00250     if (qApp)
00251         qApp->setQuitOnLastWindowClosed(false);
00252 
00253     helpMenu = 0;
00254 
00255     //actionCollection()->setWidget( this );
00256     QObject::connect(qApp, SIGNAL(aboutToQuit()), q, SLOT(_k_shuttingDown()));
00257     QObject::connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)),
00258                      q, SLOT(_k_slotSettingsChanged(int)));
00259 
00260     // force KMWSessionManager creation - someone a better idea?
00261     ksm->dummyInit();
00262 
00263     sMemberList->append( q );
00264 
00265     settingsDirty = false;
00266     autoSaveSettings = false;
00267     autoSaveWindowSize = true; // for compatibility
00268     //d->kaccel = actionCollection()->kaccel();
00269     settingsTimer = 0;
00270     sizeTimer = 0;
00271     shuttingDown = false;
00272     if ((care_about_geometry = being_first)) {
00273         being_first = false;
00274 
00275         QString geometry;
00276         KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
00277         if (args && args->isSet("geometry"))
00278             geometry = args->getOption("geometry");
00279 
00280         if ( geometry.isNull() ) // if there is no geometry, it doesn't matter
00281             care_about_geometry = false;
00282         else
00283             q->parseGeometry(false);
00284     }
00285 
00286     q->setWindowTitle( KGlobal::caption() );
00287 
00288     dockResizeListener = new DockResizeListener(_q);
00289     letDirtySettings = true;
00290 
00291     sizeApplied = false;
00292 }
00293 
00294 static bool endsWithHashNumber( const QString& s )
00295 {
00296     for( int i = s.length() - 1;
00297          i > 0;
00298          --i )
00299     {
00300         if( s[ i ] == '#' && i != s.length() - 1 )
00301             return true; // ok
00302         if( !s[ i ].isDigit())
00303             break;
00304     }
00305     return false;
00306 }
00307 
00308 static inline bool isValidDBusObjectPathCharacter(const QChar &c)
00309 {
00310     register ushort u = c.unicode();
00311     return (u >= 'a' && u <= 'z')
00312             || (u >= 'A' && u <= 'Z')
00313             || (u >= '0' && u <= '9')
00314             || (u == '_') || (u == '/');
00315 }
00316 
00317 void KMainWindowPrivate::polish(KMainWindow *q)
00318 {
00319     // Set a unique object name. Required by session management, window management, and for the dbus interface.
00320     QString objname;
00321     QString s;
00322     int unusedNumber = 1;
00323     const QString name = q->objectName();
00324     bool startNumberingImmediately = true;
00325     bool tryReuse = false;
00326     if ( name.isEmpty() )
00327     {   // no name given
00328         objname = "MainWindow#";
00329     }
00330     else if( name.endsWith( QLatin1Char( '#' ) ) )
00331     {   // trailing # - always add a number  - KWin uses this for better grouping
00332         objname = name;
00333     }
00334     else if( endsWithHashNumber( name ))
00335     {   // trailing # with a number - like above, try to use the given number first
00336         objname = name;
00337         tryReuse = true;
00338         startNumberingImmediately = false;
00339     }
00340     else
00341     {
00342         objname = name;
00343         startNumberingImmediately = false;
00344     }
00345 
00346     s = objname;
00347     if ( startNumberingImmediately )
00348         s += '1';
00349 
00350     for(;;) {
00351         const QList<QWidget*> list = qApp->topLevelWidgets();
00352         bool found = false;
00353         foreach ( QWidget* w, list ) {
00354             if( w != q && w->objectName() == s )
00355             {
00356                 found = true;
00357                 break;
00358             }
00359         }
00360         if( !found )
00361             break;
00362         if( tryReuse ) {
00363             objname = name.left( name.length() - 1 ); // lose the hash
00364             unusedNumber = 0; // start from 1 below
00365             tryReuse = false;
00366         }
00367         s.setNum( ++unusedNumber );
00368         s = objname + s;
00369     }
00370     q->setObjectName( s );
00371     q->winId(); // workaround for setWindowRole() crashing, and set also window role, just in case TT
00372     q->setWindowRole( s ); // will keep insisting that object name suddenly should not be used for window role
00373 
00374     dbusName = '/' + qApp->applicationName() + '/' + q->objectName().replace(QLatin1Char('/'), QLatin1Char('_'));
00375     // Clean up for dbus usage: any non-alphanumeric char should be turned into '_'
00376     const int len = dbusName.length();
00377     for ( int i = 0; i < len; ++i ) {
00378         if ( !isValidDBusObjectPathCharacter( dbusName[i] ) )
00379             dbusName[i] = QLatin1Char('_');
00380     }
00381 
00382     QDBusConnection::sessionBus().registerObject(dbusName, q, QDBusConnection::ExportScriptableSlots |
00383                                        QDBusConnection::ExportScriptableProperties |
00384                                        QDBusConnection::ExportNonScriptableSlots |
00385                                        QDBusConnection::ExportNonScriptableProperties |
00386                                        QDBusConnection::ExportAdaptors);
00387 }
00388 
00389 void KMainWindowPrivate::setSettingsDirty(CallCompression callCompression)
00390 {
00391     if (!letDirtySettings) {
00392         return;
00393     }
00394 
00395     settingsDirty = true;
00396     if (autoSaveSettings) {
00397         if (callCompression == CompressCalls) {
00398             if (!settingsTimer) {
00399                 settingsTimer = new QTimer(q);
00400                 settingsTimer->setInterval(500);
00401                 settingsTimer->setSingleShot(true);
00402                 QObject::connect(settingsTimer, SIGNAL(timeout()), q, SLOT(saveAutoSaveSettings()));
00403             }
00404             settingsTimer->start();
00405         } else {
00406             q->saveAutoSaveSettings();
00407         }
00408     }
00409 }
00410 
00411 void KMainWindowPrivate::setSizeDirty()
00412 {
00413     if (autoSaveWindowSize) {
00414         if (!sizeTimer) {
00415             sizeTimer = new QTimer(q);
00416             sizeTimer->setInterval(500);
00417             sizeTimer->setSingleShot(true);
00418             QObject::connect(sizeTimer, SIGNAL(timeout()), q, SLOT(_k_slotSaveAutoSaveSize()));
00419         }
00420         sizeTimer->start();
00421     }
00422 }
00423 
00424 void KMainWindow::parseGeometry(bool parsewidth)
00425 {
00426     K_D(KMainWindow);
00427     QString cmdlineGeometry;
00428     KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
00429     if (args->isSet("geometry"))
00430         cmdlineGeometry = args->getOption("geometry");
00431 
00432     assert ( !cmdlineGeometry.isNull() );
00433     assert ( d->care_about_geometry );
00434     Q_UNUSED(d); // fix compiler warning in release mode
00435 
00436 #if defined Q_WS_X11
00437     int x, y;
00438     int w, h;
00439     int m = XParseGeometry( cmdlineGeometry.toLatin1(), &x, &y, (unsigned int*)&w, (unsigned int*)&h);
00440     if (parsewidth) {
00441         const QSize minSize = minimumSize();
00442         const QSize maxSize = maximumSize();
00443         if ( !(m & WidthValue) )
00444             w = width();
00445         if ( !(m & HeightValue) )
00446             h = height();
00447          w = qMin(w,maxSize.width());
00448          h = qMin(h,maxSize.height());
00449          w = qMax(w,minSize.width());
00450          h = qMax(h,minSize.height());
00451          resize(w, h);
00452     } else {
00453         if ( (m & XNegative) )
00454             x = KApplication::desktop()->width()  + x - w;
00455         else if ( (m & XValue) )
00456             x = geometry().x();
00457         if ( (m & YNegative) )
00458             y = KApplication::desktop()->height() + y - h;
00459         else if ( (m & YValue) )
00460             y = geometry().y();
00461 
00462         move(x, y);
00463     }
00464 #endif
00465 }
00466 
00467 KMainWindow::~KMainWindow()
00468 {
00469     sMemberList->removeAll( this );
00470     delete static_cast<QObject *>(k_ptr->dockResizeListener);  //so we don't get anymore events after k_ptr is destroyed
00471     delete k_ptr;
00472     KGlobal::deref();
00473 }
00474 
00475 KMenu* KMainWindow::helpMenu( const QString &aboutAppText, bool showWhatsThis )
00476 {
00477     K_D(KMainWindow);
00478     if(!d->helpMenu) {
00479         if ( aboutAppText.isEmpty() )
00480             d->helpMenu = new KHelpMenu( this, KGlobal::mainComponent().aboutData(), showWhatsThis);
00481         else
00482             d->helpMenu = new KHelpMenu( this, aboutAppText, showWhatsThis );
00483 
00484         if (!d->helpMenu)
00485             return 0;
00486     }
00487 
00488     return d->helpMenu->menu();
00489 }
00490 
00491 KMenu* KMainWindow::customHelpMenu( bool showWhatsThis )
00492 {
00493     K_D(KMainWindow);
00494     if (!d->helpMenu) {
00495         d->helpMenu = new KHelpMenu( this, QString(), showWhatsThis );
00496         connect(d->helpMenu, SIGNAL( showAboutApplication()),
00497                 this, SLOT( showAboutApplication() ));
00498     }
00499 
00500     return d->helpMenu->menu();
00501 }
00502 
00503 bool KMainWindow::canBeRestored( int number )
00504 {
00505     if ( !qApp->isSessionRestored() )
00506         return false;
00507     KConfig *config = kapp->sessionConfig();
00508     if ( !config )
00509         return false;
00510 
00511     KConfigGroup group( config, "Number" );
00512     const int n = group.readEntry( "NumberOfWindows", 1 );
00513     return number >= 1 && number <= n;
00514 }
00515 
00516 const QString KMainWindow::classNameOfToplevel( int number )
00517 {
00518     if ( !qApp->isSessionRestored() )
00519         return QString();
00520     KConfig *config = kapp->sessionConfig();
00521     if ( !config )
00522         return QString();
00523     QString s;
00524     s.setNum( number );
00525     s.prepend( QLatin1String("WindowProperties") );
00526 
00527     KConfigGroup group( config, s );
00528     if ( !group.hasKey( "ClassName" ) )
00529         return QString();
00530     else
00531         return group.readEntry( "ClassName" );
00532 }
00533 
00534 bool KMainWindow::restore( int number, bool show )
00535 {
00536     if ( !canBeRestored( number ) )
00537         return false;
00538     KConfig *config = kapp->sessionConfig();
00539     if ( readPropertiesInternal( config, number ) ){
00540         if ( show )
00541             KMainWindow::show();
00542         return false;
00543     }
00544     return false;
00545 }
00546 
00547 void KMainWindow::setCaption( const QString &caption )
00548 {
00549     setPlainCaption( KDialog::makeStandardCaption( caption, this ) );
00550 }
00551 
00552 void KMainWindow::setCaption( const QString &caption, bool modified )
00553 {
00554     KDialog::CaptionFlags flags = KDialog::HIGCompliantCaption;
00555 
00556     if ( modified )
00557     {
00558         flags |= KDialog::ModifiedCaption;
00559     }
00560 
00561     setPlainCaption( KDialog::makeStandardCaption(caption, this, flags) );
00562 }
00563 
00564 void KMainWindow::setPlainCaption( const QString &caption )
00565 {
00566     setWindowTitle(caption);
00567 }
00568 
00569 void KMainWindow::appHelpActivated( void )
00570 {
00571     K_D(KMainWindow);
00572     if( !d->helpMenu ) {
00573         d->helpMenu = new KHelpMenu( this );
00574         if ( !d->helpMenu )
00575             return;
00576     }
00577     d->helpMenu->appHelpActivated();
00578 }
00579 
00580 void KMainWindow::closeEvent ( QCloseEvent *e )
00581 {
00582     K_D(KMainWindow);
00583 
00584     // Save settings if auto-save is enabled, and settings have changed
00585     if (d->settingsTimer && d->settingsTimer->isActive()) {
00586         d->settingsTimer->stop();
00587         saveAutoSaveSettings();
00588     }
00589     if (d->sizeTimer && d->sizeTimer->isActive()) {
00590         d->sizeTimer->stop();
00591         d->_k_slotSaveAutoSaveSize();
00592     }
00593 
00594     if (queryClose()) {
00595         e->accept();
00596 
00597         int not_withdrawn = 0;
00598         foreach (KMainWindow* mw, KMainWindow::memberList()) {
00599             if ( !mw->isHidden() && mw->isTopLevel() && mw != this )
00600                 not_withdrawn++;
00601         }
00602 
00603         if ( !no_query_exit && not_withdrawn <= 0 ) { // last window close accepted?
00604             if (!( queryExit() && ( !kapp || !kapp->sessionSaving() ) && !d->shuttingDown )) {
00605               // cancel closing, it's stupid to end up with no windows at all....
00606               e->ignore();
00607             }
00608         }
00609     } else e->ignore(); //if the window should not be closed, don't close it
00610 }
00611 
00612 bool KMainWindow::queryExit()
00613 {
00614     return true;
00615 }
00616 
00617 bool KMainWindow::queryClose()
00618 {
00619     return true;
00620 }
00621 
00622 void KMainWindow::saveGlobalProperties( KConfig*  )
00623 {
00624 }
00625 
00626 void KMainWindow::readGlobalProperties( KConfig*  )
00627 {
00628 }
00629 
00630 void KMainWindow::showAboutApplication()
00631 {
00632 }
00633 
00634 void KMainWindow::savePropertiesInternal( KConfig *config, int number )
00635 {
00636     K_D(KMainWindow);
00637     const bool oldASWS = d->autoSaveWindowSize;
00638     d->autoSaveWindowSize = true; // make saveMainWindowSettings save the window size
00639 
00640     QString s;
00641     s.setNum(number);
00642     s.prepend(QLatin1String("WindowProperties"));
00643     KConfigGroup cg(config, s);
00644 
00645     // store objectName, className, Width and Height  for later restoring
00646     // (Only useful for session management)
00647     cg.writeEntry(QLatin1String("ObjectName"), objectName());
00648     cg.writeEntry(QLatin1String("ClassName"), metaObject()->className());
00649 
00650     saveMainWindowSettings(cg); // Menubar, statusbar and Toolbar settings.
00651 
00652     s.setNum(number);
00653     cg = KConfigGroup(config, s);
00654     saveProperties(cg);
00655 
00656     d->autoSaveWindowSize = oldASWS;
00657 }
00658 
00659 void KMainWindow::saveMainWindowSettings(const KConfigGroup &_cg)
00660 {
00661     K_D(KMainWindow);
00662     //kDebug(200) << "KMainWindow::saveMainWindowSettings " << _cg.name();
00663 
00664     // Called by session management - or if we want to save the window size anyway
00665     if ( d->autoSaveWindowSize )
00666         saveWindowSize( _cg );
00667 
00668     KConfigGroup cg(_cg); // for saving
00669 
00670     // One day will need to save the version number, but for now, assume 0
00671     // Utilise the QMainWindow::saveState() functionality.
00672     const QByteArray state = saveState();
00673     cg.writeEntry(QString("State"), state.toBase64());
00674 
00675     QStatusBar* sb = internalStatusBar(this);
00676     if (sb) {
00677        if(!cg.hasDefault("StatusBar") && !sb->isHidden() )
00678            cg.revertToDefault("StatusBar");
00679        else
00680            cg.writeEntry("StatusBar", sb->isHidden() ? "Disabled" : "Enabled");
00681     }
00682 
00683     QMenuBar* mb = internalMenuBar(this);
00684     if (mb) {
00685        const QString MenuBar = QLatin1String("MenuBar");
00686        if(!cg.hasDefault("MenuBar") && !mb->isHidden() )
00687            cg.revertToDefault("MenuBar");
00688        else
00689            cg.writeEntry("MenuBar", mb->isHidden() ? "Disabled" : "Enabled");
00690     }
00691 
00692     if ( !autoSaveSettings() || cg.name() == autoSaveGroup() ) { // TODO should be cg == d->autoSaveGroup, to compare both kconfig and group name
00693         if(!cg.hasDefault("ToolBarsMovable") && !KToolBar::toolBarsLocked())
00694             cg.revertToDefault("ToolBarsMovable");
00695         else
00696             cg.writeEntry("ToolBarsMovable", KToolBar::toolBarsLocked() ? "Disabled" : "Enabled");
00697     }
00698 
00699     int n = 1; // Toolbar counter. toolbars are counted from 1,
00700     foreach (KToolBar* toolbar, toolBars()) {
00701         QString group("Toolbar");
00702         // Give a number to the toolbar, but prefer a name if there is one,
00703         // because there's no real guarantee on the ordering of toolbars
00704         group += (toolbar->objectName().isEmpty() ? QString::number(n) : QString(" ")+toolbar->objectName());
00705 
00706         KConfigGroup toolbarGroup(&cg, group);
00707         toolbar->saveSettings(toolbarGroup);
00708         n++;
00709     }
00710 }
00711 
00712 bool KMainWindow::readPropertiesInternal( KConfig *config, int number )
00713 {
00714     K_D(KMainWindow);
00715 
00716     const bool oldLetDirtySettings = d->letDirtySettings;
00717     d->letDirtySettings = false;
00718 
00719     if ( number == 1 )
00720         readGlobalProperties( config );
00721 
00722     // in order they are in toolbar list
00723     QString s;
00724     s.setNum(number);
00725     s.prepend(QLatin1String("WindowProperties"));
00726 
00727     KConfigGroup cg(config, s);
00728 
00729     // restore the object name (window role)
00730     if ( cg.hasKey(QLatin1String("ObjectName" )) )
00731         setObjectName( cg.readEntry("ObjectName").toLatin1()); // latin1 is right here
00732 
00733     d->sizeApplied = false; // since we are changing config file, reload the size of the window
00734                             // if necessary. Do it before the call to applyMainWindowSettings.
00735     applyMainWindowSettings(cg); // Menubar, statusbar and toolbar settings.
00736 
00737     s.setNum(number);
00738     KConfigGroup grp(config, s);
00739     readProperties(grp);
00740 
00741     d->letDirtySettings = oldLetDirtySettings;
00742 
00743     return true;
00744 }
00745 
00746 void KMainWindow::applyMainWindowSettings(const KConfigGroup &cg, bool force)
00747 {
00748     K_D(KMainWindow);
00749     kDebug(200) << "KMainWindow::applyMainWindowSettings " << cg.name();
00750 
00751     QWidget *focusedWidget = QApplication::focusWidget();
00752 
00753     const bool oldLetDirtySettings = d->letDirtySettings;
00754     d->letDirtySettings = false;
00755 
00756     if (!d->sizeApplied) {
00757         restoreWindowSize(cg);
00758         d->sizeApplied = true;
00759     }
00760 
00761     QStatusBar* sb = internalStatusBar(this);
00762     if (sb) {
00763         QString entry = cg.readEntry("StatusBar", "Enabled");
00764         if ( entry == "Disabled" )
00765            sb->hide();
00766         else
00767            sb->show();
00768     }
00769 
00770     QMenuBar* mb = internalMenuBar(this);
00771     if (mb) {
00772         QString entry = cg.readEntry ("MenuBar", "Enabled");
00773         if ( entry == "Disabled" )
00774            mb->hide();
00775         else
00776            mb->show();
00777     }
00778 
00779     if ( !autoSaveSettings() || cg.name() == autoSaveGroup() ) { // TODO should be cg == d->autoSaveGroup, to compare both kconfig and group name
00780         QString entry = cg.readEntry ("ToolBarsMovable", "Disabled");
00781         if ( entry == "Disabled" )
00782             KToolBar::setToolBarsLocked(true);
00783         else
00784             KToolBar::setToolBarsLocked(false);
00785     }
00786 
00787     int n = 1; // Toolbar counter. toolbars are counted from 1,
00788     foreach (KToolBar* toolbar, toolBars()) {
00789         QString group("Toolbar");
00790         // Give a number to the toolbar, but prefer a name if there is one,
00791         // because there's no real guarantee on the ordering of toolbars
00792         group += (toolbar->objectName().isEmpty() ? QString::number(n) : QString(" ")+toolbar->objectName());
00793 
00794         KConfigGroup toolbarGroup(&cg, group);
00795         toolbar->applySettings(toolbarGroup, force);
00796         n++;
00797     }
00798 
00799     QByteArray state;
00800     if (cg.hasKey("State")) {
00801         state = cg.readEntry("State", state);
00802         state = QByteArray::fromBase64(state);
00803         // One day will need to load the version number, but for now, assume 0
00804         restoreState(state);
00805     }
00806 
00807     if (focusedWidget) {
00808         focusedWidget->setFocus();
00809     }
00810 
00811     d->settingsDirty = false;
00812     d->letDirtySettings = oldLetDirtySettings;
00813 }
00814 
00815 #ifdef Q_WS_WIN
00816 
00817 /*
00818  The win32 implementation for restoring/savin windows size differs
00819  from the unix/max implementation in three topics:
00820 
00821 1. storing and restoring the position, which may not work on x11
00822     see http://doc.trolltech.com/4.3/geometry.html#x11-peculiarities
00823 2. using QWidget::saveGeometry() and QWidget::restoreGeometry()
00824     this would probably be usable on x11 and/or on mac, but I'm unable to
00825     check this on unix/mac, so I leave this fix to the x11/mac experts.
00826 3. store geometry separately for each resolution -> on unix/max the size
00827     and with of the window are already saved separately on non windows
00828     system although not using ...Geometry functions -> could also be
00829     fixed by x11/mac experts.
00830 */
00831 void KMainWindow::restoreWindowSize( const KConfigGroup & _cg )
00832 {
00833     K_D(KMainWindow);
00834 
00835     int scnum = QApplication::desktop()->screenNumber(window());
00836     QRect desk = QApplication::desktop()->screenGeometry(scnum);
00837 
00838     QString geometryKey = QString::fromLatin1("geometry-%1-%2").arg(desk.width()).arg(desk.height());
00839     QByteArray geometry = _cg.readEntry( geometryKey, QByteArray() );
00840     // if first time run, center window
00841     if (!restoreGeometry( QByteArray::fromBase64(geometry) ))
00842         move( (desk.width()-width())/2, (desk.height()-height())/2 );
00843 }
00844 
00845 void KMainWindow::saveWindowSize( const KConfigGroup & _cg ) const
00846 {
00847     K_D(const KMainWindow);
00848     int scnum = QApplication::desktop()->screenNumber(window());
00849     QRect desk = QApplication::desktop()->screenGeometry(scnum);
00850 
00851     // geometry is saved separately for each resolution
00852     QString geometryKey = QString::fromLatin1("geometry-%1-%2").arg(desk.width()).arg(desk.height());
00853     QByteArray geometry = saveGeometry();
00854     KConfigGroup cg(_cg);
00855     cg.writeEntry( geometryKey, geometry.toBase64() );
00856 }
00857 #else
00858 void KMainWindow::saveWindowSize( const KConfigGroup & _cg ) const
00859 {
00860     K_D(const KMainWindow);
00861     int scnum = QApplication::desktop()->screenNumber(window());
00862     QRect desk = QApplication::desktop()->screenGeometry(scnum);
00863 
00864     int w, h;
00865 #if defined Q_WS_X11
00866     // save maximalization as desktop size + 1 in that direction
00867     KWindowInfo info = KWindowSystem::windowInfo( winId(), NET::WMState );
00868     w = info.state() & NET::MaxHoriz ? desk.width() + 1 : width();
00869     h = info.state() & NET::MaxVert ? desk.height() + 1 : height();
00870 #else
00871     if (isMaximized()) {
00872         w = desk.width() + 1;
00873         h = desk.height() + 1;
00874     } else {
00875         w = width();
00876         h = height();
00877     }
00878     //TODO: add "Maximized" property instead "+1" hack
00879 #endif
00880     KConfigGroup cg(_cg);
00881 
00882     QRect size( desk.width(), w, desk.height(), h );
00883     bool defaultSize = (size == d->defaultWindowSize);
00884     QString widthString = QString::fromLatin1("Width %1").arg(desk.width());
00885     QString heightString = QString::fromLatin1("Height %1").arg(desk.height());
00886     if (!cg.hasDefault(widthString) && defaultSize)
00887         cg.revertToDefault(widthString);
00888     else
00889         cg.writeEntry(widthString, w );
00890 
00891     if (!cg.hasDefault(heightString) && defaultSize)
00892         cg.revertToDefault(heightString);
00893     else
00894         cg.writeEntry(heightString, h );
00895 }
00896 
00897 void KMainWindow::restoreWindowSize( const KConfigGroup & config )
00898 {
00899     K_D(KMainWindow);
00900     if (d->care_about_geometry) {
00901         parseGeometry(true);
00902     } else {
00903         // restore the size
00904         const int scnum = QApplication::desktop()->screenNumber(window());
00905         QRect desk = QApplication::desktop()->screenGeometry(scnum);
00906 
00907         if ( d->defaultWindowSize.isNull() ) // only once
00908           d->defaultWindowSize = QRect(desk.width(), width(), desk.height(), height()); // store default values
00909         const QSize size( config.readEntry( QString::fromLatin1("Width %1").arg(desk.width()), 0 ),
00910                     config.readEntry( QString::fromLatin1("Height %1").arg(desk.height()), 0 ) );
00911         if ( !size.isEmpty() ) {
00912 #ifdef Q_WS_X11
00913             int state = ( size.width() > desk.width() ? NET::MaxHoriz : 0 )
00914                         | ( size.height() > desk.height() ? NET::MaxVert : 0 );
00915             if(( state & NET::Max ) == NET::Max )
00916                 resize( desk.width(), desk.height() ); // WORKAROUND: this should not be needed. KWindowSystem::setState
00917                                                        //             should be enough for maximizing. (ereslibre)
00918             else if(( state & NET::MaxHoriz ) == NET::MaxHoriz )
00919                 resize( desk.width(), size.height() );
00920             else if(( state & NET::MaxVert ) == NET::MaxVert )
00921                 resize( size.width(), desk.height() );
00922             else
00923                 resize( size );
00924             // QWidget::showMaximized() is both insufficient and broken
00925             KWindowSystem::setState( winId(), state );
00926 #else
00927             if (size.width() > desk.width() || size.height() > desk.height())
00928               setWindowState( Qt::WindowMaximized );
00929             else
00930               resize( size );
00931 #endif
00932         }
00933     }
00934 }
00935 #endif
00936 
00937 bool KMainWindow::initialGeometrySet() const
00938 {
00939     K_D(const KMainWindow);
00940     return d->care_about_geometry;
00941 }
00942 
00943 void KMainWindow::ignoreInitialGeometry()
00944 {
00945     K_D(KMainWindow);
00946     d->care_about_geometry = false;
00947 }
00948 
00949 void KMainWindow::setSettingsDirty()
00950 {
00951     K_D(KMainWindow);
00952     d->setSettingsDirty();
00953 }
00954 
00955 bool KMainWindow::settingsDirty() const
00956 {
00957     K_D(const KMainWindow);
00958     return d->settingsDirty;
00959 }
00960 
00961 void KMainWindow::setAutoSaveSettings( const QString & groupName, bool saveWindowSize )
00962 {
00963     setAutoSaveSettings(KConfigGroup(KGlobal::config(), groupName), saveWindowSize);
00964 }
00965 
00966 void KMainWindow::setAutoSaveSettings( const KConfigGroup & group,
00967                                        bool saveWindowSize )
00968 {
00969     K_D(KMainWindow);
00970     d->autoSaveSettings = true;
00971     d->autoSaveGroup = group;
00972     d->autoSaveWindowSize = saveWindowSize;
00973 
00974     if (!saveWindowSize && d->sizeTimer) {
00975         d->sizeTimer->stop();
00976     }
00977 
00978     // Now read the previously saved settings
00979     applyMainWindowSettings(d->autoSaveGroup);
00980 }
00981 
00982 void KMainWindow::resetAutoSaveSettings()
00983 {
00984     K_D(KMainWindow);
00985     d->autoSaveSettings = false;
00986     if (d->settingsTimer) {
00987         d->settingsTimer->stop();
00988     }
00989 }
00990 
00991 bool KMainWindow::autoSaveSettings() const
00992 {
00993     K_D(const KMainWindow);
00994     return d->autoSaveSettings;
00995 }
00996 
00997 QString KMainWindow::autoSaveGroup() const
00998 {
00999     K_D(const KMainWindow);
01000     return d->autoSaveSettings ? d->autoSaveGroup.name() : QString();
01001 }
01002 
01003 KConfigGroup KMainWindow::autoSaveConfigGroup() const
01004 {
01005     K_D(const KMainWindow);
01006     return d->autoSaveSettings ? d->autoSaveGroup : KConfigGroup();
01007 }
01008 
01009 void KMainWindow::saveAutoSaveSettings()
01010 {
01011     K_D(KMainWindow);
01012     Q_ASSERT( d->autoSaveSettings );
01013     //kDebug(200) << "KMainWindow::saveAutoSaveSettings -> saving settings";
01014     saveMainWindowSettings(d->autoSaveGroup);
01015     d->autoSaveGroup.sync();
01016     d->settingsDirty = false;
01017 }
01018 
01019 bool KMainWindow::event( QEvent* ev )
01020 {
01021     K_D(KMainWindow);
01022     switch( ev->type() ) {
01023 #ifdef Q_WS_WIN
01024     case QEvent::Move:
01025 #endif
01026     case QEvent::Resize:
01027         d->setSizeDirty();
01028         break;
01029     case QEvent::Polish:
01030         d->polish(this);
01031         break;
01032     case QEvent::ChildPolished:
01033         {
01034             QChildEvent *event = static_cast<QChildEvent*>(ev);
01035             QDockWidget *dock = qobject_cast<QDockWidget*>(event->child());
01036             KToolBar *toolbar = qobject_cast<KToolBar*>(event->child());
01037             QMenuBar *menubar = qobject_cast<QMenuBar*>(event->child());
01038             if (dock) {
01039                 connect(dock, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)),
01040                         this, SLOT(setSettingsDirty()));
01041                 connect(dock, SIGNAL(visibilityChanged(bool)),
01042                         this, SLOT(setSettingsDirty()), Qt::QueuedConnection);
01043                 connect(dock, SIGNAL(topLevelChanged(bool)),
01044                         this, SLOT(setSettingsDirty()));
01045 
01046                 // there is no signal emitted if the size of the dock changes,
01047                 // hence install an event filter instead
01048                 dock->installEventFilter(k_ptr->dockResizeListener);
01049             } else if (toolbar) {
01050                 // there is no signal emitted if the size of the toolbar changes,
01051                 // hence install an event filter instead
01052                 toolbar->installEventFilter(k_ptr->dockResizeListener);
01053             } else if (menubar) {
01054                 // there is no signal emitted if the size of the menubar changes,
01055                 // hence install an event filter instead
01056                 menubar->installEventFilter(k_ptr->dockResizeListener);
01057             }
01058         }
01059         break;
01060     case QEvent::ChildRemoved:
01061         {
01062             QChildEvent *event = static_cast<QChildEvent*>(ev);
01063             QDockWidget *dock = qobject_cast<QDockWidget*>(event->child());
01064             KToolBar *toolbar = qobject_cast<KToolBar*>(event->child());
01065             QMenuBar *menubar = qobject_cast<QMenuBar*>(event->child());
01066             if (dock) {
01067                 disconnect(dock, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)),
01068                            this, SLOT(setSettingsDirty()));
01069                 disconnect(dock, SIGNAL(visibilityChanged(bool)),
01070                            this, SLOT(setSettingsDirty()));
01071                 disconnect(dock, SIGNAL(topLevelChanged(bool)),
01072                            this, SLOT(setSettingsDirty()));
01073                 dock->removeEventFilter(k_ptr->dockResizeListener);
01074             } else if (toolbar) {
01075                 toolbar->removeEventFilter(k_ptr->dockResizeListener);
01076             } else if (menubar) {
01077                 menubar->removeEventFilter(k_ptr->dockResizeListener);
01078             }
01079         }
01080         break;
01081     default:
01082         break;
01083     }
01084     return QMainWindow::event( ev );
01085 }
01086 
01087 bool KMainWindow::hasMenuBar()
01088 {
01089     return internalMenuBar(this);
01090 }
01091 
01092 KMenuBar *KMainWindow::menuBar()
01093 {
01094     KMenuBar * mb = internalMenuBar(this);
01095     if ( !mb ) {
01096         mb = new KMenuBar( this );
01097         // trigger a re-layout and trigger a call to the private
01098         // setMenuBar method.
01099         setMenuBar(mb);
01100     }
01101     return mb;
01102 }
01103 
01104 KStatusBar *KMainWindow::statusBar()
01105 {
01106     KStatusBar * sb = internalStatusBar(this);
01107     if ( !sb ) {
01108         sb = new KStatusBar( this );
01109         // trigger a re-layout and trigger a call to the private
01110         // setStatusBar method.
01111         setStatusBar(sb);
01112     }
01113     return sb;
01114 }
01115 
01116 void KMainWindowPrivate::_k_shuttingDown()
01117 {
01118     // Needed for Qt <= 3.0.3 at least to prevent reentrancy
01119     // when queryExit() shows a dialog. Check before removing!
01120     static bool reentrancy_protection = false;
01121     if (!reentrancy_protection)
01122     {
01123        reentrancy_protection = true;
01124        shuttingDown = true;
01125        // call the virtual queryExit
01126        q->queryExit();
01127        reentrancy_protection = false;
01128     }
01129 }
01130 
01131 void KMainWindowPrivate::_k_slotSettingsChanged(int category)
01132 {
01133     Q_UNUSED(category);
01134 
01135     // This slot will be called when the style KCM changes settings that need
01136     // to be set on the already running applications.
01137 
01138     // At this level (KMainWindow) the only thing we need to restore is the
01139     // animations setting (whether the user wants builtin animations or not).
01140 
01141     q->setAnimated(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects);
01142 }
01143 
01144 void KMainWindowPrivate::_k_slotSaveAutoSaveSize()
01145 {
01146     if (autoSaveGroup.isValid()) {
01147         q->saveWindowSize(autoSaveGroup);
01148     }
01149 }
01150 
01151 KToolBar *KMainWindow::toolBar( const QString& name )
01152 {
01153     QString childName = name;
01154     if (childName.isEmpty())
01155        childName = "mainToolBar";
01156 
01157     KToolBar *tb = findChild<KToolBar*>(childName);
01158     if ( tb )
01159         return tb;
01160 
01161     KToolBar* toolbar = new KToolBar(childName, this); // non-XMLGUI toolbar
01162     return toolbar;
01163 }
01164 
01165 QList<KToolBar*> KMainWindow::toolBars() const
01166 {
01167     QList<KToolBar*> ret;
01168 
01169     foreach (QObject* child, children())
01170         if (KToolBar* toolBar = qobject_cast<KToolBar*>(child))
01171             ret.append(toolBar);
01172 
01173     return ret;
01174 }
01175 
01176 QList<KMainWindow*> KMainWindow::memberList() { return *sMemberList; }
01177 
01178 QString KMainWindow::dbusName() const
01179 {
01180     return k_func()->dbusName;
01181 }
01182 
01183 #include "kmainwindow.moc"
01184 

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal