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