/*
 * mainwin.cpp - the main window.  holds contactlist and buttons.
 * Copyright (C) 2001-2003  Justin Karneges, Michail Pishchagin
 *
 * 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 library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include"mainwin.h"

#include<qmessagebox.h>
#include<qiconset.h>
#include<qtooltip.h>
#include<qstyle.h>
#include<qapplication.h>
#include<qptrlist.h>
#include<qtimer.h>
#include<qobjectlist.h>
#include<qpainter.h>
#include<qsignalmapper.h>
#include<qstatusbar.h>
#include<qmenubar.h>
#include"im.h"
#include"common.h"
#include"showtextdlg.h"
#include"psicon.h"
#include"psiaccount.h"
#include"psitoolbar.h"
#include"ui_about.h"
#include"ui_tip.h"
#include"fancylabel.h"
#include"psitoolbar.h"
#include"psipopup.h"

#include"mainwin_p.h"

using namespace XMPP;

// deletes submenus in a popupmenu
void qpopupmenuclear(QPopupMenu *p)
{
	while(p->count()) {
		QMenuItem *item = p->findItem(p->idAt(0));
		QPopupMenu *popup = item->popup();
		p->removeItemAt(0);

		if(popup)
			delete popup;
	}
}

//----------------------------------------------------------------------------
// MainWin::Private
//----------------------------------------------------------------------------

class MainWin::Private
{
public:
	Private(PsiCon *, MainWin *);
	~Private();

	QVBoxLayout *vb_main;
	bool onTop, asTool;
	QPopupMenu *mainMenu, *statusMenu, *optionsMenu, *toolsMenu;
	int sbState;
	QString nickname;
	MTray *tray;
	QPopupMenu *trayMenu;
	QString statusTip;

	PopupAction *optionsButton, *statusButton;
	IconActionGroup *statusGroup;
	EventNotifierAction *eventNotifier;
	PsiCon *psi;
	MainWin *mainWin;

	QSignalMapper *statusMapper;

	Icon *nextAnim;
	int nextAmount;

	QMap<QAction *, int> statusActions;

	int lastStatus;
	QMenuBar *gm;

	QString infoString;

	void registerActions();
	IconAction *getAction( QString name );
};

MainWin::Private::Private(PsiCon *_psi, MainWin *_mainWin)
{
	psi = _psi;
	mainWin = _mainWin;

	statusGroup   = (IconActionGroup *)getAction("status_all");
	eventNotifier = (EventNotifierAction *)getAction("event_notifier");

	optionsButton = (PopupAction *)getAction("button_options");
	statusButton  = (PopupAction *)getAction("button_status");

	statusMapper = new QSignalMapper(mainWin, "statusMapper");
	mainWin->connect(statusMapper, SIGNAL(mapped(int)), mainWin, SLOT(activatedStatusAction(int)));
}

MainWin::Private::~Private()
{
}

void MainWin::Private::registerActions()
{
	struct {
		const char *name;
		int id;
	} statuslist[] = {
		{ "status_chat",      STATUS_CHAT      },
		{ "status_online",    STATUS_ONLINE    },
		{ "status_away",      STATUS_AWAY      },
		{ "status_xa",        STATUS_XA        },
		{ "status_dnd",       STATUS_DND       },
		{ "status_invisible", STATUS_INVISIBLE },
		{ "status_offline",   STATUS_OFFLINE   },
		{ "", 0 }
	};

	int i;
	QString aName;
	for ( i = 0; !(aName = QString(statuslist[i].name)).isEmpty(); i++ ) {
		IconAction *action = getAction( aName );
		connect (action, SIGNAL(activated()), statusMapper, SLOT(map()));

		statusMapper->setMapping(action, statuslist[i].id);
		statusActions[action] = statuslist[i].id;
	}

	// register all actions
	PsiActionList::ActionsType type = PsiActionList::ActionsType( PsiActionList::Actions_MainWin | PsiActionList::Actions_Common );
	ActionList actions = psi->actionList()->suitableActions( type );
	QStringList names = actions.actions();
	QStringList::Iterator it = names.begin();
	for ( ; it != names.end(); ++it ) {
		IconAction *action = actions.action( *it );
		if ( action )
			mainWin->registerAction( action );
	}
}

IconAction *MainWin::Private::getAction( QString name )
{
	PsiActionList::ActionsType type = PsiActionList::ActionsType( PsiActionList::Actions_MainWin | PsiActionList::Actions_Common );
	ActionList actions = psi->actionList()->suitableActions( type );
	IconAction *action = actions.action( name );

	if ( !action )
		qWarning("MainWin::Private::getAction(): action %s not found!", name.latin1());
	//else
	//	mainWin->registerAction( action );

	return action;
}

//----------------------------------------------------------------------------
// MainWin
//----------------------------------------------------------------------------

//#ifdef Q_WS_X11
//#define TOOLW_FLAGS WStyle_Customize
//#else
#define TOOLW_FLAGS 0
//#endif

MainWin::MainWin(bool _onTop, bool _asTool, PsiCon *psi, const char *name)
:AdvancedWidget<QMainWindow>(0, name, 0 | (_onTop ? WStyle_StaysOnTop: 0) | (_asTool ? WStyle_Tool | TOOLW_FLAGS : 0))
{
	d = new Private(psi, this);

	setIcon(is->status(STATUS_OFFLINE));

	d->onTop = _onTop;
	d->asTool = _asTool;

	// sbState:
	//   -1 : connect
	// >= 0 : STATUS_*
	d->sbState = STATUS_OFFLINE;
	d->lastStatus = -2;

	d->nextAmount = 0;
	d->nextAnim = 0;
	d->tray = 0;
	d->trayMenu = 0;
	d->statusTip = "";
	d->infoString = "";
	d->nickname = "";

	QWidget *center = new QWidget (this, "Central widget");
	setCentralWidget ( center );

	d->vb_main = new QVBoxLayout(center, 2);
	cvlist = new ContactView(center);
	d->vb_main->addWidget(cvlist, 1);
#ifdef Q_WS_MAC
	// If the space isn't there, MacOS draws an empty vertical scrollbar :(
	d->vb_main->addSpacing(1);
#endif

	d->statusMenu = new QPopupMenu(this);
	d->optionsMenu = new QPopupMenu(this);

	buildStatusMenu();
	buildOptionsMenu();
	connect(d->statusMenu, SIGNAL(aboutToShow()), SLOT(buildStatusMenu()));
	connect(d->optionsMenu, SIGNAL(aboutToShow()), SLOT(buildOptionsMenu()));

	d->optionsButton->setPopup( d->optionsMenu );
	d->statusButton->setPopup( d->statusMenu );

	X11WM_CLASS("main");

	connect(d->psi, SIGNAL(accountCountChanged()), SLOT(numAccountsChanged()));
	numAccountsChanged();

	updateCaption();

	d->registerActions();
	buildToolbars();

	decorateButton(STATUS_OFFLINE);

	// show tip of the day
	if ( option.showTips )
		actTipActivated();

#ifdef Q_WS_MAC
	// Create a global menubar
	d->gm = new QMenuBar(0);
#else
	// Create a menu for the current window
	d->gm = new QMenuBar(this);
#endif

	// Mac-only menus
#ifdef Q_WS_MAC
	QPopupMenu *mainMenu = new QPopupMenu(this);
	d->gm->insertItem(tr("Menu"), mainMenu);
	mainMenu->insertItem(tr("Preferences"), this, SIGNAL(doOptions()));
	mainMenu->insertItem(tr("Quit"), this, SLOT(try2tryCloseProgram()));
	d->getAction("help_about")->addTo(mainMenu);
	d->getAction("help_about_qt")->addTo(mainMenu);

	d->mainMenu = new QPopupMenu(this);
	d->gm->insertItem(tr("General"), d->mainMenu);
	connect(d->mainMenu, SIGNAL(aboutToShow()), SLOT(buildMainMenu()));
#else
	d->gm->insertItem(tr("General"), d->optionsMenu);
#endif

	d->gm->insertItem(tr("Status"), d->statusMenu);

	QPopupMenu *viewMenu = new QPopupMenu(this);
	d->gm->insertItem(tr("View"), viewMenu);
	d->getAction("show_offline")->addTo(viewMenu);
	d->getAction("show_away")->addTo(viewMenu);
	d->getAction("show_hidden")->addTo(viewMenu);
	d->getAction("show_agents")->addTo(viewMenu);
	d->getAction("show_self")->addTo(viewMenu);

	// Mac-only menus
#ifdef Q_WS_MAC
	d->toolsMenu = new QPopupMenu(this);
	d->gm->insertItem(tr("Tools"), d->toolsMenu);
	connect(d->toolsMenu, SIGNAL(aboutToShow()), SLOT(buildToolsMenu()));

	QPopupMenu *helpMenu = new QPopupMenu(this);
	d->gm->insertItem(tr("Help"), helpMenu);
	d->getAction("help_readme")->addTo (helpMenu);
	d->getAction("help_tip")->addTo (helpMenu);
	helpMenu->insertSeparator();
	d->getAction("help_online_help")->addTo (helpMenu);
	d->getAction("help_online_wiki")->addTo (helpMenu);
	d->getAction("help_online_home")->addTo (helpMenu);
	d->getAction("help_report_bug")->addTo (helpMenu);

	d->gm->show();
#else
	if (option.hideMenubar) 
		d->gm->hide();
	else 
		d->gm->show();
#endif
	
#if QT_VERSION >= 0x030300
	setWindowOpacity(double(option.rosterOpacity)/100);
#endif

	connect(qApp, SIGNAL(dockActivated()), SLOT(dockActivated()));
}
	

MainWin::~MainWin()
{
	PsiPopup::deleteAll();

	if (d->gm)
		delete d->gm;

	if(d->tray) {
		delete d->tray;
		d->tray = 0;
		delete d->trayMenu;
		d->trayMenu = 0;
	}

	//saveToolbarsPositions();
	// need to find some workaround to case, when you're logging off. in that case
	// toobars are all disabled, and when you start psi again you need to enable
	// your toolbars

	delete d;
}

void MainWin::registerAction( IconAction *action )
{
	char activated[] = SIGNAL( activated() );
	char toggled[]   = SIGNAL( toggled(bool) );
	char setOn[]     = SLOT( setOn(bool) );

	struct {
		const char *name;
		const char *signal;
		QObject *receiver;
		const char *slot;
	} actionlist[] = {
		{ "show_offline", toggled, cvlist, SLOT( setShowOffline(bool) ) },
		{ "show_away",    toggled, cvlist, SLOT( setShowAway(bool) ) },
		{ "show_hidden",  toggled, cvlist, SLOT( setShowHidden(bool) ) },
		{ "show_agents",  toggled, cvlist, SLOT( setShowAgents(bool) ) },
		{ "show_self",    toggled, cvlist, SLOT( setShowSelf(bool) ) },

		{ "button_options", activated, this, SIGNAL( doOptions() ) },

		{ "menu_disco",       SIGNAL( activated(PsiAccount *, int) ), this, SLOT( activatedAccOption(PsiAccount*, int) ) },
		{ "menu_add_contact", SIGNAL( activated(PsiAccount *, int) ), this, SLOT( activatedAccOption(PsiAccount*, int) ) },
		{ "menu_xml_console", SIGNAL( activated(PsiAccount *, int) ), this, SLOT( activatedAccOption(PsiAccount*, int) ) },

		{ "menu_new_message",    activated, this, SIGNAL( blankMessage() ) },
		{ "menu_join_groupchat", activated, this, SIGNAL( doGroupChat() ) },
		{ "menu_account_setup",  activated, this, SIGNAL( doManageAccounts() ) },
		{ "menu_options",        activated, this, SIGNAL( doOptions() ) },
		{ "menu_file_transfer",  activated, this, SIGNAL( doFileTransDlg() ) },
		{ "menu_toolbars",       activated, this, SIGNAL( doToolbars() ) },
		{ "menu_change_profile", activated, this, SIGNAL( changeProfile() ) },
		{ "menu_quit",           activated, this, SLOT( try2tryCloseProgram() ) },
		{ "menu_play_sounds",    toggled,   this, SLOT( actPlaySoundsActivated(bool) ) },

		{ "event_notifier", SIGNAL( clicked(int) ), this, SLOT( statusClicked(int) ) },
		{ "event_notifier", activated, this, SLOT( doRecvNextEvent() ) },

		{ "help_readme",      activated, this, SLOT( actReadmeActivated() ) },
		{ "help_tip",         activated, this, SLOT( actTipActivated() ) },
		{ "help_online_help", activated, this, SLOT( actOnlineHelpActivated() ) },
		{ "help_online_wiki", activated, this, SLOT( actOnlineWikiActivated() ) },
		{ "help_online_home", activated, this, SLOT( actOnlineHomeActivated() ) },
		{ "help_report_bug",  activated, this, SLOT( actBugReportActivated() ) },
		{ "help_about",       activated, this, SLOT( actAboutActivated() ) },
		{ "help_about_qt",    activated, this, SLOT( actAboutQtActivated() ) },

		{ "", 0, 0, 0 }
	};

	int i;
	QString aName;
	for ( i = 0; !(aName = QString(actionlist[i].name)).isEmpty(); i++ ) {
		if ( aName == action->name() ) {
			disconnect( action, actionlist[i].signal, actionlist[i].receiver, actionlist[i].slot ); // for safety
			connect( action, actionlist[i].signal, actionlist[i].receiver, actionlist[i].slot );

			// special cases
			if ( aName == "menu_play_sounds" )
				action->setOn( useSound );
			//else if ( aName == "foobar" )
			//	;
		}
	}

	struct {
		const char *name;
		QObject *sender;
		const char *signal;
		const char *slot;
	} reverseactionlist[] = {
		{ "show_away",    cvlist, SIGNAL( showAway(bool) ), setOn },
		{ "show_hidden",  cvlist, SIGNAL( showHidden(bool) ), setOn },
		{ "show_offline", cvlist, SIGNAL( showOffline(bool) ), setOn },
		{ "show_self",    cvlist, SIGNAL( showSelf(bool) ), setOn },
		{ "show_agents",  cvlist, SIGNAL( showAgents(bool) ), setOn },
		{ "", 0, 0, 0 }
	};

	for ( i = 0; !(aName = QString(reverseactionlist[i].name)).isEmpty(); i++ ) {
		if ( aName == action->name() ) {
			disconnect( reverseactionlist[i].sender, reverseactionlist[i].signal, action, reverseactionlist[i].slot ); // for safety
			connect( reverseactionlist[i].sender, reverseactionlist[i].signal, action, reverseactionlist[i].slot );

			action->setOn( true );
		}
	}
}

PsiCon *MainWin::psiCon() const
{
	return d->psi;
}

void MainWin::setWindowOpts(bool _onTop, bool _asTool)
{
	if(_onTop == d->onTop && _asTool == d->asTool)
		return;

	d->onTop = _onTop;
	d->asTool = _asTool;

	WFlags flags = 0;
	if(d->onTop)
		flags |= WStyle_StaysOnTop;
	if(d->asTool)
		flags |= WStyle_Tool | TOOLW_FLAGS;

	QPoint p = pos();
	reparent(parentWidget(), flags, p, FALSE);
	move(p);
	show();
}

void MainWin::setUseDock(bool use)
{
	if(use == false || (d->tray && option.isWMDock != d->tray->isWMDock())) {
		if(d->tray) {
			delete d->tray;
			d->tray = 0;
			delete d->trayMenu;
			d->trayMenu = 0;
		}

		if (use == false)
			return;
	}

	if(d->tray)
		return;

	d->trayMenu = new QPopupMenu;
	connect(d->trayMenu, SIGNAL(aboutToShow()), SLOT(buildTrayMenu()));

	d->tray = new MTray("Psi", d->trayMenu);
	d->tray->setIcon( is->statusPtr( STATUS_OFFLINE ));
	d->tray->setToolTip(PROG_NAME);
	connect(d->tray, SIGNAL(clicked(const QPoint &, int)), SLOT(trayClicked(const QPoint &, int)));
	connect(d->tray, SIGNAL(doubleClicked(const QPoint &)), SLOT(trayDoubleClicked()));
	connect(d->tray, SIGNAL(closed()), SLOT(dockActivated()));
	connect(qApp, SIGNAL(trayOwnerDied()), SLOT(dockActivated()));

	updateReadNext(d->nextAnim, d->nextAmount);

	d->tray->show();
}

void MainWin::setInfo(const QString &str)
{
	d->infoString = str;

	if(d->nextAmount == 0)
		d->eventNotifier->setText(d->infoString);
}

void MainWin::buildStatusMenu()
{
	//statusMenu->clear();
	qpopupmenuclear(d->statusMenu);

	d->statusGroup->addTo(d->statusMenu);
}

void MainWin::activatedStatusAction(int id)
{
	QObjectList *l = d->statusGroup->queryList( "IconAction" );
	QObjectListIt it( *l );
	QObject *obj;
	for ( ; (obj = it.current()); ++it) {
		IconAction *action = (IconAction *)obj;
		action->setOn ( d->statusActions[action] == id );
	}
	delete l;

	statusChanged(id);
}

void MainWin::buildToolbars()
{
	bool dockBottom = false;

	while ( option.toolbars.count() < toolbars.count() && toolbars.count() ) {
		PsiToolBar *tb = toolbars.last();
		toolbars.removeLast();
		delete tb;
	}

	uint i;
	for (i = 0; i < option.toolbars["mainWin"].count(); i++) {
		PsiToolBar *tb = 0;
		if ( i < toolbars.count() )
			tb = toolbars.at(i);

		Options::ToolbarPrefs &tbPref = option.toolbars["mainWin"][i];
		if ( tb && !tbPref.dirty )
			continue;

		if ( tb )
			delete tb;

		tb = new PsiToolBar (tbPref.name, this, this);
		moveDockWindow ( tb, tbPref.dock, tbPref.nl, tbPref.index, tbPref. extraOffset );

		tb->setGroup( "mainWin", i );
		tb->setPsiCon( d->psi );
		tb->setType( PsiActionList::Actions_MainWin );
		//connect( tb, SIGNAL( registerAction( IconAction * ) ), SLOT( registerAction( IconAction * ) ) );
		tb->initialize( tbPref, false );

		// MacOS stuff
		dockBottom = dockBottom || (tbPref.dock == Qt::DockBottom && tbPref.on);

		if ( i < toolbars.count() )
			toolbars.remove(i);
		toolbars.insert(i, tb);
	}

#ifdef Q_WS_MAC
	if (dockBottom) {
		statusBar()->show();
	}
	else {
		statusBar()->hide();
	}
#endif
}

void MainWin::saveToolbarsPositions()
{
	for (uint i = 0; i < toolbars.count(); i++) {
		Options::ToolbarPrefs &tbPref = option.toolbars["mainWin"][i];
		getLocation ( toolbars.at(i), tbPref.dock, tbPref.index, tbPref.nl, tbPref.extraOffset );
		tbPref.on = toolbars.at(i)->isVisible();
	}
}

bool MainWin::showDockMenu(const QPoint &)
{
	return false;
}

void MainWin::buildOptionsMenu()
{
	d->optionsMenu->clear();

	// help menu
	QPopupMenu *helpMenu = new QPopupMenu(d->optionsMenu);

	QStringList actionNames;
	actionNames << "help_readme";
	actionNames << "help_tip";
	actionNames << "separator";
	actionNames << "help_online_help";
	actionNames << "help_online_wiki";
	actionNames << "help_online_home";
	actionNames << "help_report_bug";
	actionNames << "separator";
	actionNames << "help_about";
	actionNames << "help_about_qt";

	QStringList::Iterator it;
	IconAction *action;
	for ( it = actionNames.begin(); it != actionNames.end(); ++it )
		if ( (action = d->getAction(*it)) )
			action->addTo( helpMenu );

	buildGeneralMenu( d->optionsMenu );

	d->optionsMenu->insertSeparator();
	d->optionsMenu->insertItem(IconsetFactory::icon("psi/help"), tr("&Help"), helpMenu);
	d->getAction("menu_quit")->addTo( d->optionsMenu );

}

void MainWin::buildMainMenu()
{
	d->mainMenu->clear();

	QStringList actionNames;

	// options menu
	if(!option.lockdown.roster)
		actionNames << "menu_add_contact";
	actionNames << "menu_new_message";
	if(!option.lockdown.services)
		actionNames << "menu_disco";
	actionNames << "menu_join_groupchat";
	actionNames << "";
	if(!option.lockdown.accounts)
		actionNames << "menu_account_setup";
	if(!option.lockdown.profiles)
		actionNames << "menu_change_profile";
	actionNames << "menu_toolbars";
	actionNames << "menu_play_sounds";

	QStringList::Iterator it;
	IconAction *action;
	for ( it = actionNames.begin(); it != actionNames.end(); ++it ) {
		if ((*it).isEmpty())
			d->mainMenu->insertSeparator();
		else if ( (action = d->getAction(*it)) )
			action->addTo( d->mainMenu );
	}
}

void MainWin::buildToolsMenu()
{
	IconAction* action;

	d->toolsMenu->clear();
	if ( (action = d->getAction("menu_file_transfer")) )
		action->addTo(d->toolsMenu);
	d->toolsMenu->insertSeparator();
	if ( (action = d->getAction("menu_xml_console")) )
		action->addTo(d->toolsMenu);
}
	
void MainWin::buildGeneralMenu(QPopupMenu *menu)
{
	menu->clear();

	QStringList actionNames;

	// options menu
	if(!option.lockdown.roster)
		actionNames << "menu_add_contact";
	actionNames << "menu_new_message";
	if(!option.lockdown.services)
		actionNames << "menu_disco";
	actionNames << "menu_join_groupchat";
	if(!option.lockdown.accounts)
		actionNames << "menu_account_setup";
	if(!option.lockdown.options)
		actionNames << "menu_options";
	actionNames << "menu_file_transfer"; // TODO: probably we want to lock down filetransfer, right?
	if(!option.lockdown.profiles)
		actionNames << "menu_change_profile";
	actionNames << "menu_toolbars";
	actionNames << "menu_play_sounds";

	QStringList::Iterator it;
	IconAction *action;
	for ( it = actionNames.begin(); it != actionNames.end(); ++it )
		if ( (action = d->getAction(*it)) )
			action->addTo( menu );
}

// WTF??
void MainWin::testme()
{
	d->optionsMenu->setItemEnabled(10, false);
}

void MainWin::actReadmeActivated ()
{
#ifdef Q_WS_WIN
	ShowTextDlg *w = new ShowTextDlg(g.pathBase + "/readme.txt");
#else
	ShowTextDlg *w = new ShowTextDlg(g.pathBase + "/README");
#endif
	w->setCaption(CAP(tr("ReadMe")));
	w->show();
}

void MainWin::actOnlineHelpActivated ()
{
	openURL("http://psi-im.org/wiki/User_Guide");
}

void MainWin::actOnlineWikiActivated ()
{
	openURL("http://psi-im.org/wiki");
}

void MainWin::actOnlineHomeActivated ()
{
	openURL("http://psi-im.org");
}

void MainWin::actBugReportActivated ()
{
	openURL("http://psi-im.org/forum/forum/2");
}

void MainWin::actAboutActivated ()
{
	AboutDlg *about = new AboutDlg (this, "AboutDlg", false, WDestructiveClose);
	about->show();
}

void MainWin::actTipActivated ()
{
	TipUI *tip = new TipUI (this, "TipDlg", false, WDestructiveClose);
	tip->show();
}

void MainWin::actAboutQtActivated ()
{
	QMessageBox::aboutQt(this);
}

void MainWin::actPlaySoundsActivated (bool state)
{
	useSound = state;
}

void MainWin::activatedAccOption(PsiAccount *pa, int x)
{
	if(x == 0)
		pa->openAddUserDlg();
	else if(x == 2)
		pa->showXmlConsole();
	else if(x == 3)
		pa->doDisco();
}

void MainWin::buildTrayMenu()
{
	if(!d->trayMenu)
		return;
	d->trayMenu->clear();

	if(d->nextAmount > 0) {
		d->trayMenu->insertItem(tr("Receive next event"), this, SLOT(doRecvNextEvent()));
		d->trayMenu->insertSeparator();
	}

	if(isHidden())
		d->trayMenu->insertItem(tr("Un&hide"), this, SLOT(trayShow()));
	else
		d->trayMenu->insertItem(tr("&Hide"), this, SLOT(trayHide()));
	d->optionsButton->addTo(d->trayMenu);
	d->statusButton->addTo(d->trayMenu);
	d->trayMenu->insertSeparator();
	// TODO!
	d->getAction("menu_quit")->addTo(d->trayMenu);
}

void MainWin::setTrayToolTip(int status)
{
	if (!d->tray)
		return;
	d->tray->setToolTip(QString("Psi - " + status2txt(status)));
}

void MainWin::decorateButton(int status)
{
	// update the 'change status' buttons
	QObjectList *l = d->statusGroup->queryList( "IconAction" );
	QObjectListIt it( *l );
	QObject *obj;
	for ( ; (obj = it.current()); ++it) {
		IconAction *action = (IconAction *)obj;
		action->setOn ( d->statusActions[action] == status );
	}
	delete l;

	if(d->lastStatus == status)
		return;
	d->lastStatus = status;

	QIconSet icon;
	icon.setPixmap(is->status(status), QIconSet::Small);

	if(status == -1) {
		d->statusButton->setText(tr("Connecting"));
		if (option.alertStyle != 0)
			d->statusButton->setAlert(IconsetFactory::iconPtr("psi/connect"));
		else
			d->statusButton->setIcon(is->statusPtr(STATUS_OFFLINE));

		setIcon(is->status(STATUS_OFFLINE));
	}
	else {
		d->statusButton->setText(status2txt(status));
		d->statusButton->setIcon(is->statusPtr(status));

		setIcon(is->status(status));
	}

	updateTray();
}

bool MainWin::askQuit()
{
	return TRUE;
}

void MainWin::try2tryCloseProgram()
{
	QTimer::singleShot(0, this, SLOT(tryCloseProgram()));
}

void MainWin::tryCloseProgram()
{
	if(askQuit())
		closeProgram();
}

void MainWin::closeEvent(QCloseEvent *e)
{
#ifdef Q_WS_MAC
	trayHide();
	e->accept();
#else
	if(d->tray) {
		trayHide();
		e->accept();
		return;
	}

	if(!askQuit())
		return;

        closeProgram();
	e->accept();
#endif
}

void MainWin::keyPressEvent(QKeyEvent *e)
{
#ifdef Q_WS_MAC
	bool allowed = true;
#else
	bool allowed = d->tray ? true: false;
#endif

	bool closekey = false;
	if(e->key() == Key_Escape)
		closekey = true;
#ifdef Q_WS_MAC
	else if(e->key() == Key_W && e->state() & ControlButton)
		closekey = true;
#endif

	if(allowed && closekey) {
		close();
		e->accept();
		return;
	}

	QWidget::keyPressEvent(e);
}

void MainWin::updateCaption()
{
	QString str = "";

	if(d->nextAmount > 0)
		str += "* ";

	if(d->nickname.isEmpty())
		str += PROG_NAME;
	else
		str += d->nickname;

	if(str == caption())
		return;

	setCaption(str);
}

void MainWin::optionsUpdate()
{
	int status = d->lastStatus;
	d->lastStatus = -2;
	decorateButton(status);

	if (option.hideMenubar) 
		d->gm->hide();
	else 
		d->gm->show();
	
#if QT_VERSION >= 0x030300
	setWindowOpacity(double(option.rosterOpacity)/100);
#endif
	
	updateTray();
}

void MainWin::toggleVisible()
{
	if(!isHidden())
		trayHide();
	else
		trayShow();
}

void MainWin::setTrayToolTip(const Status &status)
{
	if (!d->tray)
		return;
	QString s = "Psi";

 	QString show = status.show();
	if(!show.isEmpty()) {
		show[0] = show[0].upper();
		s += " - "+show;
	}

	QString text = status.status();
	if(!text.isEmpty())
		s += ": "+text;

	d->tray->setToolTip(s);
}

void MainWin::trayClicked(const QPoint &, int button)
{
	if(option.dockDCstyle)
		return;

	if(button == MidButton) {
		doRecvNextEvent();
		return;
	}

	if(!isHidden())
		trayHide();
	else
		trayShow();
}

void MainWin::trayDoubleClicked()
{
	if(!option.dockDCstyle)
		return;

	if(d->nextAmount > 0) {
		doRecvNextEvent();
		return;
	}


	if(!isHidden())
		trayHide();
	else
		trayShow();
}

void MainWin::trayShow()
{
	bringToFront(this);
}

void MainWin::trayHide()
{
	emit geomChanged(x(), y(), width(), height());
	hide();
}

void MainWin::updateReadNext(Icon *anim, int amount)
{
	d->nextAnim = anim;
	if(anim == 0)
		d->nextAmount = 0;
	else
		d->nextAmount = amount;

	if(d->nextAmount <= 0) {
		d->eventNotifier->hide();
		d->eventNotifier->setText("");
	}
	else {
		d->eventNotifier->setText(QString("<b>") + numEventsString(d->nextAmount) + "</b>");
		d->eventNotifier->show();
		// make sure it shows
		//qApp->processEvents();
	}

	updateTray();
	updateCaption();
}

QString MainWin::numEventsString(int x) const
{
	QString s;
	if(x <= 0)
		s = "";
	else if(x == 1)
		s = tr("1 event received");
	else
		s = tr("%1 events received").arg(x);

	return s;
}

void MainWin::updateTray()
{
	if(!d->tray)
		return;

	if ( d->nextAmount > 0 )
		d->tray->setAlert(d->nextAnim);
	else if ( d->lastStatus == -1 )
		d->tray->setAlert(IconsetFactory::iconPtr("psi/connect"));
	else
		d->tray->setIcon(is->statusPtr(d->lastStatus));
}

void MainWin::doRecvNextEvent()
{
	recvNextEvent();
}

void MainWin::statusClicked(int x)
{
	if(x == MidButton)
		recvNextEvent();
}

void MainWin::numAccountsChanged()
{
	bool enabled = d->psi->accountList(TRUE).isEmpty() ? false : true;
	d->statusButton->setEnabled (enabled);
}

void MainWin::dockActivated()
{
	if(isHidden())
		show();
}


#ifdef Q_WS_MAC
void MainWin::setIcon(const QPixmap&)
{
}
#else
void MainWin::setIcon(const QPixmap& p)
{
	QMainWindow::setIcon(p);
}
#endif

#if defined(Q_WS_WIN)
#include<windows.h>
void MainWin::showNoFocus()
{
	clearWState( WState_ForceHide );

	if ( testWState(WState_Visible) ) {
		SetWindowPos(winId(),HWND_TOPMOST,0,0,0,0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE);
		if(!d->onTop)
			SetWindowPos(winId(),HWND_NOTOPMOST,0,0,0,0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE);
		return; // nothing to do
	}

	if ( isTopLevel() && !testWState( WState_Resized ) )  {
		// do this before sending the posted resize events. Otherwise
		// the layout would catch the resize event and may expand the
		// minimum size.
		QSize s = sizeHint();
		QSizePolicy::ExpandData exp;
#ifndef QT_NO_LAYOUT
		if ( layout() ) {
			if ( layout()->hasHeightForWidth() )
				s.setHeight( layout()->totalHeightForWidth( s.width() ) );
			exp =  layout()->expanding();
		} else
#endif
		{
			if ( sizePolicy().hasHeightForWidth() )
				s.setHeight( heightForWidth( s.width() ) );
			exp = sizePolicy().expanding();
		}
		if ( exp & QSizePolicy::Horizontally )
			s.setWidth( QMAX( s.width(), 200 ) );
		if ( exp & QSizePolicy::Vertically )
			s.setHeight( QMAX( s.height(), 150 ) );
		QRect screen = QApplication::desktop()->screenGeometry( QApplication::desktop()->screenNumber( pos() ) );
		s.setWidth( QMIN( s.width(), screen.width()*2/3 ) );
		s.setHeight( QMIN( s.height(), screen.height()*2/3 ) );
		if ( !s.isEmpty() )
			resize( s );
	}

	QApplication::sendPostedEvents( this, QEvent::Move );
	QApplication::sendPostedEvents( this, QEvent::Resize );

	setWState( WState_Visible );

	if ( testWFlags(WStyle_Tool) || isPopup() ) {
		raise();
	} else if ( testWFlags(WType_TopLevel) ) {
		while ( QApplication::activePopupWidget() )
		QApplication::activePopupWidget()->close();
	}

	if ( !testWState(WState_Polished) )
		polish();

	if ( children() ) {
		QObjectListIt it(*children());
		register QObject *object;
		QWidget *widget;
		while ( it ) {				// show all widget children
			object = it.current();		//   (except popups and other toplevels)
			++it;
			if ( object->isWidgetType() ) {
				widget = (QWidget*)object;
				if ( !widget->isHidden() && !widget->isTopLevel() )
				widget->show();
			}
		}
	}

#if defined(QT_ACCESSIBILITY_SUPPORT)
	QAccessible::updateAccessibility( this, 0, QAccessible::ObjectShow );
#endif

	SetWindowPos(winId(),HWND_TOP,0,0,0,0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
	UpdateWindow(winId());
}

#else

void MainWin::showNoFocus()
{
	bringToFront(this);
}

#endif
