Browse Source

Added tray icon

Malte Veerman 6 years ago
parent
commit
11f0950af6

+ 1 - 1
CMakeLists.txt

@@ -44,7 +44,7 @@ include(FindPkgConfig)
 
 #Find Qt5
 find_package(Qt5Core REQUIRED)
-find_package(Qt5 COMPONENTS Quick)
+find_package(Qt5 5.8 COMPONENTS Quick)
 set_package_properties(Qt5Quick PROPERTIES TYPE RUNTIME PURPOSE "Needed by the QML parts")
 
 #Find KF5

+ 5 - 3
fancontrol-gui/CMakeLists.txt

@@ -1,5 +1,6 @@
 set(Fancontrol_GUI_SRCS src/main.cpp
-                        src/windowconfig.cpp)
+                        src/windowconfig.cpp
+                        src/systemtrayicon.cpp)
 
 set(LIBRARIES Qt5::Gui
               Qt5::Widgets
@@ -7,10 +8,11 @@ set(LIBRARIES Qt5::Gui
               KF5::Declarative
               KF5::I18n
               KF5::ConfigGui
-              KF5::ConfigCore)
+              KF5::ConfigCore
+              KF5::Notifications)
 
 find_package(Qt5 COMPONENTS Gui Widgets REQUIRED)
-find_package(KF5 COMPONENTS CoreAddons Package Declarative Config REQUIRED)
+find_package(KF5 COMPONENTS CoreAddons Package Declarative Config Notifications REQUIRED)
 
 include_directories(${Qt5Widgets_INCLUDE_DIRS})
 add_definitions(${Qt5Widgets_DEFINITIONS})

+ 28 - 0
fancontrol-gui/package/contents/ui/Application.qml

@@ -22,6 +22,8 @@ import QtQuick 2.4
 import QtQuick.Controls 1.3
 import QtQuick.Dialogs 1.3
 import QtQuick.Layouts 1.1
+import QtQml 2.8
+import Fancontrol.Gui 1.0 as Gui
 import Fancontrol.Qml 1.0 as Fancontrol
 
 
@@ -39,6 +41,7 @@ ApplicationWindow {
         if (Fancontrol.Base.needsApply && !saveOnCloseDialog.answered) {
             close.accepted = false;
             saveOnCloseDialog.open();
+            return;
         }
     }
 
@@ -102,6 +105,30 @@ ApplicationWindow {
         }
     }
 
+    Loader {
+        id: trayLoader
+
+        active: Fancontrol.Base.showTray
+
+        sourceComponent: Component {
+            Gui.SystemTrayIcon {
+                title: "Fancontrol-GUI"
+                iconName: "org.kde.fancontrol.gui"
+                profileModel: Fancontrol.Base.profileModel
+
+                onActivateRequested: {
+                    window.show()
+                    window.raise()
+                    window.requestActivate()
+                }
+                onActivateProfile: {
+                    Fancontrol.Base.applyProfile(profile);
+                    Fancontrol.Base.apply();
+                }
+            }
+        }
+    }
+
     Fancontrol.ErrorDialog {
         id: errorDialog
 
@@ -174,6 +201,7 @@ ApplicationWindow {
 
         onTriggered: Fancontrol.Base.systemdCom.serviceActive = false
     }
+
     SystemPalette {
         id: palette
     }

+ 5 - 0
fancontrol-gui/package/contents/ui/PwmFansTab.qml

@@ -61,6 +61,11 @@ Item {
             Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
 
             onActivated: Fancontrol.Base.applyProfile(index)
+
+            Connections {
+                target: Fancontrol.Base
+                onProfileChanged: profileComboBox.currentIndex = profile
+            }
         }
         Button {
             Layout.alignment: Qt.AlignRight | Qt.AlignVCenter

+ 25 - 0
fancontrol-gui/package/contents/ui/SettingsTab.qml

@@ -208,6 +208,31 @@ Item {
                 }
             }
         }
