From 87a10c5b33e3e3573eea482c9c43f0cbfe5cc153 Mon Sep 17 00:00:00 2001 From: Martchus Date: Wed, 10 Oct 2018 17:48:48 +0200 Subject: [PATCH] Allow hiding Plasma applet in certain states See https://github.com/Martchus/syncthingtray/issues/23 --- connector/syncthingconnection.cpp | 6 ++-- connector/syncthingconnection.h | 12 ++++++- model/CMakeLists.txt | 4 ++- model/syncthingstatusselectionmodel.cpp | 34 +++++++++++++++++++ model/syncthingstatusselectionmodel.h | 22 ++++++++++++ plasmoid/lib/CMakeLists.txt | 2 +- plasmoid/lib/appearanceoptionpage.ui | 21 ++++++++++-- plasmoid/lib/settingsdialog.cpp | 35 +++++++++++++++---- plasmoid/lib/settingsdialog.h | 33 ++++++++++++++++++ plasmoid/lib/syncthingapplet.cpp | 23 +++++++++++-- plasmoid/lib/syncthingapplet.h | 45 ++++++++++++++++++++++--- plasmoid/testing.md | 6 ++++ widgets/settings/settingsdialog.cpp | 6 ++++ widgets/settings/settingsdialog.h | 1 + 14 files changed, 229 insertions(+), 21 deletions(-) create mode 100644 model/syncthingstatusselectionmodel.cpp create mode 100644 model/syncthingstatusselectionmodel.h diff --git a/connector/syncthingconnection.cpp b/connector/syncthingconnection.cpp index 7f66ba2..e707387 100644 --- a/connector/syncthingconnection.cpp +++ b/connector/syncthingconnection.cpp @@ -117,11 +117,11 @@ bool SyncthingConnection::isLocal() const } /*! - * \brief Returns the string representation of the current status(). + * \brief Returns the string representation of the specified \a status. */ -QString SyncthingConnection::statusText() const +QString SyncthingConnection::statusText(SyncthingStatus status) { - switch (m_status) { + switch (status) { case SyncthingStatus::Disconnected: return tr("disconnected"); case SyncthingStatus::Reconnecting: diff --git a/connector/syncthingconnection.h b/connector/syncthingconnection.h index 4cf8f1b..28e6a9b 100644 --- a/connector/syncthingconnection.h +++ b/connector/syncthingconnection.h @@ -106,6 +106,7 @@ public: void setCredentials(const QString &user, const QString &password); SyncthingStatus status() const; QString statusText() const; + static QString statusText(SyncthingStatus status); bool isConnected() const; bool hasUnreadNotifications() const; bool hasOutOfSyncDirs() const; @@ -379,7 +380,16 @@ inline const QString &SyncthingConnection::password() const */ inline void SyncthingConnection::setCredentials(const QString &user, const QString &password) { - m_user = user, m_password = password; + m_user = user; + m_password = password; +} + +/*! + * \brief Returns the string representation of the current status(). + */ +inline QString SyncthingConnection::statusText() const +{ + return statusText(m_status); } /*! diff --git a/model/CMakeLists.txt b/model/CMakeLists.txt index d5b6975..ce429c3 100644 --- a/model/CMakeLists.txt +++ b/model/CMakeLists.txt @@ -16,6 +16,7 @@ set(HEADER_FILES syncthingdirectorymodel.h syncthingdevicemodel.h syncthingdownloadmodel.h + syncthingstatusselectionmodel.h syncthingicons.h colors.h ) @@ -24,6 +25,7 @@ set(SRC_FILES syncthingdirectorymodel.cpp syncthingdevicemodel.cpp syncthingdownloadmodel.cpp + syncthingstatusselectionmodel.cpp syncthingicons.cpp ) set(RES_FILES @@ -41,7 +43,7 @@ use_cpp_utilities() # find qtutilities (only CMake modules used) find_package(qtutilities 5.0.0 REQUIRED) -list(APPEND CMAKE_MODULE_PATH ${QT_UTILITIES_MODULE_DIRS}) +use_qt_utilities() # find backend libraries find_package(syncthingconnector ${META_APP_VERSION} REQUIRED) diff --git a/model/syncthingstatusselectionmodel.cpp b/model/syncthingstatusselectionmodel.cpp new file mode 100644 index 0000000..097169a --- /dev/null +++ b/model/syncthingstatusselectionmodel.cpp @@ -0,0 +1,34 @@ +#include "./syncthingstatusselectionmodel.h" + +#include "../connector/syncthingconnection.h" + +using namespace Models; + +namespace Data { + +inline ChecklistItem itemFor(SyncthingStatus status) +{ + return ChecklistItem(static_cast(status), QString(), Qt::Unchecked); +} + +SyncthingStatusSelectionModel::SyncthingStatusSelectionModel(QObject *parent) + : ChecklistModel(parent) +{ + setItems({ + itemFor(SyncthingStatus::Disconnected), + itemFor(SyncthingStatus::Reconnecting), + itemFor(SyncthingStatus::Idle), + itemFor(SyncthingStatus::Scanning), + itemFor(SyncthingStatus::Paused), + itemFor(SyncthingStatus::Synchronizing), + itemFor(SyncthingStatus::OutOfSync), + itemFor(SyncthingStatus::BeingDestroyed), + }); +} + +QString SyncthingStatusSelectionModel::labelForId(const QVariant &id) const +{ + return SyncthingConnection::statusText(static_cast(id.toInt())); +} + +} // namespace Data diff --git a/model/syncthingstatusselectionmodel.h b/model/syncthingstatusselectionmodel.h new file mode 100644 index 0000000..a5b2cbe --- /dev/null +++ b/model/syncthingstatusselectionmodel.h @@ -0,0 +1,22 @@ +#ifndef DATA_SYNCTHINGSTATUSSELECTIONMODELL_H +#define DATA_SYNCTHINGSTATUSSELECTIONMODELL_H + +#include "./global.h" + +#include + +namespace Data { + +class LIB_SYNCTHING_MODEL_EXPORT SyncthingStatusSelectionModel : public Models::ChecklistModel { + Q_OBJECT + +public: + explicit SyncthingStatusSelectionModel(QObject *parent = nullptr); + QString labelForId(const QVariant &id) const override; + +protected: +}; + +} // namespace Data + +#endif // DATA_SYNCTHINGSTATUSSELECTIONMODELL_H diff --git a/plasmoid/lib/CMakeLists.txt b/plasmoid/lib/CMakeLists.txt index 689ce74..2ed205e 100644 --- a/plasmoid/lib/CMakeLists.txt +++ b/plasmoid/lib/CMakeLists.txt @@ -39,7 +39,7 @@ find_package(c++utilities 4.10.0 REQUIRED) list(APPEND CMAKE_MODULE_PATH ${CPP_UTILITIES_MODULE_DIRS}) # find qtutilities -find_package(qtutilities 5.10.0 REQUIRED) +find_package(qtutilities 5.12.0 REQUIRED) use_qt_utilities() # check whether qtutilities supports DBus notifications diff --git a/plasmoid/lib/appearanceoptionpage.ui b/plasmoid/lib/appearanceoptionpage.ui index 268206f..2a7bf1d 100644 --- a/plasmoid/lib/appearanceoptionpage.ui +++ b/plasmoid/lib/appearanceoptionpage.ui @@ -19,14 +19,14 @@ - + Colors - + Bright custom text colors (use for dark color scheme) @@ -118,6 +118,23 @@ + + + + States to enable passive mode + + + + + + + QAbstractItemView::NoSelection + + + QListView::Batched + + + diff --git a/plasmoid/lib/settingsdialog.cpp b/plasmoid/lib/settingsdialog.cpp index 09e7ff6..6532c72 100644 --- a/plasmoid/lib/settingsdialog.cpp +++ b/plasmoid/lib/settingsdialog.cpp @@ -6,6 +6,7 @@ #include "../../widgets/settings/settingsdialog.h" #include +#include #include #include @@ -86,40 +87,62 @@ AppearanceOptionPage::~AppearanceOptionPage() { } +void AppearanceOptionPage::restoreSelectedStates(SyncthingStatusSelectionModel &statusSelectionModel, const KConfigGroup &config, const char *key) +{ + const auto states = config.readEntry(key, QVariantList()); + int row = 0; + for (auto &item : statusSelectionModel.items()) { + statusSelectionModel.setChecked(row++, states.contains(item.id())); + } +} + bool AppearanceOptionPage::apply() { KConfigGroup config = m_applet->config(); config.writeEntry("size", QSize(ui()->widthSpinBox->value(), ui()->heightSpinBox->value())); config.writeEntry("brightColors", ui()->brightTextColorsCheckBox->isChecked()); + + QVariantList passiveStates; + passiveStates.reserve(m_passiveStatusSelection.items().size()); + for (auto &item : m_passiveStatusSelection.items()) { + if (item.isChecked()) { + passiveStates << item.id(); + } + } + config.writeEntry("passiveStates", passiveStates); + return true; } void AppearanceOptionPage::reset() { const KConfigGroup config = m_applet->config(); - const QSize size(config.readEntry("size", QSize(25, 25))); + const auto size(config.readEntry<>("size", QSize(25, 25))); ui()->widthSpinBox->setValue(size.width()); ui()->heightSpinBox->setValue(size.height()); - ui()->brightTextColorsCheckBox->setChecked(config.readEntry("brightColors", false)); + ui()->brightTextColorsCheckBox->setChecked(config.readEntry<>("brightColors", false)); + restoreSelectedStates(m_passiveStatusSelection, config, "passiveStates"); } QWidget *AppearanceOptionPage::setupWidget() { auto *const widget = AppearanceOptionPageBase::setupWidget(); addPlasmoidSpecificNote(ui()->verticalLayout, widget); + ui()->passiveListView->setModel(&m_passiveStatusSelection); return widget; } -QtGui::SettingsDialog *setupSettingsDialog(SyncthingApplet &applet) +SettingsDialog::SettingsDialog(Plasmoid::SyncthingApplet &applet) { // setup categories QList categories; Dialogs::OptionCategory *category; category = new OptionCategory; + m_appearanceOptionPage = new AppearanceOptionPage(applet); category->setDisplayName(QCoreApplication::translate("Plasmoid::SettingsDialog", "Plasmoid")); category->assignPages(QList() - << new ConnectionOptionPage(applet.connection()) << new NotificationsOptionPage(GuiType::Plasmoid) << new AppearanceOptionPage(applet) + << new ConnectionOptionPage(applet.connection()) << new NotificationsOptionPage(GuiType::Plasmoid) << m_appearanceOptionPage << new ShortcutOptionPage(applet)); category->setIcon(QIcon::fromTheme(QStringLiteral("plasma"))); categories << category; @@ -145,7 +168,7 @@ QtGui::SettingsDialog *setupSettingsDialog(SyncthingApplet &applet) category->setIcon( QIcon::fromTheme(QStringLiteral("preferences-other"), QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/preferences-other.svg")))); categories << category; - - return new ::QtGui::SettingsDialog(categories); + categoryModel()->setCategories(categories); } + } // namespace Plasmoid diff --git a/plasmoid/lib/settingsdialog.h b/plasmoid/lib/settingsdialog.h index b47609c..4b95a06 100644 --- a/plasmoid/lib/settingsdialog.h +++ b/plasmoid/lib/settingsdialog.h @@ -1,14 +1,24 @@ #ifndef SETTINGSDIALOG_H #define SETTINGSDIALOG_H +#include "../../model/syncthingstatusselectionmodel.h" + +#include "../../widgets/settings/settingsdialog.h" + #include +#include + QT_FORWARD_DECLARE_CLASS(QKeySequenceEdit) namespace QtGui { class SettingsDialog; } +namespace Data { +class SyncthingStatusSelectionModel; +} + namespace Plasmoid { class SyncthingApplet; @@ -25,12 +35,35 @@ END_DECLARE_OPTION_PAGE BEGIN_DECLARE_UI_FILE_BASED_OPTION_PAGE_CUSTOM_CTOR(AppearanceOptionPage) public: AppearanceOptionPage(SyncthingApplet &applet, QWidget *parentWidget = nullptr); +Data::SyncthingStatusSelectionModel *passiveStatusSelection(); +static void restoreSelectedStates(Data::SyncthingStatusSelectionModel &statusSelectionModel, const KConfigGroup &config, const char *key); private: DECLARE_SETUP_WIDGETS SyncthingApplet *m_applet; +Data::SyncthingStatusSelectionModel m_passiveStatusSelection; END_DECLARE_OPTION_PAGE +inline Data::SyncthingStatusSelectionModel *AppearanceOptionPage::passiveStatusSelection() +{ + return &m_passiveStatusSelection; +} + +class SettingsDialog : public QtGui::SettingsDialog { +public: + SettingsDialog(Plasmoid::SyncthingApplet &applet); + + AppearanceOptionPage *appearanceOptionPage(); + +private: + AppearanceOptionPage *m_appearanceOptionPage; +}; + +inline AppearanceOptionPage *SettingsDialog::appearanceOptionPage() +{ + return m_appearanceOptionPage; +} + QtGui::SettingsDialog *setupSettingsDialog(Plasmoid::SyncthingApplet &applet); } // namespace Plasmoid diff --git a/plasmoid/lib/syncthingapplet.cpp b/plasmoid/lib/syncthingapplet.cpp index 0bfde0f..730f30c 100644 --- a/plasmoid/lib/syncthingapplet.cpp +++ b/plasmoid/lib/syncthingapplet.cpp @@ -202,6 +202,13 @@ bool SyncthingApplet::areNotificationsAvailable() const return !m_notifications.empty(); } +void SyncthingApplet::setPassiveStates(const QList &passiveStates) +{ + m_passiveSelectionModel.setItems(passiveStates); + const auto currentState = static_cast(m_connection.status()); + setPassive(currentState >= 0 && currentState < passiveStates.size() && passiveStates.at(currentState).isChecked()); +} + void SyncthingApplet::updateStatusIconAndTooltip() { m_statusInfo.updateConnectionStatus(m_connection); @@ -212,7 +219,7 @@ void SyncthingApplet::updateStatusIconAndTooltip() void SyncthingApplet::showSettingsDlg() { if (!m_settingsDlg) { - m_settingsDlg = setupSettingsDialog(*this); + m_settingsDlg = new SettingsDialog(*this); // ensure settings take effect when applied connect(m_settingsDlg, &Dialogs::SettingsDialog::applied, this, &SyncthingApplet::handleSettingsChanged); // save plasmoid specific settings to disk when applied @@ -341,6 +348,16 @@ void SyncthingApplet::handleSettingsChanged() m_devModel.setBrightColors(brightColors); m_downloadModel.setBrightColors(brightColors); + // restore selected states + // note: The settings dialog writes this to the Plasmoid's config like the other settings. However, it + // is simpler and more efficient to assign the states directly. Of course this is only possible if + // the dialog has already been shown. + if (m_settingsDlg) { + setPassiveStates(m_settingsDlg->appearanceOptionPage()->passiveStatusSelection()->items()); + } else { + AppearanceOptionPage::restoreSelectedStates(m_passiveSelectionModel, config, "passiveStates"); + } + // apply connection config const int currentConfig = m_currentConnectionConfig; m_currentConnectionConfig = -1; // force update @@ -351,11 +368,13 @@ void SyncthingApplet::handleSettingsChanged() void SyncthingApplet::handleConnectionStatusChanged(SyncthingStatus status) { - VAR_UNUSED(status) if (!m_initialized) { return; } + // update whether passive + setPassive(static_cast(status) < passiveStates().size() && passiveStates().at(static_cast(status)).isChecked()); + // update status icon and tooltip text m_statusInfo.updateConnectionStatus(m_connection); m_statusInfo.updateConnectedDevices(m_connection); diff --git a/plasmoid/lib/syncthingapplet.h b/plasmoid/lib/syncthingapplet.h index 42b99ad..20ea89b 100644 --- a/plasmoid/lib/syncthingapplet.h +++ b/plasmoid/lib/syncthingapplet.h @@ -8,21 +8,19 @@ #include "../../model/syncthingdevicemodel.h" #include "../../model/syncthingdirectorymodel.h" #include "../../model/syncthingdownloadmodel.h" +#include "../../model/syncthingstatusselectionmodel.h" #include "../../connector/syncthingconnection.h" #include "../../connector/syncthingnotifier.h" #include "../../connector/syncthingservice.h" #include +#include #include #include -namespace Dialogs { -class SettingsDialog; -} - namespace Data { class SyncthingConnection; struct SyncthingConnectionSettings; @@ -39,12 +37,15 @@ class WebViewDialog; namespace Plasmoid { +class SettingsDialog; + class SyncthingApplet : public Plasma::Applet { Q_OBJECT Q_PROPERTY(Data::SyncthingConnection *connection READ connection NOTIFY connectionChanged) Q_PROPERTY(Data::SyncthingDirectoryModel *dirModel READ dirModel NOTIFY dirModelChanged) Q_PROPERTY(Data::SyncthingDeviceModel *devModel READ devModel NOTIFY devModelChanged) Q_PROPERTY(Data::SyncthingDownloadModel *downloadModel READ downloadModel NOTIFY downloadModelChanged) + Q_PROPERTY(Data::SyncthingStatusSelectionModel *passiveSelectionModel READ passiveSelectionModel NOTIFY passiveSelectionModelChanged) Q_PROPERTY(Data::SyncthingService *service READ service NOTIFY serviceChanged) Q_PROPERTY(bool local READ isLocal NOTIFY localChanged) Q_PROPERTY(QString statusText READ statusText NOTIFY connectionStatusChanged) @@ -59,6 +60,8 @@ class SyncthingApplet : public Plasma::Applet { Q_PROPERTY(bool startStopEnabled READ isStartStopEnabled NOTIFY settingsChanged) Q_PROPERTY(QSize size READ size WRITE setSize NOTIFY sizeChanged) Q_PROPERTY(bool notificationsAvailable READ areNotificationsAvailable NOTIFY notificationsAvailableChanged) + Q_PROPERTY(bool passive READ isPassive NOTIFY passiveChanged) + Q_PROPERTY(QList passiveStates READ passiveStates WRITE setPassiveStates) public: SyncthingApplet(QObject *parent, const QVariantList &data); @@ -69,6 +72,7 @@ public: Data::SyncthingDirectoryModel *dirModel() const; Data::SyncthingDeviceModel *devModel() const; Data::SyncthingDownloadModel *downloadModel() const; + Data::SyncthingStatusSelectionModel *passiveSelectionModel() const; Data::SyncthingService *service() const; bool isLocal() const; QString statusText() const; @@ -86,6 +90,9 @@ public: QSize size() const; void setSize(const QSize &size); bool areNotificationsAvailable() const; + bool isPassive() const; + const QList &passiveStates() const; + void setPassiveStates(const QList &passiveStates); public Q_SLOTS: void init() Q_DECL_OVERRIDE; @@ -111,6 +118,8 @@ Q_SIGNALS: /// \remarks Never emitted, just to silence "... depends on non-NOTIFYable ..." void downloadModelChanged(); /// \remarks Never emitted, just to silence "... depends on non-NOTIFYable ..." + void passiveSelectionModelChanged(); + /// \remarks Never emitted, just to silence "... depends on non-NOTIFYable ..." void serviceChanged(); void localChanged(); void connectionStatusChanged(); @@ -119,6 +128,7 @@ Q_SIGNALS: void currentConnectionConfigIndexChanged(int index); void sizeChanged(const QSize &size); void notificationsAvailableChanged(bool notificationsAvailable); + void passiveChanged(bool passive); private Q_SLOTS: void handleSettingsChanged(); @@ -136,6 +146,7 @@ private Q_SLOTS: #ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD void handleSystemdStatusChanged(); #endif + void setPassive(bool passive); private: Dialogs::AboutDialog *m_aboutDlg; @@ -148,7 +159,8 @@ private: Data::SyncthingDirectoryModel m_dirModel; Data::SyncthingDeviceModel m_devModel; Data::SyncthingDownloadModel m_downloadModel; - Dialogs::SettingsDialog *m_settingsDlg; + Data::SyncthingStatusSelectionModel m_passiveSelectionModel; + SettingsDialog *m_settingsDlg; QtGui::DBusStatusNotifier m_dbusNotifier; std::vector m_notifications; #ifndef SYNCTHINGWIDGETS_NO_WEBVIEW @@ -179,6 +191,11 @@ inline Data::SyncthingDownloadModel *SyncthingApplet::downloadModel() const return const_cast(&m_downloadModel); } +inline Data::SyncthingStatusSelectionModel *SyncthingApplet::passiveSelectionModel() const +{ + return const_cast(&m_passiveSelectionModel); +} + inline Data::SyncthingService *SyncthingApplet::service() const { #ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD @@ -224,6 +241,24 @@ inline void SyncthingApplet::setSize(const QSize &size) emit sizeChanged(m_size = size); } } + +inline bool SyncthingApplet::isPassive() const +{ + return status() == Plasma::Types::PassiveStatus; +} + +inline const QList &SyncthingApplet::passiveStates() const +{ + return m_passiveSelectionModel.items(); +} + +inline void SyncthingApplet::setPassive(bool passive) +{ + if (passive != isPassive()) { + setStatus(passive ? Plasma::Types::PassiveStatus : Plasma::Types::ActiveStatus); + emit passiveChanged(passive); + } +} } // namespace Plasmoid #endif // SYNCTHINGAPPLET_H diff --git a/plasmoid/testing.md b/plasmoid/testing.md index 0e7a91e..6ebda1c 100644 --- a/plasmoid/testing.md +++ b/plasmoid/testing.md @@ -18,6 +18,12 @@ rather than the regular home to separate testing from production. 6. Ignore warning that executable is no debug build, it is sufficiant when the plugin is a debug build (see next section for QML debugging) +## Saving/restoring settings + +Be aware that `plasmoidviewer` will revert Plasmoid-specific settings to the defaults on +startup. So it is not possible to test restoring/saving settings using it. +For this use case, `plasmawindowed` can be used instead. + ## Enable QML debugging To enable QML debugging, it is required to rebuild `plasmoidviewer` with QML debugging diff --git a/widgets/settings/settingsdialog.cpp b/widgets/settings/settingsdialog.cpp index 751bc85..f7b26ba 100644 --- a/widgets/settings/settingsdialog.cpp +++ b/widgets/settings/settingsdialog.cpp @@ -952,6 +952,12 @@ SettingsDialog::SettingsDialog(const QList &categories, QWidge init(); } +SettingsDialog::SettingsDialog(QWidget *parent) + : Dialogs::SettingsDialog(parent) +{ + init(); +} + SettingsDialog::SettingsDialog(Data::SyncthingConnection *connection, QWidget *parent) : Dialogs::SettingsDialog(parent) { diff --git a/widgets/settings/settingsdialog.h b/widgets/settings/settingsdialog.h index 981c6b7..ff33e4d 100644 --- a/widgets/settings/settingsdialog.h +++ b/widgets/settings/settingsdialog.h @@ -114,6 +114,7 @@ class SYNCTHINGWIDGETS_EXPORT SettingsDialog : public Dialogs::SettingsDialog { public: explicit SettingsDialog(Data::SyncthingConnection *connection, QWidget *parent = nullptr); explicit SettingsDialog(const QList &categories, QWidget *parent = nullptr); + explicit SettingsDialog(QWidget *parent = nullptr); ~SettingsDialog(); private: