/*
    This file is part of KDE Kontact.

    Copyright (c) 2001 Matthias Hoelzer-Kluepfel <mhk@kde.org>
    Copyright (c) 2002-2005 Daniel Molkentin <molkentin@kde.org>
    Copyright (c) 2003-2005 Cornelius Schumacher <schumacher@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include <tqaction.h>
#include <tqcombobox.h>
#include <tqdockarea.h>
#include <tqguardedptr.h>
#include <tqhbox.h>
#include <tqimage.h>
#include <tqobjectlist.h>
#include <tqprogressbar.h>
#include <tqpushbutton.h>
#include <tqsplitter.h>
#include <tqtimer.h>
#include <tqwhatsthis.h>

#include <dcopclient.h>
#include <kapplication.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kedittoolbar.h>
#include <kguiitem.h>
#include <khelpmenu.h>
#include <kiconloader.h>
#include <kkeydialog.h>
#include <klibloader.h>
#include <klistbox.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kparts/componentfactory.h>
#include <kplugininfo.h>
#include <kpopupmenu.h>
#include <ksettings/dialog.h>
#include <ksettings/dispatcher.h>
#include <kshortcut.h>
#include <kstandarddirs.h>
#include <kstatusbar.h>
#include <kstdaction.h>
#include <ktip.h>
#include <ktrader.h>
#include <ksettings/componentsdialog.h>
#include <kstringhandler.h>
#include <krsqueezedtextlabel.h>
#include <khtml_part.h>
#include <khtmlview.h>
#include <libtdepim/kfileio.h>
#include <kcursor.h>
#include <krun.h>
#include <kaboutdata.h>
#include <kmenubar.h>
#include <kstdaccel.h>
#include <kcmultidialog.h>
#include <kipc.h>

#include "aboutdialog.h"
#include "iconsidepane.h"
#include "mainwindow.h"
#include "plugin.h"
#include "prefs.h"
#include "profiledialog.h"
#include "profilemanager.h"
#include "progressdialog.h"
#include "statusbarprogresswidget.h"
#include "broadcaststatus.h"

using namespace Kontact;

class SettingsDialogWrapper : public KSettings::Dialog
{
  public:
    SettingsDialogWrapper( ContentInListView content, TQWidget * parent = 0 )
      : KSettings::Dialog( content, parent, 0 )
    {
    }


    void fixButtonLabel( TQWidget *widget )
    {
      TQObject *object = widget->child( "KJanusWidget::buttonBelowList" );
      TQPushButton *button = static_cast<TQPushButton*>( TQT_TQWIDGET(object) );
      if ( button )
        button->setText( i18n( "Select Components ..." ) );
    }
};

MainWindow::MainWindow()
  : Kontact::Core(), mTopWidget( 0 ), mSplitter( 0 ),
    mCurrentPlugin( 0 ), mAboutDialog( 0 ), mReallyClose( false ), mSyncActionsEnabled( true )
{
  // Set this to be the group leader for all subdialogs - this means
  // modal subdialogs will only affect this dialog, not the other windows
  setWFlags( getWFlags() | WGroupLeader );

  initGUI();
  initObject();
}

void MainWindow::initGUI()
{
  initWidgets();
  setupActions();
  setHelpMenuEnabled( false );
  KHelpMenu *helpMenu = new KHelpMenu( this, 0, true, actionCollection() );
  connect( helpMenu, TQT_SIGNAL( showAboutApplication() ),
           TQT_SLOT( showAboutDialog() ) );

  KTrader::OfferList offers = KTrader::self()->query(
      TQString::fromLatin1( "Kontact/Plugin" ),
      TQString( "[X-KDE-KontactPluginVersion] == %1" ).arg( KONTACT_PLUGIN_VERSION ) );
  mPluginInfos = KPluginInfo::fromServices( offers, Prefs::self()->config(), "Plugins" );

  KPluginInfo::List::Iterator it;
  for ( it = mPluginInfos.begin(); it != mPluginInfos.end(); ++it ) {
    (*it)->load();

    KAction *action = new KAction( (*it)->name(), (*it)->icon(), KShortcut(),
                                   TQT_TQOBJECT(this), TQT_SLOT(slotActionTriggered()),
                                   actionCollection(), (*it)->pluginName().latin1() );
    action->setName( (*it)->pluginName().latin1() );
    action->setWhatsThis( i18n( "Switch to plugin %1" ).arg( (*it)->name() ) );

    TQVariant hasPartProp = (*it)->property( "X-KDE-KontactPluginHasPart" );
    if ( !hasPartProp.isValid() || hasPartProp.toBool() ) {
      mActionPlugins.append( action );
    }
  }

  KStdAction::keyBindings( TQT_TQOBJECT(this), TQT_SLOT( configureShortcuts() ), actionCollection() );
  KStdAction::configureToolbars( TQT_TQOBJECT(this), TQT_SLOT( configureToolbars() ), actionCollection() );
  setXMLFile( "kontactui.rc" );

  setStandardToolBarMenuEnabled( true );

  createGUI( 0 );

  loadPlugins();

  resize( 700, 520 ); // initial size to prevent a scrollbar in sidepane
  setAutoSaveSettings();

  connect( Kontact::ProfileManager::self(), TQT_SIGNAL( profileLoaded( const TQString& ) ),
           this, TQT_SLOT( slotLoadProfile( const TQString& ) ) );
  connect( Kontact::ProfileManager::self(), TQT_SIGNAL( saveToProfileRequested( const TQString& ) ),
           this, TQT_SLOT( slotSaveToProfile( const TQString& ) ) );
}


void MainWindow::initObject()
{
  // prepare the part manager
  mPartManager = new KParts::PartManager( this );
  connect( mPartManager, TQT_SIGNAL( activePartChanged( KParts::Part* ) ),
           this, TQT_SLOT( slotActivePartChanged( KParts::Part* ) ) );

  if ( mSidePane ) {
    mSidePane->updatePlugins();
  }

  KSettings::Dispatcher::self()->registerInstance( instance(), TQT_TQOBJECT(this),
                                                   TQT_SLOT( updateConfig() ) );

  loadSettings();

  statusBar()->show();

  showTip( false );

  // done initializing
  slotShowStatusMsg( TQString() );

  connect( KPIM::BroadcastStatus::instance(), TQT_SIGNAL( statusMsg( const TQString& ) ),
           this, TQT_SLOT( slotShowStatusMsg( const TQString&  ) ) );

  // launch commandline specified module if any
  activatePluginModule();

  if ( Prefs::lastVersionSeen() == kapp->aboutData()->version() ) {
    selectPlugin( mCurrentPlugin );
  }

  paintAboutScreen( introductionString() );
  Prefs::setLastVersionSeen( kapp->aboutData()->version() );
}

MainWindow::~MainWindow()
{
  saveSettings();

  TQPtrList<KParts::Part> parts = *mPartManager->parts();

  for ( KParts::Part *p = parts.last(); p; p = parts.prev() ) {
    delete p;
    p = 0;
  }

  Prefs::self()->writeConfig();
}

void MainWindow::setActivePluginModule( const TQString &module )
{
  mActiveModule = module;
  activatePluginModule();
}

void MainWindow::activatePluginModule()
{
  if ( !mActiveModule.isEmpty() ) {
    PluginList::ConstIterator end = mPlugins.end();
    for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it )
      if ( ( *it )->identifier().contains( mActiveModule ) ) {
        selectPlugin( *it );
        return;
      }
  }
}

void MainWindow::initWidgets()
{
  // includes sidebar and part stack
  mTopWidget = new TQHBox( this );
  mTopWidget->setFrameStyle( TQFrame::Panel | TQFrame::Sunken );
  setCentralWidget( mTopWidget );

  TQHBox *mBox = 0;
  mSplitter = new TQSplitter( mTopWidget );
  mBox = new TQHBox( mTopWidget );
  mSidePane = new IconSidePane( this, mSplitter );
  mSidePane->setSizePolicy( TQSizePolicy( TQSizePolicy::Maximum,
                                         TQSizePolicy::Preferred ) );
  // donÄt occupy screen estate on load
  TQValueList<int> sizes;
  sizes << 0;
  mSplitter->setSizes(sizes);

  connect( mSidePane, TQT_SIGNAL( pluginSelected( Kontact::Plugin * ) ),
           TQT_SLOT( selectPlugin( Kontact::Plugin * ) ) );

  TQVBox *vBox;
  if ( mSplitter ) {
    vBox = new TQVBox( mSplitter );
  } else {
    vBox = new TQVBox( mBox );
  }

  vBox->setSpacing( 0 );

  mPartsStack = new TQWidgetStack( vBox );
  initAboutScreen();

  TQString loading = i18n( "<h2 style='text-align:center; margin-top: 0px; margin-bottom: 0px'>%1</h2>" )
                    .arg( i18n("Loading Kontact...") );

  paintAboutScreen( loading );

  /* Create a progress dialog and hide it. */
  KPIM::ProgressDialog *progressDialog = new KPIM::ProgressDialog( statusBar(), this );
  progressDialog->hide();

  mLittleProgress = new KPIM::StatusbarProgressWidget( progressDialog, statusBar() );

  mStatusMsgLabel = new KRSqueezedTextLabel( i18n( " Initializing..." ), statusBar() );
  mStatusMsgLabel->setAlignment( AlignLeft | AlignVCenter );

  statusBar()->addWidget( mStatusMsgLabel, 10 , false );
  statusBar()->addWidget( mLittleProgress, 0 , true );
  mLittleProgress->show();
}


void MainWindow::paintAboutScreen( const TQString& msg )
{
  TQString location = locate( "data", "kontact/about/main.html" );
  TQString content = KPIM::kFileToString( location );
  content = content.arg( locate( "data", "libtdepim/about/kde_infopage.css" ) );
  if ( kapp->reverseLayout() )
    content = content.arg( "@import \"%1\";" ).arg( locate( "data", "libtdepim/about/kde_infopage_rtl.css" ) );
  else
    content = content.arg( "" );

  mIntroPart->begin( KURL( location ) );

  TQString appName( i18n( "KDE Kontact" ) );
  TQString catchPhrase( i18n( "Get Organized!" ) );
  TQString quickDescription( i18n( "The KDE Personal Information Management Suite" ) );

  mIntroPart->write( content.arg( TQFont().pointSize() + 2 ).arg( appName )
      .arg( catchPhrase ).arg( quickDescription ).arg( msg ) );
  mIntroPart->end();
}

void MainWindow::initAboutScreen()
{
  TQHBox *introbox = new TQHBox( mPartsStack );
  mPartsStack->addWidget( introbox );
  mPartsStack->raiseWidget( introbox );
  mIntroPart = new KHTMLPart( introbox );
  mIntroPart->widget()->setFocusPolicy( TQ_WheelFocus );
  // Let's better be paranoid and disable plugins (it defaults to enabled):
  mIntroPart->setPluginsEnabled( false );
  mIntroPart->setJScriptEnabled( false ); // just make this explicit
  mIntroPart->setJavaEnabled( false );    // just make this explicit
  mIntroPart->setMetaRefreshEnabled( false );
  mIntroPart->setURLCursor( KCursor::handCursor() );
  mIntroPart->view()->setLineWidth( 0 );

  connect( mIntroPart->browserExtension(),
           TQT_SIGNAL( openURLRequest( const KURL&, const KParts::URLArgs& ) ),
           TQT_SLOT( slotOpenUrl( const KURL& ) ) );

  connect( mIntroPart->browserExtension(),
           TQT_SIGNAL( createNewWindow( const KURL&, const KParts::URLArgs& ) ),
           TQT_SLOT( slotOpenUrl( const KURL& ) ) );
}

void MainWindow::setupActions()
{
  KStdAction::quit( TQT_TQOBJECT(this), TQT_SLOT( slotQuit() ), actionCollection() );
  mNewActions = new KToolBarPopupAction( KGuiItem( i18n( "New" ), "" ),
                                         KStdAccel::shortcut(KStdAccel::New), TQT_TQOBJECT(this), TQT_SLOT( slotNewClicked() ),
                                         actionCollection(), "action_new" );

  KConfig* const cfg = Prefs::self()->config();
  cfg->setGroup( "Kontact Groupware Settings" );
  mSyncActionsEnabled = cfg->readBoolEntry( "GroupwareMailFoldersEnabled", true );

  if ( mSyncActionsEnabled ) {
    mSyncActions = new KToolBarPopupAction( KGuiItem( i18n( "Synchronize" ), "kitchensync" ),
                                            KStdAccel::shortcut(KStdAccel::Reload), TQT_TQOBJECT(this), TQT_SLOT( slotSyncClicked() ),
                                            actionCollection(), "action_sync" );
  }
  new KAction( i18n( "Configure Kontact..." ), "configure", 0, TQT_TQOBJECT(this), TQT_SLOT( slotPreferences() ),
               actionCollection(), "settings_configure_kontact" );

  new KAction( i18n( "Configure &Profiles..." ), 0, TQT_TQOBJECT(this), TQT_SLOT( slotConfigureProfiles() ),
               actionCollection(), "settings_configure_kontact_profiles" );

  new KAction( i18n( "&Kontact Introduction" ), 0, TQT_TQOBJECT(this), TQT_SLOT( slotShowIntroduction() ),
               actionCollection(), "help_introduction" );
  new KAction( i18n( "&Tip of the Day" ), 0, TQT_TQOBJECT(this), TQT_SLOT( slotShowTip() ),
               actionCollection(), "help_tipofday" );

  KWidgetAction* spacerAction = new KWidgetAction( new TQWidget( this ), "SpacerAction", "", 0, 0, actionCollection(), "navigator_spacer_item" );
  spacerAction->setAutoSized( true );
}

void MainWindow::slotConfigureProfiles()
{
  TQGuardedPtr<Kontact::ProfileDialog> dlg = new Kontact::ProfileDialog( this );
  dlg->setModal( true );
  dlg->exec();
  delete dlg;
}

namespace {
    void copyConfigEntry( KConfig* source, KConfig* dest, const TQString& group, const TQString& key, const TQString& defaultValue=TQString() )
    {
        source->setGroup( group );
        dest->setGroup( group );
        dest->writeEntry( key, source->readEntry( key, defaultValue ) );
    }
}

void MainWindow::slotSaveToProfile( const TQString& id )
{
  const TQString path = Kontact::ProfileManager::self()->profileById( id ).saveLocation();
  if ( path.isNull() )
    return;

  KConfig* const cfg = Prefs::self()->config();
  Prefs::self()->writeConfig();
  saveMainWindowSettings( cfg );
  saveSettings();

  KConfig profile( path+"/kontactrc", /*read-only=*/false, /*useglobals=*/false );
  ::copyConfigEntry( cfg, &profile, "MainWindow Toolbar navigatorToolBar", "Hidden", "true" );
  ::copyConfigEntry( cfg, &profile, "View", "SidePaneSplitter" );
  ::copyConfigEntry( cfg, &profile, "Icons", "Theme" );

  for ( PluginList::Iterator it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
    if ( !(*it)->isRunningStandalone() ) {
        (*it)->part();
    }
    (*it)->saveToProfile( path );
  }
}

void MainWindow::slotLoadProfile( const TQString& id )
{
  const TQString path = Kontact::ProfileManager::self()->profileById( id ).saveLocation();
  if ( path.isNull() )
    return;

  KConfig* const cfg = Prefs::self()->config();
  Prefs::self()->writeConfig();
  saveMainWindowSettings( cfg );
  saveSettings();

  const KConfig profile( path+"/kontactrc", /*read-only=*/false, /*useglobals=*/false );
  const TQStringList groups = profile.groupList();
  for ( TQStringList::ConstIterator it = groups.begin(), end = groups.end(); it != end; ++it )
  {
    cfg->setGroup( *it );
    typedef TQMap<TQString, TQString> StringMap;
    const StringMap entries = profile.entryMap( *it );
    for ( StringMap::ConstIterator it2 = entries.begin(), end = entries.end(); it2 != end; ++it2 )
    {
      if ( it2.data() == "KONTACT_PROFILE_DELETE_KEY" )
        cfg->deleteEntry( it2.key() );
      else
        cfg->writeEntry( it2.key(), it2.data() );
    }
  }

  cfg->sync();
  Prefs::self()->readConfig();
  applyMainWindowSettings( cfg );
  KIconTheme::reconfigure();
  const WId wid = winId();
  KIPC::sendMessage( KIPC::PaletteChanged, wid );
  KIPC::sendMessage( KIPC::FontChanged, wid );
  KIPC::sendMessage( KIPC::StyleChanged, wid );
  KIPC::sendMessage( KIPC::SettingsChanged, wid );
  for ( int i = 0; i < KIcon::LastGroup; ++i )
      KIPC::sendMessage( KIPC::IconChanged, wid, i );

  loadSettings();

  for ( PluginList::Iterator it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
    if ( !(*it)->isRunningStandalone() ) {
        kdDebug() << "Ensure loaded: " << (*it)->identifier() << endl;
        (*it)->part();
    }
    (*it)->loadProfile( path );
  }
}

bool MainWindow::isPluginLoaded( const KPluginInfo *info )
{
  return (pluginFromInfo( info ) != 0);
}

Plugin *MainWindow::pluginFromInfo( const KPluginInfo *info )
{
  PluginList::ConstIterator end = mPlugins.end();
  for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it )
    if ( (*it)->identifier() == info->pluginName() )
      return *it;

  return 0;
}

Plugin *MainWindow::pluginFromAction( const KAction *action )
{
  PluginList::ConstIterator end = mPlugins.end();
  for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it ) {
    if ( (*it)->identifier() == action->name() ) {
      return *it;
    }
  }
  return 0;
}

bool MainWindow::isPluginLoadedByAction( const KAction *action )
{
  KPluginInfo::List::ConstIterator it;
  for ( it = mPluginInfos.begin(); it != mPluginInfos.end(); ++it ) {
    if ( !(*it)->isPluginEnabled() )
      continue;
    if ( isPluginLoaded( *it ) ) {
      Plugin *plugin = pluginFromInfo( *it );
      if ( plugin ) {
        if ( plugin->identifier() == action->name() ) {
          return true;
        }
      }
    }
  }
  return false;
}

void MainWindow::sortActionsByWeight()
{
  TQPtrList<KAction> sorted;

  TQPtrListIterator<KAction> eit( mActionPlugins );
  KAction *action;
  while ( ( action = eit.current() ) != 0 ) {
    ++eit;
    TQPtrListIterator<KAction> sortIt( sorted );
    uint at = 0;
    KAction *saction;
    Plugin *p1 = pluginFromAction( action );
    while ( ( saction = sortIt.current() ) != 0 ) {
      Plugin *p2 = pluginFromAction( saction );
      if ( p1 && p2 && p1->weight() >= p2->weight() ) {
        ++sortIt;
        ++at;
      } else {
        break;
      }
    }
    sorted.insert( at, action );
  }
  mActionPlugins = sorted;
}

void MainWindow::loadPlugins()
{
  TQPtrList<Plugin> plugins;
  TQPtrList<KParts::Part> loadDelayed;

  uint i;
  KPluginInfo::List::ConstIterator it;
  for ( it = mPluginInfos.begin(); it != mPluginInfos.end(); ++it ) {
    if ( !(*it)->isPluginEnabled() )
      continue;
    if ( isPluginLoaded( *it ) ) {
      Plugin *plugin = pluginFromInfo( *it );
      if ( plugin )
        plugin->configUpdated();
      continue;
    }

    kdDebug(5600) << "Loading Plugin: " << (*it)->name() << endl;
    Kontact::Plugin *plugin =
      KParts::ComponentFactory::createInstanceFromService<Kontact::Plugin>(
          (*it)->service(), TQT_TQOBJECT(this) );

    if ( !plugin )
      continue;

    plugin->setIdentifier( (*it)->pluginName() );
    plugin->setTitle( (*it)->name() );
    plugin->setIcon( (*it)->icon() );

    TQVariant libNameProp = (*it)->property( "X-KDE-KontactPartLibraryName" );
    TQVariant exeNameProp = (*it)->property( "X-KDE-KontactPartExecutableName" );
    TQVariant loadOnStart = (*it)->property( "X-KDE-KontactPartLoadOnStart" );
    TQVariant hasPartProp = (*it)->property( "X-KDE-KontactPluginHasPart" );

    if ( !loadOnStart.isNull() && loadOnStart.toBool() )
      mDelayedPreload.append( plugin );

    kdDebug(5600) << "LIBNAMEPART: " << libNameProp.toString() << endl;

    plugin->setPartLibraryName( libNameProp.toString().utf8() );
    plugin->setExecutableName( exeNameProp.toString() );
    if ( hasPartProp.isValid() )
      plugin->setShowInSideBar( hasPartProp.toBool() );

    for ( i = 0; i < plugins.count(); ++i ) {
      Plugin *p = plugins.at( i );
      if ( plugin->weight() < p->weight() )
        break;
    }

    plugins.insert( i, plugin );
  }

  for ( i = 0; i < plugins.count(); ++ i ) {
    Plugin *plugin = plugins.at( i );

    KAction *action;
    TQPtrList<KAction> *actionList = plugin->newActions();

    for ( action = actionList->first(); action; action = actionList->next() ) {
      kdDebug(5600) << "Plugging " << action->name() << endl;
      action->plug( mNewActions->popupMenu() );
      if ( action->name() == plugin->identifier() ) {
        mPluginAction.insert( plugin, action );
      }
    }

    if ( mSyncActionsEnabled ) {
      actionList = plugin->syncActions();
      for ( action = actionList->first(); action; action = actionList->next() ) {
        kdDebug(5600) << "Plugging " << action->name() << endl;
        action->plug( mSyncActions->popupMenu() );
      }
    }
    addPlugin( plugin );
  }
  updateShortcuts();

  mNewActions->setEnabled( mPlugins.size() != 0 );
  if ( mSyncActionsEnabled )
    mSyncActions->setEnabled( mPlugins.size() != 0 );
}

void MainWindow::unloadPlugins()
{
  KPluginInfo::List::ConstIterator end = mPluginInfos.constEnd();
  KPluginInfo::List::ConstIterator it;
  for ( it = mPluginInfos.constBegin(); it != end; ++it ) {
    if ( !(*it)->isPluginEnabled() )
      removePlugin( *it );
  }
}

void MainWindow::updateShortcuts()
{
  TQPtrList<KAction> loadedActions;

  sortActionsByWeight();

  TQPtrListIterator<KAction> it( mActionPlugins );
  int i = 1;
  KAction *action;
  while ( ( action = it.current() ) != 0 ) {
    ++it;
    if ( isPluginLoadedByAction( action ) ) {
      loadedActions.append( action );
      TQString shortcut = TQString( "CTRL+%1" ).arg( i );
      action->setShortcut( KShortcut( shortcut ) );
      i++;
    } else {
      action->setShortcut( KShortcut() );
    }
  }
  unplugActionList( "navigator_actionlist" );
  factory()->plugActionList( this, TQString( "navigator_actionlist" ), loadedActions );
}

bool MainWindow::removePlugin( const KPluginInfo *info )
{
  PluginList::Iterator end = mPlugins.end();
  for ( PluginList::Iterator it = mPlugins.begin(); it != end; ++it ) {
    if ( ( *it )->identifier() == info->pluginName() ) {
      Plugin *plugin = *it;

      KAction *action;
      TQPtrList<KAction> *actionList = plugin->newActions();
      for ( action = actionList->first(); action; action = actionList->next() ) {
        kdDebug(5600) << "Unplugging " << action->name() << endl;
        action->unplug( mNewActions->popupMenu() );
      }

      if ( mSyncActionsEnabled ) {
        actionList = plugin->syncActions();
        for ( action = actionList->first(); action; action = actionList->next() ) {
          kdDebug(5600) << "Unplugging " << action->name() << endl;
          action->unplug( mSyncActions->popupMenu() );
        }
      }
      removeChildClient( plugin );

      if ( mCurrentPlugin == plugin )
        mCurrentPlugin = 0;

      plugin->deleteLater(); // removes the part automatically
      mPlugins.remove( it );

      if ( plugin->showInSideBar() ) {
        mPluginAction.remove( plugin );
      }

      if ( mCurrentPlugin == 0 ) {
        PluginList::Iterator it;
        for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
          if ( (*it)->showInSideBar() ) {
            selectPlugin( *it );
            return true;
          }
        }
      }
      return true;
    }
  }
  return false;
}

void MainWindow::addPlugin( Kontact::Plugin *plugin )
{
  kdDebug(5600) << "Added plugin" << endl;

  mPlugins.append( plugin );

  // merge the plugins GUI into the main window
  insertChildClient( plugin );
}

void MainWindow::partLoaded( Kontact::Plugin*, KParts::ReadOnlyPart *part )
{
  // See if we have this part already (e.g. due to two plugins sharing it)
  if ( mPartsStack->id( part->widget() ) != -1 )
    return;

  mPartsStack->addWidget( part->widget() );

  mPartManager->addPart( part, false );
  // Workaround for KParts misbehavior: addPart calls show!
  part->widget()->hide();
}

void MainWindow::slotActivePartChanged( KParts::Part *part )
{
  if ( !part ) {
    createGUI( 0 );
    return;
  }

  kdDebug(5600) << "Part activated: " << part << " with stack id. "
      << mPartsStack->id( part->widget() )<< endl;

  //createGUI( part ); // moved to selectPlugin()

  statusBar()->clear();
}

void MainWindow::slotNewClicked()
{
  KAction *action = mCurrentPlugin->newActions()->first();
  if ( action ) {
    action->activate();
  } else {
    PluginList::Iterator it;
    for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
      action = (*it)->newActions()->first();
      if ( action ) {
        action->activate();
        return;
      }
    }
  }
}

void MainWindow::slotSyncClicked()
{
  KAction *action = mCurrentPlugin->syncActions()->first();
  if ( action ) {
    action->activate();
  } else {
    PluginList::Iterator it;
    for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
      action = (*it)->syncActions()->first();
      if ( action ) {
        action->activate();
        return;
      }
    }
  }
}

KToolBar* Kontact::MainWindow::findToolBar(const char* name)
{
  // like KMainWindow::toolBar, but which doesn't create the toolbar if not found
  return static_cast<KToolBar *>(TQT_TQWIDGET(child(name, "KToolBar")));
}

void MainWindow::slotActionTriggered()
{
  const KAction *actionSender = static_cast<const KAction*>( sender() );
  TQString identifier = actionSender->name();
  if ( !identifier.isEmpty() ) {
    selectPlugin( identifier );
  }
}

void MainWindow::selectPlugin( Kontact::Plugin *plugin )
{
  if ( !plugin )
    return;

  if ( plugin->isRunningStandalone() ) {
    statusBar()->message( i18n( "Application is running standalone. Foregrounding..." ), 1000 );
    mSidePane->indicateForegrunding( plugin );
    plugin->bringToForeground();
    return;
  }

  KApplication::setOverrideCursor( TQCursor( TQt::WaitCursor ) );

  KParts::Part *part = plugin->part();

  if ( !part ) {
    KApplication::restoreOverrideCursor();
    KMessageBox::error( this, i18n( "Cannot load part for %1." )
                              .arg( plugin->title() )
                        + "\n" + lastErrorMessage() );
    plugin->setDisabled( true );
    mSidePane->updatePlugins();
    return;
  }

  // store old focus widget
  TQWidget *focusWidget = kapp->focusWidget();
  if ( mCurrentPlugin && focusWidget ) {
    // save the focus widget only when it belongs to the activated part
    TQWidget *parent = focusWidget->parentWidget();
    while ( parent ) {
      if ( parent == mCurrentPlugin->part()->widget() )
        mFocusWidgets.insert( mCurrentPlugin->identifier(), TQGuardedPtr<TQWidget>( focusWidget ) );

      parent = parent->parentWidget();
    }
  }

  if ( mSidePane ) {
    mSidePane->selectPlugin( plugin->identifier() );
  }

  plugin->select();

  mPartManager->setActivePart( part );
  TQWidget *view = part->widget();
  Q_ASSERT( view );

  if ( view ) {
    mPartsStack->raiseWidget( view );
    view->show();

    if ( mFocusWidgets.contains( plugin->identifier() ) ) {
      focusWidget = mFocusWidgets[ plugin->identifier() ];
      if ( focusWidget )
        focusWidget->setFocus();
    } else
      view->setFocus();

    mCurrentPlugin = plugin;
    KAction *newAction = plugin->newActions()->first();
    KAction *syncAction = plugin->syncActions()->first();

    createGUI( plugin->part() );

    KToolBar* navigatorToolBar = findToolBar( "navigatorToolBar" );
    // Let the navigator toolbar be always the last one, if it's in the top dockwindow
    if ( navigatorToolBar && !navigatorToolBar->isHidden() &&
         navigatorToolBar->barPos() == KToolBar::Top ) {
      topDock()->moveDockWindow( navigatorToolBar, -1 );
    }

    setCaption( i18n( "Plugin dependent window title" ,"%1 - Kontact" ).arg( plugin->title() ) );

    if ( newAction ) {
      mNewActions->setIcon( newAction->icon() );
      mNewActions->setText( newAction->text() );
    } else { // we'll use the action of the first plugin which offers one
      PluginList::Iterator it;
      for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
        newAction = (*it)->newActions()->first();
        if ( newAction ) {
          mNewActions->setIcon( newAction->icon() );
          mNewActions->setText( newAction->text() );
          break;
        }
      }
    }
    if ( mSyncActionsEnabled ) {
      if ( syncAction ) {
        mSyncActions->setIcon( syncAction->icon() );
        mSyncActions->setText( syncAction->text() );
      } else { // we'll use the action of the first plugin which offers one
        PluginList::Iterator it;
        for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
          syncAction = (*it)->syncActions()->first();
          if ( syncAction ) {
            mSyncActions->setIcon( syncAction->icon() );
            mSyncActions->setText( syncAction->text() );
            break;
          }
        }
      }
    }
  }
  TQStringList invisibleActions = plugin->invisibleToolbarActions();

  TQStringList::ConstIterator it;
  for ( it = invisibleActions.begin(); it != invisibleActions.end(); ++it ) {
    KAction *action = part->actionCollection()->action( (*it).latin1() );
    if ( action ) {
      TQPtrListIterator<KToolBar> it(  toolBarIterator() );
      for (  ; it.current() ; ++it ) {
        action->unplug( it.current() );
      }
    }
  }

  KApplication::restoreOverrideCursor();
}

void MainWindow::selectPlugin( const TQString &pluginName )
{
  PluginList::ConstIterator end = mPlugins.end();
  for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it )
    if ( ( *it )->identifier() == pluginName ) {
      selectPlugin( *it );
      return;
    }
}

void MainWindow::loadSettings()
{
  if ( mSplitter )
    mSplitter->setSizes( Prefs::self()->mSidePaneSplitter );

  // Preload Plugins. This _must_ happen before the default part is loaded
  PluginList::ConstIterator it;
  for ( it = mDelayedPreload.begin(); it != mDelayedPreload.end(); ++it )
    selectPlugin( *it );

  selectPlugin( Prefs::self()->mActivePlugin );
}

void MainWindow::saveSettings()
{
  if ( mSplitter )
    Prefs::self()->mSidePaneSplitter = mSplitter->sizes();

  if ( mCurrentPlugin )
    Prefs::self()->mActivePlugin = mCurrentPlugin->identifier();
}

void MainWindow::slotShowTip()
{
  showTip( true );
}

void MainWindow::slotShowIntroduction()
{
  mPartsStack->raiseWidget( 0 ); // ###
}

void MainWindow::showTip( bool force )
{
  TQStringList tips;
  PluginList::ConstIterator end = mPlugins.end();
  for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it ) {
    TQString file = (*it)->tipFile();
    if ( !file.isEmpty() )
      tips.append( file );
  }

  KTipDialog::showMultiTip( this, tips, force );
}

void MainWindow::slotQuit()
{
  mReallyClose = true;
  close();
}

void MainWindow::slotPreferences()
{
  static SettingsDialogWrapper *dlg = 0;
  if ( !dlg ) {
    // do not show settings of components running standalone
    TQValueList<KPluginInfo*> filteredPlugins = mPluginInfos;
    PluginList::ConstIterator it;
    for ( it = mPlugins.begin(); it != mPlugins.end(); ++it )
      if ( (*it)->isRunningStandalone() ) {
        TQValueList<KPluginInfo*>::ConstIterator infoIt;
        for ( infoIt = filteredPlugins.begin(); infoIt != filteredPlugins.end(); ++infoIt ) {
          if ( (*infoIt)->pluginName() == (*it)->identifier() ) {
            filteredPlugins.remove( *infoIt );
            break;
          }
        }
      }
    dlg = new SettingsDialogWrapper( KSettings::Dialog::Configurable, this );
    dlg->addPluginInfos( filteredPlugins );
    connect( dlg, TQT_SIGNAL( pluginSelectionChanged() ),
             TQT_SLOT( pluginsChanged() ) );
  }

  dlg->show();
  dlg->fixButtonLabel( this );
}

int MainWindow::startServiceFor( const TQString& serviceType,
                                 const TQString& constraint,
                                 const TQString& preferences,
                                 TQString *error, TQCString* dcopService,
                                 int flags )
{
  PluginList::ConstIterator end = mPlugins.end();
  for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it ) {
    if ( (*it)->createDCOPInterface( serviceType ) ) {
      kdDebug(5600) << "found interface for " << serviceType << endl;
      if ( dcopService )
        *dcopService = (*it)->dcopClient()->appId();
      kdDebug(5600) << "appId=" << (*it)->dcopClient()->appId() << endl;
      return 0; // success
    }
  }

  kdDebug(5600) <<
    "Didn't find dcop interface, falling back to external process" << endl;

  return KDCOPServiceStarter::startServiceFor( serviceType, constraint,
      preferences, error, dcopService, flags );
}

void MainWindow::pluginsChanged()
{
  unloadPlugins();
  loadPlugins();
  mSidePane->updatePlugins();
  updateShortcuts();
}

void MainWindow::updateConfig()
{
  kdDebug( 5600 ) << k_funcinfo << endl;

  saveSettings();
  loadSettings();
}

void MainWindow::showAboutDialog()
{
  KApplication::setOverrideCursor( TQCursor( TQt::WaitCursor ) );

  if ( !mAboutDialog )
    mAboutDialog = new AboutDialog( this );

  mAboutDialog->show();
  mAboutDialog->raise();
  KApplication::restoreOverrideCursor();
}

void MainWindow::configureShortcuts()
{
  KKeyDialog dialog( true, this );
  dialog.insert( actionCollection() );

  if ( mCurrentPlugin && mCurrentPlugin->part() )
    dialog.insert( mCurrentPlugin->part()->actionCollection() );

  dialog.configure();
}

void MainWindow::configureToolbars()
{
  saveMainWindowSettings( KGlobal::config(), "MainWindow" );

  KEditToolbar edit( factory() );
  connect( &edit, TQT_SIGNAL( newToolbarConfig() ),
           this, TQT_SLOT( slotNewToolbarConfig() ) );
  edit.exec();
}

void MainWindow::slotNewToolbarConfig()
{
  if ( mCurrentPlugin && mCurrentPlugin->part() ) {
    createGUI( mCurrentPlugin->part() );
  }
  if ( mCurrentPlugin ) {
    applyMainWindowSettings( KGlobal::config(), "MainWindow" );
  }
  updateShortcuts(); // for the plugActionList call
}

void MainWindow::slotOpenUrl( const KURL &url )
{
  if ( url.protocol() == "exec" ) {
    if ( url.path() == "/switch" ) {
      selectPlugin( mCurrentPlugin );
    }
    if ( url.path() == "/gwwizard" ) {
      KRun::runCommand( "groupwarewizard" );
      slotQuit();
    }
    if ( url.path().startsWith( "/help" ) ) {
      TQString app( "kontact" );
      if ( !url.query().isEmpty() ) {
        app = url.query().mid( 1 );
      }
      kapp->invokeHelp( TQString(), app );
    }
  } else {
    new KRun( url, this );
  }
}

void MainWindow::readProperties( KConfig *config )
{
  Core::readProperties( config );

  TQStringList activePlugins = config->readListEntry( "ActivePlugins" );
  TQValueList<Plugin*>::ConstIterator it = mPlugins.begin();
  TQValueList<Plugin*>::ConstIterator end = mPlugins.end();
  for ( ; it != end; ++it ) {
    Plugin *plugin = *it;
    if ( !plugin->isRunningStandalone() ) {
      TQStringList::ConstIterator activePlugin = activePlugins.find( plugin->identifier() );
      if ( activePlugin != activePlugins.end() ) {
        plugin->readProperties( config );
      }
    }
  }
}

void MainWindow::saveProperties( KConfig *config )
{
  Core::saveProperties( config );

  TQStringList activePlugins;

  KPluginInfo::List::Iterator it = mPluginInfos.begin();
  KPluginInfo::List::Iterator end = mPluginInfos.end();
  for ( ; it != end; ++it ) {
    KPluginInfo *info = *it;
    if ( info->isPluginEnabled() ) {
      Plugin *plugin = pluginFromInfo( info );
      if ( plugin ) {
        activePlugins.append( plugin->identifier() );
        plugin->saveProperties( config );
      }
    }
  }

  config->writeEntry( "ActivePlugins", activePlugins );
}

bool MainWindow::queryClose()
{
  //if ( kapp->sessionSaving() || mReallyClose )
  if ( kapp->sessionSaving() )
    return true;

  bool localClose = true;
  TQValueList<Plugin*>::ConstIterator end = mPlugins.end();
  TQValueList<Plugin*>::ConstIterator it = mPlugins.begin();
  for ( ; it != end; ++it ) {
    Plugin *plugin = *it;
    if ( !plugin->isRunningStandalone() )
      if ( !plugin->queryClose() )
        localClose = false;
  }

  return localClose;
}

void MainWindow::slotShowStatusMsg( const TQString &msg )
{
  if ( !statusBar() || !mStatusMsgLabel )
     return;

  mStatusMsgLabel->setText( msg );
}

TQString MainWindow::introductionString()
{
  KIconLoader *iconloader = KGlobal::iconLoader();
  int iconSize = iconloader->currentSize( KIcon::Desktop );

  TQString handbook_icon_path = iconloader->iconPath( "contents2",  KIcon::Desktop );
  TQString html_icon_path = iconloader->iconPath( "html",  KIcon::Desktop );
  TQString wizard_icon_path = iconloader->iconPath( "wizard",  KIcon::Desktop );

  TQString info = i18n( "<h2 style='text-align:center; margin-top: 0px;'>Welcome to Kontact %1</h2>"
      "<p>%1</p>"
      "<table align=\"center\">"
      "<tr><td><a href=\"%1\"><img width=\"%1\" height=\"%1\" src=\"%1\" /></a></td>"
      "<td><a href=\"%1\">%1</a><br><span id=\"subtext\"><nobr>%1</td></tr>"
      "<tr><td><a href=\"%1\"><img width=\"%1\" height=\"%1\" src=\"%1\" /></a></td>"
      "<td><a href=\"%1\">%1</a><br><span id=\"subtext\"><nobr>%1</td></tr>"
      "<tr><td><a href=\"%1\"><img width=\"%1\" height=\"%1\" src=\"%1\" /></a></td>"
      "<td><a href=\"%1\">%1</a><br><span id=\"subtext\"><nobr>%1</td></tr>"
      "</table>"
      "<p style=\"margin-bottom: 0px\"> <a href=\"%1\">Skip this introduction</a></p>" )
      .arg( kapp->aboutData()->version() )
      .arg( i18n( "Kontact handles your e-mail, addressbook, calendar, to-do list and more." ) )
      .arg( "exec:/help?kontact" )
      .arg( iconSize )
      .arg( iconSize )
      .arg( handbook_icon_path )
      .arg( "exec:/help?kontact" )
      .arg( i18n( "Read Manual" ) )
      .arg( i18n( "Learn more about Kontact and its components" ) )
      .arg( "http://kontact.org" )
      .arg( iconSize )
      .arg( iconSize )
      .arg( html_icon_path )
      .arg( "http://kontact.org" )
      .arg( i18n( "Visit Kontact Website" ) )
      .arg( i18n( "Access online resources and tutorials" ) )
      .arg( "exec:/gwwizard" )
      .arg( iconSize )
      .arg( iconSize )
      .arg( wizard_icon_path )
      .arg( "exec:/gwwizard" )
      .arg( i18n( "Configure Kontact as Groupware Client" ) )
      .arg( i18n( "Prepare Kontact for use in corporate networks" ) )
      .arg( "exec:/switch" );
  return info;
}

#include "mainwindow.moc"