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 <tqaction.h> 00024 #include <tqcombobox.h> 00025 #include <tqdockarea.h> 00026 #include <tqguardedptr.h> 00027 #include <tqhbox.h> 00028 #include <tqimage.h> 00029 #include <tqobjectlist.h> 00030 #include <tqprogressbar.h> 00031 #include <tqpushbutton.h> 00032 #include <tqsplitter.h> 00033 #include <tqtimer.h> 00034 #include <tqwhatsthis.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, TQWidget * parent = 0 ) 00091 : KSettings::Dialog( content, parent, 0 ) 00092 { 00093 } 00094 00095 00096 void fixButtonLabel( TQWidget *widget ) 00097 { 00098 TQObject *object = widget->child( "KJanusWidget::buttonBelowList" ); 00099 TQPushButton *button = static_cast<TQPushButton*>( TQT_TQWIDGET(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, TQT_SIGNAL( showAboutApplication() ), 00124 TQT_SLOT( showAboutDialog() ) ); 00125 00126 KTrader::OfferList offers = KTrader::self()->query( 00127 TQString::fromLatin1( "Kontact/Plugin" ), 00128 TQString( "[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 TQT_TQOBJECT(this), TQT_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 TQVariant hasPartProp = (*it)->property( "X-KDE-KontactPluginHasPart" ); 00142 if ( !hasPartProp.isValid() || hasPartProp.toBool() ) { 00143 mActionPlugins.append( action ); 00144 } 00145 } 00146 00147 KStdAction::keyBindings( TQT_TQOBJECT(this), TQT_SLOT( configureShortcuts() ), actionCollection() ); 00148 KStdAction::configureToolbars( TQT_TQOBJECT(this), TQT_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(), TQT_SIGNAL( profileLoaded( const TQString& ) ), 00161 this, TQT_SLOT( slotLoadProfile( const TQString& ) ) ); 00162 connect( Kontact::ProfileManager::self(), TQT_SIGNAL( saveToProfileRequested( const TQString& ) ), 00163 this, TQT_SLOT( slotSaveToProfile( const TQString& ) ) ); 00164 } 00165 00166 00167 void MainWindow::initObject() 00168 { 00169 // prepare the part manager 00170 mPartManager = new KParts::PartManager( this ); 00171 connect( mPartManager, TQT_SIGNAL( activePartChanged( KParts::Part* ) ), 00172 this, TQT_SLOT( slotActivePartChanged( KParts::Part* ) ) ); 00173 00174 if ( mSidePane ) { 00175 mSidePane->updatePlugins(); 00176 } 00177 00178 KSettings::Dispatcher::self()->registerInstance( instance(), TQT_TQOBJECT(this), 00179 TQT_SLOT( updateConfig() ) ); 00180 00181 loadSettings(); 00182 00183 statusBar()->show(); 00184 00185 showTip( false ); 00186 00187 // done initializing 00188 slotShowStatusMsg( TQString() ); 00189 00190 connect( KPIM::BroadcastStatus::instance(), TQT_SIGNAL( statusMsg( const TQString& ) ), 00191 this, TQT_SLOT( slotShowStatusMsg( const TQString& ) ) ); 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 TQPtrList<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 TQString &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 TQHBox( this ); 00240 mTopWidget->setFrameStyle( TQFrame::Panel | TQFrame::Sunken ); 00241 setCentralWidget( mTopWidget ); 00242 00243 TQHBox *mBox = 0; 00244 mSplitter = new TQSplitter( mTopWidget ); 00245 mBox = new TQHBox( mTopWidget ); 00246 mSidePane = new IconSidePane( this, mSplitter ); 00247 mSidePane->setSizePolicy( TQSizePolicy( TQSizePolicy::Maximum, 00248 TQSizePolicy::Preferred ) ); 00249 // donÄt occupy screen estate on load 00250 TQValueList<int> sizes; 00251 sizes << 0; 00252 mSplitter->setSizes(sizes); 00253 00254 connect( mSidePane, TQT_SIGNAL( pluginSelected( Kontact::Plugin * ) ), 00255 TQT_SLOT( selectPlugin( Kontact::Plugin * ) ) ); 00256 00257 TQVBox *vBox; 00258 if ( mSplitter ) { 00259 vBox = new TQVBox( mSplitter ); 00260 } else { 00261 vBox = new TQVBox( mBox ); 00262 } 00263 00264 vBox->setSpacing( 0 ); 00265 00266 mPartsStack = new TQWidgetStack( vBox ); 00267 initAboutScreen(); 00268 00269 TQString 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 TQString& msg ) 00290 { 00291 TQString location = locate( "data", "kontact/about/main.html" ); 00292 TQString 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 TQString appName( i18n( "KDE Kontact" ) ); 00302 TQString catchPhrase( i18n( "Get Organized!" ) ); 00303 TQString quickDescription( i18n( "The KDE Personal Information Management Suite" ) ); 00304 00305 mIntroPart->write( content.arg( TQFont().pointSize() + 2 ).arg( appName ) 00306 .arg( catchPhrase ).arg( quickDescription ).arg( msg ) ); 00307 mIntroPart->end(); 00308 } 00309 00310 void MainWindow::initAboutScreen() 00311 { 00312 TQHBox *introbox = new TQHBox( mPartsStack ); 00313 mPartsStack->addWidget( introbox ); 00314 mPartsStack->raiseWidget( introbox ); 00315 mIntroPart = new KHTMLPart( introbox ); 00316 mIntroPart->widget()->setFocusPolicy( TQ_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 TQT_SIGNAL( openURLRequest( const KURL&, const KParts::URLArgs& ) ), 00327 TQT_SLOT( slotOpenUrl( const KURL& ) ) ); 00328 00329 connect( mIntroPart->browserExtension(), 00330 TQT_SIGNAL( createNewWindow( const KURL&, const KParts::URLArgs& ) ), 00331 TQT_SLOT( slotOpenUrl( const KURL& ) ) ); 00332 } 00333 00334 void MainWindow::setupActions() 00335 { 00336 KStdAction::quit( TQT_TQOBJECT(this), TQT_SLOT( slotQuit() ), actionCollection() ); 00337 mNewActions = new KToolBarPopupAction( KGuiItem( i18n( "New" ), "" ), 00338 KStdAccel::shortcut(KStdAccel::New), TQT_TQOBJECT(this), TQT_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), TQT_TQOBJECT(this), TQT_SLOT( slotSyncClicked() ), 00348 actionCollection(), "action_sync" ); 00349 } 00350 new KAction( i18n( "Configure Kontact..." ), "configure", 0, TQT_TQOBJECT(this), TQT_SLOT( slotPreferences() ), 00351 actionCollection(), "settings_configure_kontact" ); 00352 00353 new KAction( i18n( "Configure &Profiles..." ), 0, TQT_TQOBJECT(this), TQT_SLOT( slotConfigureProfiles() ), 00354 actionCollection(), "settings_configure_kontact_profiles" ); 00355 00356 new KAction( i18n( "&Kontact Introduction" ), 0, TQT_TQOBJECT(this), TQT_SLOT( slotShowIntroduction() ), 00357 actionCollection(), "help_introduction" ); 00358 new KAction( i18n( "&Tip of the Day" ), 0, TQT_TQOBJECT(this), TQT_SLOT( slotShowTip() ), 00359 actionCollection(), "help_tipofday" ); 00360 00361 KWidgetAction* spacerAction = new KWidgetAction( new TQWidget( this ), "SpacerAction", "", 0, 0, actionCollection(), "navigator_spacer_item" ); 00362 spacerAction->setAutoSized( true ); 00363 } 00364 00365 void MainWindow::slotConfigureProfiles() 00366 { 00367 TQGuardedPtr<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 TQString& group, const TQString& key, const TQString& defaultValue=TQString() ) 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 TQString& id ) 00383 { 00384 const TQString 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 TQString& id ) 00407 { 00408 const TQString 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 TQStringList groups = profile.groupList(); 00419 for ( TQStringList::ConstIterator it = groups.begin(), end = groups.end(); it != end; ++it ) 00420 { 00421 cfg->setGroup( *it ); 00422 typedef TQMap<TQString, TQString> 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 TQPtrList<KAction> sorted; 00503 00504 TQPtrListIterator<KAction> eit( mActionPlugins ); 00505 KAction *action; 00506 while ( ( action = eit.current() ) != 0 ) { 00507 ++eit; 00508 TQPtrListIterator<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 TQPtrList<Plugin> plugins; 00529 TQPtrList<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(), TQT_TQOBJECT(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 TQVariant libNameProp = (*it)->property( "X-KDE-KontactPartLibraryName" ); 00556 TQVariant exeNameProp = (*it)->property( "X-KDE-KontactPartExecutableName" ); 00557 TQVariant loadOnStart = (*it)->property( "X-KDE-KontactPartLoadOnStart" ); 00558 TQVariant 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 TQPtrList<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 TQPtrList<KAction> loadedActions; 00622 00623 sortActionsByWeight(); 00624 00625 TQPtrListIterator<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 TQString shortcut = TQString( "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, TQString( "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 TQPtrList<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 *>(TQT_TQWIDGET(child(name, "KToolBar"))); 00767 } 00768 00769 void MainWindow::slotActionTriggered() 00770 { 00771 const KAction *actionSender = static_cast<const KAction*>( sender() ); 00772 TQString 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( TQCursor( TQt::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 TQWidget *focusWidget = kapp->focusWidget(); 00806 if ( mCurrentPlugin && focusWidget ) { 00807 // save the focus widget only when it belongs to the activated part 00808 TQWidget *parent = focusWidget->parentWidget(); 00809 while ( parent ) { 00810 if ( parent == mCurrentPlugin->part()->widget() ) 00811 mFocusWidgets.insert( mCurrentPlugin->identifier(), TQGuardedPtr<TQWidget>( 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 TQWidget *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 TQStringList invisibleActions = plugin->invisibleToolbarActions(); 00885 00886 TQStringList::ConstIterator it; 00887 for ( it = invisibleActions.begin(); it != invisibleActions.end(); ++it ) { 00888 KAction *action = part->actionCollection()->action( (*it).latin1() ); 00889 if ( action ) { 00890 TQPtrListIterator<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 TQString &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 TQStringList tips; 00945 PluginList::ConstIterator end = mPlugins.end(); 00946 for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it ) { 00947 TQString 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 TQValueList<KPluginInfo*> filteredPlugins = mPluginInfos; 00967 PluginList::ConstIterator it; 00968 for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) 00969 if ( (*it)->isRunningStandalone() ) { 00970 TQValueList<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, TQT_SIGNAL( pluginSelectionChanged() ), 00981 TQT_SLOT( pluginsChanged() ) ); 00982 } 00983 00984 dlg->show(); 00985 dlg->fixButtonLabel( this ); 00986 } 00987 00988 int MainWindow::startServiceFor( const TQString& serviceType, 00989 const TQString& constraint, 00990 const TQString& preferences, 00991 TQString *error, TQCString* 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( TQCursor( TQt::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, TQT_SIGNAL( newToolbarConfig() ), 01057 this, TQT_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 TQString app( "kontact" ); 01084 if ( !url.query().isEmpty() ) { 01085 app = url.query().mid( 1 ); 01086 } 01087 kapp->invokeHelp( TQString(), 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 TQStringList activePlugins = config->readListEntry( "ActivePlugins" ); 01099 TQValueList<Plugin*>::ConstIterator it = mPlugins.begin(); 01100 TQValueList<Plugin*>::ConstIterator end = mPlugins.end(); 01101 for ( ; it != end; ++it ) { 01102 Plugin *plugin = *it; 01103 if ( !plugin->isRunningStandalone() ) { 01104 TQStringList::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 TQStringList 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 if ( kapp->sessionSaving() ) 01138 return true; 01139 01140 bool localClose = true; 01141 TQValueList<Plugin*>::ConstIterator end = mPlugins.end(); 01142 TQValueList<Plugin*>::ConstIterator it = mPlugins.begin(); 01143 for ( ; it != end; ++it ) { 01144 Plugin *plugin = *it; 01145 if ( !plugin->isRunningStandalone() ) 01146 if ( !plugin->queryClose() ) 01147 localClose = false; 01148 } 01149 01150 return localClose; 01151 } 01152 01153 void MainWindow::slotShowStatusMsg( const TQString &msg ) 01154 { 01155 if ( !statusBar() || !mStatusMsgLabel ) 01156 return; 01157 01158 mStatusMsgLabel->setText( msg ); 01159 } 01160 01161 TQString MainWindow::introductionString() 01162 { 01163 KIconLoader *iconloader = KGlobal::iconLoader(); 01164 int iconSize = iconloader->currentSize( KIcon::Desktop ); 01165 01166 TQString handbook_icon_path = iconloader->iconPath( "contents2", KIcon::Desktop ); 01167 TQString html_icon_path = iconloader->iconPath( "html", KIcon::Desktop ); 01168 TQString wizard_icon_path = iconloader->iconPath( "wizard", KIcon::Desktop ); 01169 01170 TQString info = i18n( "<h2 style='text-align:center; margin-top: 0px;'>Welcome to Kontact %1</h2>" 01171 "<p>%1</p>" 01172 "<table align=\"center\">" 01173 "<tr><td><a href=\"%1\"><img width=\"%1\" height=\"%1\" src=\"%1\" /></a></td>" 01174 "<td><a href=\"%1\">%1</a><br><span id=\"subtext\"><nobr>%1</td></tr>" 01175 "<tr><td><a href=\"%1\"><img width=\"%1\" height=\"%1\" src=\"%1\" /></a></td>" 01176 "<td><a href=\"%1\">%1</a><br><span id=\"subtext\"><nobr>%1</td></tr>" 01177 "<tr><td><a href=\"%1\"><img width=\"%1\" height=\"%1\" src=\"%1\" /></a></td>" 01178 "<td><a href=\"%1\">%1</a><br><span id=\"subtext\"><nobr>%1</td></tr>" 01179 "</table>" 01180 "<p style=\"margin-bottom: 0px\"> <a href=\"%1\">Skip this introduction</a></p>" ) 01181 .arg( kapp->aboutData()->version() ) 01182 .arg( i18n( "Kontact handles your e-mail, addressbook, calendar, to-do list and more." ) ) 01183 .arg( "exec:/help?kontact" ) 01184 .arg( iconSize ) 01185 .arg( iconSize ) 01186 .arg( handbook_icon_path ) 01187 .arg( "exec:/help?kontact" ) 01188 .arg( i18n( "Read Manual" ) ) 01189 .arg( i18n( "Learn more about Kontact and its components" ) ) 01190 .arg( "http://kontact.org" ) 01191 .arg( iconSize ) 01192 .arg( iconSize ) 01193 .arg( html_icon_path ) 01194 .arg( "http://kontact.org" ) 01195 .arg( i18n( "Visit Kontact Website" ) ) 01196 .arg( i18n( "Access online resources and tutorials" ) ) 01197 .arg( "exec:/gwwizard" ) 01198 .arg( iconSize ) 01199 .arg( iconSize ) 01200 .arg( wizard_icon_path ) 01201 .arg( "exec:/gwwizard" ) 01202 .arg( i18n( "Configure Kontact as Groupware Client" ) ) 01203 .arg( i18n( "Prepare Kontact for use in corporate networks" ) ) 01204 .arg( "exec:/switch" ); 01205 return info; 01206 } 01207 01208 #include "mainwindow.moc"