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(parentWidget()); 00836 QRect desk = QApplication::desktop()->screenGeometry(scnum); 00837 00838 // if the desktop is virtual then use virtual screen size 00839 if (QApplication::desktop()->isVirtualDesktop()) 00840 desk = QApplication::desktop()->screenGeometry(QApplication::desktop()->screen()); 00841 00842 QString geometryKey = QString::fromLatin1("geometry-%1-%2").arg(desk.width()).arg(desk.height()); 00843 QByteArray geometry = _cg.readEntry( geometryKey, QByteArray() ); 00844 // if first time run, center window 00845 if (!restoreGeometry( QByteArray::fromBase64(geometry) )) 00846 move( (desk.width()-width())/2, (desk.height()-height())/2 ); 00847 } 00848 00849 void KMainWindow::saveWindowSize( const KConfigGroup & _cg ) const 00850 { 00851 K_D(const KMainWindow); 00852 int scnum = QApplication::desktop()->screenNumber(parentWidget()); 00853 QRect desk = QApplication::desktop()->screenGeometry(scnum); 00854 00855 // if the desktop is virtual then use virtual screen size 00856 if (QApplication::desktop()->isVirtualDesktop()) 00857 desk = QApplication::desktop()->screenGeometry(QApplication::desktop()->screen()); 00858 00859 // geometry is saved separately for each resolution 00860 QString geometryKey = QString::fromLatin1("geometry-%1-%2").arg(desk.width()).arg(desk.height()); 00861 QByteArray geometry = saveGeometry(); 00862 KConfigGroup cg(_cg); 00863 cg.writeEntry( geometryKey, geometry.toBase64() ); 00864 } 00865 #else 00866 void KMainWindow::saveWindowSize( const KConfigGroup & _cg ) const 00867 { 00868 K_D(const KMainWindow); 00869 int scnum = QApplication::desktop()->screenNumber(parentWidget()); 00870 QRect desk = QApplication::desktop()->screenGeometry(scnum); 00871 00872 // if the desktop is virtual then use virtual screen size 00873 if (QApplication::desktop()->isVirtualDesktop()) 00874 desk = QApplication::desktop()->screenGeometry(QApplication::desktop()->screen()); 00875 00876 int w, h; 00877 #if defined Q_WS_X11 00878 // save maximalization as desktop size + 1 in that direction 00879 KWindowInfo info = KWindowSystem::windowInfo( winId(), NET::WMState ); 00880 w = info.state() & NET::MaxHoriz ? desk.width() + 1 : width(); 00881 h = info.state() & NET::MaxVert ? desk.height() + 1 : height(); 00882 #else 00883 if (isMaximized()) { 00884 w = desk.width() + 1; 00885 h = desk.height() + 1; 00886 } else { 00887 w = width(); 00888 h = height(); 00889 } 00890 //TODO: add "Maximized" property instead "+1" hack 00891 #endif 00892 KConfigGroup cg(_cg); 00893 00894 QRect size( desk.width(), w, desk.height(), h ); 00895 bool defaultSize = (size == d->defaultWindowSize); 00896 QString widthString = QString::fromLatin1("Width %1").arg(desk.width()); 00897 QString heightString = QString::fromLatin1("Height %1").arg(desk.height()); 00898 if (!cg.hasDefault(widthString) && defaultSize) 00899 cg.revertToDefault(widthString); 00900 else 00901 cg.writeEntry(widthString, w ); 00902 00903 if (!cg.hasDefault(heightString) && defaultSize) 00904 cg.revertToDefault(heightString); 00905 else 00906 cg.writeEntry(heightString, h ); 00907 } 00908 00909 void KMainWindow::restoreWindowSize( const KConfigGroup & config ) 00910 { 00911 K_D(KMainWindow); 00912 if (d->care_about_geometry) { 00913 parseGeometry(true); 00914 } else { 00915 // restore the size 00916 const int scnum = QApplication::desktop()->screenNumber(parentWidget()); 00917 QRect desk = QApplication::desktop()->screenGeometry(scnum); 00918 00919 // if the desktop is virtual then use virtual screen size 00920 if (QApplication::desktop()->isVirtualDesktop()) 00921 desk = QApplication::desktop()->screenGeometry(QApplication::desktop()->screen()); 00922 00923 if ( d->defaultWindowSize.isNull() ) // only once 00924 d->defaultWindowSize = QRect(desk.width(), width(), desk.height(), height()); // store default values 00925 const QSize size( config.readEntry( QString::fromLatin1("Width %1").arg(desk.width()), 0 ), 00926 config.readEntry( QString::fromLatin1("Height %1").arg(desk.height()), 0 ) ); 00927 if ( !size.isEmpty() ) { 00928 #ifdef Q_WS_X11 00929 int state = ( size.width() > desk.width() ? NET::MaxHoriz : 0 ) 00930 | ( size.height() > desk.height() ? NET::MaxVert : 0 ); 00931 if(( state & NET::Max ) == NET::Max ) 00932 resize( desk.width(), desk.height() ); // WORKAROUND: this should not be needed. KWindowSystem::setState 00933 // should be enough for maximizing. (ereslibre) 00934 else if(( state & NET::MaxHoriz ) == NET::MaxHoriz ) 00935 resize( desk.width(), size.height() ); 00936 else if(( state & NET::MaxVert ) == NET::MaxVert ) 00937 resize( size.width(), desk.height() ); 00938 else 00939 resize( size ); 00940 // QWidget::showMaximized() is both insufficient and broken 00941 KWindowSystem::setState( winId(), state ); 00942 #else 00943 if (size.width() > desk.width() || size.height() > desk.height()) 00944 setWindowState( Qt::WindowMaximized ); 00945 else 00946 resize( size ); 00947 #endif 00948 } 00949 } 00950 } 00951 #endif 00952 00953 bool KMainWindow::initialGeometrySet() const 00954 { 00955 K_D(const KMainWindow); 00956 return d->care_about_geometry; 00957 } 00958 00959 void KMainWindow::ignoreInitialGeometry() 00960 { 00961 K_D(KMainWindow); 00962 d->care_about_geometry = false; 00963 } 00964 00965 void KMainWindow::setSettingsDirty() 00966 { 00967 K_D(KMainWindow); 00968 d->setSettingsDirty(); 00969 } 00970 00971 bool KMainWindow::settingsDirty() const 00972 { 00973 K_D(const KMainWindow); 00974 return d->settingsDirty; 00975 } 00976 00977 void KMainWindow::setAutoSaveSettings( const QString & groupName, bool saveWindowSize ) 00978 { 00979 setAutoSaveSettings(KConfigGroup(KGlobal::config(), groupName), saveWindowSize); 00980 } 00981 00982 void KMainWindow::setAutoSaveSettings( const KConfigGroup & group, 00983 bool saveWindowSize ) 00984 { 00985 K_D(KMainWindow); 00986 d->autoSaveSettings = true; 00987 d->autoSaveGroup = group; 00988 d->autoSaveWindowSize = saveWindowSize; 00989 00990 if (!saveWindowSize && d->sizeTimer) { 00991 d->sizeTimer->stop(); 00992 } 00993 00994 // Now read the previously saved settings 00995 applyMainWindowSettings(d->autoSaveGroup); 00996 } 00997 00998 void KMainWindow::resetAutoSaveSettings() 00999 { 01000 K_D(KMainWindow); 01001 d->autoSaveSettings = false; 01002 if (d->settingsTimer) { 01003 d->settingsTimer->stop(); 01004 } 01005 } 01006 01007 bool KMainWindow::autoSaveSettings() const 01008 { 01009 K_D(const KMainWindow); 01010 return d->autoSaveSettings; 01011 } 01012 01013 QString KMainWindow::autoSaveGroup() const 01014 { 01015 K_D(const KMainWindow); 01016 return d->autoSaveSettings ? d->autoSaveGroup.name() : QString(); 01017 } 01018 01019 KConfigGroup KMainWindow::autoSaveConfigGroup() const 01020 { 01021 K_D(const KMainWindow); 01022 return d->autoSaveSettings ? d->autoSaveGroup : KConfigGroup(); 01023 } 01024 01025 void KMainWindow::saveAutoSaveSettings() 01026 { 01027 K_D(KMainWindow); 01028 Q_ASSERT( d->autoSaveSettings ); 01029 //kDebug(200) << "KMainWindow::saveAutoSaveSettings -> saving settings"; 01030 saveMainWindowSettings(d->autoSaveGroup); 01031 d->autoSaveGroup.sync(); 01032 d->settingsDirty = false; 01033 } 01034 01035 bool KMainWindow::event( QEvent* ev ) 01036 { 01037 K_D(KMainWindow); 01038 switch( ev->type() ) { 01039 #ifdef Q_WS_WIN 01040 case QEvent::Move: 01041 #endif 01042 case QEvent::Resize: 01043 d->setSizeDirty(); 01044 break; 01045 case QEvent::Polish: 01046 d->polish(this); 01047 break; 01048 case QEvent::ChildPolished: 01049 { 01050 QChildEvent *event = static_cast<QChildEvent*>(ev); 01051 QDockWidget *dock = qobject_cast<QDockWidget*>(event->child()); 01052 KToolBar *toolbar = qobject_cast<KToolBar*>(event->child()); 01053 QMenuBar *menubar = qobject_cast<QMenuBar*>(event->child()); 01054 if (dock) { 01055 connect(dock, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), 01056 this, SLOT(setSettingsDirty())); 01057 connect(dock, SIGNAL(visibilityChanged(bool)), 01058 this, SLOT(setSettingsDirty()), Qt::QueuedConnection); 01059 connect(dock, SIGNAL(topLevelChanged(bool)), 01060 this, SLOT(setSettingsDirty())); 01061 01062 // there is no signal emitted if the size of the dock changes, 01063 // hence install an event filter instead 01064 dock->installEventFilter(k_ptr->dockResizeListener); 01065 } else if (toolbar) { 01066 // there is no signal emitted if the size of the toolbar changes, 01067 // hence install an event filter instead 01068 toolbar->installEventFilter(k_ptr->dockResizeListener); 01069 } else if (menubar) { 01070 // there is no signal emitted if the size of the menubar changes, 01071 // hence install an event filter instead 01072 menubar->installEventFilter(k_ptr->dockResizeListener); 01073 } 01074 } 01075 break; 01076 case QEvent::ChildRemoved: 01077 { 01078 QChildEvent *event = static_cast<QChildEvent*>(ev); 01079 QDockWidget *dock = qobject_cast<QDockWidget*>(event->child()); 01080 KToolBar *toolbar = qobject_cast<KToolBar*>(event->child()); 01081 QMenuBar *menubar = qobject_cast<QMenuBar*>(event->child()); 01082 if (dock) { 01083 disconnect(dock, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), 01084 this, SLOT(setSettingsDirty())); 01085 disconnect(dock, SIGNAL(visibilityChanged(bool)), 01086 this, SLOT(setSettingsDirty())); 01087 disconnect(dock, SIGNAL(topLevelChanged(bool)), 01088 this, SLOT(setSettingsDirty())); 01089 dock->removeEventFilter(k_ptr->dockResizeListener); 01090 } else if (toolbar) { 01091 toolbar->removeEventFilter(k_ptr->dockResizeListener); 01092 } else if (menubar) { 01093 menubar->removeEventFilter(k_ptr->dockResizeListener); 01094 } 01095 } 01096 break; 01097 default: 01098 break; 01099 } 01100 return QMainWindow::event( ev ); 01101 } 01102 01103 bool KMainWindow::hasMenuBar() 01104 { 01105 return internalMenuBar(this); 01106 } 01107 01108 KMenuBar *KMainWindow::menuBar() 01109 { 01110 KMenuBar * mb = internalMenuBar(this); 01111 if ( !mb ) { 01112 mb = new KMenuBar( this ); 01113 // trigger a re-layout and trigger a call to the private 01114 // setMenuBar method. 01115 setMenuBar(mb); 01116 } 01117 return mb; 01118 } 01119 01120 KStatusBar *KMainWindow::statusBar() 01121 { 01122 KStatusBar * sb = internalStatusBar(this); 01123 if ( !sb ) { 01124 sb = new KStatusBar( this ); 01125 // trigger a re-layout and trigger a call to the private 01126 // setStatusBar method. 01127 setStatusBar(sb); 01128 } 01129 return sb; 01130 } 01131 01132 void KMainWindowPrivate::_k_shuttingDown() 01133 { 01134 // Needed for Qt <= 3.0.3 at least to prevent reentrancy 01135 // when queryExit() shows a dialog. Check before removing! 01136 static bool reentrancy_protection = false; 01137 if (!reentrancy_protection) 01138 { 01139 reentrancy_protection = true; 01140 shuttingDown = true; 01141 // call the virtual queryExit 01142 q->queryExit(); 01143 reentrancy_protection = false; 01144 } 01145 } 01146 01147 void KMainWindowPrivate::_k_slotSettingsChanged(int category) 01148 { 01149 Q_UNUSED(category); 01150 01151 // This slot will be called when the style KCM changes settings that need 01152 // to be set on the already running applications. 01153 01154 // At this level (KMainWindow) the only thing we need to restore is the 01155 // animations setting (whether the user wants builtin animations or not). 01156 01157 q->setAnimated(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects); 01158 } 01159 01160 void KMainWindowPrivate::_k_slotSaveAutoSaveSize() 01161 { 01162 if (autoSaveGroup.isValid()) { 01163 q->saveWindowSize(autoSaveGroup); 01164 } 01165 } 01166 01167 KToolBar *KMainWindow::toolBar( const QString& name ) 01168 { 01169 QString childName = name; 01170 if (childName.isEmpty()) 01171 childName = "mainToolBar"; 01172 01173 KToolBar *tb = findChild<KToolBar*>(childName); 01174 if ( tb ) 01175 return tb; 01176 01177 KToolBar* toolbar = new KToolBar(childName, this); // non-XMLGUI toolbar 01178 return toolbar; 01179 } 01180 01181 QList<KToolBar*> KMainWindow::toolBars() const 01182 { 01183 QList<KToolBar*> ret; 01184 01185 foreach (QObject* child, children()) 01186 if (KToolBar* toolBar = qobject_cast<KToolBar*>(child)) 01187 ret.append(toolBar); 01188 01189 return ret; 01190 } 01191 01192 QList<KMainWindow*> KMainWindow::memberList() { return *sMemberList; } 01193 01194 QString KMainWindow::dbusName() const 01195 { 01196 return k_func()->dbusName; 01197 } 01198 01199 #include "kmainwindow.moc" 01200
KDE 4.6 API Reference