3bf5d811d874d47422098ba2e5f11c1f104587c9
[quassel.git] / src / qtui / mainwin.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-08 by the Quassel Project                          *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 #include "mainwin.h"
21
22 #include "aboutdlg.h"
23 #include "action.h"
24 #include "actioncollection.h"
25 #include "buffermodel.h"
26 #include "bufferviewmanager.h"
27 #include "channellistdlg.h"
28 #include "chatlinemodel.h"
29 #include "chatmonitorfilter.h"
30 #include "chatmonitorview.h"
31 #include "chatview.h"
32 #include "client.h"
33 #include "clientbacklogmanager.h"
34 #include "coreinfodlg.h"
35 #include "coreconnectdlg.h"
36 #include "iconloader.h"
37 #include "inputwidget.h"
38 #include "irclistmodel.h"
39 #include "jumpkeyhandler.h"
40 #include "msgprocessorstatuswidget.h"
41 #include "nicklistwidget.h"
42 #include "qtuiapplication.h"
43 #include "qtuimessageprocessor.h"
44 #include "qtuisettings.h"
45 #include "sessionsettings.h"
46 #include "settingsdlg.h"
47 #include "settingspagedlg.h"
48 #include "topicwidget.h"
49 #include "verticaldock.h"
50
51 #ifdef HAVE_DBUS
52 #  include "desktopnotificationbackend.h"
53 #endif
54 #include "systraynotificationbackend.h"
55 #include "taskbarnotificationbackend.h"
56
57 #include "settingspages/aliasessettingspage.h"
58 #include "settingspages/appearancesettingspage.h"
59 #include "settingspages/bufferviewsettingspage.h"
60 #include "settingspages/colorsettingspage.h"
61 #include "settingspages/fontssettingspage.h"
62 #include "settingspages/generalsettingspage.h"
63 #include "settingspages/highlightsettingspage.h"
64 #include "settingspages/identitiessettingspage.h"
65 #include "settingspages/networkssettingspage.h"
66 #include "settingspages/notificationssettingspage.h"
67
68 MainWin::MainWin(QWidget *parent)
69   : QMainWindow(parent),
70     coreLagLabel(new QLabel()),
71     sslLabel(new QLabel()),
72     msgProcessorStatusWidget(new MsgProcessorStatusWidget()),
73     _titleSetter(this),
74     _trayIcon(new QSystemTrayIcon(this)),
75     _actionCollection(new ActionCollection(this))
76 {
77   QtUiSettings uiSettings;
78   QString style = uiSettings.value("Style", QString("")).toString();
79   if(style != "") {
80     QApplication::setStyle(style);
81   }
82   ui.setupUi(this);
83   setWindowTitle("Quassel IRC");
84   setWindowIconText("Quassel IRC");
85   updateIcon();
86
87   QtUi::actionCollection()->addAssociatedWidget(this);
88
89   statusBar()->showMessage(tr("Waiting for core..."));
90
91   installEventFilter(new JumpKeyHandler(this));
92
93   QtUi::registerNotificationBackend(new TaskbarNotificationBackend(this));
94   QtUi::registerNotificationBackend(new SystrayNotificationBackend(this));
95 #ifdef HAVE_DBUS
96   QtUi::registerNotificationBackend(new DesktopNotificationBackend(this));
97 #endif
98
99   QtUiApplication* app = qobject_cast<QtUiApplication*> qApp;
100   connect(app, SIGNAL(saveStateToSession(const QString&)), this, SLOT(saveStateToSession(const QString&)));
101   connect(app, SIGNAL(saveStateToSessionSettings(SessionSettings&)), this, SLOT(saveStateToSessionSettings(SessionSettings&)));
102 }
103
104 void MainWin::init() {
105   QtUiSettings s;
106   if(s.value("MainWinSize").isValid())
107     resize(s.value("MainWinSize").toSize());
108   else
109     resize(QSize(800, 500));
110
111   connect(QApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(saveLayout()));
112
113   connect(Client::instance(), SIGNAL(networkCreated(NetworkId)), this, SLOT(clientNetworkCreated(NetworkId)));
114   connect(Client::instance(), SIGNAL(networkRemoved(NetworkId)), this, SLOT(clientNetworkRemoved(NetworkId)));
115
116   show();
117
118   statusBar()->showMessage(tr("Not connected to core."));
119
120   // DOCK OPTIONS
121   setDockNestingEnabled(true);
122
123   setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
124   setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
125   setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
126   setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
127
128   // setup stuff...
129   setupActions();
130   setupMenus();
131   setupViews();
132   setupNickWidget();
133   setupTopicWidget();
134   setupChatMonitor();
135   setupInputWidget();
136   setupStatusBar();
137   setupSystray();
138
139   // restore mainwin state
140   restoreState(s.value("MainWinState").toByteArray());
141
142   // restore locked state of docks
143   ui.actionLockDockPositions->setChecked(s.value("LockDocks", false).toBool());
144
145   setDisconnectedState();  // Disable menus and stuff
146   showCoreConnectionDlg(true); // autoconnect if appropriate
147
148   // attach the BufferWidget to the BufferModel and the default selection
149   ui.bufferWidget->setModel(Client::bufferModel());
150   ui.bufferWidget->setSelectionModel(Client::bufferModel()->standardSelectionModel());
151   ui.menuViews->addAction(QtUi::actionCollection()->action("toggleSearchBar"));
152
153   _titleSetter.setModel(Client::bufferModel());
154   _titleSetter.setSelectionModel(Client::bufferModel()->standardSelectionModel());
155 }
156
157 MainWin::~MainWin() {
158   QtUiSettings s;
159   s.setValue("MainWinSize", size());
160   s.setValue("MainWinPos", pos());
161   s.setValue("MainWinState", saveState());
162 }
163
164 void MainWin::updateIcon() {
165   QPixmap icon;
166   if(Client::isConnected())
167     icon = DesktopIcon("quassel", IconLoader::SizeEnormous);
168   else
169     icon = DesktopIcon("quassel_disconnected", IconLoader::SizeEnormous);
170   setWindowIcon(icon);
171   qApp->setWindowIcon(icon);
172   systemTrayIcon()->setIcon(icon);
173 }
174
175 void MainWin::setupActions() {
176   // TODO don't get these from *.ui anymore... we shouldn't need one
177   ui.actionQuit->setIcon(SmallIcon("application-exit"));
178   ui.actionSettingsDlg->setIcon(SmallIcon("configure"));
179   ui.actionManageViews->setIcon(SmallIcon("view-tree"));
180   ui.actionManageViews2->setIcon(SmallIcon("view-tree"));
181   ui.actionAboutQt->setIcon(SmallIcon("qt"));
182   ui.actionAboutQuassel->setIcon(SmallIcon("quassel"));
183   ui.actionConnectCore->setIcon(SmallIcon("network-connect"));
184   ui.actionDisconnectCore->setIcon(SmallIcon("network-disconnect"));
185   ui.actionCoreInfo->setIcon(SmallIcon("help-about"));
186 }
187
188 void MainWin::setupMenus() {
189   connect(ui.actionConnectCore, SIGNAL(triggered()), this, SLOT(showCoreConnectionDlg()));
190   connect(ui.actionDisconnectCore, SIGNAL(triggered()), Client::instance(), SLOT(disconnectFromCore()));
191   connect(ui.actionCoreInfo, SIGNAL(triggered()), this, SLOT(showCoreInfoDlg()));
192   connect(ui.actionQuit, SIGNAL(triggered()), QCoreApplication::instance(), SLOT(quit()));
193   connect(ui.actionSettingsDlg, SIGNAL(triggered()), this, SLOT(showSettingsDlg()));
194   connect(ui.actionAboutQuassel, SIGNAL(triggered()), this, SLOT(showAboutDlg()));
195   connect(ui.actionAboutQt, SIGNAL(triggered()), QApplication::instance(), SLOT(aboutQt()));
196 }
197
198 void MainWin::setupViews() {
199   addBufferView();
200 }
201
202 void MainWin::addBufferView(int bufferViewConfigId) {
203   addBufferView(Client::bufferViewManager()->bufferViewConfig(bufferViewConfigId));
204 }
205
206 void MainWin::addBufferView(BufferViewConfig *config) {
207   BufferViewDock *dock;
208   if(config)
209     dock = new BufferViewDock(config, this);
210   else
211     dock = new BufferViewDock(this);
212
213   //create the view and initialize it's filter
214   BufferView *view = new BufferView(dock);
215   view->setFilteredModel(Client::bufferModel(), config);
216   view->show();
217
218   connect(&view->showChannelList, SIGNAL(triggered()), this, SLOT(showChannelList()));
219
220   Client::bufferModel()->synchronizeView(view);
221
222   dock->setWidget(view);
223   dock->show();
224
225   addDockWidget(Qt::LeftDockWidgetArea, dock);
226   ui.menuBufferViews->addAction(dock->toggleViewAction());
227
228   _netViews.append(dock);
229 }
230
231 void MainWin::removeBufferView(int bufferViewConfigId) {
232   QVariant actionData;
233   BufferViewDock *dock;
234   foreach(QAction *action, ui.menuBufferViews->actions()) {
235     actionData = action->data();
236     if(!actionData.isValid())
237       continue;
238
239     dock = qobject_cast<BufferViewDock *>(action->parent());
240     if(dock && actionData.toInt() == bufferViewConfigId) {
241       removeAction(action);
242       dock->deleteLater();
243     }
244   }
245 }
246
247 void MainWin::on_actionEditNetworks_triggered() {
248   SettingsPageDlg dlg(new NetworksSettingsPage(this), this);
249   dlg.exec();
250 }
251
252 void MainWin::on_actionManageViews_triggered() {
253   SettingsPageDlg dlg(new BufferViewSettingsPage(this), this);
254   dlg.exec();
255 }
256
257 void MainWin::on_actionLockDockPositions_toggled(bool lock) {
258   QList<VerticalDock *> docks = findChildren<VerticalDock *>();
259   foreach(VerticalDock *dock, docks) {
260     dock->showTitle(!lock);
261   }
262   QtUiSettings().setValue("LockDocks", lock);
263 }
264
265 void MainWin::setupNickWidget() {
266   // create nick dock
267   NickListDock *nickDock = new NickListDock(tr("Nicks"), this);
268   nickDock->setObjectName("NickDock");
269   nickDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
270
271   nickListWidget = new NickListWidget(nickDock);
272   nickDock->setWidget(nickListWidget);
273
274   addDockWidget(Qt::RightDockWidgetArea, nickDock);
275   ui.menuViews->addAction(nickDock->toggleViewAction());
276   // See NickListDock::NickListDock();
277   // connect(nickDock->toggleViewAction(), SIGNAL(triggered(bool)), nickListWidget, SLOT(showWidget(bool)));
278
279   // attach the NickListWidget to the BufferModel and the default selection
280   nickListWidget->setModel(Client::bufferModel());
281   nickListWidget->setSelectionModel(Client::bufferModel()->standardSelectionModel());
282 }
283
284 void MainWin::setupChatMonitor() {
285   VerticalDock *dock = new VerticalDock(tr("Chat Monitor"), this);
286   dock->setObjectName("ChatMonitorDock");
287
288   ChatMonitorFilter *filter = new ChatMonitorFilter(Client::messageModel(), this);
289   ChatMonitorView *chatView = new ChatMonitorView(filter, this);
290   chatView->show();
291   dock->setWidget(chatView);
292   dock->show();
293
294   addDockWidget(Qt::TopDockWidgetArea, dock, Qt::Vertical);
295   ui.menuViews->addAction(dock->toggleViewAction());
296 }
297
298 void MainWin::setupInputWidget() {
299   VerticalDock *dock = new VerticalDock(tr("Inputline"), this);
300   dock->setObjectName("InputDock");
301
302   InputWidget *inputWidget = new InputWidget(dock);
303   dock->setWidget(inputWidget);
304
305   addDockWidget(Qt::BottomDockWidgetArea, dock);
306
307   ui.menuViews->addAction(dock->toggleViewAction());
308
309   inputWidget->setModel(Client::bufferModel());
310   inputWidget->setSelectionModel(Client::bufferModel()->standardSelectionModel());
311
312   ui.bufferWidget->setFocusProxy(inputWidget);
313 }
314
315 void MainWin::setupTopicWidget() {
316   VerticalDock *dock = new VerticalDock(tr("Topic"), this);
317   dock->setObjectName("TopicDock");
318   TopicWidget *topicwidget = new TopicWidget(dock);
319
320   dock->setWidget(topicwidget);
321
322   topicwidget->setModel(Client::bufferModel());
323   topicwidget->setSelectionModel(Client::bufferModel()->standardSelectionModel());
324
325   addDockWidget(Qt::TopDockWidgetArea, dock);
326
327   ui.menuViews->addAction(dock->toggleViewAction());
328 }
329
330 void MainWin::setupStatusBar() {
331   // MessageProcessor progress
332   statusBar()->addPermanentWidget(msgProcessorStatusWidget);
333   connect(Client::messageProcessor(), SIGNAL(progressUpdated(int, int)), msgProcessorStatusWidget, SLOT(setProgress(int, int)));
334
335   // Core Lag:
336   updateLagIndicator(0);
337   statusBar()->addPermanentWidget(coreLagLabel);
338   connect(Client::signalProxy(), SIGNAL(lagUpdated(int)), this, SLOT(updateLagIndicator(int)));
339
340   // SSL indicator
341   connect(Client::instance(), SIGNAL(securedConnection()), this, SLOT(securedConnection()));
342   sslLabel->setPixmap(QPixmap());
343   statusBar()->addPermanentWidget(sslLabel);
344
345   ui.menuViews->addSeparator();
346   QAction *showStatusbar = ui.menuViews->addAction(tr("Statusbar"));
347   showStatusbar->setCheckable(true);
348
349   UiSettings uiSettings;
350
351   bool enabled = uiSettings.value("ShowStatusBar", QVariant(true)).toBool();
352   showStatusbar->setChecked(enabled);
353   enabled ? statusBar()->show() : statusBar()->hide();
354
355   connect(showStatusbar, SIGNAL(toggled(bool)), statusBar(), SLOT(setVisible(bool)));
356   connect(showStatusbar, SIGNAL(toggled(bool)), this, SLOT(saveStatusBarStatus(bool)));
357 }
358
359 void MainWin::saveStatusBarStatus(bool enabled) {
360   UiSettings uiSettings;
361   uiSettings.setValue("ShowStatusBar", enabled);
362 }
363
364 void MainWin::setupSystray() {
365   connect(Client::messageModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)),
366                                   SLOT(messagesInserted(const QModelIndex &, int, int)));
367
368   systrayMenu = new QMenu(this);
369   systrayMenu->addAction(ui.actionAboutQuassel);
370   systrayMenu->addSeparator();
371   systrayMenu->addAction(ui.actionConnectCore);
372   systrayMenu->addAction(ui.actionDisconnectCore);
373   systrayMenu->addSeparator();
374   systrayMenu->addAction(ui.actionQuit);
375
376   systemTrayIcon()->setContextMenu(systrayMenu);
377
378   UiSettings s;
379   if(s.value("UseSystemTrayIcon", QVariant(true)).toBool()) {
380     systemTrayIcon()->show();
381   }
382
383 #ifndef Q_WS_MAC
384   connect(systemTrayIcon(), SIGNAL(activated( QSystemTrayIcon::ActivationReason )),
385           this, SLOT(systrayActivated( QSystemTrayIcon::ActivationReason )));
386 #endif
387
388 }
389
390 void MainWin::changeEvent(QEvent *event) {
391   if(event->type() == QEvent::WindowStateChange) {
392     if(windowState() & Qt::WindowMinimized) {
393       UiSettings s;
394       if(s.value("UseSystemTrayIcon").toBool() && s.value("MinimizeOnMinimize").toBool()) {
395         toggleVisibility();
396         event->ignore();
397       }
398     }
399   }
400 }
401
402 void MainWin::connectedToCore() {
403   Q_CHECK_PTR(Client::bufferViewManager());
404   connect(Client::bufferViewManager(), SIGNAL(bufferViewConfigAdded(int)), this, SLOT(addBufferView(int)));
405   connect(Client::bufferViewManager(), SIGNAL(bufferViewConfigDeleted(int)), this, SLOT(removeBufferView(int)));
406   connect(Client::bufferViewManager(), SIGNAL(initDone()), this, SLOT(loadLayout()));
407
408   Client::backlogManager()->requestInitialBacklog();
409   setConnectedState();
410 }
411
412 void MainWin::setConnectedState() {
413   //ui.menuCore->setEnabled(true);
414   ui.actionConnectCore->setEnabled(false);
415   ui.actionDisconnectCore->setEnabled(true);
416   ui.actionCoreInfo->setEnabled(true);
417   ui.menuViews->setEnabled(true);
418   ui.bufferWidget->show();
419   statusBar()->showMessage(tr("Connected to core."));
420   if(sslLabel->width() == 0)
421     sslLabel->setPixmap(SmallIcon("security-low"));
422   updateIcon();
423 }
424
425 void MainWin::loadLayout() {
426   QtUiSettings s;
427   int accountId = Client::currentCoreAccount().toInt();
428   restoreState(s.value(QString("MainWinState-%1").arg(accountId)).toByteArray(), accountId);
429 }
430
431 void MainWin::saveLayout() {
432   QtUiSettings s;
433   int accountId = Client::currentCoreAccount().toInt();
434   if(accountId > 0) s.setValue(QString("MainWinState-%1").arg(accountId) , saveState(accountId));
435 }
436
437 void MainWin::updateLagIndicator(int lag) {
438   coreLagLabel->setText(QString(tr("Core Lag: %1 msec")).arg(lag));
439 }
440
441
442 void MainWin::securedConnection() {
443   // todo: make status bar entry
444   sslLabel->setPixmap(SmallIcon("security-high"));
445 }
446
447 void MainWin::disconnectedFromCore() {
448   // save core specific layout and remove bufferviews;
449   saveLayout();
450   QVariant actionData;
451   BufferViewDock *dock;
452   foreach(QAction *action, ui.menuBufferViews->actions()) {
453     actionData = action->data();
454     if(!actionData.isValid())
455       continue;
456
457     dock = qobject_cast<BufferViewDock *>(action->parent());
458     if(dock && actionData.toInt() != -1) {
459       removeAction(action);
460       dock->deleteLater();
461     }
462   }
463   QtUiSettings s;
464   restoreState(s.value("MainWinState").toByteArray());
465   setDisconnectedState();
466 }
467
468 void MainWin::setDisconnectedState() {
469   //ui.menuCore->setEnabled(false);
470   ui.actionConnectCore->setEnabled(true);
471   ui.actionDisconnectCore->setEnabled(false);
472   ui.actionCoreInfo->setEnabled(false);
473   ui.menuViews->setEnabled(false);
474   ui.bufferWidget->hide();
475   statusBar()->showMessage(tr("Not connected to core."));
476   sslLabel->setPixmap(QPixmap());
477   updateIcon();
478 }
479
480 void MainWin::showCoreConnectionDlg(bool autoConnect) {
481   CoreConnectDlg(autoConnect, this).exec();
482 }
483
484 void MainWin::showChannelList(NetworkId netId) {
485   ChannelListDlg *channelListDlg = new ChannelListDlg();
486
487   if(!netId.isValid()) {
488     QAction *action = qobject_cast<QAction *>(sender());
489     if(action)
490       netId = action->data().value<NetworkId>();
491   }
492
493   channelListDlg->setAttribute(Qt::WA_DeleteOnClose);
494   channelListDlg->setNetwork(netId);
495   channelListDlg->show();
496 }
497
498 void MainWin::showCoreInfoDlg() {
499   CoreInfoDlg(this).exec();
500 }
501
502 void MainWin::showSettingsDlg() {
503   SettingsDlg *dlg = new SettingsDlg();
504
505   //Category: Appearance
506   dlg->registerSettingsPage(new ColorSettingsPage(dlg));
507   dlg->registerSettingsPage(new FontsSettingsPage(dlg));
508   dlg->registerSettingsPage(new AppearanceSettingsPage(dlg)); //General
509   //Category: Behaviour
510   dlg->registerSettingsPage(new GeneralSettingsPage(dlg));
511   dlg->registerSettingsPage(new HighlightSettingsPage(dlg));
512   dlg->registerSettingsPage(new AliasesSettingsPage(dlg));
513   dlg->registerSettingsPage(new NotificationsSettingsPage(dlg));
514   //Category: General
515   dlg->registerSettingsPage(new IdentitiesSettingsPage(dlg));
516   dlg->registerSettingsPage(new NetworksSettingsPage(dlg));
517   dlg->registerSettingsPage(new BufferViewSettingsPage(dlg));
518
519   dlg->show();
520 }
521
522 void MainWin::showAboutDlg() {
523   AboutDlg(this).exec();
524 }
525
526 void MainWin::closeEvent(QCloseEvent *event) {
527   UiSettings s;
528   if(s.value("UseSystemTrayIcon").toBool() && s.value("MinimizeOnClose").toBool()) {
529     toggleVisibility();
530     event->ignore();
531   } else {
532     event->accept();
533   }
534 }
535
536 void MainWin::systrayActivated( QSystemTrayIcon::ActivationReason activationReason) {
537   if(activationReason == QSystemTrayIcon::Trigger) {
538     toggleVisibility();
539   }
540 }
541
542 void MainWin::toggleVisibility() {
543   if(isHidden() /*|| !isActiveWindow()*/) {
544     show();
545     if(isMinimized()) {
546       if(isMaximized())
547         showMaximized();
548       else
549         showNormal();
550     }
551
552     raise();
553     activateWindow();
554     // setFocus(); //Qt::ActiveWindowFocusReason
555
556   } else {
557     if(systemTrayIcon()->isSystemTrayAvailable ()) {
558       clearFocus();
559       hide();
560       if(!systemTrayIcon()->isVisible()) {
561         systemTrayIcon()->show();
562       }
563     } else {
564       lower();
565     }
566   }
567 }
568
569 void MainWin::messagesInserted(const QModelIndex &parent, int start, int end) {
570   Q_UNUSED(parent);
571
572   if(QApplication::activeWindow() != 0)
573     return;
574
575   for(int i = start; i <= end; i++) {
576     QModelIndex idx = Client::messageModel()->index(i, ChatLineModel::ContentsColumn);
577     if(!idx.isValid()) {
578       qDebug() << "MainWin::messagesInserted(): Invalid model index!";
579       continue;
580     }
581     Message::Flags flags = (Message::Flags)idx.data(ChatLineModel::FlagsRole).toInt();
582     if(flags.testFlag(Message::Backlog)) continue;
583     flags |= Message::Backlog;  // we only want to trigger a highlight once!
584     Client::messageModel()->setData(idx, (int)flags, ChatLineModel::FlagsRole);
585
586     BufferId bufId = idx.data(ChatLineModel::BufferIdRole).value<BufferId>();
587     BufferInfo::Type bufType = Client::networkModel()->bufferType(bufId);
588
589     if(flags & Message::Highlight || bufType == BufferInfo::QueryBuffer) {
590       QModelIndex senderIdx = Client::messageModel()->index(i, ChatLineModel::SenderColumn);
591       QString sender = senderIdx.data(ChatLineModel::EditRole).toString();
592       QString contents = idx.data(ChatLineModel::DisplayRole).toString();
593       QtUi::invokeNotification(bufId, sender, contents);
594     }
595   }
596 }
597
598 bool MainWin::event(QEvent *event) {
599   if(event->type() == QEvent::WindowActivate)
600     QtUi::closeNotifications();
601   return QMainWindow::event(event);
602 }
603
604 void MainWin::clientNetworkCreated(NetworkId id) {
605   const Network *net = Client::network(id);
606   QAction *act = new QAction(net->networkName(), this);
607   act->setObjectName(QString("NetworkAction-%1").arg(id.toInt()));
608   act->setData(QVariant::fromValue<NetworkId>(id));
609   connect(net, SIGNAL(updatedRemotely()), this, SLOT(clientNetworkUpdated()));
610   connect(act, SIGNAL(triggered()), this, SLOT(connectOrDisconnectFromNet()));
611
612   QAction *beforeAction = 0;
613   foreach(QAction *action, ui.menuNetworks->actions()) {
614     if(action->isSeparator()) {
615       beforeAction = action;
616       break;
617     }
618     if(net->networkName().localeAwareCompare(action->text()) < 0) {
619       beforeAction = action;
620       break;
621     }
622   }
623   Q_CHECK_PTR(beforeAction);
624   ui.menuNetworks->insertAction(beforeAction, act);
625 }
626
627 void MainWin::clientNetworkUpdated() {
628   const Network *net = qobject_cast<const Network *>(sender());
629   if(!net)
630     return;
631
632   QAction *action = findChild<QAction *>(QString("NetworkAction-%1").arg(net->networkId().toInt()));
633   if(!action)
634     return;
635
636   action->setText(net->networkName());
637
638   switch(net->connectionState()) {
639   case Network::Initialized:
640     action->setIcon(SmallIcon("network-connect"));
641     break;
642   case Network::Disconnected:
643     action->setIcon(SmallIcon("network-disconnect"));
644     break;
645   default:
646     action->setIcon(SmallIcon("network-wired"));
647   }
648 }
649
650 void MainWin::clientNetworkRemoved(NetworkId id) {
651   QAction *action = findChild<QAction *>(QString("NetworkAction-%1").arg(id.toInt()));
652   if(!action)
653     return;
654
655   action->deleteLater();
656 }
657
658 void MainWin::connectOrDisconnectFromNet() {
659   QAction *act = qobject_cast<QAction *>(sender());
660   if(!act) return;
661   const Network *net = Client::network(act->data().value<NetworkId>());
662   if(!net) return;
663   if(net->connectionState() == Network::Disconnected) net->requestConnect();
664   else net->requestDisconnect();
665 }
666
667 void MainWin::on_actionDebugNetworkModel_triggered(bool) {
668   QTreeView *view = new QTreeView;
669   view->setAttribute(Qt::WA_DeleteOnClose);
670   view->setWindowTitle("Debug NetworkModel View");
671   view->setModel(Client::networkModel());
672   view->setColumnWidth(0, 250);
673   view->setColumnWidth(1, 250);
674   view->setColumnWidth(2, 80);
675   view->resize(610, 300);
676   view->show();
677 }
678
679 void MainWin::saveStateToSession(const QString &sessionId) {
680   return;
681   SessionSettings s(sessionId);
682
683   s.setValue("MainWinSize", size());
684   s.setValue("MainWinPos", pos());
685   s.setValue("MainWinState", saveState());
686 }
687
688 void MainWin::saveStateToSessionSettings(SessionSettings & s)
689 {
690   s.setValue("MainWinSize", size());
691   s.setValue("MainWinPos", pos());
692   s.setValue("MainWinState", saveState());
693 }