kontact

mainwindow.cpp
1 /*
2  This file is part of KDE Kontact.
3 
4  Copyright (c) 2001 Matthias Hoelzer-Kluepfel <mhk@kde.org>
5  Copyright (c) 2002-2005 Daniel Molkentin <molkentin@kde.org>
6  Copyright (c) 2003-2005 Cornelius Schumacher <schumacher@kde.org>
7 
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22 
23 #include <tqaction.h>
24 #include <tqcombobox.h>
25 #include <tqdockarea.h>
26 #include <tqguardedptr.h>
27 #include <tqhbox.h>
28 #include <tqimage.h>
29 #include <tqobjectlist.h>
30 #include <tqprogressbar.h>
31 #include <tqpushbutton.h>
32 #include <tqsplitter.h>
33 #include <tqtimer.h>
34 #include <tqwhatsthis.h>
35 
36 #include <dcopclient.h>
37 #include <tdeapplication.h>
38 #include <tdeconfig.h>
39 #include <kdebug.h>
40 #include <kedittoolbar.h>
41 #include <kguiitem.h>
42 #include <khelpmenu.h>
43 #include <kiconloader.h>
44 #include <kkeydialog.h>
45 #include <klibloader.h>
46 #include <tdelistbox.h>
47 #include <tdelocale.h>
48 #include <tdemessagebox.h>
49 #include <tdeparts/componentfactory.h>
50 #include <kplugininfo.h>
51 #include <tdepopupmenu.h>
52 #include <ksettings/dialog.h>
53 #include <ksettings/dispatcher.h>
54 #include <tdeshortcut.h>
55 #include <kstandarddirs.h>
56 #include <kstatusbar.h>
57 #include <kstdaction.h>
58 #include <ktip.h>
59 #include <ktrader.h>
60 #include <ksettings/componentsdialog.h>
61 #include <kstringhandler.h>
62 #include <krsqueezedtextlabel.h>
63 #include <tdehtml_part.h>
64 #include <tdehtmlview.h>
65 #include <libtdepim/tdefileio.h>
66 #include <kcursor.h>
67 #include <krun.h>
68 #include <tdeaboutdata.h>
69 #include <tdemenubar.h>
70 #include <tdestdaccel.h>
71 #include <kcmultidialog.h>
72 #include <kipc.h>
73 
74 #include "aboutdialog.h"
75 #include "iconsidepane.h"
76 #include "mainwindow.h"
77 #include "plugin.h"
78 #include "prefs.h"
79 #include "profiledialog.h"
80 #include "profilemanager.h"
81 #include "progressdialog.h"
82 #include "statusbarprogresswidget.h"
83 #include "broadcaststatus.h"
84 
85 using namespace Kontact;
86 
87 class SettingsDialogWrapper : public KSettings::Dialog
88 {
89  public:
90  SettingsDialogWrapper( ContentInListView content, TQWidget * parent = 0 )
91  : KSettings::Dialog( content, parent, 0 )
92  {
93  }
94 
95 
96  void fixButtonLabel( TQWidget *widget )
97  {
98  TQObject *object = widget->child( "KJanusWidget::buttonBelowList" );
99  TQPushButton *button = static_cast<TQPushButton*>( object );
100  if ( button )
101  button->setText( i18n( "Select Components ..." ) );
102  }
103 };
104 
105 MainWindow::MainWindow()
106  : Kontact::Core(), mTopWidget( 0 ), mSplitter( 0 ),
107  mCurrentPlugin( 0 ), mAboutDialog( 0 ), mReallyClose( false ), mSyncActionsEnabled( true )
108 {
109  // Set this to be the group leader for all subdialogs - this means
110  // modal subdialogs will only affect this dialog, not the other windows
111  setWFlags( getWFlags() | WGroupLeader );
112 
113  initGUI();
114  initObject();
115 }
116 
117 void MainWindow::initGUI()
118 {
119  initWidgets();
120  setupActions();
121  setHelpMenuEnabled( false );
122  KHelpMenu *helpMenu = new KHelpMenu( this, 0, true, actionCollection() );
123  connect( helpMenu, TQ_SIGNAL( showAboutApplication() ),
124  TQ_SLOT( showAboutDialog() ) );
125 
126  TDETrader::OfferList offers = TDETrader::self()->query(
127  TQString::fromLatin1( "Kontact/Plugin" ),
128  TQString( "[X-TDE-KontactPluginVersion] == %1" ).arg( KONTACT_PLUGIN_VERSION ) );
129  mPluginInfos = KPluginInfo::fromServices( offers, Prefs::self()->config(), "Plugins" );
130 
131  KPluginInfo::List::Iterator it;
132  for ( it = mPluginInfos.begin(); it != mPluginInfos.end(); ++it ) {
133  (*it)->load();
134 
135  TDEAction *action = new TDEAction( (*it)->name(), (*it)->icon(), TDEShortcut(),
136  this, TQ_SLOT(slotActionTriggered()),
137  actionCollection(), (*it)->pluginName().latin1() );
138  action->setName( (*it)->pluginName().latin1() );
139  action->setWhatsThis( i18n( "Switch to plugin %1" ).arg( (*it)->name() ) );
140 
141  TQVariant hasPartProp = (*it)->property( "X-TDE-KontactPluginHasPart" );
142  if ( !hasPartProp.isValid() || hasPartProp.toBool() ) {
143  mActionPlugins.append( action );
144  }
145  }
146 
147  KStdAction::keyBindings( this, TQ_SLOT( configureShortcuts() ), actionCollection() );
148  KStdAction::configureToolbars( this, TQ_SLOT( configureToolbars() ), actionCollection() );
149  setXMLFile( "kontactui.rc" );
150 
151  setStandardToolBarMenuEnabled( true );
152 
153  createGUI( 0 );
154 
155  loadPlugins();
156 
157  resize( 700, 520 ); // initial size to prevent a scrollbar in sidepane
158  setAutoSaveSettings();
159 
160  connect( Kontact::ProfileManager::self(), TQ_SIGNAL( profileLoaded( const TQString& ) ),
161  this, TQ_SLOT( slotLoadProfile( const TQString& ) ) );
162  connect( Kontact::ProfileManager::self(), TQ_SIGNAL( saveToProfileRequested( const TQString& ) ),
163  this, TQ_SLOT( slotSaveToProfile( const TQString& ) ) );
164 }
165 
166 
167 void MainWindow::initObject()
168 {
169  // prepare the part manager
170  mPartManager = new KParts::PartManager( this );
171  connect( mPartManager, TQ_SIGNAL( activePartChanged( KParts::Part* ) ),
172  this, TQ_SLOT( slotActivePartChanged( KParts::Part* ) ) );
173 
174  if ( mSidePane ) {
175  mSidePane->updatePlugins();
176  }
177 
178  KSettings::Dispatcher::self()->registerInstance( instance(), this,
179  TQ_SLOT( updateConfig() ) );
180 
181  loadSettings();
182 
183  statusBar()->show();
184 
185  showTip( false );
186 
187  // done initializing
188  slotShowStatusMsg( TQString() );
189 
190  connect( KPIM::BroadcastStatus::instance(), TQ_SIGNAL( statusMsg( const TQString& ) ),
191  this, TQ_SLOT( slotShowStatusMsg( const TQString& ) ) );
192 
193  // launch commandline specified module if any
194  activatePluginModule();
195 
196  if ( Prefs::lastVersionSeen() == kapp->aboutData()->version() ) {
197  selectPlugin( mCurrentPlugin );
198  }
199 
200  paintAboutScreen( introductionString() );
201  Prefs::setLastVersionSeen( kapp->aboutData()->version() );
202 }
203 
204 MainWindow::~MainWindow()
205 {
206  saveSettings();
207 
208  TQPtrList<KParts::Part> parts = *mPartManager->parts();
209 
210  for ( KParts::Part *p = parts.last(); p; p = parts.prev() ) {
211  delete p;
212  p = 0;
213  }
214 
215  Prefs::self()->writeConfig();
216 }
217 
218 void MainWindow::setActivePluginModule( const TQString &module )
219 {
220  mActiveModule = module;
221  activatePluginModule();
222 }
223 
224 void MainWindow::activatePluginModule()
225 {
226  if ( !mActiveModule.isEmpty() ) {
227  PluginList::ConstIterator end = mPlugins.end();
228  for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it )
229  if ( ( *it )->identifier().contains( mActiveModule ) ) {
230  selectPlugin( *it );
231  return;
232  }
233  }
234 }
235 
236 void MainWindow::initWidgets()
237 {
238  // includes sidebar and part stack
239  mTopWidget = new TQHBox( this );
240  mTopWidget->setFrameStyle( TQFrame::Panel | TQFrame::Sunken );
241  setCentralWidget( mTopWidget );
242 
243  TQHBox *mBox = 0;
244  mSplitter = new TQSplitter( mTopWidget );
245  mBox = new TQHBox( mTopWidget );
246  mSidePane = new IconSidePane( this, mSplitter );
247  mSidePane->setSizePolicy( TQSizePolicy( TQSizePolicy::Maximum,
248  TQSizePolicy::Preferred ) );
249  // donĂ„t occupy screen estate on load
250  TQValueList<int> sizes;
251  sizes << 0;
252  mSplitter->setSizes(sizes);
253 
254  connect( mSidePane, TQ_SIGNAL( pluginSelected( Kontact::Plugin * ) ),
255  TQ_SLOT( selectPlugin( Kontact::Plugin * ) ) );
256 
257  TQVBox *vBox;
258  if ( mSplitter ) {
259  vBox = new TQVBox( mSplitter );
260  } else {
261  vBox = new TQVBox( mBox );
262  }
263 
264  vBox->setSpacing( 0 );
265 
266  mPartsStack = new TQWidgetStack( vBox );
267  initAboutScreen();
268 
269  TQString loading = i18n( "<h2 style='text-align:center; margin-top: 0px; margin-bottom: 0px'>%1</h2>" )
270  .arg( i18n("Loading Kontact...") );
271 
272  paintAboutScreen( loading );
273 
274  /* Create a progress dialog and hide it. */
275  KPIM::ProgressDialog *progressDialog = new KPIM::ProgressDialog( statusBar(), this );
276  progressDialog->hide();
277 
278  mLittleProgress = new KPIM::StatusbarProgressWidget( progressDialog, statusBar() );
279 
280  mStatusMsgLabel = new KRSqueezedTextLabel( i18n( " Initializing..." ), statusBar() );
281  mStatusMsgLabel->setAlignment( AlignLeft | AlignVCenter );
282 
283  statusBar()->addWidget( mStatusMsgLabel, 10 , false );
284  statusBar()->addWidget( mLittleProgress, 0 , true );
285  mLittleProgress->show();
286 }
287 
288 
289 void MainWindow::paintAboutScreen( const TQString& msg )
290 {
291  TQString location = locate( "data", "kontact/about/main.html" );
292  TQString content = KPIM::kFileToString( location );
293  content = content.arg( locate( "data", "libtdepim/about/kde_infopage.css" ) );
294  if ( kapp->reverseLayout() )
295  content = content.arg( "@import \"%1\";" ).arg( locate( "data", "libtdepim/about/kde_infopage_rtl.css" ) );
296  else
297  content = content.arg( "" );
298 
299  mIntroPart->begin( KURL( location ) );
300 
301  TQString appName( i18n( "TDE Kontact" ) );
302  TQString catchPhrase( i18n( "Get Organized!" ) );
303  TQString quickDescription( i18n( "The TDE Personal Information Management Suite" ) );
304 
305  mIntroPart->write( content.arg( TQFont().pointSize() + 2 ).arg( appName )
306  .arg( catchPhrase ).arg( quickDescription ).arg( msg ) );
307  mIntroPart->end();
308 }
309 
310 void MainWindow::initAboutScreen()
311 {
312  TQHBox *introbox = new TQHBox( mPartsStack );
313  mPartsStack->addWidget( introbox );
314  mPartsStack->raiseWidget( introbox );
315  mIntroPart = new TDEHTMLPart( introbox );
316  mIntroPart->widget()->setFocusPolicy( TQWidget::WheelFocus );
317  // Let's better be paranoid and disable plugins (it defaults to enabled):
318  mIntroPart->setPluginsEnabled( false );
319  mIntroPart->setJScriptEnabled( false ); // just make this explicit
320  mIntroPart->setJavaEnabled( false ); // just make this explicit
321  mIntroPart->setMetaRefreshEnabled( false );
322  mIntroPart->setURLCursor( KCursor::handCursor() );
323  mIntroPart->view()->setLineWidth( 0 );
324 
325  connect( mIntroPart->browserExtension(),
326  TQ_SIGNAL( openURLRequest( const KURL&, const KParts::URLArgs& ) ),
327  TQ_SLOT( slotOpenUrl( const KURL& ) ) );
328 
329  connect( mIntroPart->browserExtension(),
330  TQ_SIGNAL( createNewWindow( const KURL&, const KParts::URLArgs& ) ),
331  TQ_SLOT( slotOpenUrl( const KURL& ) ) );
332 }
333 
334 void MainWindow::setupActions()
335 {
336  KStdAction::quit( this, TQ_SLOT( slotQuit() ), actionCollection() );
337  mNewActions = new TDEToolBarPopupAction( KGuiItem( i18n( "New" ), "" ),
338  TDEStdAccel::shortcut(TDEStdAccel::New), this, TQ_SLOT( slotNewClicked() ),
339  actionCollection(), "action_new" );
340 
341  TDEConfig* const cfg = Prefs::self()->config();
342  cfg->setGroup( "Kontact Groupware Settings" );
343  mSyncActionsEnabled = cfg->readBoolEntry( "GroupwareMailFoldersEnabled", true );
344 
345  if ( mSyncActionsEnabled ) {
346  mSyncActions = new TDEToolBarPopupAction( KGuiItem( i18n( "Synchronize" ) ),
347  TDEStdAccel::shortcut(TDEStdAccel::Reload), this, TQ_SLOT( slotSyncClicked() ),
348  actionCollection(), "action_sync" );
349  }
350  new TDEAction( i18n( "Configure Kontact..." ), "configure", 0, this, TQ_SLOT( slotPreferences() ),
351  actionCollection(), "settings_configure_kontact" );
352 
353  new TDEAction( i18n( "Configure &Profiles..." ), 0, this, TQ_SLOT( slotConfigureProfiles() ),
354  actionCollection(), "settings_configure_kontact_profiles" );
355 
356  new TDEAction( i18n( "&Kontact Introduction" ), 0, this, TQ_SLOT( slotShowIntroduction() ),
357  actionCollection(), "help_introduction" );
358  new TDEAction( i18n( "&Tip of the Day" ), 0, this, TQ_SLOT( slotShowTip() ),
359  actionCollection(), "help_tipofday" );
360 
361  KWidgetAction* spacerAction = new KWidgetAction( new TQWidget( this ), "SpacerAction", "", 0, 0, actionCollection(), "navigator_spacer_item" );
362  spacerAction->setAutoSized( true );
363 }
364 
365 void MainWindow::slotConfigureProfiles()
366 {
367  TQGuardedPtr<Kontact::ProfileDialog> dlg = new Kontact::ProfileDialog( this );
368  dlg->setModal( true );
369  dlg->exec();
370  delete dlg;
371 }
372 
373 namespace {
374  void copyConfigEntry( TDEConfig* source, TDEConfig* dest, const TQString& group, const TQString& key, const TQString& defaultValue=TQString() )
375  {
376  source->setGroup( group );
377  dest->setGroup( group );
378  dest->writeEntry( key, source->readEntry( key, defaultValue ) );
379  }
380 }
381 
382 void MainWindow::slotSaveToProfile( const TQString& id )
383 {
384  const TQString path = Kontact::ProfileManager::self()->profileById( id ).saveLocation();
385  if ( path.isNull() )
386  return;
387 
388  TDEConfig* const cfg = Prefs::self()->config();
389  Prefs::self()->writeConfig();
390  saveMainWindowSettings( cfg );
391  saveSettings();
392 
393  TDEConfig profile( path+"/kontactrc", /*read-only=*/false, /*useglobals=*/false );
394  ::copyConfigEntry( cfg, &profile, "MainWindow Toolbar navigatorToolBar", "Hidden", "true" );
395  ::copyConfigEntry( cfg, &profile, "View", "SidePaneSplitter" );
396  ::copyConfigEntry( cfg, &profile, "Icons", "Theme" );
397 
398  for ( PluginList::Iterator it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
399  if ( !(*it)->isRunningStandalone() ) {
400  (*it)->part();
401  }
402  (*it)->saveToProfile( path );
403  }
404 }
405 
406 void MainWindow::slotLoadProfile( const TQString& id )
407 {
408  const TQString path = Kontact::ProfileManager::self()->profileById( id ).saveLocation();
409  if ( path.isNull() )
410  return;
411 
412  TDEConfig* const cfg = Prefs::self()->config();
413  Prefs::self()->writeConfig();
414  saveMainWindowSettings( cfg );
415  saveSettings();
416 
417  const TDEConfig profile( path+"/kontactrc", /*read-only=*/false, /*useglobals=*/false );
418  const TQStringList groups = profile.groupList();
419  for ( TQStringList::ConstIterator it = groups.begin(), end = groups.end(); it != end; ++it )
420  {
421  cfg->setGroup( *it );
422  typedef TQMap<TQString, TQString> StringMap;
423  const StringMap entries = profile.entryMap( *it );
424  for ( StringMap::ConstIterator it2 = entries.begin(), end = entries.end(); it2 != end; ++it2 )
425  {
426  if ( it2.data() == "KONTACT_PROFILE_DELETE_KEY" )
427  cfg->deleteEntry( it2.key() );
428  else
429  cfg->writeEntry( it2.key(), it2.data() );
430  }
431  }
432 
433  cfg->sync();
434  Prefs::self()->readConfig();
435  applyMainWindowSettings( cfg );
436  TDEIconTheme::reconfigure();
437  const WId wid = winId();
438  KIPC::sendMessage( KIPC::PaletteChanged, wid );
439  KIPC::sendMessage( KIPC::FontChanged, wid );
440  KIPC::sendMessage( KIPC::StyleChanged, wid );
441  KIPC::sendMessage( KIPC::SettingsChanged, wid );
442  for ( int i = 0; i < TDEIcon::LastGroup; ++i )
443  KIPC::sendMessage( KIPC::IconChanged, wid, i );
444 
445  loadSettings();
446 
447  for ( PluginList::Iterator it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
448  if ( !(*it)->isRunningStandalone() ) {
449  kdDebug() << "Ensure loaded: " << (*it)->identifier() << endl;
450  (*it)->part();
451  }
452  (*it)->loadProfile( path );
453  }
454 }
455 
456 bool MainWindow::isPluginLoaded( const KPluginInfo *info )
457 {
458  return (pluginFromInfo( info ) != 0);
459 }
460 
461 Plugin *MainWindow::pluginFromInfo( const KPluginInfo *info )
462 {
463  PluginList::ConstIterator end = mPlugins.end();
464  for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it )
465  if ( (*it)->identifier() == info->pluginName() )
466  return *it;
467 
468  return 0;
469 }
470 
471 Plugin *MainWindow::pluginFromAction( const TDEAction *action )
472 {
473  PluginList::ConstIterator end = mPlugins.end();
474  for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it ) {
475  if ( (*it)->identifier() == action->name() ) {
476  return *it;
477  }
478  }
479  return 0;
480 }
481 
482 bool MainWindow::isPluginLoadedByAction( const TDEAction *action )
483 {
484  KPluginInfo::List::ConstIterator it;
485  for ( it = mPluginInfos.begin(); it != mPluginInfos.end(); ++it ) {
486  if ( !(*it)->isPluginEnabled() )
487  continue;
488  if ( isPluginLoaded( *it ) ) {
489  Plugin *plugin = pluginFromInfo( *it );
490  if ( plugin ) {
491  if ( plugin->identifier() == action->name() ) {
492  return true;
493  }
494  }
495  }
496  }
497  return false;
498 }
499 
500 void MainWindow::sortActionsByWeight()
501 {
502  TQPtrList<TDEAction> sorted;
503 
504  TQPtrListIterator<TDEAction> eit( mActionPlugins );
505  TDEAction *action;
506  while ( ( action = eit.current() ) != 0 ) {
507  ++eit;
508  TQPtrListIterator<TDEAction> sortIt( sorted );
509  uint at = 0;
510  TDEAction *saction;
511  Plugin *p1 = pluginFromAction( action );
512  while ( ( saction = sortIt.current() ) != 0 ) {
513  Plugin *p2 = pluginFromAction( saction );
514  if ( p1 && p2 && p1->weight() >= p2->weight() ) {
515  ++sortIt;
516  ++at;
517  } else {
518  break;
519  }
520  }
521  sorted.insert( at, action );
522  }
523  mActionPlugins = sorted;
524 }
525 
526 void MainWindow::loadPlugins()
527 {
528  TQPtrList<Plugin> plugins;
529  TQPtrList<KParts::Part> loadDelayed;
530 
531  uint i;
532  KPluginInfo::List::ConstIterator it;
533  for ( it = mPluginInfos.begin(); it != mPluginInfos.end(); ++it ) {
534  if ( !(*it)->isPluginEnabled() )
535  continue;
536  if ( isPluginLoaded( *it ) ) {
537  Plugin *plugin = pluginFromInfo( *it );
538  if ( plugin )
539  plugin->configUpdated();
540  continue;
541  }
542 
543  kdDebug(5600) << "Loading Plugin: " << (*it)->name() << endl;
544  Kontact::Plugin *plugin =
545  KParts::ComponentFactory::createInstanceFromService<Kontact::Plugin>(
546  (*it)->service(), this );
547 
548  if ( !plugin )
549  continue;
550 
551  plugin->setIdentifier( (*it)->pluginName() );
552  plugin->setTitle( (*it)->name() );
553  plugin->setIcon( (*it)->icon() );
554 
555  TQVariant libNameProp = (*it)->property( "X-TDE-KontactPartLibraryName" );
556  TQVariant exeNameProp = (*it)->property( "X-TDE-KontactPartExecutableName" );
557  TQVariant loadOnStart = (*it)->property( "X-TDE-KontactPartLoadOnStart" );
558  TQVariant hasPartProp = (*it)->property( "X-TDE-KontactPluginHasPart" );
559 
560  if ( !loadOnStart.isNull() && loadOnStart.toBool() )
561  mDelayedPreload.append( plugin );
562 
563  kdDebug(5600) << "LIBNAMEPART: " << libNameProp.toString() << endl;
564 
565  plugin->setPartLibraryName( libNameProp.toString().utf8() );
566  plugin->setExecutableName( exeNameProp.toString() );
567  if ( hasPartProp.isValid() )
568  plugin->setShowInSideBar( hasPartProp.toBool() );
569 
570  for ( i = 0; i < plugins.count(); ++i ) {
571  Plugin *p = plugins.at( i );
572  if ( plugin->weight() < p->weight() )
573  break;
574  }
575 
576  plugins.insert( i, plugin );
577  }
578 
579  for ( i = 0; i < plugins.count(); ++ i ) {
580  Plugin *plugin = plugins.at( i );
581 
582  TDEAction *action;
583  TQPtrList<TDEAction> *actionList = plugin->newActions();
584 
585  for ( action = actionList->first(); action; action = actionList->next() ) {
586  kdDebug(5600) << "Plugging " << action->name() << endl;
587  action->plug( mNewActions->popupMenu() );
588  if ( action->name() == plugin->identifier() ) {
589  mPluginAction.insert( plugin, action );
590  }
591  }
592 
593  if ( mSyncActionsEnabled ) {
594  actionList = plugin->syncActions();
595  for ( action = actionList->first(); action; action = actionList->next() ) {
596  kdDebug(5600) << "Plugging " << action->name() << endl;
597  action->plug( mSyncActions->popupMenu() );
598  }
599  }
600  addPlugin( plugin );
601  }
602  updateShortcuts();
603 
604  mNewActions->setEnabled( mPlugins.size() != 0 );
605  if ( mSyncActionsEnabled )
606  mSyncActions->setEnabled( mPlugins.size() != 0 );
607 }
608 
609 void MainWindow::unloadPlugins()
610 {
611  KPluginInfo::List::ConstIterator end = mPluginInfos.constEnd();
612  KPluginInfo::List::ConstIterator it;
613  for ( it = mPluginInfos.constBegin(); it != end; ++it ) {
614  if ( !(*it)->isPluginEnabled() )
615  removePlugin( *it );
616  }
617 }
618 
619 void MainWindow::updateShortcuts()
620 {
621  TQPtrList<TDEAction> loadedActions;
622 
623  sortActionsByWeight();
624 
625  TQPtrListIterator<TDEAction> it( mActionPlugins );
626  int i = 1;
627  TDEAction *action;
628  while ( ( action = it.current() ) != 0 ) {
629  ++it;
630  if ( isPluginLoadedByAction( action ) ) {
631  loadedActions.append( action );
632  TQString shortcut = TQString( "CTRL+%1" ).arg( i );
633  action->setShortcut( TDEShortcut( shortcut ) );
634  i++;
635  } else {
636  action->setShortcut( TDEShortcut() );
637  }
638  }
639  unplugActionList( "navigator_actionlist" );
640  factory()->plugActionList( this, TQString( "navigator_actionlist" ), loadedActions );
641 }
642 
643 bool MainWindow::removePlugin( const KPluginInfo *info )
644 {
645  PluginList::Iterator end = mPlugins.end();
646  for ( PluginList::Iterator it = mPlugins.begin(); it != end; ++it ) {
647  if ( ( *it )->identifier() == info->pluginName() ) {
648  Plugin *plugin = *it;
649 
650  TDEAction *action;
651  TQPtrList<TDEAction> *actionList = plugin->newActions();
652  for ( action = actionList->first(); action; action = actionList->next() ) {
653  kdDebug(5600) << "Unplugging " << action->name() << endl;
654  action->unplug( mNewActions->popupMenu() );
655  }
656 
657  if ( mSyncActionsEnabled ) {
658  actionList = plugin->syncActions();
659  for ( action = actionList->first(); action; action = actionList->next() ) {
660  kdDebug(5600) << "Unplugging " << action->name() << endl;
661  action->unplug( mSyncActions->popupMenu() );
662  }
663  }
664  removeChildClient( plugin );
665 
666  if ( mCurrentPlugin == plugin )
667  mCurrentPlugin = 0;
668 
669  plugin->deleteLater(); // removes the part automatically
670  mPlugins.remove( it );
671 
672  if ( plugin->showInSideBar() ) {
673  mPluginAction.remove( plugin );
674  }
675 
676  if ( mCurrentPlugin == 0 ) {
677  PluginList::Iterator it;
678  for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
679  if ( (*it)->showInSideBar() ) {
680  selectPlugin( *it );
681  return true;
682  }
683  }
684  }
685  return true;
686  }
687  }
688  return false;
689 }
690 
691 void MainWindow::addPlugin( Kontact::Plugin *plugin )
692 {
693  kdDebug(5600) << "Added plugin" << endl;
694 
695  mPlugins.append( plugin );
696 
697  // merge the plugins GUI into the main window
698  insertChildClient( plugin );
699 }
700 
701 void MainWindow::partLoaded( Kontact::Plugin*, KParts::ReadOnlyPart *part )
702 {
703  // See if we have this part already (e.g. due to two plugins sharing it)
704  if ( mPartsStack->id( part->widget() ) != -1 )
705  return;
706 
707  mPartsStack->addWidget( part->widget() );
708 
709  mPartManager->addPart( part, false );
710  // Workaround for KParts misbehavior: addPart calls show!
711  part->widget()->hide();
712 }
713 
714 void MainWindow::slotActivePartChanged( KParts::Part *part )
715 {
716  if ( !part ) {
717  createGUI( 0 );
718  return;
719  }
720 
721  kdDebug(5600) << "Part activated: " << part << " with stack id. "
722  << mPartsStack->id( part->widget() )<< endl;
723 
724  //createGUI( part ); // moved to selectPlugin()
725 
726  statusBar()->clear();
727 }
728 
729 void MainWindow::slotNewClicked()
730 {
731  TDEAction *action = mCurrentPlugin->newActions()->first();
732  if ( action ) {
733  action->activate();
734  } else {
735  PluginList::Iterator it;
736  for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
737  action = (*it)->newActions()->first();
738  if ( action ) {
739  action->activate();
740  return;
741  }
742  }
743  }
744 }
745 
746 void MainWindow::slotSyncClicked()
747 {
748  TDEAction *action = mCurrentPlugin->syncActions()->first();
749  if ( action ) {
750  action->activate();
751  } else {
752  PluginList::Iterator it;
753  for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
754  action = (*it)->syncActions()->first();
755  if ( action ) {
756  action->activate();
757  return;
758  }
759  }
760  }
761 }
762 
763 TDEToolBar* Kontact::MainWindow::findToolBar(const char* name)
764 {
765  // like TDEMainWindow::toolBar, but which doesn't create the toolbar if not found
766  return static_cast<TDEToolBar *>(child(name, "TDEToolBar"));
767 }
768 
769 void MainWindow::slotActionTriggered()
770 {
771  const TDEAction *actionSender = static_cast<const TDEAction*>( sender() );
772  TQString identifier = actionSender->name();
773  if ( !identifier.isEmpty() ) {
774  selectPlugin( identifier );
775  }
776 }
777 
778 void MainWindow::selectPlugin( Kontact::Plugin *plugin )
779 {
780  if ( !plugin )
781  return;
782 
783  if ( plugin->isRunningStandalone() ) {
784  statusBar()->message( i18n( "Application is running standalone. Foregrounding..." ), 1000 );
785  mSidePane->indicateForegrunding( plugin );
786  plugin->bringToForeground();
787  return;
788  }
789 
790  TDEApplication::setOverrideCursor( TQCursor( TQt::WaitCursor ) );
791 
792  KParts::Part *part = plugin->part();
793 
794  if ( !part ) {
795  TDEApplication::restoreOverrideCursor();
796  KMessageBox::error( this, i18n( "Cannot load part for %1." )
797  .arg( plugin->title() )
798  + "\n" + lastErrorMessage() );
799  plugin->setDisabled( true );
800  mSidePane->updatePlugins();
801  return;
802  }
803 
804  // store old focus widget
805  TQWidget *focusWidget = kapp->focusWidget();
806  if ( mCurrentPlugin && focusWidget ) {
807  // save the focus widget only when it belongs to the activated part
808  TQWidget *parent = focusWidget->parentWidget();
809  while ( parent ) {
810  if ( parent == mCurrentPlugin->part()->widget() )
811  mFocusWidgets.insert( mCurrentPlugin->identifier(), TQGuardedPtr<TQWidget>( focusWidget ) );
812 
813  parent = parent->parentWidget();
814  }
815  }
816 
817  if ( mSidePane ) {
818  mSidePane->selectPlugin( plugin->identifier() );
819  }
820 
821  plugin->select();
822 
823  mPartManager->setActivePart( part );
824  TQWidget *view = part->widget();
825  Q_ASSERT( view );
826 
827  if ( view ) {
828  mPartsStack->raiseWidget( view );
829  view->show();
830 
831  if ( mFocusWidgets.contains( plugin->identifier() ) ) {
832  focusWidget = mFocusWidgets[ plugin->identifier() ];
833  if ( focusWidget )
834  focusWidget->setFocus();
835  } else
836  view->setFocus();
837 
838  mCurrentPlugin = plugin;
839  TDEAction *newAction = plugin->newActions()->first();
840  TDEAction *syncAction = plugin->syncActions()->first();
841 
842  createGUI( plugin->part() );
843 
844  TDEToolBar* navigatorToolBar = findToolBar( "navigatorToolBar" );
845  // Let the navigator toolbar be always the last one, if it's in the top dockwindow
846  if ( navigatorToolBar && !navigatorToolBar->isHidden() &&
847  navigatorToolBar->barPos() == TDEToolBar::Top ) {
848  topDock()->moveDockWindow( navigatorToolBar, -1 );
849  }
850 
851  setCaption( i18n( "Plugin dependent window title" ,"%1 - Kontact" ).arg( plugin->title() ) );
852 
853  if ( newAction ) {
854  mNewActions->setIcon( newAction->icon() );
855  mNewActions->setText( newAction->text() );
856  } else { // we'll use the action of the first plugin which offers one
857  PluginList::Iterator it;
858  for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
859  newAction = (*it)->newActions()->first();
860  if ( newAction ) {
861  mNewActions->setIcon( newAction->icon() );
862  mNewActions->setText( newAction->text() );
863  break;
864  }
865  }
866  }
867  if ( mSyncActionsEnabled ) {
868  if ( syncAction ) {
869  mSyncActions->setIcon( syncAction->icon() );
870  mSyncActions->setText( syncAction->text() );
871  } else { // we'll use the action of the first plugin which offers one
872  PluginList::Iterator it;
873  for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
874  syncAction = (*it)->syncActions()->first();
875  if ( syncAction ) {
876  mSyncActions->setIcon( syncAction->icon() );
877  mSyncActions->setText( syncAction->text() );
878  break;
879  }
880  }
881  }
882  }
883  }
884  TQStringList invisibleActions = plugin->invisibleToolbarActions();
885 
886  TQStringList::ConstIterator it;
887  for ( it = invisibleActions.begin(); it != invisibleActions.end(); ++it ) {
888  TDEAction *action = part->actionCollection()->action( (*it).latin1() );
889  if ( action ) {
890  TQPtrListIterator<TDEToolBar> it( toolBarIterator() );
891  for ( ; it.current() ; ++it ) {
892  action->unplug( it.current() );
893  }
894  }
895  }
896 
897  TDEApplication::restoreOverrideCursor();
898 }
899 
900 void MainWindow::selectPlugin( const TQString &pluginName )
901 {
902  PluginList::ConstIterator end = mPlugins.end();
903  for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it )
904  if ( ( *it )->identifier() == pluginName ) {
905  selectPlugin( *it );
906  return;
907  }
908 }
909 
910 void MainWindow::loadSettings()
911 {
912  if ( mSplitter )
913  mSplitter->setSizes( Prefs::self()->mSidePaneSplitter );
914 
915  // Preload Plugins. This _must_ happen before the default part is loaded
916  PluginList::ConstIterator it;
917  for ( it = mDelayedPreload.begin(); it != mDelayedPreload.end(); ++it )
918  selectPlugin( *it );
919 
920  selectPlugin( Prefs::self()->mActivePlugin );
921 }
922 
923 void MainWindow::saveSettings()
924 {
925  if ( mSplitter )
926  Prefs::self()->mSidePaneSplitter = mSplitter->sizes();
927 
928  if ( mCurrentPlugin )
929  Prefs::self()->mActivePlugin = mCurrentPlugin->identifier();
930 }
931 
932 void MainWindow::slotShowTip()
933 {
934  showTip( true );
935 }
936 
937 void MainWindow::slotShowIntroduction()
938 {
939  mPartsStack->raiseWidget( 0 ); // ###
940 }
941 
942 void MainWindow::showTip( bool force )
943 {
944  TQStringList tips;
945  PluginList::ConstIterator end = mPlugins.end();
946  for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it ) {
947  TQString file = (*it)->tipFile();
948  if ( !file.isEmpty() )
949  tips.append( file );
950  }
951 
952  KTipDialog::showMultiTip( this, tips, force );
953 }
954 
955 void MainWindow::slotQuit()
956 {
957  mReallyClose = true;
958  close();
959 }
960 
961 void MainWindow::slotPreferences()
962 {
963  static SettingsDialogWrapper *dlg = 0;
964  if ( !dlg ) {
965  // do not show settings of components running standalone
966  TQValueList<KPluginInfo*> filteredPlugins = mPluginInfos;
967  PluginList::ConstIterator it;
968  for ( it = mPlugins.begin(); it != mPlugins.end(); ++it )
969  if ( (*it)->isRunningStandalone() ) {
970  TQValueList<KPluginInfo*>::ConstIterator infoIt;
971  for ( infoIt = filteredPlugins.begin(); infoIt != filteredPlugins.end(); ++infoIt ) {
972  if ( (*infoIt)->pluginName() == (*it)->identifier() ) {
973  filteredPlugins.remove( *infoIt );
974  break;
975  }
976  }
977  }
978  dlg = new SettingsDialogWrapper( KSettings::Dialog::Configurable, this );
979  dlg->addPluginInfos( filteredPlugins );
980  connect( dlg, TQ_SIGNAL( pluginSelectionChanged() ),
981  TQ_SLOT( pluginsChanged() ) );
982  }
983 
984  dlg->show();
985  dlg->fixButtonLabel( this );
986 }
987 
988 int MainWindow::startServiceFor( const TQString& serviceType,
989  const TQString& constraint,
990  const TQString& preferences,
991  TQString *error, TQCString* dcopService,
992  int flags )
993 {
994  PluginList::ConstIterator end = mPlugins.end();
995  for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it ) {
996  if ( (*it)->createDCOPInterface( serviceType ) ) {
997  kdDebug(5600) << "found interface for " << serviceType << endl;
998  if ( dcopService )
999  *dcopService = (*it)->dcopClient()->appId();
1000  kdDebug(5600) << "appId=" << (*it)->dcopClient()->appId() << endl;
1001  return 0; // success
1002  }
1003  }
1004 
1005  kdDebug(5600) <<
1006  "Didn't find dcop interface, falling back to external process" << endl;
1007 
1008  return KDCOPServiceStarter::startServiceFor( serviceType, constraint,
1009  preferences, error, dcopService, flags );
1010 }
1011 
1012 void MainWindow::pluginsChanged()
1013 {
1014  unloadPlugins();
1015  loadPlugins();
1016  mSidePane->updatePlugins();
1017  updateShortcuts();
1018 }
1019 
1020 void MainWindow::updateConfig()
1021 {
1022  kdDebug( 5600 ) << k_funcinfo << endl;
1023 
1024  saveSettings();
1025  loadSettings();
1026 }
1027 
1028 void MainWindow::showAboutDialog()
1029 {
1030  TDEApplication::setOverrideCursor( TQCursor( TQt::WaitCursor ) );
1031 
1032  if ( !mAboutDialog )
1033  mAboutDialog = new AboutDialog( this );
1034 
1035  mAboutDialog->show();
1036  mAboutDialog->raise();
1037  TDEApplication::restoreOverrideCursor();
1038 }
1039 
1040 void MainWindow::configureShortcuts()
1041 {
1042  KKeyDialog dialog( true, this );
1043  dialog.insert( actionCollection() );
1044 
1045  if ( mCurrentPlugin && mCurrentPlugin->part() )
1046  dialog.insert( mCurrentPlugin->part()->actionCollection() );
1047 
1048  dialog.configure();
1049 }
1050 
1051 void MainWindow::configureToolbars()
1052 {
1053  saveMainWindowSettings( TDEGlobal::config(), "MainWindow" );
1054 
1055  KEditToolbar edit( factory() );
1056  connect( &edit, TQ_SIGNAL( newToolbarConfig() ),
1057  this, TQ_SLOT( slotNewToolbarConfig() ) );
1058  edit.exec();
1059 }
1060 
1061 void MainWindow::slotNewToolbarConfig()
1062 {
1063  if ( mCurrentPlugin && mCurrentPlugin->part() ) {
1064  createGUI( mCurrentPlugin->part() );
1065  }
1066  if ( mCurrentPlugin ) {
1067  applyMainWindowSettings( TDEGlobal::config(), "MainWindow" );
1068  }
1069  updateShortcuts(); // for the plugActionList call
1070 }
1071 
1072 void MainWindow::slotOpenUrl( const KURL &url )
1073 {
1074  if ( url.protocol() == "exec" ) {
1075  if ( url.path() == "/switch" ) {
1076  selectPlugin( mCurrentPlugin );
1077  }
1078  if ( url.path() == "/gwwizard" ) {
1079  KRun::runCommand( "groupwarewizard" );
1080  slotQuit();
1081  }
1082  if ( url.path().startsWith( "/help" ) ) {
1083  TQString app( "kontact" );
1084  if ( !url.query().isEmpty() ) {
1085  app = url.query().mid( 1 );
1086  }
1087  kapp->invokeHelp( TQString(), app );
1088  }
1089  } else {
1090  new KRun( url, this );
1091  }
1092 }
1093 
1094 void MainWindow::readProperties( TDEConfig *config )
1095 {
1096  Core::readProperties( config );
1097 
1098  TQStringList activePlugins = config->readListEntry( "ActivePlugins" );
1099  TQValueList<Plugin*>::ConstIterator it = mPlugins.begin();
1100  TQValueList<Plugin*>::ConstIterator end = mPlugins.end();
1101  for ( ; it != end; ++it ) {
1102  Plugin *plugin = *it;
1103  if ( !plugin->isRunningStandalone() ) {
1104  TQStringList::ConstIterator activePlugin = activePlugins.find( plugin->identifier() );
1105  if ( activePlugin != activePlugins.end() ) {
1106  plugin->readProperties( config );
1107  }
1108  }
1109  }
1110 }
1111 
1112 void MainWindow::saveProperties( TDEConfig *config )
1113 {
1114  Core::saveProperties( config );
1115 
1116  TQStringList activePlugins;
1117 
1118  KPluginInfo::List::Iterator it = mPluginInfos.begin();
1119  KPluginInfo::List::Iterator end = mPluginInfos.end();
1120  for ( ; it != end; ++it ) {
1121  KPluginInfo *info = *it;
1122  if ( info->isPluginEnabled() ) {
1123  Plugin *plugin = pluginFromInfo( info );
1124  if ( plugin ) {
1125  activePlugins.append( plugin->identifier() );
1126  plugin->saveProperties( config );
1127  }
1128  }
1129  }
1130 
1131  config->writeEntry( "ActivePlugins", activePlugins );
1132 }
1133 
1134 bool MainWindow::queryClose()
1135 {
1136  //if ( kapp->sessionSaving() || mReallyClose )
1137  if ( kapp->sessionSaving() )
1138  return true;
1139 
1140  bool localClose = true;
1141  TQValueList<Plugin*>::ConstIterator end = mPlugins.end();
1142  TQValueList<Plugin*>::ConstIterator it = mPlugins.begin();
1143  for ( ; it != end; ++it ) {
1144  Plugin *plugin = *it;
1145  if ( !plugin->isRunningStandalone() )
1146  if ( !plugin->queryClose() )
1147  localClose = false;
1148  }
1149 
1150  return localClose;
1151 }
1152 
1153 void MainWindow::slotShowStatusMsg( const TQString &msg )
1154 {
1155  if ( !statusBar() || !mStatusMsgLabel )
1156  return;
1157 
1158  mStatusMsgLabel->setText( msg );
1159 }
1160 
1161 TQString MainWindow::introductionString()
1162 {
1163  TDEIconLoader *iconloader = TDEGlobal::iconLoader();
1164  int iconSize = iconloader->currentSize( TDEIcon::Desktop );
1165 
1166  TQString handbook_icon_path = iconloader->iconPath( "contents2", TDEIcon::Desktop );
1167  TQString html_icon_path = iconloader->iconPath( "text-html", TDEIcon::Desktop );
1168  TQString wizard_icon_path = iconloader->iconPath( "wizard", TDEIcon::Desktop );
1169 
1170  TQString info = i18n( "<h2 style='text-align:center; margin-top: 0px;'>Welcome to Kontact %1</h2>"
1171  "<p>%1</p>"
1172  "<table align=\"center\">"
1173  "<tr><td><a href=\"%1\"><img width=\"%1\" height=\"%1\" src=\"%1\" /></a></td>"
1174  "<td><a href=\"%1\">%1</a><br><span id=\"subtext\"><nobr>%1</td></tr>"
1175  "<tr><td><a href=\"%1\"><img width=\"%1\" height=\"%1\" src=\"%1\" /></a></td>"
1176  "<td><a href=\"%1\">%1</a><br><span id=\"subtext\"><nobr>%1</td></tr>"
1177  "<tr><td><a href=\"%1\"><img width=\"%1\" height=\"%1\" src=\"%1\" /></a></td>"
1178  "<td><a href=\"%1\">%1</a><br><span id=\"subtext\"><nobr>%1</td></tr>"
1179  "</table>"
1180  "<p style=\"margin-bottom: 0px\"> <a href=\"%1\">Skip this introduction</a></p>" )
1181  .arg( kapp->aboutData()->version() )
1182  .arg( i18n( "Kontact handles your e-mail, addressbook, calendar, to-do list and more." ) )
1183  .arg( "exec:/help?kontact" )
1184  .arg( iconSize )
1185  .arg( iconSize )
1186  .arg( handbook_icon_path )
1187  .arg( "exec:/help?kontact" )
1188  .arg( i18n( "Read Manual" ) )
1189  .arg( i18n( "Learn more about Kontact and its components" ) )
1190  .arg( "http://kontact.org" )
1191  .arg( iconSize )
1192  .arg( iconSize )
1193  .arg( html_icon_path )
1194  .arg( "http://kontact.org" )
1195  .arg( i18n( "Visit Kontact Website" ) )
1196  .arg( i18n( "Access online resources and tutorials" ) )
1197  .arg( "exec:/gwwizard" )
1198  .arg( iconSize )
1199  .arg( iconSize )
1200  .arg( wizard_icon_path )
1201  .arg( "exec:/gwwizard" )
1202  .arg( i18n( "Configure Kontact as Groupware Client" ) )
1203  .arg( i18n( "Prepare Kontact for use in corporate networks" ) )
1204  .arg( "exec:/switch" );
1205  return info;
1206 }
1207 
1208 #include "mainwindow.moc"
This class provides the interface to the Kontact core for the plugins.
Definition: core.h:42
Base class for all Plugins in Kontact.
Definition: plugin.h:59
KParts::ReadOnlyPart * part()
You can use this method if you need to access the current part.
Definition: plugin.cpp:145
virtual TQStringList invisibleToolbarActions() const
Returns a list of action name which shall be hidden in the main toolbar.
Definition: plugin.h:233
TQString title() const
Returns the localized title.
Definition: plugin.cpp:94
virtual bool isRunningStandalone()
Reimplement this method and return whether a standalone application is still running This is only req...
Definition: plugin.h:131
virtual bool queryClose() const
Reimplement this method if you want to add checks before closing down the main kontact window.
Definition: plugin.h:191
virtual bool showInSideBar() const
Returns whether the plugin provides a part that should be shown in the sidebar.
Definition: plugin.cpp:225
void setTitle(const TQString &title)
Sets the localized title.
Definition: plugin.cpp:89
void setIcon(const TQString &icon)
Sets the icon name.
Definition: plugin.cpp:99
TQPtrList< TDEAction > * syncActions() const
FIXME: write API doc for Kontact::Plugin::syncActions().
Definition: plugin.cpp:191
virtual void bringToForeground()
Reimplement this method if your application needs a different approach to be brought in the foregroun...
Definition: plugin.cpp:219
void setPartLibraryName(const TQCString &)
Set name of library which contains the KPart used by this plugin.
Definition: plugin.cpp:119
void setIdentifier(const TQString &identifier)
Sets the identifier.
Definition: plugin.cpp:79
virtual void select()
This function is called when the plugin is selected by the user before the widget of the KPart belong...
Definition: plugin.cpp:201
TQString identifier() const
Returns the identifier.
Definition: plugin.cpp:84
virtual int weight() const
Return the weight of the plugin.
Definition: plugin.h:208
virtual void saveProperties(TDEConfig *)
Session management: save properties.
Definition: plugin.h:257
virtual void readProperties(TDEConfig *)
Session management: read properties.
Definition: plugin.h:252
virtual void configUpdated()
This function is called whenever the config dialog has been closed successfully.
Definition: plugin.cpp:205
void setShowInSideBar(bool hasPart)
Set if the plugin provides a part that should be shown in the sidebar.
Definition: plugin.cpp:230
TQPtrList< TDEAction > * newActions() const
FIXME: write API doc for Kontact::Plugin::newActions().
Definition: plugin.cpp:186
void setExecutableName(const TQString &bin)
Sets the name of executable (if existant).
Definition: plugin.cpp:109
bool view(TQWidget *parent, Attachment *attachment)