Commit e3bdcc28 authored by Cyril Rossi's avatar Cyril Rossi

KCModule: Indicate when a setting has been changed from the default value

Co-author Kevin Ottens

Task related : Figure out a good UI for the "show which settings have been changed" feature https://phabricator.kde.org/T13008

Part of the aforementioned feature, this patch allow to indicate when a widget bound to a kconfig settings has been changed from its default value.

See plasma/breeze!12
parent daaf5e92
......@@ -25,7 +25,6 @@
#include "kcmodule.h"
#include "kconfigwidgets_debug.h"
#include <KAboutData>
#include <KConfigSkeleton>
#include <kconfigdialogmanager.h>
......@@ -45,7 +44,8 @@ public:
_needsAuthorization(false),
_unmanagedWidgetChangeState(false),
_unmanagedWidgetDefaultState(false),
_unmanagedWidgetDefaultStateCalled(false)
_unmanagedWidgetDefaultStateCalled(false),
_defaultsIndicatorsVisible(false)
{ }
void authStatusChanged(int status);
......@@ -73,6 +73,8 @@ public:
bool _unmanagedWidgetChangeState : 1;
bool _unmanagedWidgetDefaultState : 1;
bool _unmanagedWidgetDefaultStateCalled : 1;
bool _defaultsIndicatorsVisible : 1;
};
KCModule::KCModule(const KAboutData *aboutData, QWidget *parent, const QVariantList &)
......@@ -146,6 +148,24 @@ bool KCModule::needsAuthorization() const
return d->_needsAuthorization;
}
void KCModule::setDefaultsIndicatorsVisible(bool show)
{
if (d->_defaultsIndicatorsVisible == show) {
return;
}
d->_defaultsIndicatorsVisible = show;
for (KConfigDialogManager *manager : qAsConst(d->managers)) {
manager->setDefaultsIndicatorsVisible(show);
}
emit defaultsIndicatorsVisibleChanged(show);
}
bool KCModule::defaultsIndicatorsVisible() const
{
return d->_defaultsIndicatorsVisible;
}
#ifndef KCONFIGWIDGETS_NO_KAUTH
void KCModule::setAuthAction(const KAuth::Action &action)
{
......
......@@ -232,6 +232,13 @@ public:
*/
bool needsAuthorization() const;
/**
* Returns whether an indicator is shown when a setting differs from default.
*
* @since 5.73
*/
bool defaultsIndicatorsVisible() const;
#ifndef KCONFIGWIDGETS_NO_KAUTH
/**
* @brief Set if the module's save() method requires authorization to be executed
......@@ -321,6 +328,13 @@ public Q_SLOTS:
*/
virtual void defaults();
/**
* Show an indicator when settings value differ from default
*
* @since 5.73
*/
void setDefaultsIndicatorsVisible(bool show);
protected:
/**
* Adds a KCoreConfigskeleton @p config to watch the widget @p widget
......@@ -396,6 +410,12 @@ Q_SIGNALS:
*/
void rootOnlyMessageChanged(bool use, QString message);
/**
* Emitted when show defaults indicators changed
* @since 5.73
*/
void defaultsIndicatorsVisibleChanged(bool show);
protected Q_SLOTS:
#if KCONFIGWIDGETS_ENABLE_DEPRECATED_SINCE(5, 64)
......
......@@ -3,6 +3,8 @@
* Copyright (C) 2003 Benjamin C Meyer (ben+kdelibs at meyerhome dot net)
* Copyright (C) 2003 Waldo Bastian <bastian@kde.org>
* Copyright (C) 2017 Friedrich W. H. Kossebau <kossebau@kde.org>
* Copyright (C) 2020 Kevin Ottens <kevin.ottens@enioka.com>
* Copyright (C) 2020 Cyril Rossi <cyril.rossi@enioka.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
......@@ -21,6 +23,7 @@
*/
#include "kconfigdialogmanager.h"
#include "kconfigdialogmanager_p.h"
#include "kconfigwidgets_debug.h"
#include <QComboBox>
......@@ -38,32 +41,6 @@ typedef QHash<QString, QByteArray> MyHash;
Q_GLOBAL_STATIC(MyHash, s_propertyMap)
Q_GLOBAL_STATIC(MyHash, s_changedMap)
class KConfigDialogManagerPrivate
{
public:
KConfigDialogManagerPrivate(KConfigDialogManager *q) : q(q), insideGroupBox(false) { }
public:
KConfigDialogManager * const q;
/**
* KConfigSkeleton object used to store settings
*/
KCoreConfigSkeleton *m_conf = nullptr;
/**
* Dialog being managed
*/
QWidget *m_dialog = nullptr;
QHash<QString, QWidget *> knownWidget;
QHash<QString, QWidget *> buddyWidget;
QSet<QWidget *> allExclusiveGroupBoxes;
bool insideGroupBox : 1;
bool trackChanges : 1;
};
KConfigDialogManager::KConfigDialogManager(QWidget *parent, KCoreConfigSkeleton *conf)
: QObject(parent), d(new KConfigDialogManagerPrivate(this))
{
......@@ -226,6 +203,8 @@ void KConfigDialogManager::setupWidget(QWidget *widget, KConfigSkeletonItem *ite
if (!item->isEqual(property(widget))) {
setProperty(widget, item->property());
}
d->updateWidgetIndicator(item->name(), widget);
}
bool KConfigDialogManager::parseChildren(const QWidget *widget, bool trackChanges)
......@@ -236,8 +215,8 @@ bool KConfigDialogManager::parseChildren(const QWidget *widget, bool trackChange
return valueChanged;
}
const QMetaMethod widgetModifiedSignal = metaObject()->method(metaObject()->indexOfSignal("widgetModified()"));
Q_ASSERT(widgetModifiedSignal.isValid() && metaObject()->indexOfSignal("widgetModified()")>=0);
const QMetaMethod onWidgetModifiedSlot = metaObject()->method(metaObject()->indexOfSlot("onWidgetModified()"));
Q_ASSERT(onWidgetModifiedSlot.isValid() && metaObject()->indexOfSlot("onWidgetModified()")>=0);
for (QObject *object : listOfChildren) {
if (!object->isWidgetType()) {
......@@ -266,7 +245,7 @@ bool KConfigDialogManager::parseChildren(const QWidget *widget, bool trackChange
const QList<QAbstractButton *> buttons = childWidget->findChildren<QAbstractButton *>();
for (QAbstractButton *button : buttons) {
connect(button, &QAbstractButton::toggled,
this, &KConfigDialogManager::widgetModified);
this, [this] { d->onWidgetModified(); });
}
}
......@@ -288,7 +267,7 @@ bool KConfigDialogManager::parseChildren(const QWidget *widget, bool trackChange
const QMetaProperty property = metaObject->property(indexOfProperty);
const QMetaMethod notifySignal = property.notifySignal();
if (notifySignal.isValid()) {
connect(childWidget, notifySignal, this, widgetModifiedSignal);
connect(childWidget, notifySignal, this, onWidgetModifiedSlot);
changeSignalFound = true;
}
}
......@@ -297,7 +276,7 @@ bool KConfigDialogManager::parseChildren(const QWidget *widget, bool trackChange
}
} else {
connect(childWidget, propertyChangeSignal,
this, SIGNAL(widgetModified()));
this, SLOT(onWidgetModified()));
changeSignalFound = true;
}
......@@ -388,6 +367,7 @@ void KConfigDialogManager::updateWidgets()
if (changed) {
QTimer::singleShot(0, this, &KConfigDialogManager::widgetModified);
d->updateAllWidgetIndicators();
}
}
......@@ -396,6 +376,12 @@ void KConfigDialogManager::updateWidgetsDefault()
bool bUseDefaults = d->m_conf->useDefaults(true);
updateWidgets();
d->m_conf->useDefaults(bUseDefaults);
d->updateAllWidgetIndicators();
}
void KConfigDialogManager::setDefaultsIndicatorsVisible(bool enabled)
{
d->setDefaultsIndicatorsVisible(enabled);
}
void KConfigDialogManager::updateSettings()
......@@ -423,6 +409,7 @@ void KConfigDialogManager::updateSettings()
if (changed) {
d->m_conf->save();
emit settingsChanged();
d->updateAllWidgetIndicators();
}
}
......@@ -601,3 +588,74 @@ bool KConfigDialogManager::isDefault() const
return result;
}
KConfigDialogManagerPrivate::KConfigDialogManagerPrivate(KConfigDialogManager *q)
: q(q)
, insideGroupBox(false)
, defaultsIndicatorsVisible(false)
{
}
void KConfigDialogManagerPrivate::setDefaultsIndicatorsVisible(bool enabled)
{
if (defaultsIndicatorsVisible != enabled) {
defaultsIndicatorsVisible = enabled;
updateAllWidgetIndicators();
}
}
void KConfigDialogManagerPrivate::onWidgetModified()
{
const auto widget = qobject_cast<QWidget*>(q->sender());
Q_ASSERT(widget);
if (!widget->objectName().startsWith("kcfg_")) {
Q_ASSERT(widget->parent()->objectName().startsWith("kcfg_"));
const auto configId = widget->parent()->objectName().mid(5);
const auto parent = qobject_cast<QWidget*>(widget->parent());
Q_ASSERT(parent);
updateWidgetIndicator(configId, parent);
} else {
const auto configId = widget->objectName().mid(5);
updateWidgetIndicator(configId, widget);
}
emit q->widgetModified();
}
void KConfigDialogManagerPrivate::updateWidgetIndicator(const QString &configId, QWidget *widget)
{
const auto item = m_conf->findItem(configId);
Q_ASSERT(item);
const auto widgetValue = q->property(widget);
const auto defaultValue = [item] {
item->swapDefault();
const auto value = item->property();
item->swapDefault();
return value;
}();
const auto defaulted = widgetValue == defaultValue;
if (allExclusiveGroupBoxes.contains(widget)) {
const QList<QAbstractButton *> buttons = widget->findChildren<QAbstractButton *>();
for (int i = 0; i < buttons.count(); i++) {
const auto value = widgetValue.toInt() == i && !defaulted && defaultsIndicatorsVisible;
buttons.at(i)->setProperty("_kde_highlight_neutral", value);
buttons.at(i)->update();
}
} else {
widget->setProperty("_kde_highlight_neutral", !defaulted && defaultsIndicatorsVisible);
widget->update();
}
}
void KConfigDialogManagerPrivate::updateAllWidgetIndicators()
{
QHashIterator<QString, QWidget *> it(knownWidget);
while (it.hasNext()) {
it.next();
updateWidgetIndicator(it.key(), it.value());
}
}
#include "moc_kconfigdialogmanager.cpp"
......@@ -305,6 +305,14 @@ public Q_SLOTS:
*/
void updateWidgetsDefault();
/**
* Show or hide an indicator when settings have changed from their default value.
* Update all widgets to show or hide the indicator accordingly.
*
* @since 5.73
*/
void setDefaultsIndicatorsVisible(bool enabled);
protected:
/**
......@@ -381,8 +389,10 @@ private:
* KConfigDialogManager KConfigDialogManagerPrivate class.
*/
KConfigDialogManagerPrivate *const d;
friend class KConfigDialogManagerPrivate;
Q_DISABLE_COPY(KConfigDialogManager)
Q_PRIVATE_SLOT(d, void onWidgetModified())
};
#endif // KCONFIGDIALOGMANAGER_H
......
/*
* This file is part of the KDE libraries
* Copyright (C) 2003 Benjamin C Meyer (ben+kdelibs at meyerhome dot net)
* Copyright (C) 2003 Waldo Bastian <bastian@kde.org>
* Copyright (C) 2017 Friedrich W. H. Kossebau <kossebau@kde.org>
* Copyright (C) 2020 Kevin Ottens <kevin.ottens@enioka.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KCONFIGDIALOGMANAGER_P_H
#define KCONFIGDIALOGMANAGER_P_H
#include <QHash>
#include <QSet>
#include <QString>
class QWidget;
class KConfigDialogManager;
class KCoreConfigSkeleton;
class KConfigDialogManagerPrivate
{
public:
KConfigDialogManagerPrivate(KConfigDialogManager *q);
void setDefaultsIndicatorsVisible(bool enabled);
void onWidgetModified();
void updateWidgetIndicator(const QString &configId, QWidget *widget);
void updateAllWidgetIndicators();
public:
KConfigDialogManager * const q;
/**
* KConfigSkeleton object used to store settings
*/
KCoreConfigSkeleton *m_conf = nullptr;
/**
* Dialog being managed
*/
QWidget *m_dialog = nullptr;
QHash<QString, QWidget *> knownWidget;
QHash<QString, QWidget *> buddyWidget;
QSet<QWidget *> allExclusiveGroupBoxes;
bool insideGroupBox : 1;
bool trackChanges : 1;
bool defaultsIndicatorsVisible : 1;
};
#endif // KCONFIGDIALOGMANAGER_P_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment