Changeset View
Changeset View
Standalone View
Standalone View
src/settings/ConfigurationDialog.h
- This file was added.
1 | /* | ||||
---|---|---|---|---|---|
2 | Copyright 2019 by Mariusz Glebocki <mglb@arccos-1.net> | ||||
3 | | ||||
4 | Based on KConfigDialog and KConfigDialogManager from KConfigWidgets | ||||
5 | | ||||
6 | Copyright (C) 2003 Benjamin C Meyer (ben+kdelibs at meyerhome dot net) | ||||
7 | Copyright (C) 2003 Waldo Bastian <bastian@kde.org> | ||||
8 | | ||||
9 | This program is free software; you can redistribute it and/or modify | ||||
10 | it under the terms of the GNU General Public License as published by | ||||
11 | the Free Software Foundation; either version 2 of the License, or | ||||
12 | (at your option) any later version. | ||||
13 | | ||||
14 | This program is distributed in the hope that it will be useful, | ||||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
17 | GNU General Public License for more details. | ||||
18 | | ||||
19 | You should have received a copy of the GNU General Public License | ||||
20 | along with this program; if not, write to the Free Software | ||||
21 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||||
22 | 02110-1301 USA. | ||||
23 | */ | ||||
24 | | ||||
25 | #ifndef CONFIGURATIONDIALOG_H | ||||
26 | #define CONFIGURATIONDIALOG_H | ||||
27 | | ||||
28 | // Qt | ||||
29 | #include <QWidget> | ||||
30 | #include <QButtonGroup> | ||||
31 | #include <QAbstractButton> | ||||
32 | #include <QTimer> | ||||
33 | #include <QMap> | ||||
34 | | ||||
35 | // KDE | ||||
36 | #include <KPageDialog> | ||||
37 | #include <KCoreConfigSkeleton> | ||||
38 | #include <QDebug> | ||||
39 | | ||||
40 | // Konsole | ||||
41 | #include "konsoleprivate_export.h" | ||||
42 | | ||||
43 | class KConfig; | ||||
44 | class KCoreConfigSkeleton; | ||||
45 | class KConfigDialogManager; | ||||
46 | | ||||
47 | namespace Konsole { | ||||
48 | | ||||
49 | class ConfigDialogButtonGroupManager; | ||||
50 | | ||||
51 | // KConfigDialog-like class, as the original KConfigDialog wraps | ||||
52 | // all pages in QScrollArea. KConfigDialog, when fixed, should | ||||
53 | // be source compatible with this class, so simple class replace | ||||
54 | // should suffice. | ||||
55 | class KONSOLEPRIVATE_EXPORT ConfigurationDialog: public KPageDialog | ||||
56 | { | ||||
57 | Q_OBJECT | ||||
58 | | ||||
59 | Q_SIGNALS: | ||||
60 | void widgetModified(); | ||||
61 | void settingsChanged(); | ||||
62 | | ||||
63 | public: | ||||
64 | explicit ConfigurationDialog(QWidget *parent, KCoreConfigSkeleton *config); | ||||
65 | ~ConfigurationDialog() override = default; | ||||
66 | | ||||
67 | void addPage(KPageWidgetItem *item, bool manage); | ||||
68 | | ||||
69 | protected Q_SLOTS: | ||||
70 | void updateButtons(); | ||||
71 | void settingsChangedSlot(); | ||||
72 | | ||||
73 | protected: | ||||
74 | void setApplyButtonEnabled(bool enabled); | ||||
75 | void setRestoreDefaultsButtonEnabled(bool enabled); | ||||
76 | void showEvent(QShowEvent *event) override; | ||||
77 | | ||||
78 | private: | ||||
79 | Q_DISABLE_COPY(ConfigurationDialog) | ||||
80 | | ||||
81 | KConfigDialogManager *_manager = nullptr; | ||||
82 | ConfigDialogButtonGroupManager *_groupManager = nullptr; | ||||
83 | bool _shown = false; | ||||
84 | }; | ||||
85 | | ||||
86 | // KConfigDialogManager-like class for managing QButtonGroups, | ||||
87 | // which are not supported by KConfigDialogManager yet. When | ||||
88 | // support will be available in minimum KF5 used by Konsole, | ||||
89 | // just remove this class and all expressions which refer to it. | ||||
90 | class ConfigDialogButtonGroupManager: public QObject | ||||
91 | { | ||||
92 | Q_OBJECT | ||||
93 | | ||||
94 | public: | ||||
95 | ConfigDialogButtonGroupManager(QObject *parent, KCoreConfigSkeleton *config) | ||||
96 | : QObject(parent) | ||||
97 | , _config(config) | ||||
98 | { | ||||
99 | Q_ASSERT(config); | ||||
100 | connect(_config, &KCoreConfigSkeleton::configChanged, | ||||
101 | this, &ConfigDialogButtonGroupManager::updateWidgets); | ||||
102 | } | ||||
103 | | ||||
104 | void addChildren(const QObject *parentObj) | ||||
105 | { | ||||
106 | for (const QObject *child: parentObj->children()) { | ||||
107 | if (!child->objectName().startsWith(ManagedNamePrefix)) { | ||||
108 | continue; | ||||
109 | } | ||||
110 | | ||||
111 | const char *className = child->metaObject()->className(); | ||||
112 | if (qstrcmp(className, "QButtonGroup") == 0) { | ||||
113 | add(qobject_cast<const QButtonGroup *>(child)); | ||||
114 | } | ||||
115 | } | ||||
116 | } | ||||
117 | void add(const QButtonGroup *obj) | ||||
118 | { | ||||
119 | Q_ASSERT(obj->exclusive()); | ||||
120 | connect(obj, QOverload<QAbstractButton *, bool>::of(&QButtonGroup::buttonToggled), | ||||
121 | this, &ConfigDialogButtonGroupManager::setButtonState, Qt::UniqueConnection); | ||||
122 | _groups.append(obj); | ||||
123 | | ||||
124 | } | ||||
125 | | ||||
126 | bool hasChanged() const { | ||||
127 | for(const QButtonGroup *group: qAsConst(_groups)) { | ||||
128 | int value = buttonToEnumValue(group->checkedButton()); | ||||
129 | const auto enumItem = groupToConfigItemEnum(group); | ||||
130 | | ||||
131 | if(!enumItem->isEqual(value)) { | ||||
132 | return true; | ||||
133 | } | ||||
134 | } | ||||
135 | return false; | ||||
136 | } | ||||
137 | | ||||
138 | bool isDefault() const { | ||||
139 | bool useDefaults = _config->useDefaults(true); | ||||
140 | bool result = !hasChanged(); | ||||
141 | _config->useDefaults(useDefaults); | ||||
142 | return result; | ||||
143 | } | ||||
144 | | ||||
145 | Q_SIGNALS: | ||||
146 | void settingsChanged(); | ||||
147 | void widgetModified(); | ||||
148 | | ||||
149 | public Q_SLOTS: | ||||
150 | void updateWidgets() | ||||
151 | { | ||||
152 | bool prevSignalsBlocked = signalsBlocked(); | ||||
153 | bool changed = false; | ||||
154 | blockSignals(true); | ||||
155 | for(const QButtonGroup *group: qAsConst(_groups)) { | ||||
156 | auto *enumItem = groupToConfigItemEnum(group); | ||||
157 | if(!enumItem) { | ||||
158 | continue; | ||||
159 | } | ||||
160 | | ||||
161 | int value = enumItem->value(); | ||||
162 | const QString &valueName = enumItem->choices().at(value).name; | ||||
163 | QAbstractButton *currentButton = nullptr; | ||||
164 | for(auto &button: group->buttons()) { | ||||
165 | if(button->objectName() == valueName) { | ||||
166 | currentButton = button; | ||||
167 | break; | ||||
168 | } | ||||
169 | } | ||||
170 | if(!currentButton) { | ||||
171 | return; | ||||
172 | } | ||||
173 | currentButton->setChecked(true); | ||||
174 | changed = true; | ||||
175 | } | ||||
176 | blockSignals(prevSignalsBlocked); | ||||
177 | if(changed) { | ||||
178 | QTimer::singleShot(0, this, &ConfigDialogButtonGroupManager::widgetModified); | ||||
179 | } | ||||
180 | } | ||||
181 | | ||||
182 | void updateWidgetsDefault() { | ||||
183 | bool useDefaults = _config->useDefaults(true); | ||||
184 | updateWidgets(); | ||||
185 | _config->useDefaults(useDefaults); | ||||
186 | } | ||||
187 | | ||||
188 | void updateSettings() { | ||||
189 | bool updateConfig = false; | ||||
190 | for(const QButtonGroup *group: qAsConst(_groups)) { | ||||
191 | auto *enumItem = groupToConfigItemEnum(group); | ||||
192 | if(!enumItem) { | ||||
193 | continue; | ||||
194 | } | ||||
195 | const auto *currentButton = group->checkedButton(); | ||||
196 | if(!currentButton) { | ||||
197 | continue; | ||||
198 | } | ||||
199 | const int value = buttonToEnumValue(currentButton); | ||||
200 | if(value < 0) { | ||||
201 | continue; | ||||
202 | } | ||||
203 | | ||||
204 | if(!enumItem->isEqual(value)) { | ||||
205 | enumItem->setValue(value); | ||||
206 | updateConfig = true; | ||||
207 | } | ||||
208 | } | ||||
209 | if(updateConfig) { | ||||
210 | _config->save(); | ||||
211 | emit settingsChanged(); | ||||
212 | } | ||||
213 | } | ||||
214 | | ||||
215 | protected Q_SLOTS: | ||||
216 | void setButtonState(QAbstractButton *button, bool checked) | ||||
217 | { | ||||
218 | Q_ASSERT(button); | ||||
219 | Q_ASSERT(button->group()); | ||||
220 | if(!checked) { | ||||
221 | // Both deselected and selected buttons trigger this slot, ignore the deselected one | ||||
222 | return; | ||||
223 | } | ||||
224 | auto *enumItem = groupToConfigItemEnum(button->group()); | ||||
225 | if(!enumItem) { | ||||
226 | return; | ||||
227 | } | ||||
228 | | ||||
229 | int value = buttonToEnumValue(button); | ||||
230 | if(value < 0) { | ||||
231 | return; | ||||
232 | } | ||||
233 | | ||||
234 | emit settingsChanged(); | ||||
235 | } | ||||
236 | | ||||
237 | private: | ||||
238 | // Returns configuration item associated with the group | ||||
239 | KCoreConfigSkeleton::ItemEnum * groupToConfigItemEnum(const QButtonGroup *group) const { | ||||
240 | Q_ASSERT(group); | ||||
241 | const QString key = group->objectName().mid(ManagedNamePrefix.length()); | ||||
242 | auto *item = _config->findItem(key); | ||||
243 | if(!item) { | ||||
244 | return nullptr; | ||||
245 | } | ||||
246 | auto *enumItem = dynamic_cast<KCoreConfigSkeleton::ItemEnum *>(item); | ||||
247 | if(!enumItem) { | ||||
248 | return nullptr; | ||||
249 | } | ||||
250 | return enumItem; | ||||
251 | } | ||||
252 | | ||||
253 | // Returns a value the button represents in its group | ||||
254 | int buttonToEnumValue(const QAbstractButton *button) const { | ||||
255 | Q_ASSERT(button); | ||||
256 | Q_ASSERT(button->group()); | ||||
257 | | ||||
258 | if(_buttonValues.contains(button)) { | ||||
259 | return _buttonValues[button]; | ||||
260 | } | ||||
261 | | ||||
262 | const auto *enumItem = groupToConfigItemEnum(button->group()); | ||||
263 | if(!enumItem) { | ||||
264 | return -1; | ||||
265 | } | ||||
266 | const auto &choices = enumItem->choices(); | ||||
267 | | ||||
268 | const QString buttonName = button->objectName(); | ||||
269 | int value = -1; | ||||
270 | for(int i = 0; i < choices.size(); ++i) { | ||||
271 | if(buttonName == choices.at(i).name) { | ||||
272 | value = i; | ||||
273 | break; | ||||
274 | } | ||||
275 | } | ||||
276 | _buttonValues[button] = value; | ||||
277 | return value; | ||||
278 | } | ||||
279 | | ||||
280 | static const QString ManagedNamePrefix; | ||||
281 | | ||||
282 | mutable QMap<const QAbstractButton *, int> _buttonValues; | ||||
283 | KCoreConfigSkeleton *_config = nullptr; | ||||
284 | QList<const QButtonGroup *> _groups; | ||||
285 | }; | ||||
286 | | ||||
287 | } | ||||
288 | | ||||
289 | #endif // CONFIGURATIONDIALOG_H |