Complete and pimp DesktopNotificationBackend.
authorManuel Nickschas <sputnick@quassel-irc.org>
Sun, 12 Oct 2008 16:48:09 +0000 (18:48 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Sun, 12 Oct 2008 18:38:43 +0000 (20:38 +0200)
You'll need to reset your notification settings, as things have moved around in the
settings files.
Thanks to TerrorBite for providing the patches in BR #278, this information was
very valuable!

src/qtui/CMakeLists.txt
src/qtui/desktopnotificationbackend.cpp
src/qtui/desktopnotificationbackend.h
src/qtui/mainwin.cpp
src/qtui/ui/desktopnotificationconfigwidget.ui [new file with mode: 0644]

index 59d3837..0bf28ee 100644 (file)
@@ -111,6 +111,7 @@ set(FORMS
 IF(HAVE_DBUS)
   set(SOURCES ${SOURCES} desktopnotificationbackend.cpp)
   set(MOC_HDRS ${MOC_HDRS} desktopnotificationbackend.h)
 IF(HAVE_DBUS)
   set(SOURCES ${SOURCES} desktopnotificationbackend.cpp)
   set(MOC_HDRS ${MOC_HDRS} desktopnotificationbackend.h)
+  set(FORMS ${FORMS} desktopnotificationconfigwidget.ui)
   qt4_add_dbus_interface(DBUS ../../interfaces/org.freedesktop.Notifications.xml desktopnotificationinterface)
 ENDIF(HAVE_DBUS)
 
   qt4_add_dbus_interface(DBUS ../../interfaces/org.freedesktop.Notifications.xml desktopnotificationinterface)
 ENDIF(HAVE_DBUS)
 
index de87344..45d18b5 100644 (file)
 
 #include "desktopnotificationbackend.h"
 
 
 #include "desktopnotificationbackend.h"
 
+#include <QTextDocument>
+
 #include "client.h"
 #include "clientsettings.h"
 #include "networkmodel.h"
 
 DesktopNotificationBackend::DesktopNotificationBackend(QObject *parent) : AbstractNotificationBackend(parent) {
 #include "client.h"
 #include "clientsettings.h"
 #include "networkmodel.h"
 
 DesktopNotificationBackend::DesktopNotificationBackend(QObject *parent) : AbstractNotificationBackend(parent) {
+  _configWidget = new ConfigWidget();
+
   _dbusInterface = new org::freedesktop::Notifications(
     "org.freedesktop.Notifications",
     "/org/freedesktop/Notifications",
     QDBusConnection::sessionBus(), this);
   _dbusInterface = new org::freedesktop::Notifications(
     "org.freedesktop.Notifications",
     "/org/freedesktop/Notifications",
     QDBusConnection::sessionBus(), this);
-  _dbusNotificationId = 0;
+
+  QStringList desktopCapabilities = _dbusInterface->GetCapabilities();
+  _daemonSupportsMarkup = desktopCapabilities.contains("body-markup");
+
+  _lastDbusId = 0;
   connect(_dbusInterface, SIGNAL(NotificationClosed(uint, uint)), SLOT(desktopNotificationClosed(uint, uint)));
   connect(_dbusInterface, SIGNAL(ActionInvoked(uint, const QString &)), SLOT(desktopNotificationInvoked(uint, const QString&)));
 
   NotificationSettings notificationSettings;
   _enabled = notificationSettings.value("DesktopNotification/Enabled", false).toBool();
   connect(_dbusInterface, SIGNAL(NotificationClosed(uint, uint)), SLOT(desktopNotificationClosed(uint, uint)));
   connect(_dbusInterface, SIGNAL(ActionInvoked(uint, const QString &)), SLOT(desktopNotificationInvoked(uint, const QString&)));
 
   NotificationSettings notificationSettings;
   _enabled = notificationSettings.value("DesktopNotification/Enabled", false).toBool();
+  _useHints = notificationSettings.value("DesktopNotification/UseHints", false).toBool();
   _xHint = notificationSettings.value("DesktopNotification/XHint", 0).toInt();
   _yHint = notificationSettings.value("DesktopNotification/YHint", 0).toInt();
   _xHint = notificationSettings.value("DesktopNotification/XHint", 0).toInt();
   _yHint = notificationSettings.value("DesktopNotification/YHint", 0).toInt();
+  _queueNotifications = notificationSettings.value("DesktopNotification/QueueNotifications", true).toBool();
+  _timeout = notificationSettings.value("DesktopNotification/Timeout", 10000).toInt();
+  _useTimeout = notificationSettings.value("DesktopNotification/UseTimeout", true).toBool();
+
   notificationSettings.notify("DesktopNotification/Enabled", this, SLOT(enabledChanged(const QVariant &)));
   notificationSettings.notify("DesktopNotification/Enabled", this, SLOT(enabledChanged(const QVariant &)));
+  notificationSettings.notify("DesktopNotification/UseHints", this, SLOT(useHintsChanged(const QVariant &)));
   notificationSettings.notify("DesktopNotification/XHint", this, SLOT(xHintChanged(const QVariant &)));
   notificationSettings.notify("DesktopNotification/YHint", this, SLOT(yHintChanged(const QVariant &)));
   notificationSettings.notify("DesktopNotification/XHint", this, SLOT(xHintChanged(const QVariant &)));
   notificationSettings.notify("DesktopNotification/YHint", this, SLOT(yHintChanged(const QVariant &)));
+  notificationSettings.notify("DesktopNotification/Timeout", this, SLOT(timeoutChanged(const QVariant &)));
+  notificationSettings.notify("DesktopNotification/UseTimeout", this, SLOT(useTimeoutChanged(const QVariant &)));
+  notificationSettings.notify("DesktopNotification/QueueNotifications", this, SLOT(queueNotificationsChanged(const QVariant &)));
 }
 
 DesktopNotificationBackend::~DesktopNotificationBackend() {
 }
 
 DesktopNotificationBackend::~DesktopNotificationBackend() {
-
+  delete _configWidget;
 }
 
 void DesktopNotificationBackend::enabledChanged(const QVariant &v) {
   _enabled = v.toBool();
 }
 
 }
 
 void DesktopNotificationBackend::enabledChanged(const QVariant &v) {
   _enabled = v.toBool();
 }
 
+void DesktopNotificationBackend::useHintsChanged(const QVariant &v) {
+  _useHints = v.toBool();
+}
+
 void DesktopNotificationBackend::xHintChanged(const QVariant &v) {
   _xHint = v.toInt();
 }
 void DesktopNotificationBackend::xHintChanged(const QVariant &v) {
   _xHint = v.toInt();
 }
@@ -58,54 +79,156 @@ void DesktopNotificationBackend::yHintChanged(const QVariant &v) {
   _yHint = v.toInt();
 }
 
   _yHint = v.toInt();
 }
 
+void DesktopNotificationBackend::queueNotificationsChanged(const QVariant &v) {
+  _queueNotifications = v.toBool();
+}
+
+void DesktopNotificationBackend::timeoutChanged(const QVariant &v) {
+  _timeout = v.toInt();
+}
+
+void DesktopNotificationBackend::useTimeoutChanged(const QVariant &v) {
+  _useTimeout = v.toBool();
+}
+
 void DesktopNotificationBackend::notify(const Notification &n) {
   if(_enabled) {
     QStringList actions;
     QMap<QString, QVariant> hints;
 
 void DesktopNotificationBackend::notify(const Notification &n) {
   if(_enabled) {
     QStringList actions;
     QMap<QString, QVariant> hints;
 
-    hints["x"] = _xHint; // Standard hint: x location for the popup to show up
-    hints["y"] = _yHint; // Standard hint: y location for the popup to show up
+    if(_useHints) {
+      hints["x"] = _xHint; // Standard hint: x location for the popup to show up
+      hints["y"] = _yHint; // Standard hint: y location for the popup to show up
+    }
+
+    uint oldId = _queueNotifications ? 0 : _lastDbusId;
 
     // actions << "click" << "Click Me!";
 
     QString title = Client::networkModel()->networkName(n.bufferId) + " - " + Client::networkModel()->bufferName(n.bufferId);
     QString message = QString("<%1> %2").arg(n.sender, n.message);
 
 
     // actions << "click" << "Click Me!";
 
     QString title = Client::networkModel()->networkName(n.bufferId) + " - " + Client::networkModel()->bufferName(n.bufferId);
     QString message = QString("<%1> %2").arg(n.sender, n.message);
 
+    if(_daemonSupportsMarkup)
+      message = Qt::escape(message);
+
     QDBusReply<uint> reply = _dbusInterface->Notify(
       "Quassel IRC", // Application name
     QDBusReply<uint> reply = _dbusInterface->Notify(
       "Quassel IRC", // Application name
-      _dbusNotificationId, // ID of previous notification to replace
+      oldId, // ID of previous notification to replace
       "quassel", // Icon to display
       title, // Summary / Header of the message to display
       message, // Body of the message to display
       actions, // Actions from which the user may choose
       hints, // Hints to the server displaying the message
       "quassel", // Icon to display
       title, // Summary / Header of the message to display
       message, // Body of the message to display
       actions, // Actions from which the user may choose
       hints, // Hints to the server displaying the message
-      5000 // Timeout in milliseconds
+      _useTimeout? _timeout : 0 // Timeout in milliseconds
     );
 
     if(!reply.isValid()) {
       /* ERROR */
       // could also happen if no notification service runs, so... whatever :)
     );
 
     if(!reply.isValid()) {
       /* ERROR */
       // could also happen if no notification service runs, so... whatever :)
-      //qDebug() << "Error on sending notification..." << reply.error();
+      // qDebug() << "Error on sending notification..." << reply.error();
       return;
     }
       return;
     }
-    _dbusNotificationId = reply.value();
+    uint dbusid = reply.value();
+    _idMap.insert(n.notificationId, dbusid);
+    _lastDbusId = dbusid;
   }
 }
 
 void DesktopNotificationBackend::close(uint notificationId) {
   }
 }
 
 void DesktopNotificationBackend::close(uint notificationId) {
-  Q_UNUSED(notificationId);
+  uint dbusId = _idMap.value(notificationId, 0);
+  if(dbusId) {
+    _idMap.remove(notificationId);
+    _dbusInterface->CloseNotification(dbusId);
+  }
+  _lastDbusId = 0;
 }
 
 void DesktopNotificationBackend::desktopNotificationClosed(uint id, uint reason) {
 }
 
 void DesktopNotificationBackend::desktopNotificationClosed(uint id, uint reason) {
-  Q_UNUSED(id); Q_UNUSED(reason);
-  // qDebug() << "OID: " << notificationId << " ID: " << id << " Reason: " << reason << " Time: " << QTime::currentTime().toString();
-  _dbusNotificationId = 0;
+  Q_UNUSED(reason);
+  _idMap.remove(_idMap.key(id));
+  _lastDbusId = 0;
 }
 
 
 void DesktopNotificationBackend::desktopNotificationInvoked(uint id, const QString & action) {
   Q_UNUSED(id); Q_UNUSED(action);
 }
 
 
 void DesktopNotificationBackend::desktopNotificationInvoked(uint id, const QString & action) {
   Q_UNUSED(id); Q_UNUSED(action);
-  // qDebug() << "OID: " << notificationId << " ID: " << id << " Action: " << action << " Time: " << QTime::currentTime().toString();
 }
 
 }
 
+SettingsPage *DesktopNotificationBackend::configWidget() const {
+  return _configWidget;
+}
+
+/***************************************************************************/
+
+DesktopNotificationBackend::ConfigWidget::ConfigWidget(QWidget *parent) : SettingsPage("Internal", "DesktopNotification", parent) {
+  ui.setupUi(this);
+
+  connect(ui.enabled, SIGNAL(toggled(bool)), SLOT(widgetChanged()));
+  connect(ui.useHints, SIGNAL(toggled(bool)), SLOT(widgetChanged()));
+  connect(ui.xHint, SIGNAL(valueChanged(int)), SLOT(widgetChanged()));
+  connect(ui.yHint, SIGNAL(valueChanged(int)), SLOT(widgetChanged()));
+  connect(ui.queueNotifications, SIGNAL(toggled(bool)), SLOT(widgetChanged()));
+  connect(ui.useTimeout, SIGNAL(toggled(bool)), SLOT(widgetChanged()));
+  connect(ui.timeout, SIGNAL(valueChanged(int)), SLOT(widgetChanged()));
+}
+
+void DesktopNotificationBackend::ConfigWidget::widgetChanged() {
+  bool changed =
+       enabled != ui.enabled->isChecked()
+    || useHints != ui.useHints->isChecked()
+    || xHint != ui.xHint->value()
+    || yHint != ui.yHint->value()
+    || queueNotifications != ui.queueNotifications->isChecked()
+    || timeout/1000 != ui.timeout->value()
+    || useTimeout != ui.useTimeout->isChecked();
+  if(changed != hasChanged()) setChangedState(changed);
+}
+
+bool DesktopNotificationBackend::ConfigWidget::hasDefaults() const {
+  return true;
+}
+
+void DesktopNotificationBackend::ConfigWidget::defaults() {
+  ui.enabled->setChecked(false);
+  ui.useTimeout->setChecked(true);
+  ui.timeout->setValue(10);
+  ui.useHints->setChecked(false);
+  ui.xHint->setValue(0);
+  ui.yHint->setValue(0);
+  ui.queueNotifications->setChecked(true);
+  widgetChanged();
+}
+
+void DesktopNotificationBackend::ConfigWidget::load() {
+  NotificationSettings s;
+  enabled = s.value("DesktopNotification/Enabled", false).toBool();
+  useTimeout = s.value("DesktopNotification/UseTimeout", true).toBool();
+  timeout = s.value("DesktopNotification/Timeout", 10).toInt();
+  useHints = s.value("DesktopNotification/UseHints", false).toBool();
+  xHint = s.value("DesktopNotification/XHint", 0).toInt();
+  yHint = s.value("DesktopNotification/YHint", 0).toInt();
+  queueNotifications = s.value("DesktopNotification/QueueNotifications", true).toBool();
+
+  ui.enabled->setChecked(enabled);
+  ui.useTimeout->setChecked(useTimeout);
+  ui.timeout->setValue(timeout/1000);
+  ui.useHints->setChecked(useHints);
+  ui.xHint->setValue(xHint);
+  ui.yHint->setValue(yHint);
+  ui.queueNotifications->setChecked(queueNotifications);
+
+  setChangedState(false);
+}
 
 
+void DesktopNotificationBackend::ConfigWidget::save() {
+  NotificationSettings s;
+  s.setValue("DesktopNotification/Enabled", ui.enabled->isChecked());
+  s.setValue("DesktopNotification/UseTimeout", ui.useTimeout->isChecked());
+  s.setValue("DesktopNotification/Timeout", ui.timeout->value() * 1000);
+  s.setValue("DesktopNotification/UseHints", ui.useHints->isChecked());
+  s.setValue("DesktopNotification/XHint", ui.xHint->value());
+  s.setValue("DesktopNotification/YHint", ui.yHint->value());
+  s.setValue("DesktopNotification/QueueNotifications", ui.queueNotifications->isChecked());
+
+  load();
+}
index 0c06b70..4427afe 100644 (file)
 #ifndef DESKTOPNOTIFICATIONBACKEND_H_
 #define DESKTOPNOTIFICATIONBACKEND_H_
 
 #ifndef DESKTOPNOTIFICATIONBACKEND_H_
 #define DESKTOPNOTIFICATIONBACKEND_H_
 
+#include <QHash>
+
 #include "abstractnotificationbackend.h"
 
 #include "settingspage.h"
 
 #include "desktopnotificationinterface.h"
 #include "abstractnotificationbackend.h"
 
 #include "settingspage.h"
 
 #include "desktopnotificationinterface.h"
+#include "ui_desktopnotificationconfigwidget.h"
 
 //! Implements the freedesktop.org notifications specification (via D-Bus)
 /**
 
 //! Implements the freedesktop.org notifications specification (via D-Bus)
 /**
@@ -49,15 +52,49 @@ private slots:
   void desktopNotificationInvoked(uint id, const QString &action);
 
   void enabledChanged(const QVariant &);
   void desktopNotificationInvoked(uint id, const QString &action);
 
   void enabledChanged(const QVariant &);
+  void useHintsChanged(const QVariant &);
   void xHintChanged(const QVariant &);
   void yHintChanged(const QVariant &);
   void xHintChanged(const QVariant &);
   void yHintChanged(const QVariant &);
+  void queueNotificationsChanged(const QVariant &);
+  void timeoutChanged(const QVariant &);
+  void useTimeoutChanged(const QVariant &);
 
 private:
 
 private:
+  class ConfigWidget;
+  SettingsPage *_configWidget;
+
   org::freedesktop::Notifications *_dbusInterface;
   org::freedesktop::Notifications *_dbusInterface;
-  quint32 _dbusNotificationId;
+  bool _daemonSupportsMarkup;
+  quint32 _lastDbusId;
+  QHash<uint, uint> _idMap; ///< Maps our own notification Id to the D-Bus one
 
 
-  bool _enabled;
+  bool _enabled, _queueNotifications, _useHints;
   int _xHint, _yHint;
   int _xHint, _yHint;
+  int _timeout;
+  bool _useTimeout;
+
+};
+
+class DesktopNotificationBackend::ConfigWidget : public SettingsPage {
+  Q_OBJECT
+
+  public:
+    ConfigWidget(QWidget *parent = 0);
+    void save();
+    void load();
+    bool hasDefaults() const;
+    void defaults();
+
+  private slots:
+    void widgetChanged();
+
+  private:
+    Ui::DesktopNotificationConfigWidget ui;
+    int xHint, yHint;
+    bool useHints, queueNotifications;
+    int timeout;
+    bool useTimeout;
+    bool enabled;
 };
 
 #endif
 };
 
 #endif
index 3485cca..9cc1c3e 100644 (file)
@@ -89,7 +89,7 @@ MainWin::MainWin(QWidget *parent)
 
   QtUi::registerNotificationBackend(new SystrayNotificationBackend(this));
 #ifdef HAVE_DBUS
 
   QtUi::registerNotificationBackend(new SystrayNotificationBackend(this));
 #ifdef HAVE_DBUS
-  //QtUi::registerNotificationBackend(new DesktopNotificationBackend(this));
+  QtUi::registerNotificationBackend(new DesktopNotificationBackend(this));
 #endif
 
   QtUiApplication* app = qobject_cast<QtUiApplication*> qApp;
 #endif
 
   QtUiApplication* app = qobject_cast<QtUiApplication*> qApp;
diff --git a/src/qtui/ui/desktopnotificationconfigwidget.ui b/src/qtui/ui/desktopnotificationconfigwidget.ui
new file mode 100644 (file)
index 0000000..e641282
--- /dev/null
@@ -0,0 +1,157 @@
+<ui version="4.0" >
+ <class>DesktopNotificationConfigWidget</class>
+ <widget class="QWidget" name="DesktopNotificationConfigWidget" >
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>435</width>
+    <height>144</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2" >
+   <item>
+    <widget class="QGroupBox" name="enabled" >
+     <property name="title" >
+      <string>Desktop Notification (via D-Bus)</string>
+     </property>
+     <property name="checkable" >
+      <bool>true</bool>
+     </property>
+     <property name="checked" >
+      <bool>false</bool>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout" >
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_2" >
+        <item>
+         <widget class="QCheckBox" name="useTimeout" >
+          <property name="text" >
+           <string>Timeout:</string>
+          </property>
+          <property name="checked" >
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QSpinBox" name="timeout" >
+          <property name="specialValueText" >
+           <string/>
+          </property>
+          <property name="suffix" >
+           <string> s</string>
+          </property>
+          <property name="minimum" >
+           <number>1</number>
+          </property>
+          <property name="value" >
+           <number>10</number>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <spacer name="horizontalSpacer" >
+          <property name="orientation" >
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeHint" stdset="0" >
+           <size>
+            <width>40</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout" >
+        <item>
+         <widget class="QCheckBox" name="useHints" >
+          <property name="text" >
+           <string>Position hint:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QSpinBox" name="xHint" >
+          <property name="enabled" >
+           <bool>false</bool>
+          </property>
+          <property name="suffix" >
+           <string> px</string>
+          </property>
+          <property name="prefix" >
+           <string>X: </string>
+          </property>
+          <property name="maximum" >
+           <number>9999</number>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QSpinBox" name="yHint" >
+          <property name="enabled" >
+           <bool>false</bool>
+          </property>
+          <property name="suffix" >
+           <string> px</string>
+          </property>
+          <property name="prefix" >
+           <string>Y: </string>
+          </property>
+          <property name="maximum" >
+           <number>9999</number>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <spacer name="horizontalSpacer_2" >
+          <property name="orientation" >
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeHint" stdset="0" >
+           <size>
+            <width>40</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="queueNotifications" >
+        <property name="text" >
+         <string>Queue unread notifications</string>
+        </property>
+        <property name="checked" >
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer" >
+     <property name="orientation" >
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0" >
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>