fixing BR #261 (making fields removable from the chatmonitor). Changes effect current...
[quassel.git] / src / qtui / mainwin.cpp
index 4c3f16b..9d0de30 100644 (file)
 #include "mainwin.h"
 
 #include "aboutdlg.h"
-#include "chatwidget.h"
 #include "bufferview.h"
 #include "bufferviewconfig.h"
 #include "bufferviewfilter.h"
 #include "bufferviewmanager.h"
 #include "channellistdlg.h"
+#include "chatlinemodel.h"
+#include "chatmonitorfilter.h"
+#include "chatmonitorview.h"
+#include "chatview.h"
 #include "client.h"
 #include "clientbacklogmanager.h"
 #include "coreinfodlg.h"
 #include "coreconnectdlg.h"
+#include "msgprocessorstatuswidget.h"
+#include "qtuimessageprocessor.h"
 #include "networkmodel.h"
 #include "buffermodel.h"
 #include "nicklistwidget.h"
@@ -45,8 +50,6 @@
 #include "qtuisettings.h"
 #include "jumpkeyhandler.h"
 
-#include "uisettings.h"
-
 #include "selectionmodelsynchronizer.h"
 #include "mappedselectionmodel.h"
 
 #include "settingspages/highlightsettingspage.h"
 #include "settingspages/identitiessettingspage.h"
 #include "settingspages/networkssettingspage.h"
-
+#include "settingspages/notificationssettingspage.h"
 
 #include "debugconsole.h"
 #include "global.h"
 #include "qtuistyle.h"
 
-#include <Qt/QtDBus>
-
-
 MainWin::MainWin(QtUi *_gui, QWidget *parent)
   : QMainWindow(parent),
     gui(_gui),
     coreLagLabel(new QLabel()),
     sslLabel(new QLabel()),
+    msgProcessorStatusWidget(new MsgProcessorStatusWidget()),
     _titleSetter(this),
     systray(new QSystemTrayIcon(this)),
     activeTrayIcon(":/icons/quassel-icon-active.png"),
