kontact

mainwindow.cpp

00001 /*
00002     This file is part of KDE Kontact.
00003 
00004     Copyright (c) 2001 Matthias Hoelzer-Kluepfel <mhk@kde.org>
00005     Copyright (c) 2002-2005 Daniel Molkentin <molkentin@kde.org>
00006     Copyright (c) 2003-2005 Cornelius Schumacher <schumacher@kde.org>
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00021 */
00022 
00023 #include <qcombobox.h>
00024 #include <qdockarea.h>
00025 #include <qguardedptr.h>
00026 #include <qhbox.h>
00027 #include <qimage.h>
00028 #include <qobjectlist.h>
00029 #include <qprogressbar.h>
00030 #include <qpushbutton.h>
00031 #include <qsplitter.h>
00032 #include <qtimer.h>
00033 #include <qwhatsthis.h>
00034 
00035 #include <dcopclient.h>
00036 #include <kapplication.h>
00037 #include <kconfig.h>
00038 #include <kdebug.h>
00039 #include <kedittoolbar.h>
00040 #include <kguiitem.h>
00041 #include <khelpmenu.h>
00042 #include <kiconloader.h>
00043 #include <kkeydialog.h>
00044 #include <klibloader.h>
00045 #include <klistbox.h>
00046 #include <klocale.h>
00047 #include <kmessagebox.h>
00048 #include <kparts/componentfactory.h>
00049 #include <kplugininfo.h>
00050 #include <kpopupmenu.h>
00051 #include <ksettings/dialog.h>
00052 #include <ksettings/dispatcher.h>
00053 #include <kshortcut.h>
00054 #include <kstandarddirs.h>
00055 #include <kstatusbar.h>
00056 #include <kstdaction.h>
00057 #include <ktip.h>
00058 #include <ktrader.h>
00059 #include <ksettings/componentsdialog.h>
00060 #include <kstringhandler.h>
00061 #include <krsqueezedtextlabel.h>
00062 #include <khtml_part.h>
00063 #include <khtmlview.h>
00064 #include <libkdepim/kfileio.h>
00065 #include <kcursor.h>
00066 #include <krun.h>
00067 #include <kaboutdata.h>
00068 #include <kmenubar.h>
00069 #include <kstdaccel.h>
00070 #include <kcmultidialog.h>
00071 #include <kipc.h>
00072 
00073 #include "aboutdialog.h"
00074 #include "iconsidepane.h"
00075 #include "mainwindow.h"
00076 #include "plugin.h"
00077 #include "prefs.h"
00078 #include "profiledialog.h"
00079 #include "profilemanager.h"
00080 #include "progressdialog.h"
00081 #include "statusbarprogresswidget.h"
00082 #include "broadcaststatus.h"
00083 
00084 using namespace Kontact;
00085 
00086 class SettingsDialogWrapper : public KSettings::Dialog
00087 {
00088   public:
00089     SettingsDialogWrapper( ContentInListView content, QWidget * parent = 0 )
00090       : KSettings::Dialog( content, parent, 0 )
00091     {
00092     }
00093 
00094 
00095     void fixButtonLabel( QWidget *widget )
00096     {
00097       QObject *object = widget->child( "KJanusWidget::buttonBelowList" );
00098       QPushButton *button = static_cast<QPushButton*>( object );
00099       if ( button )
00100         button->setText( i18n( "Select Components ..." ) );
00101     }
00102 };
00103 
00104 MainWindow::MainWindow()
00105   : Kontact::Core(), mTopWidget( 0 ), mSplitter( 0 ),
00106     mCurrentPlugin( 0 ), mAboutDialog( 0 ), mReallyClose( false ), mSyncActionsEnabled( true )
00107 {
00108   // Set this to be the group leader for all subdialogs - this means
00109   // modal subdialogs will only affect this dialog, not the other windows
00110   setWFlags( getWFlags() | WGroupLeader );
00111 
00112   initGUI();
00113   initObject();
00114 }
00115 
00116 void MainWindow::initGUI()
00117 {
00118   initWidgets();
00119   setupActions();
00120   setHelpMenuEnabled( false );
00121   KHelpMenu *helpMenu = new KHelpMenu( this, 0, true, actionCollection() );
00122   connect( helpMenu, SIGNAL( showAboutApplication() ),
00123            SLOT( showAboutDialog() ) );
00124 
00125   KStdAction::keyBindings( this, SLOT( configureShortcuts() ), actionCollection() );
00126   KStdAction::configureToolbars( this, SLOT( configureToolbars() ), actionCollection() );
00127   setXMLFile( "kontactui.rc" );
00128 
00129   setStandardToolBarMenuEnabled( true );
00130 
00131   createGUI( 0 );
00132 
00133   resize( 700, 520 ); // initial size to prevent a scrollbar in sidepane
00134   setAutoSaveSettings();
00135 
00136   connect( Kontact::ProfileManager::self(), SIGNAL( profileLoaded( const QString& ) ), 
00137            this, SLOT( slotLoadProfile( const QString& ) ) );
00138   connect( Kontact::ProfileManager::self(), SIGNAL( saveToProfileRequested( const QString& ) ), 
00139            this, SLOT( slotSaveToProfile( const QString& ) ) );
00140 }
00141 
00142 
00143 void MainWindow::initObject()
00144 {
00145   KTrader::OfferList offers = KTrader::self()->query(
00146       QString::fromLatin1( "Kontact/Plugin" ),
00147       QString( "[X-KDE-KontactPluginVersion] == %1" ).arg( KONTACT_PLUGIN_VERSION ) );
00148   mPluginInfos = KPluginInfo::fromServices( offers, Prefs::self()->config(), "Plugins" );
00149 
00150   KPluginInfo::List::Iterator it;
00151   for ( it = mPluginInfos.begin(); it != mPluginInfos.end(); ++it ) {
00152     ( *it )->load();
00153   }
00154 
00155   // prepare the part manager
00156   mPartManager = new KParts::PartManager( this );
00157   connect( mPartManager, SIGNAL( activePartChanged( KParts::Part* ) ),
00158            this, SLOT( slotActivePartChanged( KParts::Part* ) ) );
00159 
00160   loadPlugins();
00161 
00162   if ( mSidePane ) {
00163     mSidePane->updatePlugins();
00164     plugActionList( "navigator_actionlist", mSidePane->actions() );
00165   }
00166 
00167   KSettings::Dispatcher::self()->registerInstance( instance(), this,
00168                                                    SLOT( updateConfig() ) );
00169 
00170   loadSettings();
00171 
00172   statusBar()->show();
00173 
00174   showTip( false );
00175 
00176   // done initializing
00177   slotShowStatusMsg( QString::null );
00178 
00179   connect( KPIM::BroadcastStatus::instance(), SIGNAL( statusMsg( const QString& ) ),
00180            this, SLOT( slotShowStatusMsg( const QString&  ) ) );
00181 
00182   // launch commandline specified module if any
00183   activatePluginModule();
00184 
00185   if ( Prefs::lastVersionSeen() == kapp->aboutData()->version() ) {
00186     selectPlugin( mCurrentPlugin );
00187   }
00188 
00189   paintAboutScreen( introductionString() );
00190   Prefs::setLastVersionSeen( kapp->aboutData()->version() );
00191 }
00192 
00193 MainWindow::~MainWindow()
00194 {
00195   saveSettings();
00196 
00197   QPtrList<KParts::Part> parts = *mPartManager->parts();
00198 
00199   for ( KParts::Part *p = parts.last(); p; p = parts.prev() ) {
00200     delete p;
00201     p = 0;
00202   }
00203 
00204   Prefs::self()->writeConfig();
00205 }
00206 
00207 void MainWindow::setActivePluginModule( const QString &module )
00208 {
00209   mActiveModule = module;
00210   activatePluginModule();
00211 }
00212 
00213 void MainWindow::activatePluginModule()
00214 {
00215   if ( !mActiveModule.isEmpty() ) {
00216     PluginList::ConstIterator end = mPlugins.end();
00217     for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it )
00218       if ( ( *it )->identifier().contains( mActiveModule ) ) {
00219         selectPlugin( *it );
00220         return;
00221       }
00222   }
00223 }
00224 
00225 void MainWindow::initWidgets()
00226 {
00227   // includes sidebar and part stack
00228   mTopWidget = new QHBox( this );
00229   mTopWidget->setFrameStyle( QFrame::Panel | QFrame::Sunken );
00230   setCentralWidget( mTopWidget );
00231 
00232   QHBox *mBox = 0;
00233   mSplitter = new QSplitter( mTopWidget );
00234   mBox = new QHBox( mTopWidget );
00235   mSidePane = new IconSidePane( this, mSplitter );
00236   mSidePane->setSizePolicy( QSizePolicy( QSizePolicy::Maximum,
00237                                          QSizePolicy::Preferred ) );
00238   // donÄt occupy screen estate on load
00239   QValueList<int> sizes;
00240   sizes << 0;
00241   mSplitter->setSizes(sizes);
00242 
00243   mSidePane->setActionCollection( actionCollection() );
00244 
00245   connect( mSidePane, SIGNAL( pluginSelected( Kontact::Plugin * ) ),
00246            SLOT( selectPlugin( Kontact::Plugin * ) ) );
00247 
00248   QVBox *vBox;
00249   if ( mSplitter ) {
00250     vBox = new QVBox( mSplitter );
00251   } else {
00252     vBox = new QVBox( mBox );
00253   }
00254 
00255   vBox->setSpacing( 0 );
00256 
00257   mPartsStack = new QWidgetStack( vBox );
00258   initAboutScreen();
00259 
00260   QString loading = i18n( "<h2 style='text-align:center; margin-top: 0px; margin-bottom: 0px'>%1</h2>" )
00261                     .arg( i18n("Loading Kontact...") );
00262 
00263   paintAboutScreen( loading );
00264 
00265   /* Create a progress dialog and hide it. */
00266   KPIM::ProgressDialog *progressDialog = new KPIM::ProgressDialog( statusBar(), this );
00267   progressDialog->hide();
00268 
00269   mLittleProgress = new KPIM::StatusbarProgressWidget( progressDialog, statusBar() );
00270 
00271   mStatusMsgLabel = new KRSqueezedTextLabel( i18n( " Initializing..." ), statusBar() );
00272   mStatusMsgLabel->setAlignment( AlignLeft | AlignVCenter );
00273 
00274   statusBar()->addWidget( mStatusMsgLabel, 10 , false );
00275   statusBar()->addWidget( mLittleProgress, 0 , true );
00276   mLittleProgress->show();
00277 }
00278 
00279 
00280 void MainWindow::paintAboutScreen( const QString& msg )
00281 {
00282   QString location = locate( "data", "kontact/about/main.html" );
00283   QString content = KPIM::kFileToString( location );
00284   content = content.arg( locate( "data", "libkdepim/about/kde_infopage.css" ) );
00285   if ( kapp->reverseLayout() )
00286     content = content.arg( "@import \"%1\";" ).arg( locate( "data", "libkdepim/about/kde_infopage_rtl.css" ) );
00287   else
00288     content = content.arg( "" );
00289 
00290   mIntroPart->begin( KURL( location ) );
00291 
00292   QString appName( i18n( "KDE Kontact" ) );
00293   QString catchPhrase( i18n( "Get Organized!" ) );
00294   QString quickDescription( i18n( "The KDE Personal Information Management Suite" ) );
00295 
00296   mIntroPart->write( content.arg( QFont().pointSize() + 2 ).arg( appName )
00297       .arg( catchPhrase ).arg( quickDescription ).arg( msg ) );
00298   mIntroPart->end();
00299 }
00300 
00301 void MainWindow::initAboutScreen()
00302 {
00303   QHBox *introbox = new QHBox( mPartsStack );
00304   mPartsStack->addWidget( introbox );
00305   mPartsStack->raiseWidget( introbox );
00306   mIntroPart = new KHTMLPart( introbox );
00307   mIntroPart->widget()->setFocusPolicy( WheelFocus );
00308   // Let's better be paranoid and disable plugins (it defaults to enabled):
00309   mIntroPart->setPluginsEnabled( false );
00310   mIntroPart->setJScriptEnabled( false ); // just make this explicit
00311   mIntroPart->setJavaEnabled( false );    // just make this explicit
00312   mIntroPart->setMetaRefreshEnabled( false );
00313   mIntroPart->setURLCursor( KCursor::handCursor() );
00314   mIntroPart->view()->setLineWidth( 0 );
00315 
00316   connect( mIntroPart->browserExtension(),
00317            SIGNAL( openURLRequest( const KURL&, const KParts::URLArgs& ) ),
00318            SLOT( slotOpenUrl( const KURL& ) ) );
00319 
00320   connect( mIntroPart->browserExtension(),
00321            SIGNAL( createNewWindow( const KURL&, const KParts::URLArgs& ) ),
00322            SLOT( slotOpenUrl( const KURL& ) ) );
00323 }
00324 
00325 void MainWindow::setupActions()
00326 {
00327   KStdAction::quit( this, SLOT( slotQuit() ), actionCollection() );
00328   mNewActions = new KToolBarPopupAction( KGuiItem( i18n( "New" ), "" ),
00329                                          KStdAccel::shortcut(KStdAccel::New), this, SLOT( slotNewClicked() ),
00330                                          actionCollection(), "action_new" );
00331 
00332   KConfig* const cfg = Prefs::self()->config();
00333   cfg->setGroup( "Kontact Groupware Settings" );
00334   mSyncActionsEnabled = cfg->readBoolEntry( "GroupwareMailFoldersEnabled", true );
00335 
00336   if ( mSyncActionsEnabled ) {
00337     mSyncActions = new KToolBarPopupAction( KGuiItem( i18n( "Synchronize" ), "kitchensync" ),
00338                                             KStdAccel::shortcut(KStdAccel::Reload), this, SLOT( slotSyncClicked() ),
00339                                             actionCollection(), "action_sync" );
00340   }
00341   new KAction( i18n( "Configure Kontact..." ), "configure", 0, this, SLOT( slotPreferences() ),
00342                actionCollection(), "settings_configure_kontact" );
00343 
00344   new KAction( i18n( "Configure &Profiles..." ), 0, this, SLOT( slotConfigureProfiles() ),
00345                actionCollection(), "settings_configure_kontact_profiles" );
00346 
00347   new KAction( i18n( "&Kontact Introduction" ), 0, this, SLOT( slotShowIntroduction() ),
00348                actionCollection(), "help_introduction" );
00349   new KAction( i18n( "&Tip of the Day" ), 0, this, SLOT( slotShowTip() ),
00350                actionCollection(), "help_tipofday" );
00351   new KAction( i18n( "&Request Feature..." ), 0, this, SLOT( slotRequestFeature() ),
00352                actionCollection(), "help_requestfeature" );
00353   
00354   KWidgetAction* spacerAction = new KWidgetAction( new QWidget( this ), "SpacerAction", "", 0, 0, actionCollection(), "navigator_spacer_item" );
00355   spacerAction->setAutoSized( true );
00356 }
00357 
00358 void MainWindow::slotConfigureProfiles()
00359 {
00360   QGuardedPtr<Kontact::ProfileDialog> dlg = new Kontact::ProfileDialog( this );
00361   dlg->setModal( true );
00362   dlg->exec();
00363   delete dlg;
00364 }
00365 
00366 namespace {
00367     void copyConfigEntry( KConfig* source, KConfig* dest, const QString& group, const QString& key, const QString& defaultValue=QString() )
00368     {
00369         source->setGroup( group );
00370         dest->setGroup( group );
00371         dest->writeEntry( key, source->readEntry( key, defaultValue ) );
00372     }
00373 }
00374 
00375 void MainWindow::slotSaveToProfile( const QString& id )
00376 {
00377   const QString path = Kontact::ProfileManager::self()->profileById( id ).saveLocation();
00378   if ( path.isNull() )
00379     return;
00380 
00381   KConfig* const cfg = Prefs::self()->config();
00382   Prefs::self()->writeConfig();
00383   saveMainWindowSettings( cfg );
00384   saveSettings();
00385 
00386   KConfig profile( path+"/kontactrc", /*read-only=*/false, /*useglobals=*/false );
00387   ::copyConfigEntry( cfg, &profile, "MainWindow Toolbar navigatorToolBar", "Hidden", "true" );
00388   ::copyConfigEntry( cfg, &profile, "View", "SidePaneSplitter" );
00389   ::copyConfigEntry( cfg, &profile, "Icons", "Theme" );
00390   
00391   for ( PluginList::Iterator it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
00392     if ( !(*it)->isRunningStandalone() ) {
00393         (*it)->part();
00394     }
00395     (*it)->saveToProfile( path );
00396   }
00397 }
00398 
00399 void MainWindow::slotLoadProfile( const QString& id )
00400 {
00401   const QString path = Kontact::ProfileManager::self()->profileById( id ).saveLocation();
00402   if ( path.isNull() )
00403     return;
00404 
00405   KConfig* const cfg = Prefs::self()->config();
00406   Prefs::self()->writeConfig();
00407   saveMainWindowSettings( cfg );
00408   saveSettings();
00409 
00410   const KConfig profile( path+"/kontactrc", /*read-only=*/false, /*useglobals=*/false );
00411   const QStringList groups = profile.groupList();
00412   for ( QStringList::ConstIterator it = groups.begin(), end = groups.end(); it != end; ++it )
00413   {
00414     cfg->setGroup( *it );
00415     typedef QMap<QString, QString> StringMap;
00416     const StringMap entries = profile.entryMap( *it );
00417     for ( StringMap::ConstIterator it2 = entries.begin(), end = entries.end(); it2 != end; ++it2 )
00418     {
00419       if ( it2.data() == "KONTACT_PROFILE_DELETE_KEY" )
00420         cfg->deleteEntry( it2.key() );
00421       else
00422         cfg->writeEntry( it2.key(), it2.data() );
00423     }
00424   }
00425 
00426   cfg->sync();
00427   Prefs::self()->readConfig();
00428   applyMainWindowSettings( cfg );
00429   KIconTheme::reconfigure();
00430   const WId wid = winId();
00431   KIPC::sendMessage( KIPC::PaletteChanged, wid );
00432   KIPC::sendMessage( KIPC::FontChanged, wid );
00433   KIPC::sendMessage( KIPC::StyleChanged, wid );
00434   KIPC::sendMessage( KIPC::SettingsChanged, wid );
00435   for ( int i = 0; i < KIcon::LastGroup; ++i )
00436       KIPC::sendMessage( KIPC::IconChanged, wid, i );
00437 
00438   loadSettings();
00439 
00440   for ( PluginList::Iterator it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
00441     if ( !(*it)->isRunningStandalone() ) {
00442         kdDebug() << "Ensure loaded: " << (*it)->identifier() << endl;
00443         (*it)->part();
00444     }
00445     (*it)->loadProfile( path );
00446   }
00447 }
00448 
00449 bool MainWindow::isPluginLoaded( const KPluginInfo *info )
00450 {
00451   return (pluginFromInfo( info ) != 0);
00452 }
00453 
00454 Plugin *MainWindow::pluginFromInfo( const KPluginInfo *info )
00455 {
00456   PluginList::ConstIterator end = mPlugins.end();
00457   for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it )
00458     if ( (*it)->identifier() == info->pluginName() )
00459       return *it;
00460 
00461   return 0;
00462 }
00463 
00464 void MainWindow::loadPlugins()
00465 {
00466   QPtrList<Plugin> plugins;
00467   QPtrList<KParts::Part> loadDelayed;
00468 
00469   uint i;
00470   KPluginInfo::List::ConstIterator it;
00471   for ( it = mPluginInfos.begin(); it != mPluginInfos.end(); ++it ) {
00472     if ( !(*it)->isPluginEnabled() )
00473       continue;
00474     if ( isPluginLoaded( *it ) ) {
00475       Plugin *plugin = pluginFromInfo( *it );
00476       if ( plugin )
00477         plugin->configUpdated();
00478       continue;
00479     }
00480 
00481     kdDebug(5600) << "Loading Plugin: " << (*it)->name() << endl;
00482     Kontact::Plugin *plugin =
00483       KParts::ComponentFactory::createInstanceFromService<Kontact::Plugin>(
00484           (*it)->service(), this );
00485 
00486     if ( !plugin )
00487       continue;
00488 
00489     plugin->setIdentifier( (*it)->pluginName() );
00490     plugin->setTitle( (*it)->name() );
00491     plugin->setIcon( (*it)->icon() );
00492 
00493     QVariant libNameProp = (*it)->property( "X-KDE-KontactPartLibraryName" );
00494     QVariant exeNameProp = (*it)->property( "X-KDE-KontactPartExecutableName" );
00495     QVariant loadOnStart = (*it)->property( "X-KDE-KontactPartLoadOnStart" );
00496     QVariant hasPartProp = (*it)->property( "X-KDE-KontactPluginHasPart" );
00497 
00498     if ( !loadOnStart.isNull() && loadOnStart.toBool() )
00499       mDelayedPreload.append( plugin );
00500 
00501     kdDebug(5600) << "LIBNAMEPART: " << libNameProp.toString() << endl;
00502 
00503     plugin->setPartLibraryName( libNameProp.toString().utf8() );
00504     plugin->setExecutableName( exeNameProp.toString() );
00505     if ( hasPartProp.isValid() )
00506       plugin->setShowInSideBar( hasPartProp.toBool() );
00507 
00508     for ( i = 0; i < plugins.count(); ++i ) {
00509       Plugin *p = plugins.at( i );
00510       if ( plugin->weight() < p->weight() )
00511         break;
00512     }
00513 
00514     plugins.insert( i, plugin );
00515   }
00516 
00517   for ( i = 0; i < plugins.count(); ++ i ) {
00518     Plugin *plugin = plugins.at( i );
00519 
00520     KAction *action;
00521     QPtrList<KAction> *actionList = plugin->newActions();
00522 
00523     for ( action = actionList->first(); action; action = actionList->next() ) {
00524       kdDebug(5600) << "Plugging " << action->name() << endl;
00525       action->plug( mNewActions->popupMenu() );
00526     }
00527 
00528     if ( mSyncActionsEnabled ) {
00529       actionList = plugin->syncActions();
00530       for ( action = actionList->first(); action; action = actionList->next() ) {
00531         kdDebug(5600) << "Plugging " << action->name() << endl;
00532         action->plug( mSyncActions->popupMenu() );
00533       }
00534     }
00535     addPlugin( plugin );
00536   }
00537 
00538   mNewActions->setEnabled( mPlugins.size() != 0 );
00539   if ( mSyncActionsEnabled )
00540     mSyncActions->setEnabled( mPlugins.size() != 0 );
00541 }
00542 
00543 void MainWindow::unloadPlugins()
00544 {
00545   KPluginInfo::List::ConstIterator end = mPluginInfos.end();
00546   KPluginInfo::List::ConstIterator it;
00547   for ( it = mPluginInfos.begin(); it != end; ++it ) {
00548     if ( !(*it)->isPluginEnabled() )
00549       removePlugin( *it );
00550   }
00551 }
00552 
00553 bool MainWindow::removePlugin( const KPluginInfo *info )
00554 {
00555   PluginList::Iterator end = mPlugins.end();
00556   for ( PluginList::Iterator it = mPlugins.begin(); it != end; ++it )
00557     if ( ( *it )->identifier() == info->pluginName() ) {
00558       Plugin *plugin = *it;
00559 
00560       KAction *action;
00561       QPtrList<KAction> *actionList = plugin->newActions();
00562 
00563       for ( action = actionList->first(); action; action = actionList->next() ) {
00564         kdDebug(5600) << "Unplugging " << action->name() << endl;
00565         action->unplug( mNewActions->popupMenu() );
00566       }
00567 
00568       if ( mSyncActionsEnabled ) {
00569         actionList = plugin->syncActions();
00570         for ( action = actionList->first(); action; action = actionList->next() ) {
00571           kdDebug(5600) << "Unplugging " << action->name() << endl;
00572           action->unplug( mSyncActions->popupMenu() );
00573         }
00574       }
00575       removeChildClient( plugin );
00576 
00577       if ( mCurrentPlugin == plugin )
00578         mCurrentPlugin = 0;
00579 
00580       delete plugin; // removes the part automatically
00581       mPlugins.remove( it );
00582 
00583       if ( mCurrentPlugin == 0 ) {
00584         PluginList::Iterator it;
00585         for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
00586           if ( (*it)->showInSideBar() ) {
00587             selectPlugin( *it );
00588             return true;
00589           }
00590         }
00591       }
00592 
00593       return true;
00594     }
00595 
00596   return false;
00597 }
00598 
00599 void MainWindow::addPlugin( Kontact::Plugin *plugin )
00600 {
00601   kdDebug(5600) << "Added plugin" << endl;
00602 
00603   mPlugins.append( plugin );
00604 
00605   // merge the plugins GUI into the main window
00606   insertChildClient( plugin );
00607 }
00608 
00609 void MainWindow::partLoaded( Kontact::Plugin*, KParts::ReadOnlyPart *part )
00610 {
00611   // See if we have this part already (e.g. due to two plugins sharing it)
00612   if ( mPartsStack->id( part->widget() ) != -1 )
00613     return;
00614 
00615   mPartsStack->addWidget( part->widget() );
00616 
00617   mPartManager->addPart( part, false );
00618   // Workaround for KParts misbehavior: addPart calls show!
00619   part->widget()->hide();
00620 }
00621 
00622 void MainWindow::slotActivePartChanged( KParts::Part *part )
00623 {
00624   if ( !part ) {
00625     createGUI( 0 );
00626     return;
00627   }
00628 
00629   kdDebug(5600) << "Part activated: " << part << " with stack id. "
00630       << mPartsStack->id( part->widget() )<< endl;
00631 
00632   //createGUI( part ); // moved to selectPlugin()
00633 
00634   statusBar()->clear();
00635 }
00636 
00637 void MainWindow::slotNewClicked()
00638 {
00639   KAction *action = mCurrentPlugin->newActions()->first();
00640   if ( action ) {
00641     action->activate();
00642   } else {
00643     PluginList::Iterator it;
00644     for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
00645       action = (*it)->newActions()->first();
00646       if ( action ) {
00647         action->activate();
00648         return;
00649       }
00650     }
00651   }
00652 }
00653 
00654 void MainWindow::slotSyncClicked()
00655 {
00656   KAction *action = mCurrentPlugin->syncActions()->first();
00657   if ( action ) {
00658     action->activate();
00659   } else {
00660     PluginList::Iterator it;
00661     for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
00662       action = (*it)->syncActions()->first();
00663       if ( action ) {
00664         action->activate();
00665         return;
00666       }
00667     }
00668   }
00669 }
00670 
00671 KToolBar* Kontact::MainWindow::findToolBar(const char* name)
00672 {
00673   // like KMainWindow::toolBar, but which doesn't create the toolbar if not found
00674   return static_cast<KToolBar *>(child(name, "KToolBar"));
00675 }
00676 
00677 void MainWindow::selectPlugin( Kontact::Plugin *plugin )
00678 {
00679   if ( !plugin )
00680     return;
00681 
00682   if ( plugin->isRunningStandalone() ) {
00683     statusBar()->message( i18n( "Application is running standalone. Foregrounding..." ), 1000 );
00684     mSidePane->indicateForegrunding( plugin );
00685     plugin->bringToForeground();
00686     return;
00687   }
00688 
00689   KApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
00690 
00691   KParts::Part *part = plugin->part();
00692 
00693   if ( !part ) {
00694     KApplication::restoreOverrideCursor();
00695     KMessageBox::error( this, i18n( "Cannot load part for %1." )
00696                               .arg( plugin->title() )
00697                         + "\n" + lastErrorMessage() );
00698     plugin->setDisabled( true );
00699     mSidePane->updatePlugins();
00700     return;
00701   }
00702 
00703   // store old focus widget
00704   QWidget *focusWidget = kapp->focusWidget();
00705   if ( mCurrentPlugin && focusWidget ) {
00706     // save the focus widget only when it belongs to the activated part
00707     QWidget *parent = focusWidget->parentWidget();
00708     while ( parent ) {
00709       if ( parent == mCurrentPlugin->part()->widget() )
00710         mFocusWidgets.insert( mCurrentPlugin->identifier(), QGuardedPtr<QWidget>( focusWidget ) );
00711 
00712       parent = parent->parentWidget();
00713     }
00714   }
00715 
00716   if ( mSidePane )
00717     mSidePane->selectPlugin( plugin );
00718 
00719   plugin->select();
00720 
00721   mPartManager->setActivePart( part );
00722   QWidget *view = part->widget();
00723   Q_ASSERT( view );
00724 
00725   if ( view ) {
00726     mPartsStack->raiseWidget( view );
00727     view->show();
00728 
00729     if ( mFocusWidgets.contains( plugin->identifier() ) ) {
00730       focusWidget = mFocusWidgets[ plugin->identifier() ];
00731       if ( focusWidget )
00732         focusWidget->setFocus();
00733     } else
00734       view->setFocus();
00735 
00736     mCurrentPlugin = plugin;
00737     KAction *newAction = plugin->newActions()->first();
00738     KAction *syncAction = plugin->syncActions()->first();
00739 
00740     createGUI( plugin->part() );
00741 
00742     KToolBar* navigatorToolBar = findToolBar( "navigatorToolBar" );
00743     // Let the navigator toolbar be always the last one, if it's in the top dockwindow
00744     if ( navigatorToolBar && !navigatorToolBar->isHidden() &&
00745          navigatorToolBar->barPos() == KToolBar::Top ) {
00746       topDock()->moveDockWindow( navigatorToolBar, -1 );
00747     }
00748 
00749     setCaption( i18n( "Plugin dependent window title" ,"%1 - Kontact" ).arg( plugin->title() ) );
00750 
00751     if ( newAction ) {
00752       mNewActions->setIcon( newAction->icon() );
00753       mNewActions->setText( newAction->text() );
00754     } else { // we'll use the action of the first plugin which offers one
00755       PluginList::Iterator it;
00756       for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
00757         newAction = (*it)->newActions()->first();
00758         if ( newAction ) {
00759           mNewActions->setIcon( newAction->icon() );
00760           mNewActions->setText( newAction->text() );
00761           break;
00762         }
00763       }
00764     }
00765     if ( mSyncActionsEnabled ) {
00766       if ( syncAction ) {
00767         mSyncActions->setIcon( syncAction->icon() );
00768         mSyncActions->setText( syncAction->text() );
00769       } else { // we'll use the action of the first plugin which offers one
00770         PluginList::Iterator it;
00771         for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
00772           syncAction = (*it)->syncActions()->first();
00773           if ( syncAction ) {
00774             mSyncActions->setIcon( syncAction->icon() );
00775             mSyncActions->setText( syncAction->text() );
00776             break;
00777           }
00778         }
00779       }
00780     }
00781   }
00782   QStringList invisibleActions = plugin->invisibleToolbarActions();
00783 
00784   QStringList::ConstIterator it;
00785   for ( it = invisibleActions.begin(); it != invisibleActions.end(); ++it ) {
00786     KAction *action = part->actionCollection()->action( (*it).latin1() );
00787     if ( action ) {
00788       QPtrListIterator<KToolBar> it(  toolBarIterator() );
00789       for (  ; it.current() ; ++it ) {
00790         action->unplug( it.current() );
00791       }
00792     }
00793   }
00794 
00795   KApplication::restoreOverrideCursor();
00796 }
00797 
00798 void MainWindow::selectPlugin( const QString &pluginName )
00799 {
00800   PluginList::ConstIterator end = mPlugins.end();
00801   for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it )
00802     if ( ( *it )->identifier() == pluginName ) {
00803       selectPlugin( *it );
00804       return;
00805     }
00806 }
00807 
00808 void MainWindow::loadSettings()
00809 {
00810   if ( mSplitter )
00811     mSplitter->setSizes( Prefs::self()->mSidePaneSplitter );
00812 
00813   // Preload Plugins. This _must_ happen before the default part is loaded
00814   PluginList::ConstIterator it;
00815   for ( it = mDelayedPreload.begin(); it != mDelayedPreload.end(); ++it )
00816     selectPlugin( *it );
00817 
00818   selectPlugin( Prefs::self()->mActivePlugin );
00819 }
00820 
00821 void MainWindow::saveSettings()
00822 {
00823   if ( mSplitter )
00824     Prefs::self()->mSidePaneSplitter = mSplitter->sizes();
00825 
00826   if ( mCurrentPlugin )
00827     Prefs::self()->mActivePlugin = mCurrentPlugin->identifier();
00828 }
00829 
00830 void MainWindow::slotShowTip()
00831 {
00832   showTip( true );
00833 }
00834 
00835 void MainWindow::slotRequestFeature()
00836 {
00837   if ( kapp )
00838     kapp->invokeBrowser( "http://kontact.org/shopping" );
00839 }
00840 
00841 void MainWindow::slotShowIntroduction()
00842 {
00843   mPartsStack->raiseWidget( 0 ); // ###
00844 }
00845 
00846 void MainWindow::showTip( bool force )
00847 {
00848   QStringList tips;
00849   PluginList::ConstIterator end = mPlugins.end();
00850   for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it ) {
00851     QString file = (*it)->tipFile();
00852     if ( !file.isEmpty() )
00853       tips.append( file );
00854   }
00855 
00856   KTipDialog::showMultiTip( this, tips, force );
00857 }
00858 
00859 void MainWindow::slotQuit()
00860 {
00861   mReallyClose = true;
00862   close();
00863 }
00864 
00865 void MainWindow::slotPreferences()
00866 {
00867   static SettingsDialogWrapper *dlg = 0;
00868   if ( !dlg ) {
00869     // do not show settings of components running standalone
00870     QValueList<KPluginInfo*> filteredPlugins = mPluginInfos;
00871     PluginList::ConstIterator it;
00872     for ( it = mPlugins.begin(); it != mPlugins.end(); ++it )
00873       if ( (*it)->isRunningStandalone() ) {
00874         QValueList<KPluginInfo*>::ConstIterator infoIt;
00875         for ( infoIt = filteredPlugins.begin(); infoIt != filteredPlugins.end(); ++infoIt ) {
00876           if ( (*infoIt)->pluginName() == (*it)->identifier() ) {
00877             filteredPlugins.remove( *infoIt );
00878             break;
00879           }
00880         }
00881       }
00882     dlg = new SettingsDialogWrapper( KSettings::Dialog::Configurable, this );
00883     dlg->addPluginInfos( filteredPlugins );
00884     connect( dlg, SIGNAL( pluginSelectionChanged() ),
00885              SLOT( pluginsChanged() ) );
00886   }
00887 
00888   dlg->show();
00889   dlg->fixButtonLabel( this );
00890 }
00891 
00892 int MainWindow::startServiceFor( const QString& serviceType,
00893                                  const QString& constraint,
00894                                  const QString& preferences,
00895                                  QString *error, QCString* dcopService,
00896                                  int flags )
00897 {
00898   PluginList::ConstIterator end = mPlugins.end();
00899   for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it ) {
00900     if ( (*it)->createDCOPInterface( serviceType ) ) {
00901       kdDebug(5600) << "found interface for " << serviceType << endl;
00902       if ( dcopService )
00903         *dcopService = (*it)->dcopClient()->appId();
00904       kdDebug(5600) << "appId=" << (*it)->dcopClient()->appId() << endl;
00905       return 0; // success
00906     }
00907   }
00908 
00909   kdDebug(5600) <<
00910     "Didn't find dcop interface, falling back to external process" << endl;
00911 
00912   return KDCOPServiceStarter::startServiceFor( serviceType, constraint,
00913       preferences, error, dcopService, flags );
00914 }
00915 
00916 void MainWindow::pluginsChanged()
00917 {
00918   unplugActionList( "navigator_actionlist" );
00919   unloadPlugins();
00920   loadPlugins();
00921   mSidePane->updatePlugins();
00922   plugActionList( "navigator_actionlist", mSidePane->actions() );
00923 }
00924 
00925 void MainWindow::updateConfig()
00926 {
00927   kdDebug( 5600 ) << k_funcinfo << endl;
00928 
00929   saveSettings();
00930   loadSettings();
00931 }
00932 
00933 void MainWindow::showAboutDialog()
00934 {
00935   KApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
00936 
00937   if ( !mAboutDialog )
00938     mAboutDialog = new AboutDialog( this );
00939 
00940   mAboutDialog->show();
00941   mAboutDialog->raise();
00942   KApplication::restoreOverrideCursor();
00943 }
00944 
00945 void MainWindow::configureShortcuts()
00946 {
00947   KKeyDialog dialog( true, this );
00948   dialog.insert( actionCollection() );
00949 
00950   if ( mCurrentPlugin && mCurrentPlugin->part() )
00951     dialog.insert( mCurrentPlugin->part()->actionCollection() );
00952 
00953   dialog.configure();
00954 }
00955 
00956 void MainWindow::configureToolbars()
00957 {
00958   saveMainWindowSettings( KGlobal::config(), "MainWindow" );
00959 
00960   KEditToolbar edit( factory() );
00961   connect( &edit, SIGNAL( newToolbarConfig() ),
00962            this, SLOT( slotNewToolbarConfig() ) );
00963   edit.exec();
00964 }
00965 
00966 void MainWindow::slotNewToolbarConfig()
00967 {
00968   if ( mCurrentPlugin && mCurrentPlugin->part() )
00969     createGUI( mCurrentPlugin->part() );
00970   applyMainWindowSettings( KGlobal::config(), "MainWindow" );
00971 }
00972 
00973 void MainWindow::slotOpenUrl( const KURL &url )
00974 {
00975   if ( url.protocol() == "exec" ) {
00976     if ( url.path() == "/switch" ) {
00977       selectPlugin( mCurrentPlugin );
00978     }
00979     if ( url.path() == "/gwwizard" ) {
00980       KRun::runCommand( "groupwarewizard" );
00981       slotQuit();
00982     }
00983   } else
00984     new KRun( url, this );
00985 }
00986 
00987 void MainWindow::readProperties( KConfig *config )
00988 {
00989   Core::readProperties( config );
00990 
00991   QStringList activePlugins = config->readListEntry( "ActivePlugins" );
00992   QValueList<Plugin*>::ConstIterator it = mPlugins.begin();
00993   QValueList<Plugin*>::ConstIterator end = mPlugins.end();
00994   for ( ; it != end; ++it ) {
00995     Plugin *plugin = *it;
00996     if ( !plugin->isRunningStandalone() ) {
00997       QStringList::ConstIterator activePlugin = activePlugins.find( plugin->identifier() );
00998       if ( activePlugin != activePlugins.end() ) {
00999         plugin->readProperties( config );
01000       }
01001     }
01002   }
01003 }
01004 
01005 void MainWindow::saveProperties( KConfig *config )
01006 {
01007   Core::saveProperties( config );
01008 
01009   QStringList activePlugins;
01010 
01011   KPluginInfo::List::Iterator it = mPluginInfos.begin();
01012   KPluginInfo::List::Iterator end = mPluginInfos.end();
01013   for ( ; it != end; ++it ) {
01014     KPluginInfo *info = *it;
01015     if ( info->isPluginEnabled() ) {
01016       Plugin *plugin = pluginFromInfo( info );
01017       if ( plugin ) {
01018         activePlugins.append( plugin->identifier() );
01019         plugin->saveProperties( config );
01020       }
01021     }
01022   }
01023 
01024   config->writeEntry( "ActivePlugins", activePlugins );
01025 }
01026 
01027 bool MainWindow::queryClose()
01028 {
01029   if ( kapp->sessionSaving() || mReallyClose )
01030     return true;
01031 
01032   bool localClose = true;
01033   QValueList<Plugin*>::ConstIterator end = mPlugins.end();
01034   QValueList<Plugin*>::ConstIterator it = mPlugins.begin();
01035   for ( ; it != end; ++it ) {
01036     Plugin *plugin = *it;
01037     if ( !plugin->isRunningStandalone() )
01038       if ( !plugin->queryClose() )
01039         localClose = false;
01040   }
01041 
01042   return localClose;
01043 }
01044 
01045 void MainWindow::slotShowStatusMsg( const QString &msg )
01046 {
01047   if ( !statusBar() || !mStatusMsgLabel )
01048      return;
01049 
01050   mStatusMsgLabel->setText( msg );
01051 }
01052 
01053 QString MainWindow::introductionString()
01054 {
01055   KIconLoader *iconloader = KGlobal::iconLoader();
01056   int iconSize = iconloader->currentSize( KIcon::Desktop );
01057 
01058   QString handbook_icon_path = iconloader->iconPath( "contents2",  KIcon::Desktop );
01059   QString html_icon_path = iconloader->iconPath( "html",  KIcon::Desktop );
01060   QString wizard_icon_path = iconloader->iconPath( "wizard",  KIcon::Desktop );
01061 
01062   QString info = i18n( "<h2 style='text-align:center; margin-top: 0px;'>Welcome to Kontact %1</h2>"
01063       "<p>%1</p>"
01064       "<table align=\"center\">"
01065       "<tr><td><a href=\"%1\"><img width=\"%1\" height=\"%1\" src=\"%1\" /></a></td>"
01066       "<td><a href=\"%1\">%1</a><br><span id=\"subtext\"><nobr>%1</td></tr>"
01067       "<tr><td><a href=\"%1\"><img width=\"%1\" height=\"%1\" src=\"%1\" /></a></td>"
01068       "<td><a href=\"%1\">%1</a><br><span id=\"subtext\"><nobr>%1</td></tr>"
01069       "<tr><td><a href=\"%1\"><img width=\"%1\" height=\"%1\" src=\"%1\" /></a></td>"
01070       "<td><a href=\"%1\">%1</a><br><span id=\"subtext\"><nobr>%1</td></tr>"
01071       "</table>"
01072       "<p style=\"margin-bottom: 0px\"> <a href=\"%1\">Skip this introduction</a></p>" )
01073       .arg( kapp->aboutData()->version() )
01074       .arg( i18n( "Kontact handles your e-mail, addressbook, calendar, to-do list and more." ) )
01075       .arg( "help:/kontact" )
01076       .arg( iconSize )
01077       .arg( iconSize )
01078       .arg( handbook_icon_path )
01079       .arg( "help:/kontact" )
01080       .arg( i18n( "Read Manual" ) )
01081       .arg( i18n( "Learn more about Kontact and its components" ) )
01082       .arg( "http://kontact.org" )
01083       .arg( iconSize )
01084       .arg( iconSize )
01085       .arg( html_icon_path )
01086       .arg( "http://kontact.org" )
01087       .arg( i18n( "Visit Kontact Website" ) )
01088       .arg( i18n( "Access online resources and tutorials" ) )
01089       .arg( "exec:/gwwizard" )
01090       .arg( iconSize )
01091       .arg( iconSize )
01092       .arg( wizard_icon_path )
01093       .arg( "exec:/gwwizard" )
01094       .arg( i18n( "Configure Kontact as Groupware Client" ) )
01095       .arg( i18n( "Prepare Kontact for use in corporate networks" ) )
01096       .arg( "exec:/switch" );
01097   return info;
01098 }
01099 
01100 #include "mainwindow.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys