From 423ade5f678840f82ae1ae699fa864019cb6d976 Mon Sep 17 00:00:00 2001 From: Alexander Stippich Date: Mon, 7 Feb 2022 21:44:08 +0100 Subject: [PATCH] make the quick access options configurable --- src/FilteredOptionsModel.cpp | 4 +- src/OptionsModel.cpp | 56 ++++++---- src/OptionsModel.h | 2 +- src/qml/OptionDelegate.qml | 201 ++++++++++++++++++++--------------- src/qml/OptionsPanel.qml | 40 +++++-- 5 files changed, 192 insertions(+), 111 deletions(-) diff --git a/src/FilteredOptionsModel.cpp b/src/FilteredOptionsModel.cpp index 82c4b72..8b33896 100644 --- a/src/FilteredOptionsModel.cpp +++ b/src/FilteredOptionsModel.cpp @@ -19,12 +19,12 @@ bool FilteredOptionsModel::filterAcceptsRow(int source_row, const QModelIndex &s const auto &state = sourceModel()->data(index, OptionsModel::StateRole).value(); const auto &type = sourceModel()->data(index, OptionsModel::TypeRole).value(); - if (type == KSaneIface::KSaneOption::TypeValueList && sourceModel()->data(index, OptionsModel::ValueListRole).toList().length() <= 1) { + if (type == KSaneIface::KSaneOption::TypeValueList && sourceModel()->data(index, OptionsModel::ValueListRole).toList().length() <= 1) { return false; } if (!m_showAllOptions) { - return sourceModel()->data(index, OptionsModel::FilterRole).toBool(); + return sourceModel()->data(index, OptionsModel::QuickAccessRole).toBool() && state == KSaneIface::KSaneOption::StateActive; } if (state != KSaneIface::KSaneOption::StateActive || type == KSaneIface::KSaneOption::TypeGamma || type == KSaneIface::KSaneOption::TypeDetectFail) { diff --git a/src/OptionsModel.cpp b/src/OptionsModel.cpp index e7e3f43..95a7e1c 100644 --- a/src/OptionsModel.cpp +++ b/src/OptionsModel.cpp @@ -5,7 +5,8 @@ */ //KDE includes -#include +#include +#include #include "OptionsModel.h" #include "skanpage_debug.h" @@ -14,17 +15,39 @@ class OptionsModelPrivate { public: QList mOptionsList; - QList mFilterList; + QList mQuickAccessList; + QSet mQuickAccessOptions; + bool mQuickAccessListChanged = false; }; OptionsModel::OptionsModel(QObject *parent) : QAbstractListModel(parent) , d(std::make_unique()) { + //if there are no defined quick access options yet, insert default ones + KConfigGroup quickOptions(KSharedConfig::openConfig(), QStringLiteral("quickAccessOptions")); + if (!quickOptions.exists()) { + d->mQuickAccessOptions.insert(QStringLiteral("KSane::PageSize")); + d->mQuickAccessOptions.insert(QStringLiteral("resolution")); + d->mQuickAccessOptions.insert(QStringLiteral("source")); + d->mQuickAccessOptions.insert(QStringLiteral("mode")); + } else { + const QStringList keys = quickOptions.keyList(); + d->mQuickAccessOptions = QSet(keys.begin(), keys.end()); + } } OptionsModel::~OptionsModel() -{ +{ + if (d->mQuickAccessListChanged) { + KConfigGroup quickOptions(KSharedConfig::openConfig(), QStringLiteral("quickAccessOptions")); + quickOptions.deleteGroup(); + for (int i = 0; i < d->mOptionsList.size(); i++) { + if (d->mQuickAccessList.at(i)) { + quickOptions.writeEntry(d->mOptionsList.at(i)->name(), true); + } + } + } } QHash OptionsModel::roleNames() const @@ -41,7 +64,7 @@ QHash OptionsModel::roleNames() const roles[UnitRole] = "unit"; roles[TypeRole] = "type"; roles[StateRole] = "state"; - roles[FilterRole] = "filter"; + roles[QuickAccessRole] = "quickAccess"; return roles; } @@ -94,8 +117,8 @@ QVariant OptionsModel::data(const QModelIndex &index, int role) const case StateRole: return d->mOptionsList.at(index.row())->state(); break; - case FilterRole: - return d->mFilterList.at(index.row()); + case QuickAccessRole: + return d->mQuickAccessList.at(index.row()); break; default: break; @@ -105,7 +128,7 @@ QVariant OptionsModel::data(const QModelIndex &index, int role) const bool OptionsModel::setData(const QModelIndex &index, const QVariant &value, int role) { - if ((role != ValueRole && role != FilterRole) || index.row() < 0 || index.row() >= d->mOptionsList.size()) { + if ((role != ValueRole && role != QuickAccessRole) || index.row() < 0 || index.row() >= d->mOptionsList.size()) { return false; } if (role == ValueRole) { @@ -114,9 +137,10 @@ bool OptionsModel::setData(const QModelIndex &index, const QVariant &value, int Q_EMIT dataChanged(index, index, {ValueRole}); return true; } - if (role == FilterRole) { - d->mFilterList[index.row()] = value.toBool(); - Q_EMIT dataChanged(index, index, {FilterRole}); + if (role == QuickAccessRole) { + d->mQuickAccessList[index.row()] = value.toBool(); + d->mQuickAccessListChanged = true; + Q_EMIT dataChanged(index, index, {QuickAccessRole}); } return true; } @@ -125,18 +149,14 @@ void OptionsModel::setOptionsList(const QList options { beginResetModel(); d->mOptionsList = optionsList; - d->mFilterList.clear(); - d->mFilterList.reserve(optionsList.size()); + d->mQuickAccessList.clear(); + d->mQuickAccessList.reserve(optionsList.size()); for (int i = 0; i < d->mOptionsList.size(); i++) { KSaneIface::KSaneOption *option = d->mOptionsList.at(i); qCDebug(SKANPAGE_LOG()) << "OptionsModel: Importing option " << option->name() << ", type" << option->type() << ", state" << option->state(); connect(option, &KSaneIface::KSaneOption::optionReloaded, this, [=]() { Q_EMIT dataChanged(index(i, 0), index(i, 0), {StateRole}); }); connect(option, &KSaneIface::KSaneOption::valueChanged, this, [=]() { Q_EMIT dataChanged(index(i, 0), index(i, 0), {ValueRole}); }); - if (option->name() == QStringLiteral("KSane::PageSize") || option->name() == QStringLiteral("resolution") || option->name() == QStringLiteral("source") || option->name() == QStringLiteral("mode") ) { - d->mFilterList.insert(i, true); - } else { - d->mFilterList.insert(i, false); - } + d->mQuickAccessList.insert(i, d->mQuickAccessOptions.contains(option->name())); } endResetModel(); Q_EMIT rowCountChanged(); @@ -146,7 +166,7 @@ void OptionsModel::clearOptions() { beginResetModel(); d->mOptionsList.clear(); - d->mFilterList.clear(); + d->mQuickAccessList.clear(); endResetModel(); Q_EMIT rowCountChanged(); } diff --git a/src/OptionsModel.h b/src/OptionsModel.h index 6547ad8..7f96c9c 100644 --- a/src/OptionsModel.h +++ b/src/OptionsModel.h @@ -36,7 +36,7 @@ public: UnitRole, TypeRole, StateRole, - FilterRole + QuickAccessRole }; explicit OptionsModel(QObject *parent = nullptr); diff --git a/src/qml/OptionDelegate.qml b/src/qml/OptionDelegate.qml index 3247eb9..4cba621 100644 --- a/src/qml/OptionDelegate.qml +++ b/src/qml/OptionDelegate.qml @@ -11,131 +11,164 @@ import QtQuick.Layouts 1.1 import org.kde.kirigami 2.5 as Kirigami import org.kde.skanpage 1.0 -Column { +Item { id: optionDelegate property var modelItem + property bool editMode: false + + implicitHeight: column.implicitHeight + implicitWidth: column.implicitWidth + + Loader { + active: editMode + visible: active + + anchors.fill: parent + + sourceComponent: Rectangle { + color: model.quickAccess || mouseArea.hovered ? Kirigami.Theme.highlightColor : 'transparent' + + Kirigami.Separator { + anchors.bottom: parent.bottom + width: parent.width + } - spacing: Kirigami.Units.smallSpacing - padding: Kirigami.Units.smallSpacing - - Label { - visible: modelItem.type !== KSaneOption.TypeBool - text: i18n("%1:", model.title) + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: model.quickAccess = !model.quickAccess + } + } } - RowLayout { + Column { + id: column + anchors.fill: parent - Loader { - active: modelItem.type === KSaneOption.TypeInteger - visible: active + spacing: Kirigami.Units.smallSpacing + padding: Kirigami.Units.smallSpacing + + Label { + visible: modelItem.type !== KSaneOption.TypeBool + text: i18n("%1:", model.title) + } - sourceComponent: IntegerSpinBoxWithSuffix { - id: integerSpinBox + RowLayout { + enabled: !editMode - stepSize: modelItem.step - from: modelItem.minimum - to: modelItem.maximum - suffix: getUnitString(modelItem.unit) - value: modelItem.value - editable: true + Loader { + active: modelItem.type === KSaneOption.TypeInteger + visible: active - onValueModified: { - if (value != modelItem.value) { - modelItem.value = value + sourceComponent: IntegerSpinBoxWithSuffix { + id: integerSpinBox + + stepSize: modelItem.step + from: modelItem.minimum + to: modelItem.maximum + suffix: getUnitString(modelItem.unit) + value: modelItem.value + editable: true + + onValueModified: { + if (value != modelItem.value) { + modelItem.value = value + } } } } - } - Loader { - active: modelItem.type === KSaneOption.TypeDouble - visible: active + Loader { + active: modelItem.type === KSaneOption.TypeDouble + visible: active - sourceComponent: DoubleSpinBoxWithSuffix { - id: doubleSpinBox + sourceComponent: DoubleSpinBoxWithSuffix { + id: doubleSpinBox - stepSize: modelItem.step - from: modelItem.minimum - to: modelItem.maximum + stepSize: modelItem.step + from: modelItem.minimum + to: modelItem.maximum - suffix: getUnitString(modelItem.unit) - value: modelItem.value - editable: true + suffix: getUnitString(modelItem.unit) + value: modelItem.value + editable: true - onValueModified: { - if (value != modelItem.value) { - modelItem.value = value + onValueModified: { + if (value != modelItem.value) { + modelItem.value = value + } } } } - } - Loader { - active: modelItem.type === KSaneOption.TypeString - visible: active + Loader { + active: modelItem.type === KSaneOption.TypeString + visible: active - sourceComponent: TextField { - text: modelItem.value - onTextChanged: { - if (text != modelItem.value) { - modelItem.value = value + sourceComponent: TextField { + text: modelItem.value + onTextChanged: { + if (text != modelItem.value) { + modelItem.value = value + } } } } - } - Loader { - active: modelItem.type === KSaneOption.TypeBool - visible: active + Loader { + active: modelItem.type === KSaneOption.TypeBool + visible: active - sourceComponent: CheckBox { - text: modelItem.title - checked: modelItem.value - onClicked: modelItem.value = !modelItem.value + sourceComponent: CheckBox { + text: modelItem.title + checked: modelItem.value + onClicked: modelItem.value = !modelItem.value + } } - } - Loader { - active: modelItem.type === KSaneOption.TypeAction - visible: active + Loader { + active: modelItem.type === KSaneOption.TypeAction + visible: active - sourceComponent: Button { - text: modelItem.title - onClicked: modelItem.value = 1 + sourceComponent: Button { + text: modelItem.title + onClicked: modelItem.value = 1 + } } - } - Loader { - id: comboLoader - active: modelItem.type === KSaneOption.TypeValueList - visible: active + Loader { + id: comboLoader + active: modelItem.type === KSaneOption.TypeValueList + visible: active - property var entries: modelItem.valueList - property var modelValue: modelItem.value - property string unitSuffix: getUnitString(modelItem.unit) + property var entries: modelItem.valueList + property var modelValue: modelItem.value + property string unitSuffix: getUnitString(modelItem.unit) - sourceComponent: ComboBox { - id: combo + sourceComponent: ComboBox { + id: combo - model: entries - displayText: unitSuffix === "" || currentText === "" ? currentText : i18nc("Adding unit suffix","%1 %2", currentText, unitSuffix) - currentIndex: indexOfValue(modelItem.value) + model: entries + displayText: unitSuffix === "" || currentText === "" ? currentText : i18nc("Adding unit suffix","%1 %2", currentText, unitSuffix) + currentIndex: indexOfValue(modelItem.value) - onCurrentValueChanged: { - if (combo.currentValue != modelItem.value) { - modelItem.value = combo.currentValue + onCurrentValueChanged: { + if (combo.currentValue != modelItem.value) { + modelItem.value = combo.currentValue + } } - } - Connections { - target: comboLoader - function onModelValueChanged() { - currentIndex = indexOfValue(modelItem.value) + Connections { + target: comboLoader + function onModelValueChanged() { + currentIndex = indexOfValue(modelItem.value) + } } - } - Component.onCompleted: currentIndex = indexOfValue(modelItem.value) + Component.onCompleted: currentIndex = indexOfValue(modelItem.value) + } } } } diff --git a/src/qml/OptionsPanel.qml b/src/qml/OptionsPanel.qml index be927eb..6971451 100644 --- a/src/qml/OptionsPanel.qml +++ b/src/qml/OptionsPanel.qml @@ -12,12 +12,21 @@ import org.kde.kirigami 2.5 as Kirigami import org.kde.skanpage 1.0 ColumnLayout { - id: optionDelegate + id: optionPanel property alias showAllOptions: allOptionsButton.checked property int targetWidth: Math.max(_maxChildrenWidth + optionsList.ScrollBar.vertical.width, allOptionsButton.implicitWidth, devicesButton.implicitWidth) property int _maxChildrenWidth: 0 + + property bool editMode: false + + Label { + Layout.alignment: Qt.AlignHCenter + Layout.preferredHeight: Kirigami.Units.gridUnit * 2 + text: i18n("Select options for quick access:") + visible: editMode + } ScrollView { id: optionsList @@ -34,19 +43,38 @@ ColumnLayout { delegate: OptionDelegate { modelItem: model + + width: optionsList.width - optionsList.ScrollBar.vertical.width + + editMode: optionPanel.editMode Component.onCompleted: { - if (optionDelegate._maxChildrenWidth < implicitWidth) { - optionDelegate._maxChildrenWidth = implicitWidth + if (optionPanel._maxChildrenWidth < implicitWidth) { + optionPanel._maxChildrenWidth = implicitWidth } } } } } - Button { - id: allOptionsButton + RowLayout { Layout.alignment: Qt.AlignHCenter - action: allOptionsAction + + Button { + id: allOptionsButton + action: allOptionsAction + enabled: !editOptionsButton.checked + } + + Button { + id: editOptionsButton + icon.name: "settings-configure" + text: i18n("Configure") + checkable: true + onClicked: { + optionPanel.editMode = checked + skanpage.optionsModel.showAllOptions(checked) + } + } } Button { -- GitLab