Allow hiding Plasma applet in certain states

See https://github.com/Martchus/syncthingtray/issues/23
This commit is contained in:
Martchus 2018-10-10 17:48:48 +02:00
parent f0a2d60906
commit 87a10c5b33
14 changed files with 229 additions and 21 deletions

View File

@ -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:

View File

@ -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);
}
/*!

View File

@ -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)

View File

@ -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<int>(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<SyncthingStatus>(id.toInt()));
}
} // namespace Data

View File

@ -0,0 +1,22 @@
#ifndef DATA_SYNCTHINGSTATUSSELECTIONMODELL_H
#define DATA_SYNCTHINGSTATUSSELECTIONMODELL_H
#include "./global.h"
#include <qtutilities/models/checklistmodel.h>
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

View File

@ -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

View File

@ -19,14 +19,14 @@
</property>
</widget>
</item>
<item row="1" column="0">
<item row="2" column="0">
<widget class="QLabel" name="colorsLabel">
<property name="text">
<string>Colors</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QCheckBox" name="brightTextColorsCheckBox">
<property name="text">
<string>Bright custom text colors (use for dark color scheme)</string>
@ -118,6 +118,23 @@
</item>
</layout>
</item>
<item row="3" column="0">
<widget class="QLabel" name="passiveLabel">
<property name="text">
<string>States to enable passive mode</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QListView" name="passiveListView">
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="layoutMode">
<enum>QListView::Batched</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>

View File

@ -6,6 +6,7 @@
#include "../../widgets/settings/settingsdialog.h"
#include <qtutilities/settingsdialog/optioncategory.h>
#include <qtutilities/settingsdialog/optioncategorymodel.h>
#include <qtutilities/settingsdialog/optionpage.h>
#include <qtutilities/settingsdialog/settingsdialog.h>
@ -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<QSize>("size", QSize(ui()->widthSpinBox->value(), ui()->heightSpinBox->value()));
config.writeEntry<bool>("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<QSize>("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<bool>("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<Dialogs::OptionCategory *> categories;
Dialogs::OptionCategory *category;
category = new OptionCategory;
m_appearanceOptionPage = new AppearanceOptionPage(applet);
category->setDisplayName(QCoreApplication::translate("Plasmoid::SettingsDialog", "Plasmoid"));
category->assignPages(QList<Dialogs::OptionPage *>()
<< 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

View File

@ -1,14 +1,24 @@
#ifndef SETTINGSDIALOG_H
#define SETTINGSDIALOG_H
#include "../../model/syncthingstatusselectionmodel.h"
#include "../../widgets/settings/settingsdialog.h"
#include <qtutilities/settingsdialog/optionpage.h>
#include <KConfigGroup>
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

View File

@ -202,6 +202,13 @@ bool SyncthingApplet::areNotificationsAvailable() const
return !m_notifications.empty();
}
void SyncthingApplet::setPassiveStates(const QList<Models::ChecklistItem> &passiveStates)
{
m_passiveSelectionModel.setItems(passiveStates);
const auto currentState = static_cast<int>(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<int>(status) < passiveStates().size() && passiveStates().at(static_cast<int>(status)).isChecked());
// update status icon and tooltip text
m_statusInfo.updateConnectionStatus(m_connection);
m_statusInfo.updateConnectedDevices(m_connection);

View File

@ -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 <qtutilities/aboutdialog/aboutdialog.h>
#include <qtutilities/models/checklistmodel.h>
#include <Plasma/Applet>
#include <QSize>
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<Models::ChecklistItem> 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<Models::ChecklistItem> &passiveStates() const;
void setPassiveStates(const QList<Models::ChecklistItem> &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<Data::SyncthingLogEntry> m_notifications;
#ifndef SYNCTHINGWIDGETS_NO_WEBVIEW
@ -179,6 +191,11 @@ inline Data::SyncthingDownloadModel *SyncthingApplet::downloadModel() const
return const_cast<Data::SyncthingDownloadModel *>(&m_downloadModel);
}
inline Data::SyncthingStatusSelectionModel *SyncthingApplet::passiveSelectionModel() const
{
return const_cast<Data::SyncthingStatusSelectionModel *>(&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<Models::ChecklistItem> &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

View File

@ -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

View File

@ -952,6 +952,12 @@ SettingsDialog::SettingsDialog(const QList<OptionCategory *> &categories, QWidge
init();
}
SettingsDialog::SettingsDialog(QWidget *parent)
: Dialogs::SettingsDialog(parent)
{
init();
}
SettingsDialog::SettingsDialog(Data::SyncthingConnection *connection, QWidget *parent)
: Dialogs::SettingsDialog(parent)
{

View File

@ -114,6 +114,7 @@ class SYNCTHINGWIDGETS_EXPORT SettingsDialog : public Dialogs::SettingsDialog {
public:
explicit SettingsDialog(Data::SyncthingConnection *connection, QWidget *parent = nullptr);
explicit SettingsDialog(const QList<Dialogs::OptionCategory *> &categories, QWidget *parent = nullptr);
explicit SettingsDialog(QWidget *parent = nullptr);
~SettingsDialog();
private: