kmainwindow.cpp
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 00010 This library is free software; you can redistribute it and/or 00011 modify it under the terms of the GNU Library General Public 00012 License version 2 as published by the Free Software Foundation. 00013 00014 This library is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 Library General Public License for more details. 00018 00019 You should have received a copy of the GNU Library General Public License 00020 along with this library; see the file COPYING.LIB. If not, write to 00021 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00022 Boston, MA 02110-1301, USA. 00023 */ 00024 #include "config.h" 00025 00026 #include "kmainwindow.h" 00027 #include "kmainwindowiface.h" 00028 #include "ktoolbarhandler.h" 00029 #include "kwhatsthismanager_p.h" 00030 #include <qsessionmanager.h> 00031 #include <qobjectlist.h> 00032 #include <qstyle.h> 00033 #include <qlayout.h> 00034 #include <qwidgetlist.h> 00035 #include <qtimer.h> 00036 00037 #include <kaccel.h> 00038 #include <kaction.h> 00039 #include <kapplication.h> 00040 #include <kconfig.h> 00041 #include <kdebug.h> 00042 #include <khelpmenu.h> 00043 #include <kmenubar.h> 00044 #include <kstatusbar.h> 00045 #include <kwin.h> 00046 #include <kedittoolbar.h> 00047 #include <kmainwindow.h> 00048 00049 #include <klocale.h> 00050 #include <kstandarddirs.h> 00051 #include <kstaticdeleter.h> 00052 #if defined Q_WS_X11 00053 #include <netwm.h> 00054 #endif 00055 00056 #include <stdlib.h> 00057 #include <ctype.h> 00058 #include <assert.h> 00059 00060 class KMainWindowPrivate { 00061 public: 00062 bool showHelpMenu:1; 00063 00064 bool autoSaveSettings:1; 00065 bool settingsDirty:1; 00066 bool autoSaveWindowSize:1; 00067 bool care_about_geometry:1; 00068 bool shuttingDown:1; 00069 QString autoSaveGroup; 00070 KAccel * kaccel; 00071 KMainWindowInterface *m_interface; 00072 KDEPrivate::ToolBarHandler *toolBarHandler; 00073 QTimer* settingsTimer; 00074 KToggleAction *showStatusBarAction; 00075 QRect defaultWindowSize; 00076 QPtrList<QDockWindow> hiddenDockWindows; 00077 }; 00078 00079 QPtrList<KMainWindow>* KMainWindow::memberList = 0L; 00080 static bool no_query_exit = false; 00081 static KMWSessionManaged* ksm = 0; 00082 static KStaticDeleter<KMWSessionManaged> ksmd; 00083 00084 class KMWSessionManaged : public KSessionManaged 00085 { 00086 public: 00087 KMWSessionManaged() 00088 { 00089 } 00090 ~KMWSessionManaged() 00091 { 00092 } 00093 bool saveState( QSessionManager& ) 00094 { 00095 KConfig* config = KApplication::kApplication()->sessionConfig(); 00096 if ( KMainWindow::memberList->first() ){ 00097 // According to Jochen Wilhelmy <digisnap@cs.tu-berlin.de>, this 00098 // hook is useful for better document orientation 00099 KMainWindow::memberList->first()->saveGlobalProperties(config); 00100 } 00101 00102 QPtrListIterator<KMainWindow> it(*KMainWindow::memberList); 00103 int n = 0; 00104 for (it.toFirst(); it.current(); ++it){ 00105 n++; 00106 it.current()->savePropertiesInternal(config, n); 00107 } 00108 config->setGroup(QString::fromLatin1("Number")); 00109 config->writeEntry(QString::fromLatin1("NumberOfWindows"), n ); 00110 return true; 00111 } 00112 00113 bool commitData( QSessionManager& sm ) 00114 { 00115 // not really a fast method but the only compatible one 00116 if ( sm.allowsInteraction() ) { 00117 bool canceled = false; 00118 QPtrListIterator<KMainWindow> it(*KMainWindow::memberList); 00119 ::no_query_exit = true; 00120 for (it.toFirst(); it.current() && !canceled;){ 00121 KMainWindow *window = *it; 00122 ++it; // Update now, the current window might get deleted 00123 if ( !window->testWState( Qt::WState_ForceHide ) ) { 00124 QCloseEvent e; 00125 QApplication::sendEvent( window, &e ); 00126 canceled = !e.isAccepted(); 00127 /* Don't even think_about deleting widgets with 00128 Qt::WDestructiveClose flag set at this point. We 00129 are faking a close event, but we are *not*_ 00130 closing the window. The purpose of the faked 00131 close event is to prepare the application so it 00132 can safely be quit without the user losing data 00133 (possibly showing a message box "do you want to 00134 save this or that?"). It is possible that the 00135 session manager quits the application later 00136 (emitting QApplication::aboutToQuit() when this 00137 happens), but it is also possible that the user 00138 cancels the shutdown, so the application will 00139 continue to run. 00140 */ 00141 } 00142 } 00143 ::no_query_exit = false; 00144 if (canceled) 00145 return false; 00146 00147 KMainWindow* last = 0; 00148 for (it.toFirst(); it.current() && !canceled; ++it){ 00149 KMainWindow *window = *it; 00150 if ( !window->testWState( Qt::WState_ForceHide ) ) { 00151 last = window; 00152 } 00153 } 00154 if ( last ) 00155 return last->queryExit(); 00156 // else 00157 return true; 00158 } 00159 00160 // the user wants it, the user gets it 00161 return true; 00162 } 00163 }; 00164 00165 static bool being_first = true; 00166 00167 KMainWindow::KMainWindow( QWidget* parent, const char *name, WFlags f ) 00168 : QMainWindow( parent, name, f ), KXMLGUIBuilder( this ), helpMenu2( 0 ), factory_( 0 ) 00169 { 00170 initKMainWindow(name, 0); 00171 } 00172 00173 KMainWindow::KMainWindow( int cflags, QWidget* parent, const char *name, WFlags f ) 00174 : QMainWindow( parent, name, f ), KXMLGUIBuilder( this ), helpMenu2( 0 ), factory_( 0 ) 00175 { 00176 initKMainWindow(name, cflags); 00177 } 00178 00179 void KMainWindow::initKMainWindow(const char *name, int cflags) 00180 { 00181 KWhatsThisManager::init (); 00182 setDockMenuEnabled( false ); 00183 mHelpMenu = 0; 00184 kapp->setTopWidget( this ); 00185 actionCollection()->setWidget( this ); 00186 connect(kapp, SIGNAL(shutDown()), this, SLOT(shuttingDown())); 00187 if( !memberList ) 00188 memberList = new QPtrList<KMainWindow>; 00189 00190 if ( !ksm ) 00191 ksm = ksmd.setObject(ksm, new KMWSessionManaged()); 00192 // set a unique object name. Required by session management. 00193 QCString objname; 00194 QCString s; 00195 int unusedNumber; 00196 if ( !name ) 00197 { // no name given 00198 objname = kapp->instanceName() + "-mainwindow#"; 00199 s = objname + '1'; // start adding number immediately 00200 unusedNumber = 1; 00201 } 00202 else if( name[0] != '\0' && name[ strlen( name ) - 1 ] == '#' ) 00203 { // trailing # - always add a number 00204 objname = name; 00205 s = objname + '1'; // start adding number immediately 00206 unusedNumber = 1; 00207 } 00208 else 00209 { 00210 objname = name; 00211 s = objname; 00212 unusedNumber = 0; // add numbers only when needed 00213 } 00214 for(;;) { 00215 QWidgetList* list = kapp->topLevelWidgets(); 00216 QWidgetListIt it( *list ); 00217 bool found = false; 00218 for( QWidget* w = it.current(); 00219 w != NULL; 00220 ++it, w = it.current()) 00221 if( w != this && w->name() == s ) 00222 { 00223 found = true; 00224 break; 00225 } 00226 delete list; 00227 if( !found ) 00228 break; 00229 s.setNum( ++unusedNumber ); 00230 s = objname + s; 00231 } 00232 setName( s ); 00233 00234 memberList->append( this ); 00235 00236 d = new KMainWindowPrivate; 00237 d->showHelpMenu = true; 00238 d->settingsDirty = false; 00239 d->autoSaveSettings = false; 00240 d->autoSaveWindowSize = true; // for compatibility 00241 d->kaccel = actionCollection()->kaccel(); 00242 d->toolBarHandler = 0; 00243 d->settingsTimer = 0; 00244 d->showStatusBarAction = NULL; 00245 d->shuttingDown = false; 00246 if ((d->care_about_geometry = being_first)) { 00247 being_first = false; 00248 if ( kapp->geometryArgument().isNull() ) // if there is no geometry, it doesn't mater 00249 d->care_about_geometry = false; 00250 else 00251 parseGeometry(false); 00252 } 00253 00254 setCaption( kapp->caption() ); 00255 if ( cflags & NoDCOPObject) 00256 d->m_interface = 0; 00257 else 00258 d->m_interface = new KMainWindowInterface(this); 00259 00260 if (!kapp->authorize("movable_toolbars")) 00261 setDockWindowsMovable(false); 00262 } 00263 00264 KAction *KMainWindow::toolBarMenuAction() 00265 { 00266 if ( !d->toolBarHandler ) 00267 return 0; 00268 00269 return d->toolBarHandler->toolBarMenuAction(); 00270 } 00271 00272 00273 void KMainWindow::setupToolbarMenuActions() 00274 { 00275 if ( d->toolBarHandler ) 00276 d->toolBarHandler->setupActions(); 00277 } 00278 00279 void KMainWindow::parseGeometry(bool parsewidth) 00280 { 00281 assert ( !kapp->geometryArgument().isNull() ); 00282 assert ( d->care_about_geometry ); 00283 00284 #if defined Q_WS_X11 00285 int x, y; 00286 int w, h; 00287 int m = XParseGeometry( kapp->geometryArgument().latin1(), &x, &y, (unsigned int*)&w, (unsigned int*)&h); 00288 if (parsewidth) { 00289 QSize minSize = minimumSize(); 00290 QSize maxSize = maximumSize(); 00291 if ( !(m & WidthValue) ) 00292 w = width(); 00293 if ( !(m & HeightValue) ) 00294 h = height(); 00295 w = QMIN(w,maxSize.width()); 00296 h = QMIN(h,maxSize.height()); 00297 w = QMAX(w,minSize.width()); 00298 h = QMAX(h,minSize.height()); 00299 resize(w, h); 00300 } else { 00301 if ( parsewidth && !(m & XValue) ) 00302 x = geometry().x(); 00303 if ( parsewidth && !(m & YValue) ) 00304 y = geometry().y(); 00305 if ( (m & XNegative) ) 00306 x = KApplication::desktop()->width() + x - w; 00307 if ( (m & YNegative) ) 00308 y = KApplication::desktop()->height() + y - h; 00309 move(x, y); 00310 } 00311 #endif 00312 } 00313 00314 KMainWindow::~KMainWindow() 00315 { 00316 delete d->settingsTimer; 00317 QMenuBar* mb = internalMenuBar(); 00318 delete mb; 00319 delete d->m_interface; 00320 delete d; 00321 memberList->remove( this ); 00322 } 00323 00324 KPopupMenu* KMainWindow::helpMenu( const QString &aboutAppText, bool showWhatsThis ) 00325 { 00326 if( !mHelpMenu ) { 00327 if ( aboutAppText.isEmpty() ) 00328 mHelpMenu = new KHelpMenu( this, instance()->aboutData(), showWhatsThis); 00329 else 00330 mHelpMenu = new KHelpMenu( this, aboutAppText, showWhatsThis ); 00331 00332 if ( !mHelpMenu ) 00333 return 0; 00334 connect( mHelpMenu, SIGNAL( showAboutApplication() ), 00335 this, SLOT( showAboutApplication() ) ); 00336 } 00337 00338 return mHelpMenu->menu(); 00339 } 00340 00341 KPopupMenu* KMainWindow::customHelpMenu( bool showWhatsThis ) 00342 { 00343 if( !mHelpMenu ) { 00344 mHelpMenu = new KHelpMenu( this, QString::null, showWhatsThis ); 00345 connect( mHelpMenu, SIGNAL( showAboutApplication() ), 00346 this, SLOT( showAboutApplication() ) ); 00347 } 00348 00349 return mHelpMenu->menu(); 00350 } 00351 00352 bool KMainWindow::canBeRestored( int number ) 00353 { 00354 if ( !kapp->isRestored() ) 00355 return false; 00356 KConfig *config = kapp->sessionConfig(); 00357 if ( !config ) 00358 return false; 00359 config->setGroup( QString::fromLatin1("Number") ); 00360 int n = config->readNumEntry( QString::fromLatin1("NumberOfWindows") , 1 ); 00361 return number >= 1 && number <= n; 00362 } 00363 00364 const QString KMainWindow::classNameOfToplevel( int number ) 00365 { 00366 if ( !kapp->isRestored() ) 00367 return QString::null; 00368 KConfig *config = kapp->sessionConfig(); 00369 if ( !config ) 00370 return QString::null; 00371 QString s; 00372 s.setNum( number ); 00373 s.prepend( QString::fromLatin1("WindowProperties") ); 00374 config->setGroup( s ); 00375 if ( !config->hasKey( QString::fromLatin1("ClassName") ) ) 00376 return QString::null; 00377 else 00378 return config->readEntry( QString::fromLatin1("ClassName") ); 00379 } 00380 00381 void KMainWindow::show() 00382 { 00383 QMainWindow::show(); 00384 00385 for ( QPtrListIterator<QDockWindow> it( d->hiddenDockWindows ); it.current(); ++it ) 00386 it.current()->show(); 00387 00388 d->hiddenDockWindows.clear(); 00389 } 00390 00391 void KMainWindow::hide() 00392 { 00393 if ( isVisible() ) { 00394 00395 d->hiddenDockWindows.clear(); 00396 00397 QObjectList *list = queryList( "QDockWindow" ); 00398 for( QObjectListIt it( *list ); it.current(); ++it ) { 00399 QDockWindow *dw = (QDockWindow*)it.current(); 00400 if ( dw->isTopLevel() && dw->isVisible() ) { 00401 d->hiddenDockWindows.append( dw ); 00402 dw->hide(); 00403 } 00404 } 00405 delete list; 00406 } 00407 00408 QWidget::hide(); 00409 } 00410 00411 bool KMainWindow::restore( int number, bool show ) 00412 { 00413 if ( !canBeRestored( number ) ) 00414 return false; 00415 KConfig *config = kapp->sessionConfig(); 00416 if ( readPropertiesInternal( config, number ) ){ 00417 if ( show ) 00418 KMainWindow::show(); 00419 return false; 00420 } 00421 return false; 00422 } 00423 00424 KXMLGUIFactory *KMainWindow::guiFactory() 00425 { 00426 if ( !factory_ ) 00427 factory_ = new KXMLGUIFactory( this, this, "guifactory" ); 00428 return factory_; 00429 } 00430 00431 int KMainWindow::configureToolbars() 00432 { 00433 saveMainWindowSettings(KGlobal::config()); 00434 KEditToolbar dlg(actionCollection(), xmlFile(), true, this); 00435 connect(&dlg, SIGNAL(newToolbarConfig()), SLOT(saveNewToolbarConfig())); 00436 return dlg.exec(); 00437 } 00438 00439 void KMainWindow::saveNewToolbarConfig() 00440 { 00441 createGUI(xmlFile()); 00442 applyMainWindowSettings( KGlobal::config() ); 00443 } 00444 00445 void KMainWindow::setupGUI( int options, const QString & xmlfile ) { 00446 setupGUI(QSize(), options, xmlfile); 00447 } 00448 00449 void KMainWindow::setupGUI( QSize defaultSize, int options, const QString & xmlfile ) { 00450 if( options & Keys ){ 00451 KStdAction::keyBindings(guiFactory(), 00452 SLOT(configureShortcuts()), actionCollection()); 00453 } 00454 00455 if( (options & StatusBar) && internalStatusBar() ){ 00456 createStandardStatusBarAction(); 00457 } 00458 00459 if( options & ToolBar ){ 00460 setStandardToolBarMenuEnabled( true ); 00461 KStdAction::configureToolbars(this, 00462 SLOT(configureToolbars() ), actionCollection()); 00463 } 00464 00465 if( options & Create ){ 00466 createGUI(xmlfile,false); 00467 } 00468 00469 if( options & Save ){ 00470 // setupGUI() is typically called in the constructor before show(), 00471 // so the default window size will be incorrect unless the application 00472 // hard coded the size which they should try not to do (i.e. use 00473 // size hints). 00474 if(initialGeometrySet()) 00475 { 00476 // Do nothing... 00477 } 00478 else if(defaultSize.isValid()) 00479 { 00480 resize(defaultSize); 00481 } 00482 else if(!isShown()) 00483 { 00484 adjustSize(); 00485 } 00486 setAutoSaveSettings(); 00487 } 00488 00489 } 00490 00491 void KMainWindow::createGUI( const QString &xmlfile, bool _conserveMemory ) 00492 { 00493 // disabling the updates prevents unnecessary redraws 00494 setUpdatesEnabled( false ); 00495 00496 // just in case we are rebuilding, let's remove our old client 00497 guiFactory()->removeClient( this ); 00498 00499 // make sure to have an empty GUI 00500 QMenuBar* mb = internalMenuBar(); 00501 if ( mb ) 00502 mb->clear(); 00503 00504 (void)toolBarIterator(); // make sure toolbarList is most-up-to-date 00505 toolbarList.setAutoDelete( true ); 00506 toolbarList.clear(); 00507 toolbarList.setAutoDelete( false ); 00508 00509 // don't build a help menu unless the user ask for it 00510 if (d->showHelpMenu) { 00511 // we always want a help menu 00512 if (!helpMenu2) 00513 helpMenu2 = new KHelpMenu(this, instance()->aboutData(), true, 00514 actionCollection()); 00515 } 00516 00517 // we always want to load in our global standards file 00518 setXMLFile( locate( "config", "ui/ui_standards.rc", instance() ) ); 00519 00520 // now, merge in our local xml file. if this is null, then that 00521 // means that we will be only using the global file 00522 if ( !xmlfile.isNull() ) { 00523 setXMLFile( xmlfile, true ); 00524 } else { 00525 QString auto_file(instance()->instanceName() + "ui.rc"); 00526 setXMLFile( auto_file, true ); 00527 } 00528 00529 // make sure we don't have any state saved already 00530 setXMLGUIBuildDocument( QDomDocument() ); 00531 00532 // do the actual GUI building 00533 guiFactory()->addClient( this ); 00534 00535 // try and get back *some* of our memory 00536 if ( _conserveMemory ) 00537 { 00538 // before freeing the memory allocated by the DOM document we also 00539 // free all memory allocated internally in the KXMLGUIFactory for 00540 // the menubar and the toolbars . This however implies that we 00541 // have to take care of deleting those widgets ourselves. For 00542 // destruction this is no problem, but when rebuilding we have 00543 // to take care of that (and we want to rebuild the GUI when 00544 // using stuff like the toolbar editor ). 00545 // In addition we have to take care of not removing containers 00546 // like popupmenus, defined in the XML document. 00547 // this code should probably go into a separate method in KMainWindow. 00548 // there's just one problem: I'm bad in finding names ;-) , so 00549 // I skipped this ;-) 00550 00551 QDomDocument doc = domDocument(); 00552 00553 for( QDomNode n = doc.documentElement().firstChild(); 00554 !n.isNull(); n = n.nextSibling()) 00555 { 00556 QDomElement e = n.toElement(); 00557 00558 if ( e.tagName().lower() == "toolbar" ) 00559 factory_->resetContainer( e.attribute( "name" ) ); 00560 else if ( e.tagName().lower() == "menubar" ) 00561 factory_->resetContainer( e.tagName(), true ); 00562 } 00563 00564 conserveMemory(); 00565 } 00566 00567 setUpdatesEnabled( true ); 00568 updateGeometry(); 00569 } 00570 00571 void KMainWindow::setHelpMenuEnabled(bool showHelpMenu) 00572 { 00573 d->showHelpMenu = showHelpMenu; 00574 } 00575 00576 bool KMainWindow::isHelpMenuEnabled() 00577 { 00578 return d->showHelpMenu; 00579 } 00580 00581 void KMainWindow::setCaption( const QString &caption ) 00582 { 00583 setPlainCaption( kapp->makeStdCaption(caption) ); 00584 } 00585 00586 void KMainWindow::setCaption( const QString &caption, bool modified ) 00587 { 00588 setPlainCaption( kapp->makeStdCaption(caption, true, modified) ); 00589 } 00590 00591 void KMainWindow::setPlainCaption( const QString &caption ) 00592 { 00593 QMainWindow::setCaption( caption ); 00594 #if defined Q_WS_X11 00595 NETWinInfo info( qt_xdisplay(), winId(), qt_xrootwin(), 0 ); 00596 info.setName( caption.utf8().data() ); 00597 #endif 00598 } 00599 00600 void KMainWindow::appHelpActivated( void ) 00601 { 00602 if( !mHelpMenu ) { 00603 mHelpMenu = new KHelpMenu( this ); 00604 if ( !mHelpMenu ) 00605 return; 00606 } 00607 mHelpMenu->appHelpActivated(); 00608 } 00609 00610 void KMainWindow::slotStateChanged(const QString &newstate) 00611 { 00612 stateChanged(newstate, KXMLGUIClient::StateNoReverse); 00613 } 00614 00615 /* 00616 * Get rid of this for KDE 4.0 00617 */ 00618 void KMainWindow::slotStateChanged(const QString &newstate, 00619 KXMLGUIClient::ReverseStateChange reverse) 00620 { 00621 stateChanged(newstate, reverse); 00622 } 00623 00624 /* 00625 * Enable this for KDE 4.0 00626 */ 00627 // void KMainWindow::slotStateChanged(const QString &newstate, 00628 // bool reverse) 00629 // { 00630 // stateChanged(newstate, 00631 // reverse ? KXMLGUIClient::StateReverse : KXMLGUIClient::StateNoReverse); 00632 // } 00633 00634 void KMainWindow::closeEvent ( QCloseEvent *e ) 00635 { 00636 // Save settings if auto-save is enabled, and settings have changed 00637 if (d->settingsDirty && d->autoSaveSettings) 00638 saveAutoSaveSettings(); 00639 00640 if (queryClose()) { 00641 e->accept(); 00642 00643 int not_withdrawn = 0; 00644 QPtrListIterator<KMainWindow> it(*KMainWindow::memberList); 00645 for (it.toFirst(); it.current(); ++it){ 00646 if ( !it.current()->isHidden() && it.current()->isTopLevel() && it.current() != this ) 00647 not_withdrawn++; 00648 } 00649 00650 if ( !no_query_exit && not_withdrawn <= 0 ) { // last window close accepted? 00651 if ( queryExit() && !kapp->sessionSaving() && !d->shuttingDown ) { // Yes, Quit app? 00652 // don't call queryExit() twice 00653 disconnect(kapp, SIGNAL(shutDown()), this, SLOT(shuttingDown())); 00654 d->shuttingDown = true; 00655 kapp->deref(); // ...and quit application. 00656 } else { 00657 // cancel closing, it's stupid to end up with no windows at all.... 00658 e->ignore(); 00659 } 00660 } 00661 } 00662 } 00663 00664 bool KMainWindow::queryExit() 00665 { 00666 return true; 00667 } 00668 00669 bool KMainWindow::queryClose() 00670 { 00671 return true; 00672 } 00673 00674 void KMainWindow::saveGlobalProperties( KConfig* ) 00675 { 00676 } 00677 00678 void KMainWindow::readGlobalProperties( KConfig* ) 00679 { 00680 } 00681 00682 #if defined(KDE_COMPAT) 00683 void KMainWindow::updateRects() 00684 { 00685 } 00686 #endif 00687 00688 void KMainWindow::showAboutApplication() 00689 { 00690 } 00691 00692 void KMainWindow::savePropertiesInternal( KConfig *config, int number ) 00693 { 00694 bool oldASWS = d->autoSaveWindowSize; 00695 d->autoSaveWindowSize = true; // make saveMainWindowSettings save the window size 00696 00697 QString s; 00698 s.setNum(number); 00699 s.prepend(QString::fromLatin1("WindowProperties")); 00700 config->setGroup(s); 00701 00702 // store objectName, className, Width and Height for later restoring 00703 // (Only useful for session management) 00704 config->writeEntry(QString::fromLatin1("ObjectName"), name()); 00705 config->writeEntry(QString::fromLatin1("ClassName"), className()); 00706 00707 saveMainWindowSettings(config); // Menubar, statusbar and Toolbar settings. 00708 00709 s.setNum(number); 00710 config->setGroup(s); 00711 saveProperties(config); 00712 00713 d->autoSaveWindowSize = oldASWS; 00714 } 00715 00716 void KMainWindow::saveMainWindowSettings(KConfig *config, const QString &configGroup) 00717 { 00718 kdDebug(200) << "KMainWindow::saveMainWindowSettings " << configGroup << endl; 00719 QString oldGroup; 00720 00721 if (!configGroup.isEmpty()) 00722 { 00723 oldGroup = config->group(); 00724 config->setGroup(configGroup); 00725 } 00726 00727 // Called by session management - or if we want to save the window size anyway 00728 if ( d->autoSaveWindowSize ) 00729 saveWindowSize( config ); 00730 00731 QStatusBar* sb = internalStatusBar(); 00732 if (sb) { 00733 if(!config->hasDefault("StatusBar") && !sb->isHidden() ) 00734 config->revertToDefault("StatusBar"); 00735 else 00736 config->writeEntry("StatusBar", sb->isHidden() ? "Disabled" : "Enabled"); 00737 } 00738 00739 QMenuBar* mb = internalMenuBar(); 00740 if (mb) { 00741 QString MenuBar = QString::fromLatin1("MenuBar"); 00742 if(!config->hasDefault("MenuBar") && !mb->isHidden() ) 00743 config->revertToDefault("MenuBar"); 00744 else 00745 config->writeEntry("MenuBar", mb->isHidden() ? "Disabled" : "Enabled"); 00746 } 00747 00748 int n = 1; // Toolbar counter. toolbars are counted from 1, 00749 KToolBar *toolbar = 0; 00750 QPtrListIterator<KToolBar> it( toolBarIterator() ); 00751 while ( ( toolbar = it.current() ) ) { 00752 ++it; 00753 QString group; 00754 if (!configGroup.isEmpty()) 00755 { 00756 // Give a number to the toolbar, but prefer a name if there is one, 00757 // because there's no real guarantee on the ordering of toolbars 00758 group = (!::qstrcmp(toolbar->name(), "unnamed") ? QString::number(n) : QString(" ")+toolbar->name()); 00759 group.prepend(" Toolbar"); 00760 group.prepend(configGroup); 00761 } 00762 toolbar->saveSettings(config, group); 00763 n++; 00764 } 00765 if (!configGroup.isEmpty()) 00766 config->setGroup(oldGroup); 00767 } 00768 00769 void KMainWindow::setStandardToolBarMenuEnabled( bool enable ) 00770 { 00771 if ( enable ) { 00772 if ( d->toolBarHandler ) 00773 return; 00774 00775 d->toolBarHandler = new KDEPrivate::ToolBarHandler( this ); 00776 00777 if ( factory() ) 00778 factory()->addClient( d->toolBarHandler ); 00779 } else { 00780 if ( !d->toolBarHandler ) 00781 return; 00782 00783 if ( factory() ) 00784 factory()->removeClient( d->toolBarHandler ); 00785 00786 delete d->toolBarHandler; 00787 d->toolBarHandler = 0; 00788 } 00789 } 00790 00791 bool KMainWindow::isStandardToolBarMenuEnabled() const 00792 { 00793 return ( d->toolBarHandler ); 00794 } 00795 00796 void KMainWindow::createStandardStatusBarAction(){ 00797 if(!d->showStatusBarAction){ 00798 d->showStatusBarAction = KStdAction::showStatusbar(this, SLOT(setSettingsDirty()), actionCollection()); 00799 KStatusBar *sb = statusBar(); // Creates statusbar if it doesn't exist already. 00800 connect(d->showStatusBarAction, SIGNAL(toggled(bool)), sb, SLOT(setShown(bool))); 00801 d->showStatusBarAction->setChecked(sb->isHidden()); 00802 } 00803 } 00804 00805 bool KMainWindow::readPropertiesInternal( KConfig *config, int number ) 00806 { 00807 if ( number == 1 ) 00808 readGlobalProperties( config ); 00809 00810 // in order they are in toolbar list 00811 QString s; 00812 s.setNum(number); 00813 s.prepend(QString::fromLatin1("WindowProperties")); 00814 00815 config->setGroup(s); 00816 00817 // restore the object name (window role) 00818 if ( config->hasKey(QString::fromLatin1("ObjectName" )) ) 00819 setName( config->readEntry(QString::fromLatin1("ObjectName")).latin1()); // latin1 is right here 00820 00821 applyMainWindowSettings(config); // Menubar, statusbar and toolbar settings. 00822 00823 s.setNum(number); 00824 config->setGroup(s); 00825 readProperties(config); 00826 return true; 00827 } 00828 00829 void KMainWindow::applyMainWindowSettings(KConfig *config, const QString &configGroup) 00830 { 00831 return applyMainWindowSettings(config,configGroup,false); 00832 } 00833 00834 void KMainWindow::applyMainWindowSettings(KConfig *config, const QString &configGroup,bool force) 00835 { 00836 kdDebug(200) << "KMainWindow::applyMainWindowSettings" << endl; 00837 00838 KConfigGroupSaver saver( config, configGroup.isEmpty() ? config->group() : configGroup ); 00839 00840 restoreWindowSize(config); 00841 00842 QStatusBar* sb = internalStatusBar(); 00843 if (sb) { 00844 QString entry = config->readEntry("StatusBar", "Enabled"); 00845 if ( entry == "Disabled" ) 00846 sb->hide(); 00847 else 00848 sb->show(); 00849 if(d->showStatusBarAction) 00850 d->showStatusBarAction->setChecked(!sb->isHidden()); 00851 } 00852 00853 QMenuBar* mb = internalMenuBar(); 00854 if (mb) { 00855 QString entry = config->readEntry ("MenuBar", "Enabled"); 00856 if ( entry == "Disabled" ) 00857 mb->hide(); 00858 else 00859 mb->show(); 00860 } 00861 00862 int n = 1; // Toolbar counter. toolbars are counted from 1, 00863 KToolBar *toolbar; 00864 QPtrListIterator<KToolBar> it( toolBarIterator() ); // must use own iterator 00865 00866 for ( ; it.current(); ++it) { 00867 toolbar= it.current(); 00868 QString group; 00869 if (!configGroup.isEmpty()) 00870 { 00871 // Give a number to the toolbar, but prefer a name if there is one, 00872 // because there's no real guarantee on the ordering of toolbars 00873 group = (!::qstrcmp(toolbar->name(), "unnamed") ? QString::number(n) : QString(" ")+toolbar->name()); 00874 group.prepend(" Toolbar"); 00875 group.prepend(configGroup); 00876 } 00877 toolbar->applySettings(config, group, force); 00878 n++; 00879 } 00880 00881 finalizeGUI( true ); 00882 } 00883 00884 void KMainWindow::finalizeGUI( bool force ) 00885 { 00886 //kdDebug(200) << "KMainWindow::finalizeGUI force=" << force << endl; 00887 // The whole reason for this is that moveToolBar relies on the indexes 00888 // of the other toolbars, so in theory it should be called only once per 00889 // toolbar, but in increasing order of indexes. 00890 // Since we can't do that immediately, we move them, and _then_ 00891 // we call positionYourself again for each of them, but this time 00892 // the toolbariterator should give them in the proper order. 00893 // Both the XMLGUI and applySettings call this, hence "force" for the latter. 00894 QPtrListIterator<KToolBar> it( toolBarIterator() ); 00895 for ( ; it.current() ; ++it ) { 00896 it.current()->positionYourself( force ); 00897 } 00898 00899 d->settingsDirty = false; 00900 } 00901 00902 void KMainWindow::saveWindowSize( KConfig * config ) const 00903 { 00904 int scnum = QApplication::desktop()->screenNumber(parentWidget()); 00905 QRect desk = QApplication::desktop()->screenGeometry(scnum); 00906 int w, h; 00907 #if defined Q_WS_X11 00908 // save maximalization as desktop size + 1 in that direction 00909 KWin::WindowInfo info = KWin::windowInfo( winId(), NET::WMState ); 00910 w = info.state() & NET::MaxHoriz ? desk.width() + 1 : width(); 00911 h = info.state() & NET::MaxVert ? desk.height() + 1 : height(); 00912 #else 00913 if (isMaximized()) { 00914 w = desk.width() + 1; 00915 h = desk.height() + 1; 00916 } 00917 //TODO: add "Maximized" property instead "+1" hack 00918 #endif 00919 QRect size( desk.width(), w, desk.height(), h ); 00920 bool defaultSize = (size == d->defaultWindowSize); 00921 QString widthString = QString::fromLatin1("Width %1").arg(desk.width()); 00922 QString heightString = QString::fromLatin1("Height %1").arg(desk.height()); 00923 if (!config->hasDefault(widthString) && defaultSize) 00924 config->revertToDefault(widthString); 00925 else 00926 config->writeEntry(widthString, w ); 00927 00928 if (!config->hasDefault(heightString) && defaultSize) 00929 config->revertToDefault(heightString); 00930 else 00931 config->writeEntry(heightString, h ); 00932 } 00933 00934 void KMainWindow::restoreWindowSize( KConfig * config ) 00935 { 00936 if (d->care_about_geometry) { 00937 parseGeometry(true); 00938 } else { 00939 // restore the size 00940 int scnum = QApplication::desktop()->screenNumber(parentWidget()); 00941 QRect desk = QApplication::desktop()->screenGeometry(scnum); 00942 if ( d->defaultWindowSize.isNull() ) // only once 00943 d->defaultWindowSize = QRect(desk.width(), width(), desk.height(), height()); // store default values 00944 QSize size( config->readNumEntry( QString::fromLatin1("Width %1").arg(desk.width()), 0 ), 00945 config->readNumEntry( QString::fromLatin1("Height %1").arg(desk.height()), 0 ) ); 00946 if (size.isEmpty()) { 00947 // try the KDE 2.0 way 00948 size = QSize( config->readNumEntry( QString::fromLatin1("Width"), 0 ), 00949 config->readNumEntry( QString::fromLatin1("Height"), 0 ) ); 00950 if (!size.isEmpty()) { 00951 // make sure the other resolutions don't get old settings 00952 config->writeEntry( QString::fromLatin1("Width"), 0 ); 00953 config->writeEntry( QString::fromLatin1("Height"), 0 ); 00954 } 00955 } 00956 if ( !size.isEmpty() ) { 00957 #ifdef Q_WS_X11 00958 int state = ( size.width() > desk.width() ? NET::MaxHoriz : 0 ) 00959 | ( size.height() > desk.height() ? NET::MaxVert : 0 ); 00960 if(( state & NET::Max ) == NET::Max ) 00961 ; // no resize 00962 else if(( state & NET::MaxHoriz ) == NET::MaxHoriz ) 00963 resize( width(), size.height()); 00964 else if(( state & NET::MaxVert ) == NET::MaxVert ) 00965 resize( size.width(), height()); 00966 else 00967 resize( size ); 00968 // QWidget::showMaximized() is both insufficient and broken 00969 KWin::setState( winId(), state ); 00970 #else 00971 if (size.width() > desk.width() || size.height() > desk.height()) 00972 setWindowState( WindowMaximized ); 00973 else 00974 resize( size ); 00975 #endif 00976 } 00977 } 00978 } 00979 00980 bool KMainWindow::initialGeometrySet() const 00981 { 00982 return d->care_about_geometry; 00983 } 00984 00985 void KMainWindow::ignoreInitialGeometry() 00986 { 00987 d->care_about_geometry = false; 00988 } 00989 00990 void KMainWindow::setSettingsDirty() 00991 { 00992 //kdDebug(200) << "KMainWindow::setSettingsDirty" << endl; 00993 d->settingsDirty = true; 00994 if ( d->autoSaveSettings ) 00995 { 00996 // Use a timer to save "immediately" user-wise, but not too immediately 00997 // (to compress calls and save only once, in case of multiple changes) 00998 if ( !d->settingsTimer ) 00999 { 01000 d->settingsTimer = new QTimer( this ); 01001 connect( d->settingsTimer, SIGNAL( timeout() ), SLOT( saveAutoSaveSettings() ) ); 01002 } 01003 d->settingsTimer->start( 500, true ); 01004 } 01005 } 01006 01007 bool KMainWindow::settingsDirty() const 01008 { 01009 return d->settingsDirty; 01010 } 01011 01012 QString KMainWindow::settingsGroup() const 01013 { 01014 return d->autoSaveGroup; 01015 } 01016 01017 void KMainWindow::setAutoSaveSettings( const QString & groupName, bool saveWindowSize ) 01018 { 01019 d->autoSaveSettings = true; 01020 d->autoSaveGroup = groupName; 01021 d->autoSaveWindowSize = saveWindowSize; 01022 // Get notified when the user moves a toolbar around 01023 disconnect( this, SIGNAL( dockWindowPositionChanged( QDockWindow * ) ), 01024 this, SLOT( setSettingsDirty() ) ); 01025 connect( this, SIGNAL( dockWindowPositionChanged( QDockWindow * ) ), 01026 this, SLOT( setSettingsDirty() ) ); 01027 01028 // Now read the previously saved settings 01029 applyMainWindowSettings( KGlobal::config(), groupName ); 01030 } 01031 01032 void KMainWindow::resetAutoSaveSettings() 01033 { 01034 d->autoSaveSettings = false; 01035 if ( d->settingsTimer ) 01036 d->settingsTimer->stop(); 01037 } 01038 01039 bool KMainWindow::autoSaveSettings() const 01040 { 01041 return d->autoSaveSettings; 01042 } 01043 01044 QString KMainWindow::autoSaveGroup() const 01045 { 01046 return d->autoSaveGroup; 01047 } 01048 01049 void KMainWindow::saveAutoSaveSettings() 01050 { 01051 Q_ASSERT( d->autoSaveSettings ); 01052 //kdDebug(200) << "KMainWindow::saveAutoSaveSettings -> saving settings" << endl; 01053 saveMainWindowSettings( KGlobal::config(), d->autoSaveGroup ); 01054 KGlobal::config()->sync(); 01055 d->settingsDirty = false; 01056 if ( d->settingsTimer ) 01057 d->settingsTimer->stop(); 01058 } 01059 01060 void KMainWindow::resizeEvent( QResizeEvent * ) 01061 { 01062 if ( d->autoSaveWindowSize ) 01063 setSettingsDirty(); 01064 } 01065 01066 bool KMainWindow::hasMenuBar() 01067 { 01068 return (internalMenuBar()); 01069 } 01070 01071 KMenuBar *KMainWindow::menuBar() 01072 { 01073 KMenuBar * mb = internalMenuBar(); 01074 if ( !mb ) { 01075 mb = new KMenuBar( this ); 01076 // trigger a re-layout and trigger a call to the private 01077 // setMenuBar method. 01078 QMainWindow::menuBar(); 01079 } 01080 return mb; 01081 } 01082 01083 KStatusBar *KMainWindow::statusBar() 01084 { 01085 KStatusBar * sb = internalStatusBar(); 01086 if ( !sb ) { 01087 sb = new KStatusBar( this ); 01088 // trigger a re-layout and trigger a call to the private 01089 // setStatusBar method. 01090 QMainWindow::statusBar(); 01091 } 01092 return sb; 01093 } 01094 01095 void KMainWindow::shuttingDown() 01096 { 01097 // Needed for Qt <= 3.0.3 at least to prevent reentrancy 01098 // when queryExit() shows a dialog. Check before removing! 01099 static bool reentrancy_protection = false; 01100 if (!reentrancy_protection) 01101 { 01102 reentrancy_protection = true; 01103 // call the virtual queryExit 01104 queryExit(); 01105 reentrancy_protection = false; 01106 } 01107 01108 } 01109 01110 KMenuBar *KMainWindow::internalMenuBar() 01111 { 01112 QObjectList *l = queryList( "KMenuBar", 0, false, false ); 01113 if ( !l || !l->first() ) { 01114 delete l; 01115 return 0; 01116 } 01117 01118 KMenuBar *m = (KMenuBar*)l->first(); 01119 delete l; 01120 return m; 01121 } 01122 01123 KStatusBar *KMainWindow::internalStatusBar() 01124 { 01125 QObjectList *l = queryList( "KStatusBar", 0, false, false ); 01126 if ( !l || !l->first() ) { 01127 delete l; 01128 return 0; 01129 } 01130 01131 KStatusBar *s = (KStatusBar*)l->first(); 01132 delete l; 01133 return s; 01134 } 01135 01136 void KMainWindow::childEvent( QChildEvent* e) 01137 { 01138 QMainWindow::childEvent( e ); 01139 } 01140 01141 KToolBar *KMainWindow::toolBar( const char * name ) 01142 { 01143 if (!name) 01144 name = "mainToolBar"; 01145 KToolBar *tb = (KToolBar*)child( name, "KToolBar" ); 01146 if ( tb ) 01147 return tb; 01148 bool honor_mode = (!strcmp(name, "mainToolBar")); 01149 01150 if ( builderClient() ) 01151 return new KToolBar(this, name, honor_mode); // XMLGUI constructor 01152 else 01153 return new KToolBar(this, DockTop, false, name, honor_mode ); // non-XMLGUI 01154 } 01155 01156 QPtrListIterator<KToolBar> KMainWindow::toolBarIterator() 01157 { 01158 toolbarList.clear(); 01159 QPtrList<QToolBar> lst; 01160 for ( int i = (int)QMainWindow::DockUnmanaged; i <= (int)DockMinimized; ++i ) { 01161 lst = toolBars( (ToolBarDock)i ); 01162 for ( QToolBar *tb = lst.first(); tb; tb = lst.next() ) { 01163 if ( !tb->inherits( "KToolBar" ) ) 01164 continue; 01165 toolbarList.append( (KToolBar*)tb ); 01166 } 01167 } 01168 return QPtrListIterator<KToolBar>( toolbarList ); 01169 } 01170 01171 KAccel * KMainWindow::accel() 01172 { 01173 if ( !d->kaccel ) 01174 d->kaccel = new KAccel( this, "kmw-kaccel" ); 01175 return d->kaccel; 01176 } 01177 01178 void KMainWindow::paintEvent( QPaintEvent * pe ) 01179 { 01180 QMainWindow::paintEvent(pe); //Upcall to handle SH_MainWindow_SpaceBelowMenuBar rendering 01181 } 01182 01183 QSize KMainWindow::sizeForCentralWidgetSize(QSize size) 01184 { 01185 KToolBar *tb = (KToolBar*)child( "mainToolBar", "KToolBar" ); 01186 if (tb && !tb->isHidden()) { 01187 switch( tb->barPos() ) 01188 { 01189 case KToolBar::Top: 01190 case KToolBar::Bottom: 01191 size += QSize(0, tb->sizeHint().height()); 01192 break; 01193 01194 case KToolBar::Left: 01195 case KToolBar::Right: 01196 size += QSize(toolBar()->sizeHint().width(), 0); 01197 break; 01198 01199 case KToolBar::Flat: 01200 size += QSize(0, 3+kapp->style().pixelMetric( QStyle::PM_DockWindowHandleExtent )); 01201 break; 01202 01203 default: 01204 break; 01205 } 01206 } 01207 KMenuBar *mb = internalMenuBar(); 01208 if (mb && !mb->isHidden()) { 01209 size += QSize(0,mb->heightForWidth(size.width())); 01210 if (style().styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, this)) 01211 size += QSize( 0, dockWindowsMovable() ? 1 : 2); 01212 } 01213 QStatusBar *sb = internalStatusBar(); 01214 if( sb && !sb->isHidden() ) 01215 size += QSize(0, sb->sizeHint().height()); 01216 01217 return size; 01218 } 01219 01220 #if KDE_IS_VERSION( 3, 9, 0 ) 01221 #ifdef __GNUC__ 01222 #warning Remove, should be in Qt 01223 #endif 01224 #endif 01225 void KMainWindow::setIcon( const QPixmap& p ) 01226 { 01227 QMainWindow::setIcon( p ); 01228 #ifdef Q_WS_X11 01229 // Qt3 doesn't support _NET_WM_ICON, but KApplication::setTopWidget(), which 01230 // is used by KMainWindow, sets it 01231 KWin::setIcons( winId(), p, QPixmap()); 01232 #endif 01233 } 01234 01235 QPtrList<KMainWindow>* KMainWindow::getMemberList() { return memberList; } 01236 01237 // why do we support old gcc versions? using KXMLGUIBuilder::finalizeGUI; 01238 // DF: because they compile KDE much faster :) 01239 void KMainWindow::finalizeGUI( KXMLGUIClient *client ) 01240 { KXMLGUIBuilder::finalizeGUI( client ); } 01241 01242 void KMainWindow::virtual_hook( int id, void* data ) 01243 { KXMLGUIBuilder::virtual_hook( id, data ); 01244 KXMLGUIClient::virtual_hook( id, data ); } 01245 01246 01247 01248 #include "kmainwindow.moc" 01249