@@ -86,12 +87,12 @@ MainWin::MainWin(QtUi *_gui, QWidget *parent)
 {
   UiSettings uiSettings;
   loadTranslation(uiSettings.value("Locale", QLocale::system()).value<QLocale>());
-  
+
   QString style = uiSettings.value("Style", QString("")).toString();
   if(style != "") {
     QApplication::setStyle(style);
   }
-  
+
   ui.setupUi(this);
   setWindowTitle("Quassel IRC");
   setWindowIcon(offlineTrayIcon);
@@ -103,6 +104,15 @@ MainWin::MainWin(QtUi *_gui, QWidget *parent)
 
   installEventFilter(new JumpKeyHandler(this));
 
+#ifdef HAVE_DBUS
+  desktopNotifications = new org::freedesktop::Notifications(
+                            "org.freedesktop.Notifications",
+                            "/org/freedesktop/Notifications",
+                            QDBusConnection::sessionBus(), this);
+  notificationId = 0;
+  connect(desktopNotifications, SIGNAL(NotificationClosed(uint, uint)), this, SLOT(desktopNotificationClosed(uint, uint)));
+  connect(desktopNotifications, SIGNAL(ActionInvoked(uint, const QString&)), this, SLOT(desktopNotificationInvoked(uint, const QString&)));
+#endif
 }
 
 void MainWin::init() {
@@ -146,9 +156,9 @@ void MainWin::init() {
   // restore mainwin state
   restoreState(s.value("MainWinState").toByteArray());
 
-  // restore locked state of docks  
+  // restore locked state of docks
   ui.actionLockDockPositions->setChecked(s.value("LockDocks", false).toBool());
-  
+
 
   setDisconnectedState();  // Disable menus and stuff
   showCoreConnectionDlg(true); // autoconnect if appropriate
@@ -200,7 +210,7 @@ void MainWin::addBufferView(BufferViewConfig *config) {
   view->show();
 
   connect(&view->showChannelList, SIGNAL(triggered()), this, SLOT(showChannelList()));
-  
+
   Client::bufferModel()->synchronizeView(view);
 
   dock->setWidget(view);
@@ -237,6 +247,7 @@ void MainWin::setupSettingsDlg() {
   settingsDlg->registerSettingsPage(new GeneralSettingsPage(settingsDlg));
   settingsDlg->registerSettingsPage(new HighlightSettingsPage(settingsDlg));
   settingsDlg->registerSettingsPage(new AliasesSettingsPage(settingsDlg));
+  settingsDlg->registerSettingsPage(new NotificationsSettingsPage(settingsDlg));
   //Category: General
   settingsDlg->registerSettingsPage(new IdentitiesSettingsPage(settingsDlg));
   settingsDlg->registerSettingsPage(new NetworksSettingsPage(settingsDlg));
@@ -281,26 +292,17 @@ void MainWin::setupNickWidget() {
 }
 
 void MainWin::setupChatMonitor() {
-#ifndef SPUTDEV
   VerticalDock *dock = new VerticalDock(tr("Chat Monitor"), this);
   dock->setObjectName("ChatMonitorDock");
 
-  ChatWidget *chatWidget = new ChatWidget(0, this);
-  chatWidget->show();
-  dock->setWidget(chatWidget);
+  ChatMonitorFilter *filter = new ChatMonitorFilter(Client::messageModel(), this);
+  ChatMonitorView *chatView = new ChatMonitorView(filter, this);
+  chatView->show();
+  dock->setWidget(chatView);
   dock->show();
 
-  Buffer *buf = Client::monitorBuffer();
-  if(!buf)
-    return;
-
-  chatWidget->setContents(buf->contents());
-  connect(buf, SIGNAL(msgAppended(AbstractUiMsg *)), chatWidget, SLOT(appendMsg(AbstractUiMsg *)));
-  connect(buf, SIGNAL(msgPrepended(AbstractUiMsg *)), chatWidget, SLOT(prependMsg(AbstractUiMsg *)));
-
   addDockWidget(Qt::TopDockWidgetArea, dock, Qt::Vertical);
   ui.menuViews->addAction(dock->toggleViewAction());
-#endif /* SPUTDEV */
 }
 
 void MainWin::setupInputWidget() {
@@ -337,6 +339,10 @@ void MainWin::setupTopicWidget() {
 }
 
 void MainWin::setupStatusBar() {
+  // MessageProcessor progress
+  statusBar()->addPermanentWidget(msgProcessorStatusWidget);
+  connect(Client::messageProcessor(), SIGNAL(progressUpdated(int, int)), msgProcessorStatusWidget, SLOT(setProgress(int, int)));
+
   // Core Lag:
   updateLagIndicator(0);
   statusBar()->addPermanentWidget(coreLagLabel);
@@ -368,7 +374,8 @@ void MainWin::saveStatusBarStatus(bool enabled) {
 
 void MainWin::setupSystray() {
   connect(timer, SIGNAL(timeout()), this, SLOT(makeTrayIconBlink()));
-  connect(Client::instance(), SIGNAL(messageReceived(const Message &)), this, SLOT(receiveMessage(const Message &)));
+  connect(Client::messageModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)),
+                            this, SLOT(messagesInserted(const QModelIndex &, int, int)));
 
   systrayMenu = new QMenu(this);
   systrayMenu->addAction(ui.actionAboutQuassel);
@@ -452,7 +459,7 @@ void MainWin::saveLayout() {
 }
 
 void MainWin::updateLagIndicator(int lag) {
-  coreLagLabel->setText(QString("Core Lag: %1 msec").arg(lag));
+  coreLagLabel->setText(QString(tr("Core Lag: %1 msec")).arg(lag));
 }
 
 
@@ -579,33 +586,45 @@ void MainWin::toggleVisibility() {
   }
 }
 
-void MainWin::receiveMessage(const Message &msg) {
+void MainWin::messagesInserted(const QModelIndex &parent, int start, int end) {
+  Q_UNUSED(parent);
   if(QApplication::activeWindow() != 0)
     return;
 
-  if(msg.flags() & Message::Highlight || msg.bufferInfo().type() == BufferInfo::QueryBuffer) {
-    QString title = msg.bufferInfo().bufferName();;
-    if(msg.bufferInfo().type() != BufferInfo::QueryBuffer) {
-      QString sender = msg.sender();
-      int i = sender.indexOf("!");
-      if(i != -1)
-        sender = sender.left(i);
-      title += QString(" - %1").arg(sender);
-    }
-
-    UiSettings uiSettings;
+  // FIXME
+  return;
 
-#ifndef SPUTDEV
-    if(uiSettings.value("DisplayPopupMessages", QVariant(true)).toBool()) {
-      // FIXME don't invoke style engine for this!
-      QString text = QtUi::style()->styleString(Message::mircToInternal(msg.contents())).plainText;
-      displayTrayIconMessage(title, text);
-         sendDesktopNotification(title, text);
+  for(int i = start; i <= end; i++) {
+    QModelIndex idx = Client::messageModel()->index(i, ChatLineModel::ContentsColumn);
+    if(!idx.isValid()) {
+      qDebug() << "MainWin::messagesInserted(): Invalid model index!";
+      continue;
     }
-#endif
-    if(uiSettings.value("AnimateTrayIcon", QVariant(true)).toBool()) {
-      QApplication::alert(this);
-      setTrayIconActivity(true);
+    Message::Flags flags = (Message::Flags)idx.data(ChatLineModel::FlagsRole).toInt();
+    BufferId bufId = idx.data(ChatLineModel::BufferIdRole).value<BufferId>();
+    BufferInfo::Type bufType = Client::networkModel()->bufferType(bufId);
+
+    if(flags & Message::Highlight || bufType == BufferInfo::QueryBuffer) {
+      QString title = Client::networkModel()->networkName(bufId) + " - " + Client::networkModel()->bufferName(bufId);
+
+      // FIXME Don't instantiate this for every highlight...
+      UiSettings uiSettings;
+
+      bool displayBubble = uiSettings.value("NotificationBubble", QVariant(true)).toBool();
+      bool displayDesktop = uiSettings.value("NotificationDesktop", QVariant(true)).toBool();
+      if(displayBubble || displayDesktop) {
+        if(uiSettings.value("DisplayPopupMessages", QVariant(true)).toBool()) {
+          QString text = idx.data(ChatLineModel::DisplayRole).toString();
+          if(displayBubble) displayTrayIconMessage(title, text);
+#   ifdef HAVE_DBUS
+          if(displayDesktop) sendDesktopNotification(title, text);
+#   endif
+        }
+        if(uiSettings.value("AnimateTrayIcon", QVariant(true)).toBool()) {
+          QApplication::alert(this);
+          setTrayIconActivity(true);
+        }
+      }
     }
   }
 }
@@ -616,33 +635,60 @@ bool MainWin::event(QEvent *event) {
   return QMainWindow::event(event);
 }
 
+#ifdef HAVE_DBUS
 
 /*
 Using the notification-daemon from Freedesktop's Galago project
 http://www.galago-project.org/specs/notification/0.9/x408.html#command-notify
 */
-void MainWin::sendDesktopNotification(const QString &title, const QString &message)
-{
-       QStringList actions;
-       QMap<QString, QVariant> hints;
-       QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.Notifications", "/org/freedesktop/Notifications", "", "Notify");
+void MainWin::sendDesktopNotification(const QString &title, const QString &message) {
+  QStringList actions;
+  QMap<QString, QVariant> hints;
+  UiSettings uiSettings;
 
-       hints["x"] = 100; // Standard hint: x location for the popup to show up
-       hints["y"] = 100; // Standard hint: y location for the popup to show up
+  hints["x"] = uiSettings.value("NotificationDesktopHintX", QVariant(0)).toInt(); // Standard hint: x location for the popup to show up
+  hints["y"] = uiSettings.value("NotificationDesktopHintY", QVariant(0)).toInt(); // Standard hint: y location for the popup to show up
+
+  actions << "click" << "Click Me!";
+
+  QDBusReply<uint> reply = desktopNotifications->Notify(
+                "Quassel", // Application name
+                notificationId, // ID of previous notification to replace
+                "", // Icon to display
+                title, // Summary / Header of the message to display
+                QString("%1: %2:\n%3").arg(QTime::currentTime().toString()).arg(title).arg(message), // Body of the message to display
+                actions, // Actions from which the user may choose
+                hints, // Hints to the server displaying the message
+                uiSettings.value("NotificationDesktopTimeout", QVariant(5000)).toInt() // Timeout in milliseconds
+        );
+
+  if(!reply.isValid()) {
+    /* ERROR */
+    // could also happen if no notification service runs, so... whatever :)
+    //qDebug() << "Error on sending notification..." << reply.error();
+    return;
+  }
+
+  notificationId = reply.value();
+
+  // qDebug() << "ID: " << notificationId << " Time: " << QTime::currentTime().toString();
+}
 
-       msg << "Quassel"; // Application name
-       msg << quint32(0); // ID of previous notification to replace
-       msg << ""; // Icon to display
-       msg << "Quassel: " + title; // Summary / Header of the message to display
-       msg << message; // Body of the message to display
-       msg << actions; // Actions from which the user may choose
-       msg << hints; // Hints to the server displaying the message
-       msg << qint32(10000); // Timeout in milliseconds
 
-       (void)QDBusConnection::sessionBus().call(msg); // Would return a message containing the id of this notification
+void MainWin::desktopNotificationClosed(uint id, uint reason) {
+  Q_UNUSED(id); Q_UNUSED(reason);
+  // qDebug() << "OID: " << notificationId << " ID: " << id << " Reason: " << reason << " Time: " << QTime::currentTime().toString();
+  notificationId = 0;
 }
 
 
+void MainWin::desktopNotificationInvoked(uint id, const QString & action) {
+  Q_UNUSED(id); Q_UNUSED(action);
+  // qDebug() << "OID: " << notificationId << " ID: " << id << " Action: " << action << " Time: " << QTime::currentTime().toString();
+}
+
+#endif /* HAVE_DBUS */
+
 void MainWin::displayTrayIconMessage(const QString &title, const QString &message) {
   systray->showMessage(title, message);
 }
@@ -717,7 +763,7 @@ void MainWin::clientNetworkRemoved(NetworkId id) {
   QAction *action = findChild<QAction *>(QString("NetworkAction-%1").arg(id.toInt()));
   if(!action)
     return;
-  
+
   action->deleteLater();
 }
 
@@ -730,3 +776,16 @@ void MainWin::connectOrDisconnectFromNet() {
   else net->requestDisconnect();
 }
 
+
+
+void MainWin::on_actionDebugNetworkModel_triggered(bool) {
+  QTreeView *view = new QTreeView;
+  view->setAttribute(Qt::WA_DeleteOnClose);
+  view->setWindowTitle("Debug NetworkModel View");
+  view->setModel(Client::networkModel());
+  view->setColumnWidth(0, 250);
+  view->setColumnWidth(1, 250);
+  view->setColumnWidth(2, 80);
+  view->resize(610, 300);
+  view->show();
+}