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