+        RowLayout {
+            width: column.width
+
+            Label {
+                Layout.preferredWidth: root.textWidth
+                clip: true
+                text: i18n("Show tray icon:")
+                horizontalAlignment: Text.AlignRight
+                Component.onCompleted: root.textWidth = Math.max(root.textWidth, contentWidth)
+            }
+            CheckBox {
+                id: trayBox
+
+                Layout.minimumWidth: implicitWidth
+                Layout.fillWidth: true
+                checked: Fancontrol.Base.showTray
+                onCheckedChanged: Fancontrol.Base.showTray = checked
+
+                Connections {
+                    target: Fancontrol.Base
+                    onShowTrayChanged: if (Fancontrol.Base.showTray != trayBox.checked) trayBox.checked = Fancontrol.Base.showTray
+                }
+            }
+        }
+
         FileDialog {
             id: openFileDialog
             title: i18n("Please choose a configuration file")

+ 4 - 3
fancontrol-gui/src/main.cpp

@@ -17,20 +17,19 @@
  *
  */
 
-#include <QtWidgets/QApplication>
 #include <QtQml/QQmlContext>
 #include <QtCore/QCommandLineParser>
 #include <QtCore/QLoggingCategory>
 #include <QtGui/QIcon>
+#include <QtWidgets/QApplication>
 
 #include <KDeclarative/QmlObject>
 #include <KI18n/KLocalizedString>
 #include <KCoreAddons/KAboutData>
 
+#include "systemtrayicon.h"
 #include "windowconfig.h"
 
-#include <QDebug>
-
 
 Q_DECLARE_LOGGING_CATEGORY(FANCONTROL)
 Q_LOGGING_CATEGORY(FANCONTROL, "fancontrol-gui")
@@ -60,6 +59,8 @@ int main(int argc, char *argv[])
     about.processCommandLine(parser);
     delete parser;
 
+    qmlRegisterType<SystemTrayIcon>("Fancontrol.Gui", 1, 0, "SystemTrayIcon");
+
     KDeclarative::QmlObject qmlObject;
     qmlObject.rootContext()->setContextProperty(QStringLiteral("windowConfig"), WindowConfig::instance());
     qmlObject.loadPackage("org.kde.fancontrol.gui");

+ 64 - 0
fancontrol-gui/src/systemtrayicon.cpp

@@ -0,0 +1,64 @@
+/*
+ * Copyright 2018  Malte Veerman <malte.veerman@gmail.com>
+ *
+ * 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 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "systemtrayicon.h"
+
+#include <KLocalizedString>
+
+
+SystemTrayIcon::SystemTrayIcon(QObject *parent) : KStatusNotifierItem(QStringLiteral("fancontrold.gui"), parent)
+{
+    setCategory(KStatusNotifierItem::ApplicationStatus);
+
+    m_profilesMenu = contextMenu()->addMenu(i18n("Profiles"));
+}
+
+void SystemTrayIcon::setProfileModel(QStringListModel* model)
+{
+    if (m_profileModel == model)
+        return;
+
+    m_profileModel = model;
+    emit profileModelChanged();
+
+    if (!m_profileModel)
+    {
+        setProfiles(QStringList());
+        return;
+    }
+
+    setProfiles(m_profileModel->stringList());
+
+    connect(m_profileModel, &QStringListModel::dataChanged, this, [this] () { setProfiles(m_profileModel->stringList()); });
+    connect(m_profileModel, &QStringListModel::rowsInserted, this, [this] () { setProfiles(m_profileModel->stringList()); });
+    connect(m_profileModel, &QStringListModel::rowsRemoved, this, [this] () { setProfiles(m_profileModel->stringList()); });
+    connect(m_profileModel, &QStringListModel::modelReset, this, [this] () { setProfiles(m_profileModel->stringList()); });
+}
+
+void SystemTrayIcon::setProfiles(const QStringList& profiles)
+{
+    m_profilesMenu->clear();
+
+    for (const auto &profile : profiles)
+    {
+        const auto action = m_profilesMenu->addAction(profile);
+        connect(action, &QAction::triggered, this, [this, profile] () { emit activateProfile(profile); });
+    }
+}

+ 57 - 0
fancontrol-gui/src/systemtrayicon.h

@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018  Malte Veerman <malte.veerman@gmail.com>
+ *
+ * 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 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SYSTEMTRAYICON_H
+#define SYSTEMTRAYICON_H
+
+
+#include <KNotifications/KStatusNotifierItem>
+
+#include <QtCore/QStringListModel>
+#include <QtWidgets/QMenu>
+
+
+class SystemTrayIcon : public KStatusNotifierItem
+{
+    Q_OBJECT
+    Q_PROPERTY(QStringListModel* profileModel READ profileModel WRITE setProfileModel NOTIFY profileModelChanged)
+
+public:
+
+    SystemTrayIcon(QObject *parent = nullptr);
+
+    QStringListModel *profileModel() const { return m_profileModel; }
+    void setProfileModel(QStringListModel *model);
+    void setProfiles(const QStringList &profiles);
+
+
+signals:
+
+    void activateProfile(QString profile);
+    void profileModelChanged();
+
+
+private:
+
+    QStringListModel *m_profileModel;
+    QMenu *m_profilesMenu;
+};
+
+#endif // SYSTEMTRAYICON_H

+ 4 - 4
fancontrol-gui/src/windowconfig.cpp

@@ -34,7 +34,7 @@
 #endif
 
 
-WindowConfig *WindowConfig::m_instance = Q_NULLPTR;
+WindowConfig *WindowConfig::s_instance = Q_NULLPTR;
 
 WindowConfig::WindowConfig(QObject *parent) : QObject(parent)
 {
@@ -42,10 +42,10 @@ WindowConfig::WindowConfig(QObject *parent) : QObject(parent)
 
 WindowConfig* WindowConfig::instance()
 {
-    if (!m_instance)
-        m_instance = new WindowConfig;
+    if (!s_instance)
+        s_instance = new WindowConfig;
 
-    return m_instance;
+    return s_instance;
 }
 
 void WindowConfig::save(QWindow *window)

+ 9 - 9
fancontrol-gui/src/windowconfig.h

@@ -30,22 +30,22 @@ class QWindow;
 class WindowConfig : public QObject
 {
     Q_OBJECT
-    
+
 public:
-    
+
     static WindowConfig *instance();
-    
+
     Q_INVOKABLE void save(QWindow *window);
     Q_INVOKABLE void restore(QWindow *window);
-    
-    
+
+
 private:
-    
+
     WindowConfig(QObject *parent = Q_NULLPTR);
     ~WindowConfig() {}
     Q_DISABLE_COPY(WindowConfig)
-    
-    static WindowConfig *m_instance;
+
+    static WindowConfig *s_instance;
 };
 
-#endif //WINDOWCONFIG_H
+#endif //WINDOWCONFIG_H

+ 2 - 0
import/src/config.cpp

@@ -50,6 +50,8 @@ Config::Config(QObject *parent) : KCoreConfigSkeleton(KSharedConfig::openConfig(
     addItemPath(QStringLiteral("ConfigUrl"), m_configUrl, QStringLiteral("file://") + STANDARD_CONFIG_FILE);
     addItemStringList(QStringLiteral("Profiles"), m_profiles, QStringList());
     addItemStringList(QStringLiteral("ProfileNames"), m_profileNames, QStringList());
+    addItemInt(QStringLiteral("CurrentProfile"), m_currentProfile, 0);
+    addItemBool(QStringLiteral("ShowTray"), m_showTray, true);
 
     load();
 }

+ 2 - 0
import/src/config.h

@@ -53,6 +53,8 @@ private:
     QString m_configUrl;
     QStringList m_profiles;
     QStringList m_profileNames;
+    int m_currentProfile;
+    bool m_showTray;
 };
 
 }

+ 30 - 1
import/src/guibase.cpp

@@ -77,7 +77,12 @@ void GUIBase::load()
     m_config->load();
     m_configValid = m_loader->load(configUrl());
 
-    m_profileModel->setStringList(m_config->findItem(QStringLiteral("ProfileNames"))->property().toStringList());
+    auto profileNames = m_config->findItem(QStringLiteral("ProfileNames"))->property().toStringList();
+    m_profileModel->setStringList(profileNames);
+
+    m_config->setCurrentGroup(QStringLiteral("preferences"));
+    int currentProfile = m_config->findItem(QStringLiteral("CurrentProfile"))->property().toInt();
+    emit profileChanged(currentProfile);
 
 #ifndef NO_SYSTEMD
     m_com->setServiceName(serviceName());
@@ -114,6 +119,12 @@ QUrl GUIBase::configUrl() const
     return QUrl(m_config->findItem(QStringLiteral("ConfigUrl"))->property().toString());
 }
 
+bool GUIBase::showTray() const
+{
+    m_config->setCurrentGroup(QStringLiteral("preferences"));
+    return m_config->findItem(QStringLiteral("ShowTray"))->property().toBool();
+}
+
 void GUIBase::setMaxTemp(qreal temp)
 {
     if (temp != maxTemp())
@@ -173,6 +184,21 @@ void GUIBase::setConfigUrl(const QUrl &url)
     }
 }
 
+void GUIBase::setShowTray(bool show)
+{
+    if (showTray() == show)
+        return;
+
+    qDebug() << show;
+
+    m_config->setCurrentGroup(QStringLiteral("preferences"));
+    m_config->findItem(QStringLiteral("ShowTray"))->setProperty(show);
+    emit showTrayChanged();
+
+    m_configChanged = true;
+    emit needsApplyChanged();
+}
+
 bool GUIBase::needsApply() const
 {
 #ifndef NO_SYSTEMD
@@ -292,6 +318,9 @@ void GUIBase::applyProfile(int index)
         return;
 
     m_loader->load(newConfig);
+
+    m_config->findItem(QStringLiteral("CurrentProfile"))->setProperty(index);
+    emit profileChanged(index);
 }
 
 void GUIBase::saveProfile(const QString& profile, bool updateModel)

+ 5 - 0
import/src/guibase.h

@@ -61,6 +61,7 @@ class GUIBase : public QObject
     Q_PROPERTY(bool configValid READ configValid NOTIFY configUrlChanged)
     Q_PROPERTY(QString error READ error NOTIFY errorChanged)
     Q_PROPERTY(bool needsApply READ needsApply NOTIFY needsApplyChanged)
+    Q_PROPERTY(bool showTray READ showTray WRITE setShowTray NOTIFY showTrayChanged)
 
 public:
 
@@ -85,6 +86,8 @@ public:
     void setConfigUrl(const QUrl &url);
     void setUnit(const QString &unit) { if (unit != m_unit) { m_unit = unit; emit unitChanged(m_unit); } }
     bool needsApply() const;
+    bool showTray() const;
+    void setShowTray(bool show);
     PwmFanModel *pwmFanModel() const { return m_pwmFanModel; }
     TempModel *tempModel() const { return m_tempModel; }
     QStringListModel *profileModel() const { return m_profileModel; }
@@ -114,6 +117,8 @@ signals:
     void errorChanged();
     void criticalError();
     void needsApplyChanged();
+    void showTrayChanged();
+    void profileChanged(int profile);
 
 private: