<commit_before>/*
    kopetewindow.cpp  -  Kopete Main Window

    Copyright (c) 2001-2002 by <NAME> <<EMAIL>>
    Copyright (c) 2001-2002 by <NAME>            <metz AT gehn.net>
    Copyright (c) 2002-2003 by <NAME>       <<EMAIL>>
    Copyright (c) 2002-2005 by <NAME>        <ogoffart at kde.org>
    Copyright (c) 2005-2006 by <NAME>        <<EMAIL>>

    Kopete    (c) 2002-2005 by the Kopete developers  <<EMAIL>>

    *************************************************************************
    *                                                                       *
    * 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.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "kopetewindow.h"

#include <QCursor>
#include <QLayout>

#include <QTimer>
#include <QPixmap>
#include <QCloseEvent>
#include <QMouseEvent>
#include <QEvent>
#include <QLabel>
#include <QShowEvent>
#include <QLineEdit>
#include <QSignalMapper>

#include <khbox.h>
#include <kaction.h>
#include <kactioncollection.h>
#include <ktoggleaction.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kglobalaccel.h>
#include <klocale.h>
#include <kicon.h>
#include <kiconloader.h>
#include <kmessagebox.h>
#include <knotifyconfigwidget.h>
#include <kmenu.h>
#include <kshortcutsdialog.h>
#include <kedittoolbar.h>
#include <kmenubar.h>
#include <kstatusbar.h>
#include <kwindowsystem.h>
#include <kdeversion.h>
#include <kinputdialog.h>
#include <kplugininfo.h>
#include <ksqueezedtextlabel.h>
#include <kstringhandler.h>
#include <kurl.h>
#include <kxmlguifactory.h>
#include <ktoolbar.h>
#include <kdialog.h>
#include <kstandardaction.h>

#include "addcontactpage.h"
#include "addressbooklinkwidget.h"
#include "ui_groupkabcselectorwidget.h"
#include "kabcexport.h"
#include "kopeteappearancesettings.h"
#include "kopeteapplication.h"
#include "kopeteaccount.h"
#include "kopeteaway.h"
#include "kopeteaccountmanager.h"
#include "kopeteidentitystatusbaricon.h"
#include "kopetebehaviorsettings.h"
#include "kopetecontact.h"
#include "kopetecontactlist.h"
#include "kopetecontactlistview.h"
#include "kopetegroup.h"
#include "kopeteidentity.h"
#include "kopeteidentitymanager.h"
#include "kopetelistviewsearchline.h"
#include "kopetechatsessionmanager.h"
#include "kopetepluginmanager.h"
#include "kopeteprotocol.h"
#include "kopetestdaction.h"
#include "kopeteawayaction.h"
#include "kopeteuiglobal.h"
#include "systemtray.h"
#include "kopeteonlinestatusmanager.h"
#include "identitystatuswidget.h"

//BEGIN GlobalStatusMessageIconLabel
GlobalStatusMessageIconLabel::GlobalStatusMessageIconLabel(QWidget *parent)
 : QLabel(parent)
{
}

void GlobalStatusMessageIconLabel::mouseReleaseEvent( QMouseEvent *event )
{
      if( event->button() == Qt::LeftButton || event->button() == Qt::RightButton )
      {
              emit iconClicked( event->globalPos() );
              event->accept();
      }
}
//END GlobalStatusMessageIconLabel

class KopeteWindow::Private
{
public:
	Private()
	 : contactlist(0), identitywidget(0), actionAddContact(0), actionDisconnect(0), actionExportContacts(0),
	actionAwayMenu(0), actionDockMenu(0), selectAway(0), selectBusy(0), actionSetAvailable(0),
	actionSetInvisible(0), actionPrefs(0), actionQuit(0), actionSave(0), menubarAction(0),
	statusbarAction(0), actionShowOffliners(0), actionShowEmptyGroups(0), docked(0), 
	deskRight(0), statusBarWidget(0), tray(0), hidden(false), autoHide(false),
	autoHideTimeout(0), autoHideTimer(0), addContactMapper(0), 
	globalStatusMessage(0), globalStatusMessageMenu(0), newMessageEdit(0)
	{}

	~Private()
	{}

	KopeteContactListView *contactlist;

	IdentityStatusWidget *identitywidget;

	// Some Actions
	KActionMenu *actionAddContact;

	KAction *actionDisconnect;
	KAction *actionExportContacts;

	KActionMenu *actionAwayMenu;
	KActionMenu *actionDockMenu;
	KAction *selectAway;
	KAction *selectBusy;
	KAction *actionSetAvailable;
	KAction *actionSetInvisible;


	KAction *actionPrefs;
	KAction *actionQuit;
	KAction *actionSave;
	KToggleAction *menubarAction;
	KToggleAction *statusbarAction;
	KToggleAction *actionShowOffliners;
	KToggleAction *actionShowEmptyGroups;

	int docked;
	int deskRight;
	QPoint position;
	KHBox *statusBarWidget;
	KopeteSystemTray *tray;
	bool hidden;
	bool autoHide;
	unsigned int autoHideTimeout;
	QTimer *autoHideTimer;
	QSignalMapper *addContactMapper;

	QHash<const Kopete::Identity*, KopeteIdentityStatusBarIcon*> identityStatusBarIcons;
	KSqueezedTextLabel *globalStatusMessage;
	KMenu *globalStatusMessageMenu;
	QLineEdit *newMessageEdit;
	QString globalStatusMessageStored;
};

/* KMainWindow is very broken from our point of view - it deref()'s the app
 * when the last visible KMainWindow is destroyed. But when our main window is
 * hidden when it's in the tray,closing the last chatwindow would cause the app
 * to quit. - Richard
 *
 * Fortunately KMainWindow checks queryExit before deref()ing the Kapplication.
 * KopeteWindow reimplements queryExit() and only returns true if it is shutting down
 * (either because the user quit Kopete, or the session manager did).
 *
 * KopeteWindow and ChatWindows are closed by session management.
 * App shutdown is not performed by the KopeteWindow but by KopeteApplication:
 * 1) user quit - KopeteWindow::slotQuit() was called, calls KopeteApplication::quitKopete(),
 *                which closes all chatwindows and the KopeteWindow.  The last window to close
 *                shuts down the PluginManager in queryExit().  When the PluginManager has completed its
 *                shutdown, the app is finally deref()ed, and the contactlist and accountmanager
 *                are saved.
 *                and calling KApplication::quit()
 * 2) session   - KopeteWindow and all chatwindows are closed by KApplication session management.
 *     quit        Then the shutdown proceeds as above.
 *
 * queryClose() is honoured so group chats and chats receiving recent messages can interrupt
 * (session) quit.
 */

KopeteWindow::KopeteWindow( QWidget *parent, const char *name )
: KXmlGuiWindow( parent, Qt::WType_TopLevel ), d(new Private)
{
	setObjectName( name );
	setAttribute (Qt::WA_DeleteOnClose, false);
	setAttribute (Qt::WA_QuitOnClose, false);
	// Applications should ensure that their StatusBar exists before calling createGUI()
	// so that the StatusBar is always correctly positioned when KDE is configured to use
	// a MacOS-style MenuBar.
	// This fixes a "statusbar drawn over the top of the toolbar" bug
	// e.g. it can happen when you switch desktops on Kopete startup
	d->statusBarWidget = new KHBox(statusBar());
	d->statusBarWidget->setObjectName( "m_statusBarWidget" );
	d->statusBarWidget->setMargin( 2 );
	d->statusBarWidget->setSpacing( 1 );
	statusBar()->addPermanentWidget(d->statusBarWidget, 0);
	KHBox *statusBarMessage = new KHBox(statusBar());
	d->statusBarWidget->setMargin( 2 );
	d->statusBarWidget->setSpacing( 1 );

	GlobalStatusMessageIconLabel *label = new GlobalStatusMessageIconLabel( statusBarMessage );
	label->setObjectName( QLatin1String("statusmsglabel") );
	label->setFixedSize( 16, 16 );
	label->setPixmap( SmallIcon( "kopetestatusmessage" ) );
	connect(label, SIGNAL(iconClicked( const QPoint& )),
		this, SLOT(slotGlobalStatusMessageIconClicked( const QPoint& )));
	label->setToolTip( i18n( "Global status message" ) );
	d->globalStatusMessage = new KSqueezedTextLabel( statusBarMessage );
	statusBar()->addWidget(statusBarMessage, 1);

	d->autoHideTimer = new QTimer( this );

	// --------------------------------------------------------------------------------
	initView();
	initActions();
	d->contactlist->initActions(actionCollection());
	initSystray();
	// --------------------------------------------------------------------------------

	// Trap all loaded plugins, so we can add their status bar icons accordingly , also used to add XMLGUIClient
	connect( Kopete::PluginManager::self(), SIGNAL( pluginLoaded( Kopete::Plugin * ) ),
		this, SLOT( slotPluginLoaded( Kopete::Plugin * ) ) );
	connect( Kopete::PluginManager::self(), SIGNAL( allPluginsLoaded() ),
		this, SLOT( slotAllPluginsLoaded() ));

	// Connect all identity signals
	connect( Kopete::IdentityManager::self(), SIGNAL(identityRegistered(Kopete::Identity*)),
		this, SLOT(slotIdentityRegistered(Kopete::Identity*)));
	connect( Kopete::IdentityManager::self(), SIGNAL(identityUnregistered(const Kopete::Identity*)),
		this, SLOT(slotIdentityUnregistered(const Kopete::Identity*)));
	
	//Connect the appropriate account signals
	/* Please note that I tried to put this in the slotAllPluginsLoaded() function
	 * but it seemed to break the account icons in the statusbar --Matt */
	connect( Kopete::AccountManager::self(), SIGNAL(accountRegistered(Kopete::Account*)),
		this, SLOT(slotAccountRegistered(Kopete::Account*)));
	connect( Kopete::AccountManager::self(), SIGNAL(accountUnregistered(const Kopete::Account*)),
		this, SLOT(slotAccountUnregistered(const Kopete::Account*)));

	connect( d->autoHideTimer, SIGNAL( timeout() ), this, SLOT( slotAutoHide() ) );
	connect( Kopete::AppearanceSettings::self(), SIGNAL( contactListAppearanceChanged() ),
		this, SLOT( slotContactListAppearanceChanged() ) );
	createGUI ( QLatin1String("kopeteui.rc") );

	// call this _after_ createGUI(), otherwise menubar is not set up correctly
	loadOptions();

	// If some plugins are already loaded, merge the GUI
	Kopete::PluginList plugins = Kopete::PluginManager::self()->loadedPlugins();
	foreach(Kopete::Plugin *plug, plugins)
		slotPluginLoaded( plug );

	// If some identity already registered, build the status icon
	Kopete::Identity::List identityList = Kopete::IdentityManager::self()->identities();
	foreach(Kopete::Identity *i, identityList)
		slotIdentityRegistered( i );

	// If some account already loaded, build the status icon
	QList<Kopete::Account *> accountList = Kopete::AccountManager::self()->accounts();
	foreach(Kopete::Account *a, accountList)
		slotAccountRegistered( a );

    //install an event filter for the quick search toolbar so we can
    //catch the hide events
    toolBar( "quickSearchBar" )->installEventFilter( this );
    //it does not make sense to have a toolbar that does use the half sceen...
    toolBar( "mainToolBar" )->setToolButtonStyle( Qt::ToolButtonIconOnly );
}

void KopeteWindow::initView()
{
	QWidget *w = new QWidget(this);
	QVBoxLayout *l = new QVBoxLayout(w);
	d->contactlist = new KopeteContactListView(w);
	l->addWidget(d->contactlist);
	l->setSpacing( 0 );
	l->setContentsMargins(0,0,0,0);
	d->identitywidget = new IdentityStatusWidget(0, w);
	d->identitywidget->setSizePolicy( QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum) ); 
	d->identitywidget->setVisible( false );
	l->addWidget(d->identitywidget);

	setCentralWidget(w);
}

void KopeteWindow::initActions()
{
	// this action menu contains one action per account and is updated when accounts are registered/unregistered
	d->actionAddContact = new KActionMenu( KIcon("add-user"), i18n( "&Add Contact" ), this );
	actionCollection()->addAction( "AddContact", d->actionAddContact );
	d->actionAddContact->setDelayed( false );
	// this signal mapper is needed to call slotAddContact with the correct arguments
	d->addContactMapper = new QSignalMapper( this );
	connect( d->addContactMapper, SIGNAL( mapped( const QString & ) ),
		 this, SLOT( slotAddContactDialogInternal( const QString & ) ) );

	d->actionDisconnect = new KAction( KIcon("connect-no"), i18n( "Offline" ), this );
        actionCollection()->addAction( "DisconnectAll", d->actionDisconnect );
	connect( d->actionDisconnect, SIGNAL( triggered(bool) ), this, SLOT( slotDisconnectAll() ) );
	d->actionDisconnect->setEnabled(false);

	d->actionExportContacts = new KAction( i18n( "&Export Contacts..." ), this );
        actionCollection()->addAction( "ExportContacts", d->actionExportContacts );
	connect( d->actionExportContacts, SIGNAL( triggered(bool) ), this, SLOT( showExportDialog() ) );

	d->selectAway = new KAction( KIcon("kopeteaway"), i18n("&Away"), this );
        actionCollection()->addAction( "SetAwayAll", d->selectAway );
	connect( d->selectAway, SIGNAL( triggered(bool) ), this, SLOT( slotGlobalAway() ) );

	d->selectBusy = new KAction( KIcon("kopeteaway"), i18n("&Busy"), this );
        actionCollection()->addAction( "SetBusyAll", d->selectBusy );
	connect( d->selectBusy, SIGNAL( triggered(bool) ), this, SLOT( slotGlobalBusy() ) );


	d->actionSetInvisible = new KAction( KIcon("kopeteavailable"), i18n( "&Invisible" ), this );
        actionCollection()->addAction( "SetInvisibleAll", d->actionSetInvisible );
	connect( d->actionSetInvisible, SIGNAL( triggered(bool) ), this, SLOT( slotSetInvisibleAll() ) );

	d->actionSetAvailable = new KAction( KIcon("kopeteavailable"), i18n("&Online"), this );
        actionCollection()->addAction( "SetAvailableAll", d->actionSetAvailable );
	connect( d->actionSetAvailable, SIGNAL( triggered(bool) ), this, SLOT( slotGlobalAvailable() ) );

	d->actionAwayMenu = new KActionMenu( KIcon("kopeteavailable"), i18n("&Set Status"),
                                             this );
        actionCollection()->addAction( "Status", d->actionAwayMenu );
	d->actionAwayMenu->setDelayed( false );
	d->actionAwayMenu->addAction(d->actionSetAvailable);
	d->actionAwayMenu->addAction(d->selectAway);
	d->actionAwayMenu->addAction(d->selectBusy);
	d->actionAwayMenu->addAction(d->actionSetInvisible);
	d->actionAwayMenu->addAction(d->actionDisconnect);

	d->actionPrefs = KopeteStdAction::preferences( actionCollection(), "settings_prefs" );

	KStandardAction::quit(this, SLOT(slotQuit()), actionCollection());

	setStandardToolBarMenuEnabled(true);
	d->menubarAction = KStandardAction::showMenubar(menuBar(), SLOT(setVisible(bool)), actionCollection() );
        actionCollection()->addAction( "settings_showmenubar", d->menubarAction );
	d->statusbarAction = KStandardAction::showStatusbar(statusBar(), SLOT(setVisible(bool)), actionCollection() );
        actionCollection()->addAction( "settings_showstatusbar", d->statusbarAction );

	KAction* act = KStandardAction::keyBindings( guiFactory(), SLOT( configureShortcuts() ), actionCollection() );
        actionCollection()->addAction( "settings_keys", act );

	KAction *configureGlobalShortcutsAction = new KAction( KIcon("configure-shortcuts"), i18n( "Configure &Global Shortcuts..." ), this );
        actionCollection()->addAction( "settings_global", configureGlobalShortcutsAction );
	connect( configureGlobalShortcutsAction, SIGNAL( triggered(bool) ), this, SLOT( slotConfGlobalKeys() ) );

	KStandardAction::configureToolbars( this, SLOT(slotConfToolbar()), actionCollection() );
	act = KStandardAction::configureNotifications(this, SLOT(slotConfNotifications()), actionCollection() );
        actionCollection()->addAction( "settings_notifications", act );

	d->actionShowOffliners = new KToggleAction( KIcon("show-offliners"), i18n( "Show Offline &Users" ), this );
        actionCollection()->addAction( "settings_show_offliners", d->actionShowOffliners );
	d->actionShowOffliners->setShortcut( KShortcut(Qt::CTRL + Qt::Key_U) );
	connect( d->actionShowOffliners, SIGNAL( triggered(bool) ), this, SLOT( slotToggleShowOffliners() ) );

	d->actionShowEmptyGroups = new KToggleAction( KIcon("folder-grey"), i18n( "Show Empty &Groups" ), this );
        actionCollection()->addAction( "settings_show_empty_groups", d->actionShowEmptyGroups );
	d->actionShowEmptyGroups->setShortcut( KShortcut(Qt::CTRL + Qt::Key_G) );
	connect( d->actionShowEmptyGroups, SIGNAL( triggered(bool) ), this, SLOT( slotToggleShowEmptyGroups() ) );

	d->actionShowOffliners->setCheckedState( KGuiItem( i18n("Hide Offline &Users") ) );
	d->actionShowEmptyGroups->setCheckedState( KGuiItem( i18n("Hide Empty &Groups") ) );

	// quick search bar
	QLabel *searchLabel = new QLabel( i18n("Se&arch:"), 0 );
	searchLabel->setObjectName( QLatin1String("kde toolbar widget") );
	QWidget *searchBar = new Kopete::UI::ListView::SearchLine( 0, d->contactlist );
	searchLabel->setBuddy( searchBar );
	KAction *quickSearch = new KAction( i18n("Quick Search Bar"), this );
        actionCollection()->addAction( "quicksearch_bar", quickSearch );
	quickSearch->setDefaultWidget( searchBar );
	KAction *searchLabelAction = new KAction( i18n("Search:"), this );
        actionCollection()->addAction( "quicksearch_label", searchLabelAction );
	searchLabelAction->setDefaultWidget( searchLabel );

	// KActionMenu for selecting the global status message
	KActionMenu * setStatusMenu = new KActionMenu( KIcon("kopeteeditstatusmessage"), i18n( "Set Status Message" ), this );
        actionCollection()->addAction( "SetStatusMessage", setStatusMenu );
	setStatusMenu->setDelayed( false );
	connect( setStatusMenu->menu(), SIGNAL( aboutToShow() ), SLOT(slotBuildStatusMessageMenu() ) );

	// sync actions, config and prefs-dialog
	connect ( Kopete::AppearanceSettings::self(), SIGNAL(configChanged()), this, SLOT(slotConfigChanged()) );
	slotConfigChanged();

	// Global actions
	KAction *globalReadMessage = new KAction( i18n("Read Message"), this );
        actionCollection()->addAction( "ReadMessage",  globalReadMessage );
	connect( globalReadMessage, SIGNAL( triggered(bool) ), Kopete::ChatSessionManager::self(), SLOT( slotReadMessage() ) );
	globalReadMessage->setGlobalShortcut( KShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_I) );
	globalReadMessage->setWhatsThis( i18n("Read the next pending message") );

	KAction *globalShowContactList = new KAction( i18n("Show/Hide Contact List"), this );
        actionCollection()->addAction( "ShowContactList", globalShowContactList );
	connect( globalShowContactList, SIGNAL( triggered(bool) ), this, SLOT( slotShowHide() ) );
	globalShowContactList->setGlobalShortcut( KShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_S) );
	globalShowContactList->setWhatsThis( i18n("Show or hide the contact list") );

	KAction *globalSetAway = new KAction( i18n("Set Away/Back"), this );
        actionCollection()->addAction( "Set_Away_Back",  globalSetAway );
	connect( globalSetAway, SIGNAL( triggered(bool) ), this, SLOT( slotToggleAway() ) );
	globalSetAway->setGlobalShortcut( KShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_W) );

#ifdef __GNUC__
#warning port me - it is probably safe to just remove this line as *global* shortcut setttings
#warning are now loaded automatically by default.
#endif
	//KGlobalAccel::self()->readSettings();
}

void KopeteWindow::slotShowHide()
{
	if(isActiveWindow())
	{
		d->autoHideTimer->stop(); //no timeouts if active
		hide();
	}
	else
	{
		show();
#ifdef Q_WS_X11
		//raise() and show() should normaly deIconify the window. but it doesn't do here due
		// to a bug in QT or in KDE  (qt3.1.x or KDE 3.1.x) then, i have to call KWin's method
		if(isMinimized())
			KWindowSystem::unminimizeWindow(winId());

		if(!KWindowSystem::windowInfo(winId(),NET::WMDesktop).onAllDesktops())
			KWindowSystem::setOnDesktop(winId(), KWindowSystem::currentDesktop());
#endif
		raise();
		activateWindow();
	}
}

void KopeteWindow::slotToggleAway()
{
	Kopete::Away *mAway = Kopete::Away::getInstance();
	if ( mAway->globalAway() )
	{
		Kopete::AccountManager::self()->setAvailableAll();
	}
	else
	{
		QString awayReason = mAway->getMessage( 0 );
		slotGlobalAway();
	}
}

void KopeteWindow::initSystray()
{
	d->tray = KopeteSystemTray::systemTray( this );
#ifdef __GNUC__
#warning PORT ME
#endif
//	Kopete::UI::Global::setSysTrayWId( d->tray->winId() );

	QObject::connect( d->tray, SIGNAL( aboutToShowMenu( KMenu * ) ),
	                  this, SLOT( slotTrayAboutToShowMenu( KMenu * ) ) );
	QObject::connect( d->tray, SIGNAL( quitSelected() ), this, SLOT( slotQuit() ) );
}

KopeteWindow::~KopeteWindow()
{
	delete d;
}

bool KopeteWindow::eventFilter( QObject* target, QEvent* event )
{
    KToolBar *toolBar = dynamic_cast<KToolBar*>( target );
    QAction *resetAction = actionCollection()->action( "quicksearch_reset" );

    if ( toolBar && resetAction && resetAction->associatedWidgets().contains( toolBar ) )
    {

        if ( event->type() == QEvent::Hide )
        {
            resetAction->trigger();
            return true;
        }
        return KXmlGuiWindow::eventFilter( target, event );
    }

    return KXmlGuiWindow::eventFilter( target, event );
}

void KopeteWindow::loadOptions()
{
	KSharedConfig::Ptr config = KGlobal::config();

	toolBar("mainToolBar")->applySettings( config->group( "ToolBar Settings" ) );
	toolBar("quickSearchBar")->applySettings( config->group( "QuickSearchBar Settings" ) );

	applyMainWindowSettings( config->group( "General Options" ) );
        KConfigGroup cg( config, "General Options");
	QPoint pos = cg.readEntry("Position", QPoint());
	move(pos);

	QSize size = cg.readEntry("Geometry", QSize() );
	if(size.isEmpty()) // Default size
		resize( QSize(220, 350) );
	else
		resize(size);

	d->autoHide = Kopete::AppearanceSettings::self()->contactListAutoHide();
	d->autoHideTimeout = Kopete::AppearanceSettings::self()->contactListAutoHideTimeout();


	QString tmp = cg.readEntry("State", "Shown");
	if ( tmp == "Minimized" && Kopete::BehaviorSettings::self()->showSystemTray())
	{
		showMinimized();
	}
	else if ( tmp == "Hidden" && Kopete::BehaviorSettings::self()->showSystemTray())
	{
		hide();
	}
	else if ( !Kopete::BehaviorSettings::self()->startDocked() || !Kopete::BehaviorSettings::self()->showSystemTray() )
		show();

	d->menubarAction->setChecked( !menuBar()->isHidden() );
	d->statusbarAction->setChecked( !statusBar()->isHidden() );
}

void KopeteWindow::saveOptions()
{
        KConfigGroup cg( KGlobal::config(), "ToolBar Settings" );

	toolBar("mainToolBar")->saveSettings ( cg );
        cg.changeGroup( "QuickSearchBar Settings" );
	toolBar("quickSearchBar")->saveSettings( cg );

        cg.changeGroup( "General Options" );
	saveMainWindowSettings( cg );

	cg.writeEntry("Position", pos());
	cg.writeEntry("Geometry", size());

	if(isMinimized())
	{
		cg.writeEntry("State", "Minimized");
	}
	else if(isHidden())
	{
		cg.writeEntry("State", "Hidden");
	}
	else
	{
		cg.writeEntry("State", "Shown");
	}

	cg.sync();
}

void KopeteWindow::slotToggleShowOffliners()
{
	Kopete::AppearanceSettings::self()->setShowOfflineUsers ( d->actionShowOffliners->isChecked() );
	Kopete::AppearanceSettings::self()->writeConfig();
}

void KopeteWindow::slotToggleShowEmptyGroups()
{
	Kopete::AppearanceSettings::self()->setShowEmptyGroups ( d->actionShowEmptyGroups->isChecked() );
	Kopete::AppearanceSettings::self()->writeConfig();
}

void KopeteWindow::slotConfigChanged()
{
	if( isHidden() && !Kopete::BehaviorSettings::self()->showSystemTray()) // user disabled systray while kopete is hidden, show it!
		show();

	d->actionShowOffliners->setChecked( Kopete::AppearanceSettings::self()->showOfflineUsers() );
	d->actionShowEmptyGroups->setChecked( Kopete::AppearanceSettings::self()->showEmptyGroups() );
}

void KopeteWindow::slotContactListAppearanceChanged()
{
	d->autoHide = Kopete::AppearanceSettings::self()->contactListAutoHide();
	d->autoHideTimeout = Kopete::AppearanceSettings::self()->contactListAutoHideTimeout();

	startAutoHideTimer();
}

void KopeteWindow::slotConfNotifications()
{
	KNotifyConfigWidget::configure( this );
}

void KopeteWindow::slotConfGlobalKeys()
{
	KShortcutsDialog::configure( actionCollection() );
}

void KopeteWindow::slotConfToolbar()
{
        KConfigGroup cg( KGlobal::config(), "General Options");
	saveMainWindowSettings( cg );
	KEditToolBar *dlg = new KEditToolBar(factory());
	connect( dlg, SIGNAL(newToolbarConfig()), this, SLOT(slotUpdateToolbar()) );
	connect( dlg, SIGNAL(finished()) , dlg, SLOT(deleteLater()));
	dlg->show();
}

void KopeteWindow::slotUpdateToolbar()
{
	applyMainWindowSettings(KGlobal::config()->group( "General Options") );
}

void KopeteWindow::slotGlobalAway()
{
	Kopete::AccountManager::self()->setAwayAll( d->globalStatusMessageStored );
}

void KopeteWindow::slotGlobalBusy()
{
	Kopete::AccountManager::self()->setOnlineStatus(
			Kopete::OnlineStatusManager::Busy, d->globalStatusMessageStored );
}

void KopeteWindow::slotGlobalAvailable()
{
	Kopete::AccountManager::self()->setAvailableAll( d->globalStatusMessageStored );
}

void KopeteWindow::slotSetInvisibleAll()
{
	Kopete::AccountManager::self()->setOnlineStatus( Kopete::OnlineStatusManager::Invisible  );
}

void KopeteWindow::slotDisconnectAll()
{
	d->globalStatusMessage->setText( "" );
	d->globalStatusMessageStored = QString();
	Kopete::AccountManager::self()->disconnectAll();
}

bool KopeteWindow::queryClose()
{
	KopeteApplication *app = static_cast<KopeteApplication *>( kapp );
	if ( !app->sessionSaving()	// if we are just closing but not shutting down
		&& !app->isShuttingDown()
		&& Kopete::BehaviorSettings::self()->showSystemTray()
		&& !isHidden() )
		// I would make this a KMessageBox::queuedMessageBox but there doesn't seem to be don'tShowAgain support for those
		KMessageBox::information( this,
								  i18n( "<qt>Closing the main window will keep Kopete running in the "
								        "system tray. Use 'Quit' from the 'File' menu to quit the application.</qt>" ),
								  i18n( "Docking in System Tray" ), "hideOnCloseInfo" );
// 	else	// we are shutting down either user initiated or session management
// 		Kopete::PluginManager::self()->shutdown();

	return true;
}

bool KopeteWindow::queryExit()
{
	KopeteApplication *app = static_cast<KopeteApplication *>( kapp );
 	if ( app->sessionSaving()
		|| app->isShuttingDown() /* only set if KopeteApplication::quitKopete() or
									KopeteApplication::commitData() called */
		|| !Kopete::BehaviorSettings::self()->showSystemTray() /* also close if our tray icon is hidden! */
		|| isHidden() )
	{
		kDebug( 14000 ) << " shutting down plugin manager";
		Kopete::PluginManager::self()->shutdown();
		return true;
	}
	else
		return false;
}

void KopeteWindow::closeEvent( QCloseEvent *e )
{
	// if there's a system tray applet and we are not shutting down then just do what needs to be done if a
	// window is closed.
	KopeteApplication *app = static_cast<KopeteApplication *>( kapp );
	if ( Kopete::BehaviorSettings::self()->showSystemTray() && !app->isShuttingDown() && !app->sessionSaving() ) {
		// BEGIN of code borrowed from KMainWindow::closeEvent
		// Save settings if auto-save is enabled, and settings have changed
		if ( settingsDirty() && autoSaveSettings() )
			saveAutoSaveSettings();

		if ( queryClose() ) {
			e->accept();
		}
		// END of code borrowed from KMainWindow::closeEvent
		kDebug( 14000 ) << "just closing because we have a system tray icon";
	}
	else
	{
		kDebug( 14000 ) << "delegating to KXmlGuiWindow::closeEvent()";
		KXmlGuiWindow::closeEvent( e );
	}
}

void KopeteWindow::slotQuit()
{
	saveOptions();
	KopeteApplication *app = static_cast<KopeteApplication *>( kapp );
	app->quitKopete();
}

void KopeteWindow::slotPluginLoaded( Kopete::Plugin *  p  )
{
	guiFactory()->addClient(p);
}

void KopeteWindow::slotAllPluginsLoaded()
{
//	actionConnect->setEnabled(true);
	d->actionDisconnect->setEnabled(true);
}

void KopeteWindow::slotIdentityRegistered( Kopete::Identity *identity )
{
	if ( !identity )
		return;

	connect( identity, SIGNAL(onlineStatusChanged( Kopete::Identity *, 
												   const Kopete::OnlineStatus::StatusType, const Kopete::OnlineStatus::StatusType) ),
			this, SLOT( slotIdentityStatusIconChanged( Kopete::Identity * ) ) );
	connect( identity, SIGNAL(identityChanged( Kopete::Identity * )),<commit_msg>Fix signal sifnature<commit_after>/*
    kopetewindow.cpp  -  Kopete Main Window

    Copyright (c) 2001-2002 by <NAME> <<EMAIL>>
    Copyright (c) 2001-2002 by <NAME>            <metz AT gehn.net>
    Copyright (c) 2002-2003 by <NAME>       <<EMAIL>>
    Copyright (c) 2002-2005 by <NAME>        <ogoffart at kde.org>
    Copyright (c) 2005-2006 by <NAME>        <<EMAIL>>

    Kopete    (c) 2002-2005 by the Kopete developers  <<EMAIL>>

    *************************************************************************
    *                                                                       *
    * 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.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "kopetewindow.h"

#include <QCursor>
#include <QLayout>

#include <QTimer>
#include <QPixmap>
#include <QCloseEvent>
#include <QMouseEvent>
#include <QEvent>
#include <QLabel>
#include <QShowEvent>
#include <QLineEdit>
#include <QSignalMapper>

#include <khbox.h>
#include <kaction.h>
#include <kactioncollection.h>
#include <ktoggleaction.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kglobalaccel.h>
#include <klocale.h>
#include <kicon.h>
#include <kiconloader.h>
#include <kmessagebox.h>
#include <knotifyconfigwidget.h>
#include <kmenu.h>
#include <kshortcutsdialog.h>
#include <kedittoolbar.h>
#include <kmenubar.h>
#include <kstatusbar.h>
#include <kwindowsystem.h>
#include <kdeversion.h>
#include <kinputdialog.h>
#include <kplugininfo.h>
#include <ksqueezedtextlabel.h>
#include <kstringhandler.h>
#include <kurl.h>
#include <kxmlguifactory.h>
#include <ktoolbar.h>
#include <kdialog.h>
#include <kstandardaction.h>

#include "addcontactpage.h"
#include "addressbooklinkwidget.h"
#include "ui_groupkabcselectorwidget.h"
#include "kabcexport.h"
#include "kopeteappearancesettings.h"
#include "kopeteapplication.h"
#include "kopeteaccount.h"
#include "kopeteaway.h"
#include "kopeteaccountmanager.h"
#include "kopeteidentitystatusbaricon.h"
#include "kopetebehaviorsettings.h"
#include "kopetecontact.h"
#include "kopetecontactlist.h"
#include "kopetecontactlistview.h"
#include "kopetegroup.h"
#include "kopeteidentity.h"
#include "kopeteidentitymanager.h"
#include "kopetelistviewsearchline.h"
#include "kopetechatsessionmanager.h"
#include "kopetepluginmanager.h"
#include "kopeteprotocol.h"
#include "kopetestdaction.h"
#include "kopeteawayaction.h"
#include "kopeteuiglobal.h"
#include "systemtray.h"
#include "kopeteonlinestatusmanager.h"
#include "identitystatuswidget.h"

//BEGIN GlobalStatusMessageIconLabel
GlobalStatusMessageIconLabel::GlobalStatusMessageIconLabel(QWidget *parent)
 : QLabel(parent)
{
}

void GlobalStatusMessageIconLabel::mouseReleaseEvent( QMouseEvent *event )
{
      if( event->button() == Qt::LeftButton || event->button() == Qt::RightButton )
      {
              emit iconClicked( event->globalPos() );
              event->accept();
      }
}
//END GlobalStatusMessageIconLabel

class KopeteWindow::Private
{
public:
	Private()
	 : contactlist(0), identitywidget(0), actionAddContact(0), actionDisconnect(0), actionExportContacts(0),
	actionAwayMenu(0), actionDockMenu(0), selectAway(0), selectBusy(0), actionSetAvailable(0),
	actionSetInvisible(0), actionPrefs(0), actionQuit(0), actionSave(0), menubarAction(0),
	statusbarAction(0), actionShowOffliners(0), actionShowEmptyGroups(0), docked(0), 
	deskRight(0), statusBarWidget(0), tray(0), hidden(false), autoHide(false),
	autoHideTimeout(0), autoHideTimer(0), addContactMapper(0), 
	globalStatusMessage(0), globalStatusMessageMenu(0), newMessageEdit(0)
	{}

	~Private()
	{}

	KopeteContactListView *contactlist;

	IdentityStatusWidget *identitywidget;

	// Some Actions
	KActionMenu *actionAddContact;

	KAction *actionDisconnect;
	KAction *actionExportContacts;

	KActionMenu *actionAwayMenu;
	KActionMenu *actionDockMenu;
	KAction *selectAway;
	KAction *selectBusy;
	KAction *actionSetAvailable;
	KAction *actionSetInvisible;


	KAction *actionPrefs;
	KAction *actionQuit;
	KAction *actionSave;
	KToggleAction *menubarAction;
	KToggleAction *statusbarAction;
	KToggleAction *actionShowOffliners;
	KToggleAction *actionShowEmptyGroups;

	int docked;
	int deskRight;
	QPoint position;
	KHBox *statusBarWidget;
	KopeteSystemTray *tray;
	bool hidden;
	bool autoHide;
	unsigned int autoHideTimeout;
	QTimer *autoHideTimer;
	QSignalMapper *addContactMapper;

	QHash<const Kopete::Identity*, KopeteIdentityStatusBarIcon*> identityStatusBarIcons;
	KSqueezedTextLabel *globalStatusMessage;
	KMenu *globalStatusMessageMenu;
	QLineEdit *newMessageEdit;
	QString globalStatusMessageStored;
};

/* KMainWindow is very broken from our point of view - it deref()'s the app
 * when the last visible KMainWindow is destroyed. But when our main window is
 * hidden when it's in the tray,closing the last chatwindow would cause the app
 * to quit. - Richard
 *
 * Fortunately KMainWindow checks queryExit before deref()ing the Kapplication.
 * KopeteWindow reimplements queryExit() and only returns true if it is shutting down
 * (either because the user quit Kopete, or the session manager did).
 *
 * KopeteWindow and ChatWindows are closed by session management.
 * App shutdown is not performed by the KopeteWindow but by KopeteApplication:
 * 1) user quit - KopeteWindow::slotQuit() was called, calls KopeteApplication::quitKopete(),
 *                which closes all chatwindows and the KopeteWindow.  The last window to close
 *                shuts down the PluginManager in queryExit().  When the PluginManager has completed its
 *                shutdown, the app is finally deref()ed, and the contactlist and accountmanager
 *                are saved.
 *                and calling KApplication::quit()
 * 2) session   - KopeteWindow and all chatwindows are closed by KApplication session management.
 *     quit        Then the shutdown proceeds as above.
 *
 * queryClose() is honoured so group chats and chats receiving recent messages can interrupt
 * (session) quit.
 */

KopeteWindow::KopeteWindow( QWidget *parent, const char *name )
: KXmlGuiWindow( parent, Qt::WType_TopLevel ), d(new Private)
{
	setObjectName( name );
	setAttribute (Qt::WA_DeleteOnClose, false);
	setAttribute (Qt::WA_QuitOnClose, false);
	// Applications should ensure that their StatusBar exists before calling createGUI()
	// so that the StatusBar is always correctly positioned when KDE is configured to use
	// a MacOS-style MenuBar.
	// This fixes a "statusbar drawn over the top of the toolbar" bug
	// e.g. it can happen when you switch desktops on Kopete startup
	d->statusBarWidget = new KHBox(statusBar());
	d->statusBarWidget->setObjectName( "m_statusBarWidget" );
	d->statusBarWidget->setMargin( 2 );
	d->statusBarWidget->setSpacing( 1 );
	statusBar()->addPermanentWidget(d->statusBarWidget, 0);
	KHBox *statusBarMessage = new KHBox(statusBar());
	d->statusBarWidget->setMargin( 2 );
	d->statusBarWidget->setSpacing( 1 );

	GlobalStatusMessageIconLabel *label = new GlobalStatusMessageIconLabel( statusBarMessage );
	label->setObjectName( QLatin1String("statusmsglabel") );
	label->setFixedSize( 16, 16 );
	label->setPixmap( SmallIcon( "kopetestatusmessage" ) );
	connect(label, SIGNAL(iconClicked( const QPoint& )),
		this, SLOT(slotGlobalStatusMessageIconClicked( const QPoint& )));
	label->setToolTip( i18n( "Global status message" ) );
	d->globalStatusMessage = new KSqueezedTextLabel( statusBarMessage );
	statusBar()->addWidget(statusBarMessage, 1);

	d->autoHideTimer = new QTimer( this );

	// --------------------------------------------------------------------------------
	initView();
	initActions();
	d->contactlist->initActions(actionCollection());
	initSystray();
	// --------------------------------------------------------------------------------

	// Trap all loaded plugins, so we can add their status bar icons accordingly , also used to add XMLGUIClient
	connect( Kopete::PluginManager::self(), SIGNAL( pluginLoaded( Kopete::Plugin * ) ),
		this, SLOT( slotPluginLoaded( Kopete::Plugin * ) ) );
	connect( Kopete::PluginManager::self(), SIGNAL( allPluginsLoaded() ),
		this, SLOT( slotAllPluginsLoaded() ));

	// Connect all identity signals
	connect( Kopete::IdentityManager::self(), SIGNAL(identityRegistered(Kopete::Identity*)),
		this, SLOT(slotIdentityRegistered(Kopete::Identity*)));
	connect( Kopete::IdentityManager::self(), SIGNAL(identityUnregistered(const Kopete::Identity*)),
		this, SLOT(slotIdentityUnregistered(const Kopete::Identity*)));
	
	//Connect the appropriate account signals
	/* Please note that I tried to put this in the slotAllPluginsLoaded() function
	 * but it seemed to break the account icons in the statusbar --Matt */
	connect( Kopete::AccountManager::self(), SIGNAL(accountRegistered(Kopete::Account*)),
		this, SLOT(slotAccountRegistered(Kopete::Account*)));
	connect( Kopete::AccountManager::self(), SIGNAL(accountUnregistered(const Kopete::Account*)),
		this, SLOT(slotAccountUnregistered(const Kopete::Account*)));

	connect( d->autoHideTimer, SIGNAL( timeout() ), this, SLOT( slotAutoHide() ) );
	connect( Kopete::AppearanceSettings::self(), SIGNAL( contactListAppearanceChanged() ),
		this, SLOT( slotContactListAppearanceChanged() ) );
	createGUI ( QLatin1String("kopeteui.rc") );

	// call this _after_ createGUI(), otherwise menubar is not set up correctly
	loadOptions();

	// If some plugins are already loaded, merge the GUI
	Kopete::PluginList plugins = Kopete::PluginManager::self()->loadedPlugins();
	foreach(Kopete::Plugin *plug, plugins)
		slotPluginLoaded( plug );

	// If some identity already registered, build the status icon
	Kopete::Identity::List identityList = Kopete::IdentityManager::self()->identities();
	foreach(Kopete::Identity *i, identityList)
		slotIdentityRegistered( i );

	// If some account already loaded, build the status icon
	QList<Kopete::Account *> accountList = Kopete::AccountManager::self()->accounts();
	foreach(Kopete::Account *a, accountList)
		slotAccountRegistered( a );

    //install an event filter for the quick search toolbar so we can
    //catch the hide events
    toolBar( "quickSearchBar" )->installEventFilter( this );
    //it does not make sense to have a toolbar that does use the half sceen...
    toolBar( "mainToolBar" )->setToolButtonStyle( Qt::ToolButtonIconOnly );
}

void KopeteWindow::initView()
{
	QWidget *w = new QWidget(this);
	QVBoxLayout *l = new QVBoxLayout(w);
	d->contactlist = new KopeteContactListView(w);
	l->addWidget(d->contactlist);
	l->setSpacing( 0 );
	l->setContentsMargins(0,0,0,0);
	d->identitywidget = new IdentityStatusWidget(0, w);
	d->identitywidget->setSizePolicy( QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum) ); 
	d->identitywidget->setVisible( false );
	l->addWidget(d->identitywidget);

	setCentralWidget(w);
}

void KopeteWindow::initActions()
{
	// this action menu contains one action per account and is updated when accounts are registered/unregistered
	d->actionAddContact = new KActionMenu( KIcon("add-user"), i18n( "&Add Contact" ), this );
	actionCollection()->addAction( "AddContact", d->actionAddContact );
	d->actionAddContact->setDelayed( false );
	// this signal mapper is needed to call slotAddContact with the correct arguments
	d->addContactMapper = new QSignalMapper( this );
	connect( d->addContactMapper, SIGNAL( mapped( const QString & ) ),
		 this, SLOT( slotAddContactDialogInternal( const QString & ) ) );

	d->actionDisconnect = new KAction( KIcon("connect-no"), i18n( "Offline" ), this );
        actionCollection()->addAction( "DisconnectAll", d->actionDisconnect );
	connect( d->actionDisconnect, SIGNAL( triggered(bool) ), this, SLOT( slotDisconnectAll() ) );
	d->actionDisconnect->setEnabled(false);

	d->actionExportContacts = new KAction( i18n( "&Export Contacts..." ), this );
        actionCollection()->addAction( "ExportContacts", d->actionExportContacts );
	connect( d->actionExportContacts, SIGNAL( triggered(bool) ), this, SLOT( showExportDialog() ) );

	d->selectAway = new KAction( KIcon("kopeteaway"), i18n("&Away"), this );
        actionCollection()->addAction( "SetAwayAll", d->selectAway );
	connect( d->selectAway, SIGNAL( triggered(bool) ), this, SLOT( slotGlobalAway() ) );

	d->selectBusy = new KAction( KIcon("kopeteaway"), i18n("&Busy"), this );
        actionCollection()->addAction( "SetBusyAll", d->selectBusy );
	connect( d->selectBusy, SIGNAL( triggered(bool) ), this, SLOT( slotGlobalBusy() ) );


	d->actionSetInvisible = new KAction( KIcon("kopeteavailable"), i18n( "&Invisible" ), this );
        actionCollection()->addAction( "SetInvisibleAll", d->actionSetInvisible );
	connect( d->actionSetInvisible, SIGNAL( triggered(bool) ), this, SLOT( slotSetInvisibleAll() ) );

	d->actionSetAvailable = new KAction( KIcon("kopeteavailable"), i18n("&Online"), this );
        actionCollection()->addAction( "SetAvailableAll", d->actionSetAvailable );
	connect( d->actionSetAvailable, SIGNAL( triggered(bool) ), this, SLOT( slotGlobalAvailable() ) );

	d->actionAwayMenu = new KActionMenu( KIcon("kopeteavailable"), i18n("&Set Status"),
                                             this );
        actionCollection()->addAction( "Status", d->actionAwayMenu );
	d->actionAwayMenu->setDelayed( false );
	d->actionAwayMenu->addAction(d->actionSetAvailable);
	d->actionAwayMenu->addAction(d->selectAway);
	d->actionAwayMenu->addAction(d->selectBusy);
	d->actionAwayMenu->addAction(d->actionSetInvisible);
	d->actionAwayMenu->addAction(d->actionDisconnect);

	d->actionPrefs = KopeteStdAction::preferences( actionCollection(), "settings_prefs" );

	KStandardAction::quit(this, SLOT(slotQuit()), actionCollection());

	setStandardToolBarMenuEnabled(true);
	d->menubarAction = KStandardAction::showMenubar(menuBar(), SLOT(setVisible(bool)), actionCollection() );
        actionCollection()->addAction( "settings_showmenubar", d->menubarAction );
	d->statusbarAction = KStandardAction::showStatusbar(statusBar(), SLOT(setVisible(bool)), actionCollection() );
        actionCollection()->addAction( "settings_showstatusbar", d->statusbarAction );

	KAction* act = KStandardAction::keyBindings( guiFactory(), SLOT( configureShortcuts() ), actionCollection() );
        actionCollection()->addAction( "settings_keys", act );

	KAction *configureGlobalShortcutsAction = new KAction( KIcon("configure-shortcuts"), i18n( "Configure &Global Shortcuts..." ), this );
        actionCollection()->addAction( "settings_global", configureGlobalShortcutsAction );
	connect( configureGlobalShortcutsAction, SIGNAL( triggered(bool) ), this, SLOT( slotConfGlobalKeys() ) );

	KStandardAction::configureToolbars( this, SLOT(slotConfToolbar()), actionCollection() );
	act = KStandardAction::configureNotifications(this, SLOT(slotConfNotifications()), actionCollection() );
        actionCollection()->addAction( "settings_notifications", act );

	d->actionShowOffliners = new KToggleAction( KIcon("show-offliners"), i18n( "Show Offline &Users" ), this );
        actionCollection()->addAction( "settings_show_offliners", d->actionShowOffliners );
	d->actionShowOffliners->setShortcut( KShortcut(Qt::CTRL + Qt::Key_U) );
	connect( d->actionShowOffliners, SIGNAL( triggered(bool) ), this, SLOT( slotToggleShowOffliners() ) );

	d->actionShowEmptyGroups = new KToggleAction( KIcon("folder-grey"), i18n( "Show Empty &Groups" ), this );
        actionCollection()->addAction( "settings_show_empty_groups", d->actionShowEmptyGroups );
	d->actionShowEmptyGroups->setShortcut( KShortcut(Qt::CTRL + Qt::Key_G) );
	connect( d->actionShowEmptyGroups, SIGNAL( triggered(bool) ), this, SLOT( slotToggleShowEmptyGroups() ) );

	d->actionShowOffliners->setCheckedState( KGuiItem( i18n("Hide Offline &Users") ) );
	d->actionShowEmptyGroups->setCheckedState( KGuiItem( i18n("Hide Empty &Groups") ) );

	// quick search bar
	QLabel *searchLabel = new QLabel( i18n("Se&arch:"), 0 );
	searchLabel->setObjectName( QLatin1String("kde toolbar widget") );
	QWidget *searchBar = new Kopete::UI::ListView::SearchLine( 0, d->contactlist );
	searchLabel->setBuddy( searchBar );
	KAction *quickSearch = new KAction( i18n("Quick Search Bar"), this );
        actionCollection()->addAction( "quicksearch_bar", quickSearch );
	quickSearch->setDefaultWidget( searchBar );
	KAction *searchLabelAction = new KAction( i18n("Search:"), this );
        actionCollection()->addAction( "quicksearch_label", searchLabelAction );
	searchLabelAction->setDefaultWidget( searchLabel );

	// KActionMenu for selecting the global status message
	KActionMenu * setStatusMenu = new KActionMenu( KIcon("kopeteeditstatusmessage"), i18n( "Set Status Message" ), this );
        actionCollection()->addAction( "SetStatusMessage", setStatusMenu );
	setStatusMenu->setDelayed( false );
	connect( setStatusMenu->menu(), SIGNAL( aboutToShow() ), SLOT(slotBuildStatusMessageMenu() ) );

	// sync actions, config and prefs-dialog
	connect ( Kopete::AppearanceSettings::self(), SIGNAL(configChanged()), this, SLOT(slotConfigChanged()) );
	slotConfigChanged();

	// Global actions
	KAction *globalReadMessage = new KAction( i18n("Read Message"), this );
        actionCollection()->addAction( "ReadMessage",  globalReadMessage );
	connect( globalReadMessage, SIGNAL( triggered(bool) ), Kopete::ChatSessionManager::self(), SLOT( slotReadMessage() ) );
	globalReadMessage->setGlobalShortcut( KShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_I) );
	globalReadMessage->setWhatsThis( i18n("Read the next pending message") );

	KAction *globalShowContactList = new KAction( i18n("Show/Hide Contact List"), this );
        actionCollection()->addAction( "ShowContactList", globalShowContactList );
	connect( globalShowContactList, SIGNAL( triggered(bool) ), this, SLOT( slotShowHide() ) );
	globalShowContactList->setGlobalShortcut( KShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_S) );
	globalShowContactList->setWhatsThis( i18n("Show or hide the contact list") );

	KAction *globalSetAway = new KAction( i18n("Set Away/Back"), this );
        actionCollection()->addAction( "Set_Away_Back",  globalSetAway );
	connect( globalSetAway, SIGNAL( triggered(bool) ), this, SLOT( slotToggleAway() ) );
	globalSetAway->setGlobalShortcut( KShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_W) );

#ifdef __GNUC__
#warning port me - it is probably safe to just remove this line as *global* shortcut setttings
#warning are now loaded automatically by default.
#endif
	//KGlobalAccel::self()->readSettings();
}

void KopeteWindow::slotShowHide()
{
	if(isActiveWindow())
	{
		d->autoHideTimer->stop(); //no timeouts if active
		hide();
	}
	else
	{
		show();
#ifdef Q_WS_X11
		//raise() and show() should normaly deIconify the window. but it doesn't do here due
		// to a bug in QT or in KDE  (qt3.1.x or KDE 3.1.x) then, i have to call KWin's method
		if(isMinimized())
			KWindowSystem::unminimizeWindow(winId());

		if(!KWindowSystem::windowInfo(winId(),NET::WMDesktop).onAllDesktops())
			KWindowSystem::setOnDesktop(winId(), KWindowSystem::currentDesktop());
#endif
		raise();
		activateWindow();
	}
}

void KopeteWindow::slotToggleAway()
{
	Kopete::Away *mAway = Kopete::Away::getInstance();
	if ( mAway->globalAway() )
	{
		Kopete::AccountManager::self()->setAvailableAll();
	}
	else
	{
		QString awayReason = mAway->getMessage( 0 );
		slotGlobalAway();
	}
}

void KopeteWindow::initSystray()
{
	d->tray = KopeteSystemTray::systemTray( this );
#ifdef __GNUC__
#warning PORT ME
#endif
//	Kopete::UI::Global::setSysTrayWId( d->tray->winId() );

	QObject::connect( d->tray, SIGNAL( aboutToShowMenu( KMenu * ) ),
	                  this, SLOT( slotTrayAboutToShowMenu( KMenu * ) ) );
	QObject::connect( d->tray, SIGNAL( quitSelected() ), this, SLOT( slotQuit() ) );
}

KopeteWindow::~KopeteWindow()
{
	delete d;
}

bool KopeteWindow::eventFilter( QObject* target, QEvent* event )
{
    KToolBar *toolBar = dynamic_cast<KToolBar*>( target );
    QAction *resetAction = actionCollection()->action( "quicksearch_reset" );

    if ( toolBar && resetAction && resetAction->associatedWidgets().contains( toolBar ) )
    {

        if ( event->type() == QEvent::Hide )
        {
            resetAction->trigger();
            return true;
        }
        return KXmlGuiWindow::eventFilter( target, event );
    }

    return KXmlGuiWindow::eventFilter( target, event );
}

void KopeteWindow::loadOptions()
{
	KSharedConfig::Ptr config = KGlobal::config();

	toolBar("mainToolBar")->applySettings( config->group( "ToolBar Settings" ) );
	toolBar("quickSearchBar")->applySettings( config->group( "QuickSearchBar Settings" ) );

	applyMainWindowSettings( config->group( "General Options" ) );
        KConfigGroup cg( config, "General Options");
	QPoint pos = cg.readEntry("Position", QPoint());
	move(pos);

	QSize size = cg.readEntry("Geometry", QSize() );
	if(size.isEmpty()) // Default size
		resize( QSize(220, 350) );
	else
		resize(size);

	d->autoHide = Kopete::AppearanceSettings::self()->contactListAutoHide();
	d->autoHideTimeout = Kopete::AppearanceSettings::self()->contactListAutoHideTimeout();


	QString tmp = cg.readEntry("State", "Shown");
	if ( tmp == "Minimized" && Kopete::BehaviorSettings::self()->showSystemTray())
	{
		showMinimized();
	}
	else if ( tmp == "Hidden" && Kopete::BehaviorSettings::self()->showSystemTray())
	{
		hide();
	}
	else if ( !Kopete::BehaviorSettings::self()->startDocked() || !Kopete::BehaviorSettings::self()->showSystemTray() )
		show();

	d->menubarAction->setChecked( !menuBar()->isHidden() );
	d->statusbarAction->setChecked( !statusBar()->isHidden() );
}

void KopeteWindow::saveOptions()
{
        KConfigGroup cg( KGlobal::config(), "ToolBar Settings" );

	toolBar("mainToolBar")->saveSettings ( cg );
        cg.changeGroup( "QuickSearchBar Settings" );
	toolBar("quickSearchBar")->saveSettings( cg );

        cg.changeGroup( "General Options" );
	saveMainWindowSettings( cg );

	cg.writeEntry("Position", pos());
	cg.writeEntry("Geometry", size());

	if(isMinimized())
	{
		cg.writeEntry("State", "Minimized");
	}
	else if(isHidden())
	{
		cg.writeEntry("State", "Hidden");
	}
	else
	{
		cg.writeEntry("State", "Shown");
	}

	cg.sync();
}

void KopeteWindow::slotToggleShowOffliners()
{
	Kopete::AppearanceSettings::self()->setShowOfflineUsers ( d->actionShowOffliners->isChecked() );
	Kopete::AppearanceSettings::self()->writeConfig();
}

void KopeteWindow::slotToggleShowEmptyGroups()
{
	Kopete::AppearanceSettings::self()->setShowEmptyGroups ( d->actionShowEmptyGroups->isChecked() );
	Kopete::AppearanceSettings::self()->writeConfig();
}

void KopeteWindow::slotConfigChanged()
{
	if( isHidden() && !Kopete::BehaviorSettings::self()->showSystemTray()) // user disabled systray while kopete is hidden, show it!
		show();

	d->actionShowOffliners->setChecked( Kopete::AppearanceSettings::self()->showOfflineUsers() );
	d->actionShowEmptyGroups->setChecked( Kopete::AppearanceSettings::self()->showEmptyGroups() );
}

void KopeteWindow::slotContactListAppearanceChanged()
{
	d->autoHide = Kopete::AppearanceSettings::self()->contactListAutoHide();
	d->autoHideTimeout = Kopete::AppearanceSettings::self()->contactListAutoHideTimeout();

	startAutoHideTimer();
}

void KopeteWindow::slotConfNotifications()
{
	KNotifyConfigWidget::configure( this );
}

void KopeteWindow::slotConfGlobalKeys()
{
	KShortcutsDialog::configure( actionCollection() );
}

void KopeteWindow::slotConfToolbar()
{
        KConfigGroup cg( KGlobal::config(), "General Options");
	saveMainWindowSettings( cg );
	KEditToolBar *dlg = new KEditToolBar(factory());
	connect( dlg, SIGNAL(newToolbarConfig()), this, SLOT(slotUpdateToolbar()) );
	connect( dlg, SIGNAL(finished()) , dlg, SLOT(deleteLater()));
	dlg->show();
}

void KopeteWindow::slotUpdateToolbar()
{
	applyMainWindowSettings(KGlobal::config()->group( "General Options") );
}

void KopeteWindow::slotGlobalAway()
{
	Kopete::AccountManager::self()->setAwayAll( d->globalStatusMessageStored );
}

void KopeteWindow::slotGlobalBusy()
{
	Kopete::AccountManager::self()->setOnlineStatus(
			Kopete::OnlineStatusManager::Busy, d->globalStatusMessageStored );
}

void KopeteWindow::slotGlobalAvailable()
{
	Kopete::AccountManager::self()->setAvailableAll( d->globalStatusMessageStored );
}

void KopeteWindow::slotSetInvisibleAll()
{
	Kopete::AccountManager::self()->setOnlineStatus( Kopete::OnlineStatusManager::Invisible  );
}

void KopeteWindow::slotDisconnectAll()
{
	d->globalStatusMessage->setText( "" );
	d->globalStatusMessageStored = QString();
	Kopete::AccountManager::self()->disconnectAll();
}

bool KopeteWindow::queryClose()
{
	KopeteApplication *app = static_cast<KopeteApplication *>( kapp );
	if ( !app->sessionSaving()	// if we are just closing but not shutting down
		&& !app->isShuttingDown()
		&& Kopete::BehaviorSettings::self()->showSystemTray()
		&& !isHidden() )
		// I would make this a KMessageBox::queuedMessageBox but there doesn't seem to be don'tShowAgain support for those
		KMessageBox::information( this,
								  i18n( "<qt>Closing the main window will keep Kopete running in the "
								        "system tray. Use 'Quit' from the 'File' menu to quit the application.</qt>" ),
								  i18n( "Docking in System Tray" ), "hideOnCloseInfo" );
// 	else	// we are shutting down either user initiated or session management
// 		Kopete::PluginManager::self()->shutdown();

	return true;
}

bool KopeteWindow::queryExit()
{
	KopeteApplication *app = static_cast<KopeteApplication *>( kapp );
 	if ( app->sessionSaving()
		|| app->isShuttingDown() /* only set if KopeteApplication::quitKopete() or
									KopeteApplication::commitData() called */
		|| !Kopete::BehaviorSettings::self()->showSystemTray() /* also close if our tray icon is hidden! */
		|| isHidden() )
	{
		kDebug( 14000 ) << " shutting down plugin manager";
		Kopete::PluginManager::self()->shutdown();
		return true;
	}
	else
		return false;
}

void KopeteWindow::closeEvent( QCloseEvent *e )
{
	// if there's a system tray applet and we are not shutting down then just do what needs to be done if a
	// window is closed.
	KopeteApplication *app = static_cast<KopeteApplication *>( kapp );
	if ( Kopete::BehaviorSettings::self()->showSystemTray() && !app->isShuttingDown() && !app->sessionSaving() ) {
		// BEGIN of code borrowed from KMainWindow::closeEvent
		// Save settings if auto-save is enabled, and settings have changed
		if ( settingsDirty() && autoSaveSettings() )
			saveAutoSaveSettings();

		if ( queryClose() ) {
			e->accept();
		}
		// END of code borrowed from KMainWindow::closeEvent
		kDebug( 14000 ) << "just closing because we have a system tray icon";
	}
	else
	{
		kDebug( 14000 ) << "delegating to KXmlGuiWindow::closeEvent()";
		KXmlGuiWindow::closeEvent( e );
	}
}

void KopeteWindow::slotQuit()
{
	saveOptions();
	KopeteApplication *app = static_cast<KopeteApplication *>( kapp );
	app->quitKopete();
}

void KopeteWindow::slotPluginLoaded( Kopete::Plugin *  p  )
{
	guiFactory()->addClient(p);
}

void KopeteWindow::slotAllPluginsLoaded()
{
//	actionConnect->setEnabled(true);
	d->actionDisconnect->setEnabled(true);
}

void KopeteWindow::slotIdentityRegistered( Kopete::Identity *identity )
{
	if ( !identity )
		return;

	connect( identity, SIGNAL(onlineStatusChanged( Kopete::Identity *, 
												   Kopete::OnlineStatus::StatusType, Kopete::OnlineStatus::StatusType) ),
			this, SLOT( slotIdentityStatusIconChanged( Kopete::Identity * ) ) );
	connect( identity, SIGNAL(identityChanged( Kopete::Identity * )),
{'fraction_non_alphanumeric': 0.14882398459572782, 'fraction_numerical': 0.006406449639187317, 'mean_word_length': 5.149164545756335, 'pattern_counts': {'":': 0, '<': 141, '<?xml version=': 0, '>': 581, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6238570', 'n_tokens_mistral': 17972, 'n_tokens_neox': 17156, 'n_words': 3882}