Implement QtMultimedia notification backend
authorHendrik Leppkes <h.leppkes@gmail.com>
Wed, 10 Feb 2016 09:21:09 +0000 (10:21 +0100)
committerManuel Nickschas <sputnick@quassel-irc.org>
Mon, 13 Jun 2016 20:17:08 +0000 (22:17 +0200)
Phonon is no longer officially supported since Qt5, while QtMultimedia
implements all the required functionality to provide audio notifications.

Closes GH-182.

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

index d238691..38733c6 100644 (file)
@@ -215,13 +215,22 @@ if (USE_QT5)
             )
         endif()
 
             )
         endif()
 
-        find_package(Phonon4Qt5 QUIET)
-        set_package_properties(Phonon4Qt5 PROPERTIES TYPE RECOMMENDED
-            URL "https://projects.kde.org/projects/kdesupport/phonon"
-            DESCRIPTION "a multimedia abstraction library"
+        find_package(Qt5Multimedia QUIET)
+        set_package_properties(Qt5Multimedia PROPERTIES TYPE RECOMMENDED
+            URL "http://qt.digia.com"
+            DESCRIPTION "Multimedia support for Qt5"
             PURPOSE     "Required for audio notifications"
         )
 
             PURPOSE     "Required for audio notifications"
         )
 
+        if (NOT Qt5Multimedia_FOUND)
+            find_package(Phonon4Qt5 QUIET)
+            set_package_properties(Phonon4Qt5 PROPERTIES TYPE RECOMMENDED
+                URL "https://projects.kde.org/projects/kdesupport/phonon"
+                DESCRIPTION "a multimedia abstraction library"
+                PURPOSE     "Required for audio notifications"
+            )
+        endif()
+
         find_package(LibsnoreQt5 0.7.0 QUIET)
         set_package_properties(LibsnoreQt5 PROPERTIES TYPE OPTIONAL
             URL "https://projects.kde.org/projects/playground/libs/snorenotify"
         find_package(LibsnoreQt5 0.7.0 QUIET)
         set_package_properties(LibsnoreQt5 PROPERTIES TYPE OPTIONAL
             URL "https://projects.kde.org/projects/playground/libs/snorenotify"
index eedb69c..fdf5eaa 100644 (file)
@@ -102,6 +102,13 @@ if (LibsnoreQt5_FOUND)
     list(APPEND LIBS    Snore::Libsnore Snore::LibsnoreSettings)
 endif()
 
     list(APPEND LIBS    Snore::Libsnore Snore::LibsnoreSettings)
 endif()
 
+if (Qt5Multimedia_FOUND)
+    add_definitions(-DHAVE_QTMULTIMEDIA)
+    list(APPEND QT_MODULES Multimedia)
+    set(SOURCES ${SOURCES} qtmultimedianotificationbackend.cpp)
+    set(FORMS ${FORMS}     qtmultimedianotificationconfigwidget.ui)
+endif()
+
 if (PHONON_FOUND OR Phonon4Qt5_FOUND)
     add_definitions(-DHAVE_PHONON)
     include_directories(${PHONON_INCLUDES})
 if (PHONON_FOUND OR Phonon4Qt5_FOUND)
     add_definitions(-DHAVE_PHONON)
     include_directories(${PHONON_INCLUDES})
index ca31fce..640b09c 100644 (file)
 #include "verticaldock.h"
 
 #ifndef HAVE_KDE
 #include "verticaldock.h"
 
 #ifndef HAVE_KDE
+#  ifdef HAVE_QTMULTIMEDIA
+#    include "qtmultimedianotificationbackend.h"
+#  endif
 #  ifdef HAVE_PHONON
 #    include "phononnotificationbackend.h"
 #  endif
 #  ifdef HAVE_PHONON
 #    include "phononnotificationbackend.h"
 #  endif
@@ -228,6 +231,9 @@ void MainWin::init()
     setupHotList();
 
 #ifndef HAVE_KDE
     setupHotList();
 
 #ifndef HAVE_KDE
+#  ifdef HAVE_QTMULTIMEDIA
+    QtUi::registerNotificationBackend(new QtMultimediaNotificationBackend(this));
+#  endif
 #  ifdef HAVE_PHONON
     QtUi::registerNotificationBackend(new PhononNotificationBackend(this));
 #  endif
 #  ifdef HAVE_PHONON
     QtUi::registerNotificationBackend(new PhononNotificationBackend(this));
 #  endif
diff --git a/src/qtui/qtmultimedianotificationbackend.cpp b/src/qtui/qtmultimedianotificationbackend.cpp
new file mode 100644 (file)
index 0000000..746c21c
--- /dev/null
@@ -0,0 +1,211 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2015 by the Quassel Project                        *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   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) version 3.                                           *
+ *                                                                         *
+ *   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 program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
+ ***************************************************************************/
+
+#include <QFileDialog>
+#include <QIcon>
+#include <QUrl>
+
+#include "qtmultimedianotificationbackend.h"
+
+#include "clientsettings.h"
+#include "mainwin.h"
+#include "qtui.h"
+
+QtMultimediaNotificationBackend::QtMultimediaNotificationBackend(QObject *parent)
+    : AbstractNotificationBackend(parent),
+    _media(0)
+{
+    NotificationSettings notificationSettings;
+    notificationSettings.notify("QtMultimedia/Enabled", this, SLOT(enabledChanged(const QVariant &)));
+    notificationSettings.notify("QtMultimedia/AudioFile", this, SLOT(audioFileChanged(const QVariant &)));
+
+    createMediaObject(notificationSettings.value("QtMultimedia/AudioFile", QString()).toString());
+
+    _enabled = notificationSettings.value("QtMultimedia/Enabled", true).toBool();
+}
+
+
+QtMultimediaNotificationBackend::~QtMultimediaNotificationBackend()
+{
+    if (_media)
+        delete _media;
+}
+
+
+void QtMultimediaNotificationBackend::notify(const Notification &notification)
+{
+    if (_enabled && (notification.type == Highlight || notification.type == PrivMsg)) {
+        if (_media && _media->availability() == QMultimedia::Available) {
+            _media->stop();
+            _media->play();
+        }
+        else
+            QApplication::beep();
+    }
+}
+
+
+void QtMultimediaNotificationBackend::close(uint notificationId)
+{
+    Q_UNUSED(notificationId);
+}
+
+
+void QtMultimediaNotificationBackend::enabledChanged(const QVariant &v)
+{
+    _enabled = v.toBool();
+}
+
+
+void QtMultimediaNotificationBackend::audioFileChanged(const QVariant &v)
+{
+    createMediaObject(v.toString());
+}
+
+
+SettingsPage *QtMultimediaNotificationBackend::createConfigWidget() const
+{
+    return new ConfigWidget();
+}
+
+
+void QtMultimediaNotificationBackend::createMediaObject(const QString &file)
+{
+    if (_media)
+        delete _media;
+
+    if (file.isEmpty()) {
+        _media = 0;
+        return;
+    }
+
+    _media = new QMediaPlayer;
+    _media->setMedia(QUrl::fromLocalFile(file));
+}
+
+
+/***************************************************************************/
+
+QtMultimediaNotificationBackend::ConfigWidget::ConfigWidget(QWidget *parent)
+    : SettingsPage("Internal", "QtMultimediaNotification", parent),
+    audioPreview(0)
+{
+    ui.setupUi(this);
+    ui.enabled->setIcon(QIcon::fromTheme("media-playback-start"));
+    ui.play->setIcon(QIcon::fromTheme("media-playback-start"));
+    ui.open->setIcon(QIcon::fromTheme("document-open"));
+
+    QMediaPlayer *player = new QMediaPlayer;
+    _audioAvailable = player->availability() == QMultimedia::Available;
+    delete player;
+
+    connect(ui.enabled, SIGNAL(toggled(bool)), SLOT(widgetChanged()));
+    connect(ui.filename, SIGNAL(textChanged(const QString &)), SLOT(widgetChanged()));
+}
+
+
+QtMultimediaNotificationBackend::ConfigWidget::~ConfigWidget()
+{
+    if (audioPreview)
+        delete audioPreview;
+}
+
+
+void QtMultimediaNotificationBackend::ConfigWidget::widgetChanged()
+{
+    if (! _audioAvailable) {
+        ui.play->setEnabled(ui.enabled->isChecked());
+        ui.open->setEnabled(false);
+        ui.filename->setEnabled(false);
+        ui.filename->setText(QString());
+    }
+    else {
+        ui.play->setEnabled(ui.enabled->isChecked() && !ui.filename->text().isEmpty());
+
+        bool changed = (enabled != ui.enabled->isChecked() || filename != ui.filename->text());
+
+        if (changed != hasChanged())
+            setChangedState(changed);
+    }
+}
+
+
+bool QtMultimediaNotificationBackend::ConfigWidget::hasDefaults() const
+{
+    return true;
+}
+
+
+void QtMultimediaNotificationBackend::ConfigWidget::defaults()
+{
+    ui.enabled->setChecked(false);
+    ui.filename->setText(QString());
+    widgetChanged();
+}
+
+
+void QtMultimediaNotificationBackend::ConfigWidget::load()
+{
+    NotificationSettings s;
+    enabled = s.value("QtMultimedia/Enabled", false).toBool();
+    filename = s.value("QtMultimedia/AudioFile", QString()).toString();
+
+    ui.enabled->setChecked(enabled);
+    ui.filename->setText(filename);
+
+    setChangedState(false);
+}
+
+
+void QtMultimediaNotificationBackend::ConfigWidget::save()
+{
+    NotificationSettings s;
+    s.setValue("QtMultimedia/Enabled", ui.enabled->isChecked());
+    s.setValue("QtMultimedia/AudioFile", ui.filename->text());
+    load();
+}
+
+
+void QtMultimediaNotificationBackend::ConfigWidget::on_open_clicked()
+{
+    QString file = QFileDialog::getOpenFileName(this, tr("Select Audio File"));
+    if (!file.isEmpty()) {
+        ui.filename->setText(file);
+        ui.play->setEnabled(true);
+        widgetChanged();
+    }
+}
+
+
+void QtMultimediaNotificationBackend::ConfigWidget::on_play_clicked()
+{
+    if (_audioAvailable) {
+        if (!ui.filename->text().isEmpty()) {
+            if (audioPreview)
+                delete audioPreview;
+
+            audioPreview = new QMediaPlayer;
+            audioPreview->setMedia(QUrl::fromLocalFile(ui.filename->text()));
+            audioPreview->play();
+        }
+    }
+    else
+        QApplication::beep();
+}
diff --git a/src/qtui/qtmultimedianotificationbackend.h b/src/qtui/qtmultimedianotificationbackend.h
new file mode 100644 (file)
index 0000000..aa028bd
--- /dev/null
@@ -0,0 +1,84 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2015 by the Quassel Project                        *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   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) version 3.                                           *
+ *                                                                         *
+ *   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 program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
+ ***************************************************************************/
+
+#ifndef PHONONNOTIFICATIONBACKEND_H_
+#define PHONONNOTIFICATIONBACKEND_H_
+
+#include <QMediaPlayer>
+
+#include "abstractnotificationbackend.h"
+#include "settingspage.h"
+
+#include "ui_qtmultimedianotificationconfigwidget.h"
+
+class QtMultimediaNotificationBackend : public AbstractNotificationBackend
+{
+    Q_OBJECT
+
+public:
+    QtMultimediaNotificationBackend(QObject *parent = 0);
+    ~QtMultimediaNotificationBackend();
+
+    void notify(const Notification &);
+    void close(uint notificationId);
+    virtual SettingsPage *createConfigWidget() const;
+
+private slots:
+    void enabledChanged(const QVariant &);
+    void audioFileChanged(const QVariant &);
+    void createMediaObject(const QString &name);
+
+private:
+    class ConfigWidget;
+
+    bool _enabled;
+    QMediaPlayer *_media;
+};
+
+
+class QtMultimediaNotificationBackend::ConfigWidget : public SettingsPage
+{
+    Q_OBJECT
+
+public:
+    ConfigWidget(QWidget *parent = 0);
+    ~ConfigWidget();
+
+    void save();
+    void load();
+    bool hasDefaults() const;
+    void defaults();
+
+private slots:
+    void widgetChanged();
+    void on_open_clicked();
+    void on_play_clicked();
+
+private:
+    Ui::QtMultimediaNotificationConfigWidget ui;
+
+    bool enabled;
+    bool _audioAvailable;
+    QString filename;
+    QMediaPlayer *audioPreview;
+};
+
+
+#endif
diff --git a/src/qtui/ui/qtmultimedianotificationconfigwidget.ui b/src/qtui/ui/qtmultimedianotificationconfigwidget.ui
new file mode 100644 (file)
index 0000000..539d757
--- /dev/null
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtMultimediaNotificationConfigWidget</class>
+ <widget class="QWidget" name="QtMultimediaNotificationConfigWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>439</width>
+    <height>36</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout">
+   <item>
+    <widget class="QCheckBox" name="enabled">
+     <property name="text">
+      <string>Play a sound</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <spacer name="horizontalSpacer">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::Fixed</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>20</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QToolButton" name="play">
+     <property name="enabled">
+      <bool>false</bool>
+     </property>
+     <property name="toolTip">
+      <string>Prelisten to the selected sound</string>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLineEdit" name="filename">
+     <property name="enabled">
+      <bool>false</bool>
+     </property>
+     <property name="toolTip">
+      <string>Select the sound file to play</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QToolButton" name="open">
+     <property name="enabled">
+      <bool>false</bool>
+     </property>
+     <property name="toolTip">
+      <string>Select the sound file to play</string>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>enabled</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>filename</receiver>
+   <slot>setEnabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>59</x>
+     <y>15</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>246</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>enabled</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>open</receiver>
+   <slot>setEnabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>89</x>
+     <y>18</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>426</x>
+     <y>22</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>