1 /*
2     appearanceconfigwidget.cpp
3 
4     This file is part of kleopatra, the KDE key manager
5     SPDX-FileCopyrightText: 2002, 2004, 2008 Klarälvdalens Datakonsult AB
6     SPDX-FileCopyrightText: 2002, 2003 Marc Mutz <mutz@kde.org>
7 
8     SPDX-License-Identifier: GPL-2.0-or-later
9  */
10 
11 #include <config-kleopatra.h>
12 
13 #include "appearanceconfigwidget.h"
14 #include "ui_appearanceconfigwidget.h"
15 
16 #include "tagspreferences.h"
17 #include "tooltippreferences.h"
18 
19 #include <QGpgME/Protocol>
20 #include <Libkleo/KeyFilterManager>
21 #include <Libkleo/Dn>
22 #include <Libkleo/DNAttributeOrderConfigWidget>
23 
24 #include <KIconDialog>
25 #include <QIcon>
26 
27 #include <KConfig>
28 #include <KLocalizedString>
29 #include <KConfigGroup>
30 
31 #include <QColor>
32 #include <QFont>
33 #include <QString>
34 #include <QRegularExpression>
35 #include <QApplication>
36 #include <QColorDialog>
37 #include <QFontDialog>
38 
39 #include <algorithm>
40 
41 using namespace Kleo;
42 using namespace Kleo::Config;
43 
44 enum {
45     HasNameRole = Qt::UserRole + 0x1234, /*!< Records that the user has assigned a name (to avoid comparing with i18n-strings) */
46     HasFontRole,                         /*!< Records that the user has chosen  completely different font (as opposed to italic/bold/strikeout) */
47     IconNameRole,                        /*!< Records the name of the icon (since QIcon won't give it out again, once set) */
48     MayChangeNameRole,
49     MayChangeForegroundRole,
50     MayChangeBackgroundRole,
51     MayChangeFontRole,
52     MayChangeItalicRole,
53     MayChangeBoldRole,
54     MayChangeStrikeOutRole,
55     MayChangeIconRole,
56 
57     EndDummy
58 };
59 
tryToFindFontFor(const QListWidgetItem * item)60 static QFont tryToFindFontFor(const QListWidgetItem *item)
61 {
62     if (item)
63         if (const QListWidget *const lw = item->listWidget()) {
64             return lw->font();
65         }
66     return QApplication::font("QListWidget");
67 }
68 
is(const QListWidgetItem * item,bool (QFont::* func)()const)69 static bool is(const QListWidgetItem *item, bool (QFont::*func)() const)
70 {
71     if (!item) {
72         return false;
73     }
74     const QVariant v = item->data(Qt::FontRole);
75     if (!v.isValid() || v.type() != QVariant::Font) {
76         return false;
77     }
78     return (v.value<QFont>().*func)();
79 }
80 
is_italic(const QListWidgetItem * item)81 static bool is_italic(const QListWidgetItem *item)
82 {
83     return is(item, &QFont::italic);
84 }
is_bold(const QListWidgetItem * item)85 static bool is_bold(const QListWidgetItem *item)
86 {
87     return is(item, &QFont::bold);
88 }
is_strikeout(const QListWidgetItem * item)89 static bool is_strikeout(const QListWidgetItem *item)
90 {
91     return is(item, &QFont::strikeOut);
92 }
93 
set(QListWidgetItem * item,bool on,void (QFont::* func)(bool))94 static void set(QListWidgetItem *item, bool on, void (QFont::*func)(bool))
95 {
96     if (!item) {
97         return;
98     }
99     const QVariant v = item->data(Qt::FontRole);
100     QFont font = v.isValid() && v.type() == QVariant::Font ? v.value<QFont>() : tryToFindFontFor(item);
101     (font.*func)(on);
102     item->setData(Qt::FontRole, font);
103 }
104 
set_italic(QListWidgetItem * item,bool on)105 static void set_italic(QListWidgetItem *item, bool on)
106 {
107     set(item, on, &QFont::setItalic);
108 }
set_bold(QListWidgetItem * item,bool on)109 static void set_bold(QListWidgetItem *item, bool on)
110 {
111     set(item, on, &QFont::setBold);
112 }
set_strikeout(QListWidgetItem * item,bool on)113 static void set_strikeout(QListWidgetItem *item, bool on)
114 {
115     set(item, on, &QFont::setStrikeOut);
116 }
117 
apply_config(const KConfigGroup & group,QListWidgetItem * item)118 static void apply_config(const KConfigGroup &group, QListWidgetItem *item)
119 {
120     if (!item) {
121         return;
122     }
123 
124     const QString name = group.readEntry("Name");
125     item->setText(name.isEmpty() ? i18nc("Key filter without user-assigned name", "<unnamed>") : name);
126     item->setData(HasNameRole, !name.isEmpty());
127     item->setData(MayChangeNameRole, !group.isEntryImmutable("Name"));
128 
129     const QColor fg = group.readEntry("foreground-color", QColor());
130     item->setData(Qt::ForegroundRole, fg.isValid() ? QBrush(fg) : QVariant());
131     item->setData(MayChangeForegroundRole, !group.isEntryImmutable("foreground-color"));
132 
133     const QColor bg = group.readEntry("background-color", QColor());
134     item->setData(Qt::BackgroundRole, bg.isValid() ? QBrush(bg) : QVariant());
135     item->setData(MayChangeBackgroundRole, !group.isEntryImmutable("background-color"));
136 
137     const QFont defaultFont = tryToFindFontFor(item);
138     if (group.hasKey("font")) {
139         const QFont font = group.readEntry("font", defaultFont);
140         item->setData(Qt::FontRole, font != defaultFont ? font : QVariant());
141         item->setData(HasFontRole,  font != defaultFont);
142     } else {
143         QFont font = defaultFont;
144         font.setStrikeOut(group.readEntry("font-strikeout", false));
145         font.setItalic(group.readEntry("font-italic", false));
146         font.setBold(group.readEntry("font-bold", false));
147         item->setData(Qt::FontRole, font);
148         item->setData(HasFontRole, false);
149     }
150     item->setData(MayChangeFontRole, !group.isEntryImmutable("font"));
151     item->setData(MayChangeItalicRole, !group.isEntryImmutable("font-italic"));
152     item->setData(MayChangeBoldRole, !group.isEntryImmutable("font-bold"));
153     item->setData(MayChangeStrikeOutRole, !group.isEntryImmutable("font-strikeout"));
154 
155     const QString iconName = group.readEntry("icon");
156     item->setData(Qt::DecorationRole, iconName.isEmpty() ? QVariant() : QIcon::fromTheme(iconName));
157     item->setData(IconNameRole, iconName.isEmpty() ? QVariant() : iconName);
158     item->setData(MayChangeIconRole, !group.isEntryImmutable("icon"));
159 }
160 
erase_if_allowed(QListWidgetItem * item,int role,int allowRole)161 static void erase_if_allowed(QListWidgetItem *item, int role, int allowRole)
162 {
163     if (item && item->data(allowRole).toBool()) {
164         item->setData(role, QVariant());
165     }
166 }
167 
168 #if 0
169 static void erase_if_allowed(QListWidgetItem *item, const int role[], size_t numRoles, int allowRole)
170 {
171     if (item && item->data(allowRole).toBool())
172         for (unsigned int i = 0; i < numRoles; ++i) {
173             item->setData(role[i], QVariant());
174         }
175 }
176 
177 static void erase_if_allowed(QListWidgetItem *item, int role, const int allowRole[], size_t numAllowRoles)
178 {
179     if (!item) {
180         return;
181     }
182     for (unsigned int i = 0; i < numAllowRoles; ++i)
183         if (!item->data(allowRole[i]).toBool()) {
184             return;
185         }
186     item->setData(role, QVariant());
187 }
188 #endif
189 
erase_if_allowed(QListWidgetItem * item,const int role[],size_t numRoles,const int allowRole[],size_t numAllowRoles)190 static void erase_if_allowed(QListWidgetItem *item, const int role[], size_t numRoles, const int allowRole[], size_t numAllowRoles)
191 {
192     if (!item) {
193         return;
194     }
195     for (unsigned int i = 0; i < numAllowRoles; ++i)
196         if (!item->data(allowRole[i]).toBool()) {
197             return;
198         }
199     for (unsigned int i = 0; i < numRoles; ++i) {
200         item->setData(role[i], QVariant());
201     }
202 }
203 
set_default_appearance(QListWidgetItem * item)204 static void set_default_appearance(QListWidgetItem *item)
205 {
206     if (!item) {
207         return;
208     }
209     erase_if_allowed(item, Qt::ForegroundRole, MayChangeForegroundRole);
210     erase_if_allowed(item, Qt::BackgroundRole, MayChangeBackgroundRole);
211     erase_if_allowed(item, Qt::DecorationRole, MayChangeIconRole);
212     static const int fontRoles[] = { Qt::FontRole, HasFontRole };
213     static const int fontAllowRoles[] = {
214         MayChangeFontRole,
215         MayChangeItalicRole,
216         MayChangeBoldRole,
217         MayChangeStrikeOutRole,
218     };
219     erase_if_allowed(item, fontRoles, sizeof(fontRoles) / sizeof(int), fontAllowRoles, sizeof(fontAllowRoles) / sizeof(int));
220 }
221 
writeOrDelete(KConfigGroup & group,const char * key,const QVariant & value)222 static void writeOrDelete(KConfigGroup &group, const char *key, const QVariant &value)
223 {
224     if (value.isValid()) {
225         group.writeEntry(key, value);
226     } else {
227         group.deleteEntry(key);
228     }
229 }
230 
brush2color(const QVariant & v)231 static QVariant brush2color(const QVariant &v)
232 {
233     if (v.isValid()) {
234         if (v.type() == QVariant::Color) {
235             return v;
236         } else if (v.type() == QVariant::Brush) {
237             return v.value<QBrush>().color();
238         }
239     }
240     return QVariant();
241 }
242 
save_to_config(const QListWidgetItem * item,KConfigGroup & group)243 static void save_to_config(const QListWidgetItem *item, KConfigGroup &group)
244 {
245     if (!item) {
246         return;
247     }
248     writeOrDelete(group, "Name", item->data(HasNameRole).toBool() ? item->text() : QVariant());
249     writeOrDelete(group, "foreground-color", brush2color(item->data(Qt::ForegroundRole)));
250     writeOrDelete(group, "background-color", brush2color(item->data(Qt::BackgroundRole)));
251     writeOrDelete(group, "icon", item->data(IconNameRole));
252 
253     group.deleteEntry("font");
254     group.deleteEntry("font-strikeout");
255     group.deleteEntry("font-italic");
256     group.deleteEntry("font-bold");
257 
258     if (item->data(HasFontRole).toBool()) {
259         writeOrDelete(group, "font", item->data(Qt::FontRole));
260         return;
261     }
262 
263     if (is_strikeout(item)) {
264         group.writeEntry("font-strikeout", true);
265     }
266     if (is_italic(item)) {
267         group.writeEntry("font-italic", true);
268     }
269     if (is_bold(item)) {
270         group.writeEntry("font-bold", true);
271     }
272 }
273 
kiosk_enable(QWidget * w,const QListWidgetItem * item,int allowRole)274 static void kiosk_enable(QWidget *w, const QListWidgetItem *item, int allowRole)
275 {
276     if (!w) {
277         return;
278     }
279     if (item && !item->data(allowRole).toBool()) {
280         w->setEnabled(false);
281         w->setToolTip(i18n("This parameter has been locked down by the system administrator."));
282     } else {
283         w->setEnabled(item);
284         w->setToolTip(QString());
285     }
286 }
287 
288 class AppearanceConfigWidget::Private : public Ui_AppearanceConfigWidget
289 {
290     friend class ::Kleo::Config::AppearanceConfigWidget;
291     AppearanceConfigWidget *const q;
292 public:
Private(AppearanceConfigWidget * qq)293     explicit Private(AppearanceConfigWidget *qq)
294         : Ui_AppearanceConfigWidget(),
295           q(qq),
296           dnOrderWidget(nullptr)
297     {
298         setupUi(q);
299 
300         if (QLayout *const l = q->layout()) {
301             l->setContentsMargins(0, 0, 0, 0);
302         }
303 
304         auto w = new QWidget;
305         dnOrderWidget = Kleo::DNAttributeMapper::instance()->configWidget(w);
306         dnOrderWidget->setObjectName(QStringLiteral("dnOrderWidget"));
307         (new QVBoxLayout(w))->addWidget(dnOrderWidget);
308 
309         tabWidget->addTab(w, i18n("DN-Attribute Order"));
310 
311         connect(dnOrderWidget, &DNAttributeOrderConfigWidget::changed, q, &AppearanceConfigWidget::changed);
312 
313         connect(iconButton, SIGNAL(clicked()), q, SLOT(slotIconClicked()));
314 #ifndef QT_NO_COLORDIALOG
315         connect(foregroundButton, SIGNAL(clicked()), q, SLOT(slotForegroundClicked()));
316         connect(backgroundButton, SIGNAL(clicked()), q, SLOT(slotBackgroundClicked()));
317 #else
318         foregroundButton->hide();
319         backgroundButton->hide();
320 #endif
321 #ifndef QT_NO_FONTDIALOG
322         connect(fontButton, SIGNAL(clicked()), q, SLOT(slotFontClicked()));
323 #else
324         fontButton->hide();
325 #endif
326         connect(categoriesLV, SIGNAL(itemSelectionChanged()), q, SLOT(slotSelectionChanged()));
327         connect(defaultLookPB, SIGNAL(clicked()), q, SLOT(slotDefaultClicked()));
328         connect(italicCB, SIGNAL(toggled(bool)), q, SLOT(slotItalicToggled(bool)));
329         connect(boldCB, SIGNAL(toggled(bool)), q, SLOT(slotBoldToggled(bool)));
330         connect(strikeoutCB, SIGNAL(toggled(bool)), q, SLOT(slotStrikeOutToggled(bool)));
331         connect(tooltipValidityCheckBox, SIGNAL(toggled(bool)), q, SLOT(slotTooltipValidityChanged(bool)));
332         connect(tooltipOwnerCheckBox, SIGNAL(toggled(bool)), q, SLOT(slotTooltipOwnerChanged(bool)));
333         connect(tooltipDetailsCheckBox, SIGNAL(toggled(bool)), q, SLOT(slotTooltipDetailsChanged(bool)));
334         connect(useTagsCheckBox, SIGNAL(toggled(bool)), q, SLOT(slotUseTagsChanged(bool)));
335     }
336 
337 private:
338     void enableDisableActions(QListWidgetItem *item);
339     QListWidgetItem *selectedItem() const;
340 
341 private:
342     void slotIconClicked();
343 #ifndef QT_NO_COLORDIALOG
344     void slotForegroundClicked();
345     void slotBackgroundClicked();
346 #endif
347 #ifndef QT_NO_FONTDIALOG
348     void slotFontClicked();
349 #endif
350     void slotSelectionChanged();
351     void slotDefaultClicked();
352     void slotItalicToggled(bool);
353     void slotBoldToggled(bool);
354     void slotStrikeOutToggled(bool);
355     void slotTooltipValidityChanged(bool);
356     void slotTooltipOwnerChanged(bool);
357     void slotTooltipDetailsChanged(bool);
358     void slotUseTagsChanged(bool);
359 
360 private:
361     Kleo::DNAttributeOrderConfigWidget *dnOrderWidget;
362 };
363 
AppearanceConfigWidget(QWidget * p,Qt::WindowFlags f)364 AppearanceConfigWidget::AppearanceConfigWidget(QWidget *p, Qt::WindowFlags f)
365     : QWidget(p, f), d(new Private(this))
366 {
367 //    load();
368 }
369 
~AppearanceConfigWidget()370 AppearanceConfigWidget::~AppearanceConfigWidget() {}
371 
slotSelectionChanged()372 void AppearanceConfigWidget::Private::slotSelectionChanged()
373 {
374     enableDisableActions(selectedItem());
375 }
376 
selectedItem() const377 QListWidgetItem *AppearanceConfigWidget::Private::selectedItem() const
378 {
379     const QList<QListWidgetItem *> items = categoriesLV->selectedItems();
380     return items.empty() ? nullptr : items.front();
381 }
382 
enableDisableActions(QListWidgetItem * item)383 void AppearanceConfigWidget::Private::enableDisableActions(QListWidgetItem *item)
384 {
385     kiosk_enable(iconButton, item, MayChangeIconRole);
386 #ifndef QT_NO_COLORDIALOG
387     kiosk_enable(foregroundButton, item, MayChangeForegroundRole);
388     kiosk_enable(backgroundButton, item, MayChangeBackgroundRole);
389 #endif
390 #ifndef QT_NO_FONTDIALOG
391     kiosk_enable(fontButton, item, MayChangeFontRole);
392 #endif
393     kiosk_enable(italicCB, item, MayChangeItalicRole);
394     kiosk_enable(boldCB, item, MayChangeBoldRole);
395     kiosk_enable(strikeoutCB, item, MayChangeStrikeOutRole);
396 
397     defaultLookPB->setEnabled(item);
398 
399     italicCB->setChecked(is_italic(item));
400     boldCB->setChecked(is_bold(item));
401     strikeoutCB->setChecked(is_strikeout(item));
402 }
403 
slotDefaultClicked()404 void AppearanceConfigWidget::Private::slotDefaultClicked()
405 {
406 
407     QListWidgetItem *const item = selectedItem();
408     if (!item) {
409         return;
410     }
411 
412     set_default_appearance(item);
413     enableDisableActions(item);
414 
415     Q_EMIT q->changed();
416 }
417 
defaults()418 void AppearanceConfigWidget::defaults()
419 {
420 
421     // This simply means "default look for every category"
422     for (int i = 0, end = d->categoriesLV->count(); i != end; ++i) {
423         set_default_appearance(d->categoriesLV->item(i));
424     }
425     d->tooltipValidityCheckBox->setChecked(true);
426     d->tooltipOwnerCheckBox->setChecked(false);
427     d->tooltipDetailsCheckBox->setChecked(false);
428 
429     d->dnOrderWidget->defaults();
430 
431     Q_EMIT changed();
432 }
433 
load()434 void AppearanceConfigWidget::load()
435 {
436 
437     d->dnOrderWidget->load();
438 
439     d->categoriesLV->clear();
440     KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("libkleopatrarc"));
441     if (!config) {
442         return;
443     }
444     const QStringList groups = config->groupList().filter(QRegularExpression(QStringLiteral("^Key Filter #\\d+$")));
445     for (const QString &group : groups) {
446         //QListWidgetItem * item = new QListWidgetItem( d->categoriesLV );
447         apply_config(KConfigGroup(config, group), new QListWidgetItem(d->categoriesLV));
448     }
449 
450     const TooltipPreferences prefs;
451     d->tooltipValidityCheckBox->setChecked(prefs.showValidity());
452     d->tooltipOwnerCheckBox->setChecked(prefs.showOwnerInformation());
453     d->tooltipDetailsCheckBox->setChecked(prefs.showCertificateDetails());
454 
455     const TagsPreferences tagsPrefs;
456     d->useTagsCheckBox->setChecked(tagsPrefs.useTags());
457 }
458 
save()459 void AppearanceConfigWidget::save()
460 {
461 
462     d->dnOrderWidget->save();
463 
464     TooltipPreferences prefs;
465     prefs.setShowValidity(d->tooltipValidityCheckBox->isChecked());
466     prefs.setShowOwnerInformation(d->tooltipOwnerCheckBox->isChecked());
467     prefs.setShowCertificateDetails(d->tooltipDetailsCheckBox->isChecked());
468     prefs.save();
469 
470     KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("libkleopatrarc"));
471     if (!config) {
472         return;
473     }
474     // We know (assume) that the groups in the config object haven't changed,
475     // so we just iterate over them and over the listviewitems, and map one-to-one.
476     const QStringList groups = config->groupList().filter(QRegularExpression(QStringLiteral("^Key Filter #\\d+$")));
477 #if 0
478     if (groups.isEmpty()) {
479         // If we created the default categories ourselves just now, then we need to make up their list
480         Q3ListViewItemIterator lvit(categoriesLV);
481         for (; lvit.current(); ++lvit) {
482             groups << lvit.current()->text(0);
483         }
484     }
485 #endif
486     for (int i = 0, end = std::min(groups.size(), d->categoriesLV->count()); i != end; ++i) {
487         const QListWidgetItem *const item = d->categoriesLV->item(i);
488         Q_ASSERT(item);
489         KConfigGroup group(config, groups[i]);
490         save_to_config(item, group);
491     }
492 
493     TagsPreferences tagsPrefs;
494     tagsPrefs.setUseTags(d->useTagsCheckBox->isChecked());
495 
496     config->sync();
497     KeyFilterManager::instance()->reload();
498 }
499 
slotIconClicked()500 void AppearanceConfigWidget::Private::slotIconClicked()
501 {
502     QListWidgetItem *const item = selectedItem();
503     if (!item) {
504         return;
505     }
506 
507     const QString iconName = KIconDialog::getIcon( /* repeating default arguments begin */
508                                  KIconLoader::Desktop, KIconLoader::Application, false, 0, false,
509                                  /* repeating default arguments end */
510                                  q);
511     if (iconName.isEmpty()) {
512         return;
513     }
514 
515     item->setIcon(QIcon::fromTheme(iconName));
516     item->setData(IconNameRole, iconName);
517     Q_EMIT q->changed();
518 }
519 
520 #ifndef QT_NO_COLORDIALOG
slotForegroundClicked()521 void AppearanceConfigWidget::Private::slotForegroundClicked()
522 {
523     QListWidgetItem *const item = selectedItem();
524     if (!item) {
525         return;
526     }
527 
528     const QVariant v = brush2color(item->data(Qt::ForegroundRole));
529 
530     const QColor initial = v.isValid() ? v.value<QColor>() : categoriesLV->palette().color(QPalette::Normal, QPalette::Text);
531     const QColor c = QColorDialog::getColor(initial, q);
532 
533     if (c.isValid()) {
534         item->setData(Qt::ForegroundRole, QBrush(c));
535         Q_EMIT q->changed();
536     }
537 }
538 
slotBackgroundClicked()539 void AppearanceConfigWidget::Private::slotBackgroundClicked()
540 {
541     QListWidgetItem *const item = selectedItem();
542     if (!item) {
543         return;
544     }
545 
546     const QVariant v = brush2color(item->data(Qt::BackgroundRole));
547 
548     const QColor initial = v.isValid() ? v.value<QColor>() : categoriesLV->palette().color(QPalette::Normal, QPalette::Base);
549     const QColor c = QColorDialog::getColor(initial, q);
550 
551     if (c.isValid()) {
552         item->setData(Qt::BackgroundRole, QBrush(c));
553         Q_EMIT q->changed();
554     }
555 }
556 #endif // QT_NO_COLORDIALOG
557 
558 #ifndef QT_NO_FONTDIALOG
slotFontClicked()559 void AppearanceConfigWidget::Private::slotFontClicked()
560 {
561     QListWidgetItem *const item = selectedItem();
562     if (!item) {
563         return;
564     }
565 
566     const QVariant v = item->data(Qt::FontRole);
567 
568     bool ok = false;
569     const QFont defaultFont = tryToFindFontFor(item);
570     const QFont initial = v.isValid() && v.type() == QVariant::Font ? v.value<QFont>() : defaultFont;
571     QFont f = QFontDialog::getFont(&ok, initial, q);
572     if (!ok) {
573         return;
574     }
575 
576     // disallow circumventing KIOSK:
577     if (!item->data(MayChangeItalicRole).toBool()) {
578         f.setItalic(initial.italic());
579     }
580     if (!item->data(MayChangeBoldRole).toBool()) {
581         f.setBold(initial.bold());
582     }
583     if (!item->data(MayChangeStrikeOutRole).toBool()) {
584         f.setStrikeOut(initial.strikeOut());
585     }
586 
587     item->setData(Qt::FontRole, f != defaultFont ? f : QVariant());
588     item->setData(HasFontRole, true);
589     Q_EMIT q->changed();
590 }
591 #endif // QT_NO_FONTDIALOG
592 
slotItalicToggled(bool on)593 void AppearanceConfigWidget::Private::slotItalicToggled(bool on)
594 {
595     set_italic(selectedItem(), on);
596     Q_EMIT q->changed();
597 }
598 
slotBoldToggled(bool on)599 void AppearanceConfigWidget::Private::slotBoldToggled(bool on)
600 {
601     set_bold(selectedItem(), on);
602     Q_EMIT q->changed();
603 }
604 
slotStrikeOutToggled(bool on)605 void AppearanceConfigWidget::Private::slotStrikeOutToggled(bool on)
606 {
607     set_strikeout(selectedItem(), on);
608     Q_EMIT q->changed();
609 }
610 
slotTooltipValidityChanged(bool)611 void AppearanceConfigWidget::Private::slotTooltipValidityChanged(bool)
612 {
613     Q_EMIT q->changed();
614 }
615 
slotTooltipOwnerChanged(bool)616 void AppearanceConfigWidget::Private::slotTooltipOwnerChanged(bool)
617 {
618     Q_EMIT q->changed();
619 }
620 
slotTooltipDetailsChanged(bool)621 void AppearanceConfigWidget::Private::slotTooltipDetailsChanged(bool)
622 {
623     Q_EMIT q->changed();
624 }
625 
slotUseTagsChanged(bool)626 void AppearanceConfigWidget::Private::slotUseTagsChanged(bool)
627 {
628     Q_EMIT q->changed();
629 }
630 
631 #include "moc_appearanceconfigwidget.cpp"
632