• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdepim
  • Sitemap
  • Contact Us
 

kontact

mainwindow.cpp

Go to the documentation of this file.
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 along
00019   with this program; if not, write to the Free Software Foundation, Inc.,
00020   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00021 */
00022 
00023 #include "mainwindow.h"
00024 #include "aboutdialog.h"
00025 #include "iconsidepane.h"
00026 #include "plugin.h"
00027 #include "prefs.h"
00028 #include "progressdialog.h"
00029 #include "statusbarprogresswidget.h"
00030 #include "broadcaststatus.h"
00031 
00032 #include <kpimutils/kfileio.h>
00033 
00034 #include <kparts/componentfactory.h>
00035 #include <ksettings/dialog.h>
00036 #include <ksettings/dispatcher.h>
00037 #include <kactioncollection.h>
00038 #include <kapplication.h>
00039 #include <kconfig.h>
00040 #include <kconfiggroup.h>
00041 #include <kdebug.h>
00042 #include <kdbusservicestarter.h>
00043 #include <kedittoolbar.h>
00044 #include <kguiitem.h>
00045 #include <khelpmenu.h>
00046 #include <kiconloader.h>
00047 #include <kshortcutsdialog.h>
00048 #include <klibloader.h>
00049 #include <ktoolbar.h>
00050 #include <klocale.h>
00051 #include <kmessagebox.h>
00052 #include <kplugininfo.h>
00053 #include <kmenu.h>
00054 #include <kshortcut.h>
00055 #include <kstandarddirs.h>
00056 #include <kstatusbar.h>
00057 #include <kstandardaction.h>
00058 #include <ktip.h>
00059 #include <kservice.h>
00060 #include <kservicetypetrader.h>
00061 #include <kstringhandler.h>
00062 #include <ksqueezedtextlabel.h>
00063 #include <khtml_part.h>
00064 #include <khtmlview.h>
00065 #include <krun.h>
00066 #include <kaboutdata.h>
00067 #include <kmenubar.h>
00068 #include <kstandardshortcut.h>
00069 #include <ktoolinvocation.h>
00070 #include <ktoolbarpopupaction.h>
00071 #include <khbox.h>
00072 #include <kvbox.h>
00073 #include <kicon.h>
00074 #include <kxmlguifactory.h>
00075 
00076 #include <QComboBox>
00077 #include <QCursor>
00078 #include <QDBusConnection>
00079 #include <QImage>
00080 #include <QLayout>
00081 #include <QList>
00082 #include <QObject>
00083 #include <QPushButton>
00084 #include <QSplitter>
00085 #include <QStackedWidget>
00086 #include <QTimer>
00087 
00088 using namespace Kontact;
00089 
00090 // This class extends the normal KDBusServiceStarter.
00091 //
00092 // When a service start is requested, it asks all plugins
00093 // to create their dbus interfaces in addition to the normal
00094 // way of starting a service.
00095 class ServiceStarter : public KDBusServiceStarter
00096 {
00097   public:
00098 
00099     virtual int startServiceFor( const QString &serviceType,
00100                                  const QString &constraint = QString(),
00101                                  QString *error = 0, QString *dbusService = 0,
00102                                  int flags = 0 );
00103 
00104     // We need to keep track of the plugins which are loaded, so pass a pointer
00105     // to the plugin list here. Be sure to reset it back to 0 with
00106     // setPluginList() as soon as the list gets destroyed.
00107     ServiceStarter( PluginList *pluginList ) {
00108       mPlugins = pluginList;
00109     }
00110 
00111     static void setPluginList( PluginList *pluginList ) {
00112       mPlugins = pluginList;
00113     }
00114 
00115   protected:
00116 
00117     virtual ~ServiceStarter() {}
00118     static PluginList *mPlugins;
00119 };
00120 
00121 PluginList *ServiceStarter::mPlugins = 0;
00122 
00123 int ServiceStarter::startServiceFor( const QString &serviceType,
00124                                      const QString &constraint,
00125                                      QString *error, QString *dbusService,
00126                                      int flags )
00127 {
00128   if ( mPlugins ) {
00129     PluginList::ConstIterator end = mPlugins->end();
00130     for ( PluginList::ConstIterator it = mPlugins->begin(); it != end; ++it ) {
00131       if ( (*it)->createDBUSInterface( serviceType ) ) {
00132         kDebug() << "found interface for" << serviceType;
00133         if ( dbusService ) {
00134           *dbusService = (*it)->registerClient();
00135         }
00136         return 0;
00137       }
00138     }
00139   }
00140 
00141   kDebug() << "Didn't find dbus interface, falling back to external process";
00142   return KDBusServiceStarter::startServiceFor( serviceType, constraint,
00143                                                error, dbusService, flags );
00144 }
00145 
00146 MainWindow::MainWindow()
00147   : Kontact::Core(), mSplitter( 0 ), mCurrentPlugin( 0 ), mAboutDialog( 0 ),
00148     mReallyClose( false ), mSyncActionsEnabled( true )
00149 {
00150   // The ServiceStarter created here will be deleted by the KDbusServiceStarter
00151   // base class, which is a global static.
00152   new ServiceStarter( &mPlugins );
00153 
00154   QDBusConnection::sessionBus().registerObject(
00155     "/KontactInterface", this, QDBusConnection::ExportScriptableSlots );
00156 
00157   // Set this to be the group leader for all subdialogs - this means
00158   // modal subdialogs will only affect this dialog, not the other windows
00159   setAttribute( Qt::WA_GroupLeader );
00160 
00161   initGUI();
00162   initObject();
00163 
00164   mSidePane->setMaximumWidth( mSidePane->sizeHint().width() );
00165   mSidePane->setMinimumWidth( mSidePane->sizeHint().width() );
00166 
00167   factory()->plugActionList( this, QString( "navigator_actionlist" ), mActionPlugins );
00168 }
00169 
00170 void MainWindow::initGUI()
00171 {
00172   initWidgets();
00173   setupActions();
00174   setHelpMenuEnabled( false );
00175   KHelpMenu *helpMenu = new KHelpMenu( this, 0, true, actionCollection() );
00176   connect( helpMenu, SIGNAL(showAboutApplication()), SLOT(showAboutDialog()) );
00177 
00178   KStandardAction::keyBindings( this, SLOT(configureShortcuts()), actionCollection() );
00179   KStandardAction::configureToolbars( this, SLOT(configureToolbars()), actionCollection() );
00180   setXMLFile( "kontactui.rc" );
00181 
00182   setStandardToolBarMenuEnabled( true );
00183 
00184   createGUI( 0 );
00185 
00186   resize( 700, 520 ); // initial size to prevent a scrollbar in sidepane
00187   setAutoSaveSettings();
00188 
00189   KToolBar *navigatorToolBar = findToolBar( "navigatorToolBar" );
00190   Q_ASSERT( navigatorToolBar );
00191   if ( layoutDirection() == Qt::LeftToRight ) {
00192     navigatorToolBar->setLayoutDirection( Qt::RightToLeft );
00193   } else {
00194     navigatorToolBar->setLayoutDirection( Qt::LeftToRight );
00195   }
00196   Q_ASSERT( navigatorToolBar->sizeHint().isValid() );
00197   navigatorToolBar->setMinimumWidth( navigatorToolBar->sizeHint().width() );
00198 }
00199 
00200 void MainWindow::initObject()
00201 {
00202   KService::List offers = KServiceTypeTrader::self()->query(
00203     QString::fromLatin1( "Kontact/Plugin" ),
00204     QString( "[X-KDE-KontactPluginVersion] == %1" ).arg( KONTACT_PLUGIN_VERSION ) );
00205   mPluginInfos = KPluginInfo::fromServices(
00206     offers, KConfigGroup( Prefs::self()->config(), "Plugins" ) );
00207 
00208   KPluginInfo::List::Iterator it;
00209   for ( it = mPluginInfos.begin(); it != mPluginInfos.end(); ++it ) {
00210     it->load();
00211   }
00212 
00213   // prepare the part manager
00214   mPartManager = new KParts::PartManager( this );
00215   connect( mPartManager, SIGNAL(activePartChanged(KParts::Part *)),
00216            this, SLOT(slotActivePartChanged(KParts::Part *)) );
00217 
00218   loadPlugins();
00219 
00220   if ( mSidePane ) {
00221     mSidePane->updatePlugins();
00222   }
00223 
00224   KSettings::Dispatcher::registerComponent( componentData(), this, "updateConfig" );
00225 
00226   loadSettings();
00227 
00228   statusBar()->show();
00229 
00230   QTimer::singleShot( 200, this, SLOT( slotShowTipOnStart() ) );
00231 
00232   // done initializing
00233   slotShowStatusMsg( QString::null );   //krazy:exclude=nullstrassign for old broken gcc
00234 
00235   connect( KPIM::BroadcastStatus::instance(), SIGNAL(statusMsg(const QString &)),
00236            this, SLOT(slotShowStatusMsg(const QString &)) );
00237 
00238   // launch commandline specified module if any
00239   activatePluginModule();
00240 
00241   if ( Prefs::lastVersionSeen() == KGlobal::mainComponent().aboutData()->version() ) {
00242     selectPlugin( mCurrentPlugin );
00243   }
00244 
00245   paintAboutScreen( introductionString() );
00246   Prefs::setLastVersionSeen( KGlobal::mainComponent().aboutData()->version() );
00247 }
00248 
00249 MainWindow::~MainWindow()
00250 {
00251   if ( mCurrentPlugin ) {
00252     saveMainWindowSettings( KGlobal::config()->group( QString( "MainWindow%1" ).arg( mCurrentPlugin->identifier() ) ) );
00253   }
00254 
00255   createGUI( 0 );
00256   ServiceStarter::setPluginList( 0 );
00257   saveSettings();
00258 
00259   QList<KParts::Part*> parts = mPartManager->parts();
00260 
00261   Q_FOREACH( KParts::Part *p, parts ) {
00262     delete p;
00263     p = 0;
00264   }
00265 
00266   Prefs::self()->writeConfig();
00267 
00268   // Make sure we really return from the event loop. It could happen that a KJob
00269   // somewhere is still running because a part forgot to delete it. And a running
00270   // KJob still has a reference to a KGlobal.
00271   // Normally KGlobal::deref() calls this when the last reference goes away.
00272   QCoreApplication::instance()->quit();
00273 }
00274 
00275 void MainWindow::setActivePluginModule( const QString &module )
00276 {
00277   mActiveModule = module;
00278   activatePluginModule();
00279 }
00280 
00281 bool MainWindow::pluginActionWeightLessThan( const QAction *left, const QAction *right )
00282 {
00283   // Since this lessThan method is used only for the toolbar (which is on the inverse layout direction
00284   // than the rest of the system), we add the elements on the exactly inverse order. (ereslibre)
00285   return !pluginWeightLessThan( left->data().value<Kontact::Plugin*>(),
00286                                 right->data().value<Kontact::Plugin*>() );
00287 }
00288 
00289 bool MainWindow::pluginWeightLessThan( const Kontact::Plugin *left, const Kontact::Plugin *right )
00290 {
00291   return left->weight() < right->weight();
00292 }
00293 
00294 void MainWindow::activatePluginModule()
00295 {
00296   if ( !mActiveModule.isEmpty() ) {
00297     PluginList::ConstIterator end = mPlugins.end();
00298     for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it ) {
00299       if ( ( *it )->identifier().contains( mActiveModule ) ) {
00300         selectPlugin( *it );
00301         return;
00302       }
00303     }
00304   }
00305 }
00306 
00307 void MainWindow::initWidgets()
00308 {
00309   QWidget *mTopWidget = new QWidget( this );
00310   QVBoxLayout *layout = new QVBoxLayout;
00311   mTopWidget->setLayout( layout );
00312   setCentralWidget( mTopWidget );
00313 
00314   mSplitter = new QSplitter( mTopWidget );
00315   layout->addWidget( mSplitter );
00316   mSidePane = new IconSidePane( this, mSplitter );
00317 /*
00318   // don't occupy screen estate on load
00319 
00320   QList<int> sizes;
00321   sizes << 0;
00322   mSplitter->setSizes(sizes);
00323 */
00324   connect( mSidePane, SIGNAL(pluginSelected(Kontact::Plugin *)),
00325            SLOT(selectPlugin(Kontact::Plugin *)) );
00326 
00327   mPartsStack = new QStackedWidget( mSplitter );
00328   mPartsStack->layout()->setSpacing( 0 );
00329 
00330   initAboutScreen();
00331 
00332   QString loading =
00333     i18n( "<h2 style='text-align:center; margin-top: 0px; margin-bottom: 0px'>%1</h2>",
00334           i18n( "Loading Kontact..." ) );
00335 
00336   paintAboutScreen( loading );
00337 
00338   /* Create a progress dialog and hide it. */
00339   KPIM::ProgressDialog *progressDialog = new KPIM::ProgressDialog( statusBar(), this );
00340   progressDialog->hide();
00341 
00342   mLittleProgress = new KPIM::StatusbarProgressWidget( progressDialog, statusBar() );
00343 
00344   mStatusMsgLabel = new KSqueezedTextLabel( i18n( " Initializing..." ), statusBar() );
00345   mStatusMsgLabel->setTextElideMode( Qt::ElideRight );
00346   mStatusMsgLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
00347 
00348   statusBar()->addWidget( mStatusMsgLabel, 10 );
00349   statusBar()->addPermanentWidget( mLittleProgress, 0 );
00350   mLittleProgress->show();
00351 
00352   mSplitter->setCollapsible( 1, false );
00353 }
00354 
00355 void MainWindow::paintAboutScreen( const QString &msg )
00356 {
00357   QString location = KStandardDirs::locate( "data", "kontact/about/main.html" );
00358   QString content = KPIMUtils::kFileToByteArray( location );
00359   content = content.arg( KStandardDirs::locate( "data", "kdeui/about/kde_infopage.css" ) );
00360   if ( QApplication::isRightToLeft() ) {
00361     content = content.arg( "@import \"%1\";" ).
00362               arg( KStandardDirs::locate( "data", "kdeui/about/kde_infopage_rtl.css" ) );
00363   } else {
00364     content = content.arg( "" );
00365   }
00366 
00367   mIntroPart->begin( KUrl( location ) );
00368 
00369   QString appName( i18n( "KDE Kontact" ) );
00370   QString catchPhrase( i18n( "Get Organized!" ) );
00371   QString quickDescription( i18n( "The KDE Personal Information Management Suite" ) );
00372 
00373   mIntroPart->write(
00374     content.arg( QFont().pointSize() + 2 ).
00375     arg( appName ).arg( catchPhrase ).arg( quickDescription ).arg( msg ) );
00376   mIntroPart->end();
00377 }
00378 
00379 void MainWindow::initAboutScreen()
00380 {
00381   KHBox *introbox = new KHBox( mPartsStack );
00382   mPartsStack->addWidget( introbox );
00383   mPartsStack->setCurrentWidget( introbox );
00384   mIntroPart = new KHTMLPart( introbox );
00385   mIntroPart->widget()->setFocusPolicy( Qt::WheelFocus );
00386   // Let's better be paranoid and disable plugins (it defaults to enabled):
00387   mIntroPart->setPluginsEnabled( false );
00388   mIntroPart->setJScriptEnabled( false ); // just make this explicit
00389   mIntroPart->setJavaEnabled( false );    // just make this explicit
00390   mIntroPart->setMetaRefreshEnabled( false );
00391   mIntroPart->setURLCursor( QCursor( Qt::PointingHandCursor ) );
00392   mIntroPart->view()->setLineWidth( 0 );
00393 
00394   connect( mIntroPart->browserExtension(),
00395            SIGNAL(openUrlRequest(const KUrl &,const KParts::OpenUrlArguments &,
00396                                  const KParts::BrowserArguments &)),
00397            SLOT(slotOpenUrl(const KUrl &)) );
00398 
00399   connect( mIntroPart->browserExtension(),
00400            SIGNAL(createNewWindow(const KUrl &,const KParts::OpenUrlArguments &,
00401                                   const KParts::BrowserArguments &)),
00402            SLOT(slotOpenUrl(const KUrl&)) );
00403 }
00404 
00405 void MainWindow::setupActions()
00406 {
00407   actionCollection()->addAction( KStandardAction::Quit, this, SLOT(slotQuit()) );
00408 
00409   mNewActions = new KToolBarPopupAction(
00410     KIcon( "" ),
00411     i18nc( "@title:menu create new pim items (message,calendar,to-do,etc.)", "New" ), this );
00412   actionCollection()->addAction( "action_new", mNewActions );
00413   mNewActions->setShortcut( KStandardShortcut::openNew() );
00414   connect( mNewActions, SIGNAL(triggered(bool)), this, SLOT(slotNewClicked()) );
00415 
00416   // If the user is using disconnected imap mail folders as groupware, we add plugins' Synchronize
00417   // actions to the toolbar which trigger an imap sync.  Otherwise it's redundant and
00418   // misleading.
00419   KConfig *_cfg = Prefs::self()->config();
00420   KConfigGroup cfg( _cfg, "Kontact Groupware Settings" );
00421   mSyncActionsEnabled = cfg.readEntry( "GroupwareMailFoldersEnabled", false );
00422 
00423   if ( mSyncActionsEnabled ) {
00424     mSyncActions = new KToolBarPopupAction(
00425       KIcon( "view-refresh" ),
00426       i18nc( "@title:menu synchronize pim items (message,calendar,to-do,etc.)", "Sync" ), this );
00427     actionCollection()->addAction( "action_sync", mSyncActions );
00428     mSyncActions->setShortcut( KStandardShortcut::reload() );
00429     connect( mSyncActions, SIGNAL(triggered(bool)), this, SLOT(slotSyncClicked()) );
00430   }
00431 
00432   KAction *action = new KAction( KIcon( "configure" ), i18n( "Configure Kontact..." ), this );
00433   actionCollection()->addAction( "settings_configure_kontact", action );
00434   connect( action, SIGNAL(triggered(bool)), SLOT(slotPreferences()) );
00435 
00436   action = new KAction( KIcon( "kontact" ), i18n( "&Kontact Introduction" ), this );
00437   actionCollection()->addAction( "help_introduction", action );
00438   connect( action, SIGNAL(triggered(bool)), SLOT(slotShowIntroduction()) );
00439   action = new KAction( KIcon( "ktip" ), i18n( "&Tip of the Day" ), this );
00440   actionCollection()->addAction( "help_tipofday", action );
00441   connect( action, SIGNAL(triggered(bool)), SLOT(slotShowTip()) );
00442 }
00443 
00444 bool MainWindow::isPluginLoaded( const KPluginInfo &info )
00445 {
00446   return ( pluginFromInfo( info ) != 0 );
00447 }
00448 
00449 Plugin *MainWindow::pluginFromInfo( const KPluginInfo &info )
00450 {
00451   PluginList::ConstIterator end = mPlugins.end();
00452   for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it ) {
00453     if ( (*it)->identifier() == info.pluginName() ) {
00454       return *it;
00455     }
00456   }
00457   return 0;
00458 }
00459 
00460 void MainWindow::loadPlugins()
00461 {
00462   QList<Plugin*> plugins;
00463 
00464   int i;
00465   KPluginInfo::List::ConstIterator it;
00466   for ( it = mPluginInfos.begin(); it != mPluginInfos.end(); ++it ) {
00467     if ( !it->isPluginEnabled() ) {
00468       continue;
00469     }
00470 
00471     Plugin *plugin = 0;
00472     if ( isPluginLoaded( *it ) ) {
00473       plugin = pluginFromInfo( *it );
00474       if ( plugin ) {
00475         plugin->configUpdated();
00476       }
00477       continue;
00478     }
00479 
00480     kDebug() << "Loading Plugin:" << it->name();
00481     plugin =  KService::createInstance<Kontact::Plugin>( it->service(), this );
00482 
00483     if ( !plugin ) {
00484       kDebug() << "Unable to create plugin for " << it->name();
00485       continue;
00486     }
00487 
00488     plugin->setIdentifier( it->pluginName() );
00489     plugin->setTitle( it->name() );
00490     plugin->setIcon( it->icon() );
00491 
00492     QVariant libNameProp = it->property( "X-KDE-KontactPartLibraryName" );
00493     QVariant exeNameProp = it->property( "X-KDE-KontactPartExecutableName" );
00494     QVariant loadOnStart = it->property( "X-KDE-KontactPartLoadOnStart" );
00495     QVariant hasPartProp = it->property( "X-KDE-KontactPluginHasPart" );
00496 
00497     if ( !loadOnStart.isNull() && loadOnStart.toBool() ) {
00498       mDelayedPreload.append( plugin );
00499     }
00500 
00501     kDebug() << "LIBNAMEPART:" << libNameProp.toString();
00502 
00503     plugin->setPartLibraryName( libNameProp.toString().toUtf8() );
00504     plugin->setExecutableName( exeNameProp.toString() );
00505     if ( hasPartProp.isValid() ) {
00506       plugin->setShowInSideBar( hasPartProp.toBool() );
00507     }
00508 
00509     for ( i = 0; i < plugins.count(); ++i ) {
00510       Plugin *p = plugins.at( i );
00511       if ( plugin->weight() < p->weight() ) {
00512         break;
00513       }
00514     }
00515     plugins.insert( i, plugin );
00516 
00517   }
00518 
00519   for ( i = 0; i < plugins.count(); ++ i ) {
00520     Plugin *plugin = plugins.at( i );
00521 
00522     const QList<KAction*> *actionList = plugin->newActions();
00523     QList<KAction*>::const_iterator listIt;
00524 
00525     for ( listIt = actionList->begin(); listIt != actionList->end(); ++listIt ) {
00526       kDebug() << "Plugging New actions" << (*listIt)->objectName();
00527       mNewActions->menu()->addAction( (*listIt) );
00528     }
00529 
00530     actionList = plugin->syncActions();
00531     if ( mSyncActionsEnabled ) {
00532       Q_FOREACH( KAction *listIt, *actionList ) {
00533         kDebug() << "Plugging Sync actions" << listIt->objectName();
00534         mSyncActions->menu()->addAction( listIt );
00535       }
00536     }
00537     addPlugin( plugin );
00538   }
00539 
00540   mNewActions->setEnabled( mPlugins.size() != 0 );
00541   if ( mSyncActionsEnabled ) {
00542     mSyncActions->setEnabled( mPlugins.size() != 0 );
00543   }
00544 }
00545 
00546 void MainWindow::unloadPlugins()
00547 {
00548   KPluginInfo::List::ConstIterator end = mPluginInfos.end();
00549   KPluginInfo::List::ConstIterator it;
00550   for ( it = mPluginInfos.begin(); it != end; ++it ) {
00551     if ( !it->isPluginEnabled() ) {
00552       removePlugin( *it );
00553     }
00554   }
00555 }
00556 
00557 void MainWindow::updateShortcuts()
00558 {
00559   ActionPluginList::ConstIterator end = mActionPlugins.end();
00560   ActionPluginList::ConstIterator it;
00561   int i = 1;
00562   for ( it = mActionPlugins.begin(); it != end; ++it ) {
00563     KAction *action = static_cast<KAction*>( *it );
00564     QString shortcut = QString( "Ctrl+%1" ).arg( i );
00565     action->setShortcut( KShortcut( shortcut ) );
00566     i++;
00567   }
00568   factory()->plugActionList( this, QString( "navigator_actionlist" ), mActionPlugins );
00569 }
00570 
00571 bool MainWindow::removePlugin( const KPluginInfo &info )
00572 {
00573   PluginList::Iterator end = mPlugins.end();
00574   ActionPluginList::Iterator it2 = mActionPlugins.begin();
00575   for ( PluginList::Iterator it = mPlugins.begin(); it != end; ++it ) {
00576     Plugin *plugin = *it;
00577     if ( ( *it )->identifier() == info.pluginName() ) {
00578       const QList<KAction*> *actionList = plugin->newActions();
00579       QList<KAction*>::const_iterator listIt;
00580 
00581       for ( listIt = actionList->begin(); listIt != actionList->end(); ++listIt ) {
00582         kDebug() << "Unplugging New actions" << (*listIt)->objectName();
00583         mNewActions->menu()->removeAction( *listIt );
00584       }
00585 
00586       if ( mSyncActionsEnabled ) {
00587         actionList = plugin->syncActions();
00588         for ( listIt = actionList->begin(); listIt != actionList->end(); ++listIt ) {
00589             kDebug() << "Unplugging Sync actions" << (*listIt)->objectName();
00590             mSyncActions->menu()->removeAction( *listIt );
00591         }
00592       }
00593       removeChildClient( plugin );
00594 
00595       if ( mCurrentPlugin == plugin ) {
00596         mCurrentPlugin = 0;
00597         createGUI( 0 );
00598       }
00599 
00600       plugin->deleteLater(); // removes the part automatically
00601       mPlugins.erase( it );
00602       if ( plugin->showInSideBar() ) {
00603         delete *it2; // remove the KAction, so we free the shortcut for later us
00604         mActionPlugins.erase( it2 );
00605       }
00606 
00607       if ( mCurrentPlugin == 0 ) {
00608         PluginList::Iterator it;
00609         for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
00610           if ( (*it)->showInSideBar() ) {
00611             selectPlugin( *it );
00612             return true;
00613           }
00614         }
00615       }
00616       return true;
00617     }
00618 
00619     if ( plugin->showInSideBar() ) {
00620       it2++;
00621     }
00622   }
00623 
00624   return false;
00625 }
00626 
00627 void MainWindow::addPlugin( Kontact::Plugin *plugin )
00628 {
00629   kDebug();
00630 
00631   mPlugins.append( plugin );
00632 
00633   if ( plugin->showInSideBar() ) {
00634     KAction *action = new KAction( KIcon( plugin->icon() ), plugin->title(), this );
00635     action->setCheckable( true );
00636     action->setData( QVariant::fromValue( plugin ) ); // on the slot we can decode which action was
00637                                                       // triggered
00638     connect( action, SIGNAL(triggered(bool)), SLOT(slotActionTriggered()) );
00639     actionCollection()->addAction( plugin->title(), action );
00640     mActionPlugins.append( action );
00641     mPluginAction.insert( plugin, action );
00642   }
00643 
00644   // merge the plugins GUI into the main window
00645   insertChildClient( plugin );
00646 
00647   // sort the action plugins again and reset shortcuts. If we removed and then readded some plugins
00648   // we need to take in count their weights for setting shortcuts again
00649   qSort( mActionPlugins.begin(), mActionPlugins.end(), pluginActionWeightLessThan );
00650   qSort( mPlugins.begin(), mPlugins.end(), pluginWeightLessThan );
00651   int i = 1;
00652   foreach ( QAction *qaction, mActionPlugins ) {
00653     KAction *action = static_cast<KAction*>( qaction );
00654     QString shortcut = QString( "Ctrl+%1" ).arg( i );
00655     action->setShortcut( KShortcut( shortcut ) );
00656     i++;
00657   }
00658 }
00659 
00660 void MainWindow::partLoaded( Kontact::Plugin *plugin, KParts::ReadOnlyPart *part )
00661 {
00662   Q_UNUSED( plugin );
00663 
00664   // See if we have this part already (e.g. due to two plugins sharing it)
00665   if ( mPartsStack->indexOf( part->widget() ) != -1 ) {
00666     return;
00667   }
00668 
00669   mPartsStack->addWidget( part->widget() );
00670 
00671   mPartManager->addPart( part, false );
00672   // Workaround for KParts misbehavior: addPart calls show!
00673   part->widget()->hide();
00674 }
00675 
00676 void MainWindow::slotActivePartChanged( KParts::Part *part )
00677 {
00678   if ( !part ) {
00679     createGUI( 0 );
00680     return;
00681   }
00682 
00683   kDebug() << "Part activated:" << part
00684            << "with stack id."<< mPartsStack->indexOf( part->widget() );
00685 
00686   statusBar()->clearMessage();
00687 }
00688 
00689 void MainWindow::slotNewClicked()
00690 {
00691   if ( !mCurrentPlugin->newActions()->isEmpty() ) {
00692     mCurrentPlugin->newActions()->first()->trigger();
00693   } else {
00694     PluginList::Iterator it;
00695     for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
00696       if ( !(*it)->newActions()->isEmpty() ) {
00697         (*it)->newActions()->first()->trigger();
00698         return;
00699       }
00700     }
00701   }
00702 }
00703 
00704 void MainWindow::slotSyncClicked()
00705 {
00706   if ( !mCurrentPlugin->syncActions()->isEmpty() ) {
00707     mCurrentPlugin->syncActions()->first()->trigger();
00708   } else {
00709     PluginList::Iterator it;
00710     for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
00711       if ( !(*it)->syncActions()->isEmpty() ) {
00712         (*it)->syncActions()->first()->trigger();
00713         return;
00714       }
00715     }
00716   }
00717 }
00718 
00719 KToolBar *Kontact::MainWindow::findToolBar( const char *name )
00720 {
00721   // like KMainWindow::toolBar, but which doesn't create the toolbar if not found
00722   return findChild<KToolBar *>( name );
00723 }
00724 
00725 void MainWindow::selectPlugin( Kontact::Plugin *plugin )
00726 {
00727   if ( !plugin ) {
00728     return;
00729   }
00730 
00731   if ( plugin->isRunningStandalone() ) {
00732     statusBar()->showMessage( i18n( "Application is running standalone. Foregrounding..." ), 1000 );
00733     plugin->bringToForeground();
00734     return;
00735   }
00736 
00737   QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
00738 
00739   if ( mCurrentPlugin ) {
00740     saveMainWindowSettings( KGlobal::config()->group( QString( "MainWindow%1" ).arg( mCurrentPlugin->identifier() ) ) );
00741   }
00742 
00743   KParts::Part *part = plugin->part();
00744 
00745   if ( !part ) {
00746     QApplication::restoreOverrideCursor();
00747     KMessageBox::error( this, i18n( "Cannot load part for %1.",
00748                                     plugin->title() ) + '\n' + lastErrorMessage() );
00749     plugin->setDisabled( true );
00750     mSidePane->updatePlugins();
00751     return;
00752   }
00753 
00754   if ( mCurrentPlugin ) {
00755     KAction *action = mPluginAction[ mCurrentPlugin ];
00756     if ( action ) {
00757       action->setChecked( false );
00758     }
00759   }
00760   KAction *selectedPluginAction = mPluginAction[ plugin ];
00761   if ( selectedPluginAction ) {
00762     selectedPluginAction->setChecked( true );
00763   }
00764 
00765   // store old focus widget
00766   QWidget *focusWidget = kapp->focusWidget();
00767   if ( mCurrentPlugin && focusWidget ) {
00768     // save the focus widget only when it belongs to the activated part
00769     QWidget *parent = focusWidget->parentWidget();
00770     while ( parent ) {
00771       if ( parent == mCurrentPlugin->part()->widget() ) {
00772         mFocusWidgets.insert( mCurrentPlugin->identifier(), QPointer<QWidget>( focusWidget ) );
00773       }
00774       parent = parent->parentWidget();
00775     }
00776   }
00777 
00778   if ( mSidePane ) {
00779     mSidePane->setCurrentPlugin( plugin->identifier() );
00780   }
00781 
00782   plugin->select();
00783 
00784   mPartManager->setActivePart( part );
00785   QWidget *view = part->widget();
00786   Q_ASSERT( view );
00787 
00788   if ( view ) {
00789     mPartsStack->setCurrentWidget( view );
00790     view->show();
00791 
00792     if ( mFocusWidgets.contains( plugin->identifier() ) ) {
00793       focusWidget = mFocusWidgets[ plugin->identifier() ];
00794       if ( focusWidget ) {
00795         focusWidget->setFocus();
00796       }
00797     } else {
00798       view->setFocus();
00799     }
00800 
00801     mCurrentPlugin = plugin;
00802 
00803     QAction *newAction = 0;
00804     if ( plugin->newActions()->count() > 0 ) {
00805       newAction = plugin->newActions()->first();
00806     }
00807 
00808     QAction *syncAction = 0;
00809     if ( plugin->syncActions()->count() > 0 ) {
00810       syncAction = plugin->syncActions()->first();
00811     }
00812 
00813     createGUI( plugin->part() );
00814 
00815     setCaption( i18nc( "Plugin dependent window title", "%1 - Kontact", plugin->title() ) );
00816 
00817     if ( newAction ) {
00818       mNewActions->setIcon( newAction->icon() );
00819       static_cast<QAction*>( mNewActions )->setText( newAction->text() );
00820     } else { // we'll use the action of the first plugin which offers one
00821       PluginList::Iterator it;
00822       for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
00823         if ( (*it)->newActions()->count() > 0 ) {
00824           newAction = (*it)->newActions()->first();
00825         }
00826         if ( newAction ) {
00827           static_cast<QAction*>( mNewActions )->setIcon( newAction->icon() );
00828           mNewActions->setText( newAction->text() );
00829           break;
00830         }
00831       }
00832     }
00833 
00834     if ( mSyncActionsEnabled ) {
00835       if ( syncAction ) {
00836         mSyncActions->setIcon( syncAction->icon() );
00837         static_cast<QAction*>( mSyncActions )->setText( syncAction->text() );
00838       } else { // we'll use the action of the first plugin which offers one
00839         PluginList::Iterator it;
00840         for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
00841           if ( (*it)->syncActions()->count() > 0 ) {
00842             syncAction = (*it)->syncActions()->first();
00843           }
00844           if ( syncAction ) {
00845             static_cast<QAction*>( mSyncActions )->setIcon( syncAction->icon() );
00846             mSyncActions->setText( syncAction->text() );
00847             break;
00848           }
00849         }
00850       }
00851     }
00852   }
00853   QStringList invisibleActions = plugin->invisibleToolbarActions();
00854 
00855   QStringList::ConstIterator it;
00856   for ( it = invisibleActions.begin(); it != invisibleActions.end(); ++it ) {
00857     QAction *action = part->actionCollection()->action( (*it) );
00858     if ( action ) {
00859       QList<KToolBar*> toolbars = toolBars();
00860       for ( QList<KToolBar*>::Iterator it = toolbars.begin(); it != toolbars.end(); ++it ) {
00861         ( *it )->removeAction( action );
00862       }
00863     }
00864   }
00865 
00866   KToolBar *navigatorToolBar = findToolBar( "navigatorToolBar" );
00867   if ( navigatorToolBar && !navigatorToolBar->isHidden() &&
00868        ( toolBarArea( navigatorToolBar ) == Qt::TopToolBarArea ||
00869          toolBarArea( navigatorToolBar ) == Qt::BottomToolBarArea ) ) {
00870     addToolBar( toolBarArea( navigatorToolBar ), navigatorToolBar );
00871   }
00872 
00873   applyMainWindowSettings( KGlobal::config()->group( QString( "MainWindow%1" ).arg( plugin->identifier() ) ) );
00874 
00875   QApplication::restoreOverrideCursor();
00876 }
00877 
00878 void MainWindow::slotActionTriggered()
00879 {
00880   KAction *actionSender = static_cast<KAction*>( sender() );
00881   actionSender->setChecked( true );
00882   Kontact::Plugin *plugin = actionSender->data().value<Kontact::Plugin*>();
00883   if ( !plugin ) {
00884     return;
00885   }
00886   mSidePane->setCurrentPlugin( plugin->identifier() );
00887 }
00888 
00889 void MainWindow::selectPlugin( const QString &pluginName )
00890 {
00891   PluginList::ConstIterator end = mPlugins.end();
00892   for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it ) {
00893     if ( ( *it )->identifier() == pluginName ) {
00894       selectPlugin( *it );
00895       return;
00896     }
00897   }
00898 }
00899 
00900 void MainWindow::loadSettings()
00901 {
00902   if ( mSplitter ) {
00903     // if the preferences do not contain useful values, the side pane part of the splitter
00904     // takes up the full width of the window, so leave the splitter sizing at the widget defaults
00905     QList<int> sizes = Prefs::self()->sidePaneSplitter();
00906     if ( sizes.count() == mSplitter->count() ) {
00907       mSplitter->setSizes( sizes );
00908     }
00909   }
00910 
00911   // Preload Plugins. This _must_ happen before the default part is loaded
00912   PluginList::ConstIterator it;
00913   for ( it = mDelayedPreload.begin(); it != mDelayedPreload.end(); ++it ) {
00914     selectPlugin( *it );
00915   }
00916   selectPlugin( Prefs::self()->mActivePlugin );
00917 }
00918 
00919 void MainWindow::saveSettings()
00920 {
00921   if ( mSplitter ) {
00922     Prefs::self()->mSidePaneSplitter = mSplitter->sizes();
00923   }
00924 
00925   if ( mCurrentPlugin ) {
00926     Prefs::self()->mActivePlugin = mCurrentPlugin->identifier();
00927   }
00928 }
00929 
00930 void MainWindow::slotShowTip()
00931 {
00932   showTip( true );
00933 }
00934 
00935 void MainWindow::slotShowTipOnStart()
00936 {
00937   showTip( false );
00938 }
00939 
00940 void MainWindow::slotShowIntroduction()
00941 {
00942   mPartsStack->setCurrentIndex( 0 );
00943 }
00944 
00945 void MainWindow::showTip( bool force )
00946 {
00947   QStringList tips;
00948   PluginList::ConstIterator end = mPlugins.end();
00949   for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it ) {
00950     QString file = (*it)->tipFile();
00951     if ( !file.isEmpty() ) {
00952       tips.append( file );
00953     }
00954   }
00955 
00956   KTipDialog::showMultiTip( this, tips, force );
00957 }
00958 
00959 void MainWindow::slotQuit()
00960 {
00961   mReallyClose = true;
00962   close();
00963 }
00964 
00965 void MainWindow::slotPreferences()
00966 {
00967   static KSettings::Dialog *dlg = 0;
00968   if ( !dlg ) {
00969     dlg = new KSettings::Dialog( this );
00970     dlg->setAllowComponentSelection( true );
00971 
00972     // do not show settings of components running standalone
00973     KPluginInfo::List filteredPlugins = mPluginInfos;
00974     PluginList::ConstIterator it;
00975     for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
00976       if ( (*it)->isRunningStandalone() ) {
00977         KPluginInfo::List::ConstIterator infoIt;
00978         for ( infoIt = filteredPlugins.begin(); infoIt != filteredPlugins.end(); ++infoIt ) {
00979           if ( infoIt->pluginName() == (*it)->identifier() ) {
00980             filteredPlugins.removeAll( *infoIt );
00981             break;
00982           }
00983         }
00984       }
00985     }
00986 
00987     dlg->addPluginInfos( filteredPlugins );
00988     connect( dlg, SIGNAL(pluginSelectionChanged()), SLOT(pluginsChanged()) );
00989   }
00990 
00991   dlg->show();
00992 }
00993 
00994 void MainWindow::pluginsChanged()
00995 {
00996   unplugActionList( "navigator_actionlist" );
00997   unloadPlugins();
00998   loadPlugins();
00999   mSidePane->updatePlugins();
01000   updateShortcuts();
01001 }
01002 
01003 void MainWindow::updateConfig()
01004 {
01005   kDebug();
01006 
01007   saveSettings();
01008   loadSettings();
01009 }
01010 
01011 void MainWindow::showAboutDialog()
01012 {
01013   QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
01014 
01015   if ( !mAboutDialog ) {
01016     mAboutDialog = new AboutDialog( this );
01017   }
01018 
01019   mAboutDialog->show();
01020   mAboutDialog->raise();
01021   QApplication::restoreOverrideCursor();
01022 }
01023 
01024 void MainWindow::configureShortcuts()
01025 {
01026   KShortcutsDialog dialog(
01027     KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, this );
01028   dialog.addCollection( actionCollection() );
01029 
01030   if ( mCurrentPlugin && mCurrentPlugin->part() ) {
01031     dialog.addCollection( mCurrentPlugin->part()->actionCollection() );
01032   }
01033 
01034   dialog.configure();
01035 }
01036 
01037 void MainWindow::configureToolbars()
01038 {
01039   if ( mCurrentPlugin ) {
01040     saveMainWindowSettings( KGlobal::config()->group( QString( "MainWindow%1" ).arg( mCurrentPlugin->identifier() ) ) );
01041   }
01042   KEditToolBar edit( factory() );
01043   connect( &edit, SIGNAL(newToolbarConfig()), this, SLOT(slotNewToolbarConfig()) );
01044   edit.exec();
01045 }
01046 
01047 void MainWindow::slotNewToolbarConfig()
01048 {
01049   if ( mCurrentPlugin && mCurrentPlugin->part() ) {
01050     createGUI( mCurrentPlugin->part() );
01051   }
01052   if ( mCurrentPlugin ) {
01053     applyMainWindowSettings( KGlobal::config()->group( QString( "MainWindow%1" ).arg( mCurrentPlugin->identifier() ) ) );
01054   }
01055 }
01056 
01057 void MainWindow::slotOpenUrl( const KUrl &url )
01058 {
01059   if ( url.protocol() == "exec" ) {
01060     if ( url.path() == "/switch" ) {
01061       if ( mCurrentPlugin ) {
01062         mPartsStack->setCurrentIndex( mPartsStack->indexOf( mCurrentPlugin->part()->widget() ) );
01063       }
01064     }
01065     if ( url.path() == "/gwwizard" ) {
01066       KRun::runCommand( "groupwarewizard", this );
01067       slotQuit();
01068     }
01069   } else {
01070     new KRun( url, this );
01071   }
01072 }
01073 
01074 void MainWindow::readProperties( const KConfigGroup &config )
01075 {
01076   Core::readProperties( config );
01077 
01078   QSet<QString> activePlugins =
01079     QSet<QString>::fromList( config.readEntry( "ActivePlugins", QStringList() ) );
01080   foreach ( Plugin *plugin, mPlugins ) {
01081     if ( !plugin->isRunningStandalone() && activePlugins.contains( plugin->identifier() ) ) {
01082       plugin->readProperties( config );
01083     }
01084   }
01085 }
01086 
01087 void MainWindow::saveProperties( KConfigGroup &config )
01088 {
01089   Core::saveProperties( config );
01090 
01091   QStringList activePlugins;
01092 
01093   foreach ( const KPluginInfo &pluginInfo, mPluginInfos ) {
01094     if ( pluginInfo.isPluginEnabled() ) {
01095       Plugin *plugin = pluginFromInfo( pluginInfo );
01096       if ( plugin ) {
01097         activePlugins.append( plugin->identifier() );
01098         plugin->saveProperties( config );
01099       }
01100     }
01101   }
01102 
01103   config.writeEntry( "ActivePlugins", activePlugins );
01104 }
01105 
01106 bool MainWindow::queryClose()
01107 {
01108   if ( kapp->sessionSaving() || mReallyClose ) {
01109     return true;
01110   }
01111 
01112   foreach ( Plugin *plugin, mPlugins ) {
01113     if ( !plugin->isRunningStandalone() ) {
01114       if ( !plugin->queryClose() ) {
01115         return false;
01116       }
01117     }
01118   }
01119   return true;
01120 }
01121 
01122 void MainWindow::slotShowStatusMsg( const QString &msg )
01123 {
01124   if ( !statusBar() || !mStatusMsgLabel ) {
01125      return;
01126   }
01127 
01128   mStatusMsgLabel->setText( msg );
01129 }
01130 
01131 QString MainWindow::introductionString()
01132 {
01133   KIconLoader *iconloader = KIconLoader::global();
01134   int iconSize = iconloader->currentSize( KIconLoader::Desktop );
01135 
01136   QString handbook_icon_path = iconloader->iconPath( "help-contents", KIconLoader::Desktop );
01137   QString html_icon_path = iconloader->iconPath( "text-html", KIconLoader::Desktop );
01138   QString wizard_icon_path = iconloader->iconPath( "tools-wizard", KIconLoader::Desktop );
01139 
01140   QString info = ki18n( "<h2 style='text-align:center; margin-top: 0px;'>Welcome to Kontact %1</h2>"
01141       "<p>%2</p>"
01142       "<table align=\"center\">"
01143       "<tr><td><a href=\"%3\"><img width=\"%4\" height=\"%5\" src=\"%6\" /></a></td>"
01144       "<td><a href=\"%7\">%8</a><br /><span id=\"subtext\"><nobr>%9</nobr></span></td></tr>"
01145       "<tr><td><a href=\"%10\"><img width=\"%11\" height=\"%12\" src=\"%13\" /></a></td>"
01146       "<td><a href=\"%14\">%15</a><br /><span id=\"subtext\"><nobr>%16</nobr></span></td></tr>"
01147       "<tr><td><a href=\"%17\"><img width=\"%18\" height=\"%19\" src=\"%20\" /></a></td>"
01148       "<td><a href=\"%21\">%22</a><br /><span id=\"subtext\"><nobr>%23</nobr></span></td></tr>"
01149       "</table>"
01150       "<p style=\"margin-bottom: 0px\"> <a href=\"%24\">Skip this introduction</a></p>" )
01151       .subs( KGlobal::mainComponent().aboutData()->version() )
01152       .subs( i18n( "Kontact handles your e-mail, addressbook, calendar, to-do list and more." ) )
01153       .subs( "help:/kontact" )
01154       .subs( iconSize )
01155       .subs( iconSize )
01156       .subs( handbook_icon_path )
01157       .subs( "help:/kontact" )
01158       .subs( i18n( "Read Manual" ) )
01159       .subs( i18n( "Learn more about Kontact and its components" ) )
01160       .subs( "http://kontact.org" )
01161       .subs( iconSize )
01162       .subs( iconSize )
01163       .subs( html_icon_path )
01164       .subs( "http://kontact.org" )
01165       .subs( i18n( "Visit Kontact Website" ) )
01166       .subs( i18n( "Access online resources and tutorials" ) )
01167       .subs( "exec:/gwwizard" )
01168       .subs( iconSize )
01169       .subs( iconSize )
01170       .subs( wizard_icon_path )
01171       .subs( "exec:/gwwizard" )
01172       .subs( i18n( "Configure Kontact as Groupware Client" ) )
01173       .subs( i18n( "Prepare Kontact for use in corporate networks" ) )
01174       .subs( "exec:/switch" )
01175       .toString();
01176   return info;
01177 }
01178 
01179 #include "mainwindow.moc"

kontact

Skip menu "kontact"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members