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