File indexing completed on 2023-09-24 11:39:10
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2003 Benjamin C Meyer <ben+kdelibs at meyerhome dot net> 0004 SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org> 0005 SPDX-FileCopyrightText: 2017 Friedrich W. H. Kossebau <kossebau@kde.org> 0006 SPDX-FileCopyrightText: 2020 Kevin Ottens <kevin.ottens@enioka.com> 0007 SPDX-FileCopyrightText: 2020 Cyril Rossi <cyril.rossi@enioka.com> 0008 0009 SPDX-License-Identifier: LGPL-2.0-or-later 0010 */ 0011 0012 #include "kconfigdialogmanager.h" 0013 #include "kconfigdialogmanager_p.h" 0014 #include "kconfigwidgets_debug.h" 0015 0016 #include <QComboBox> 0017 #include <QGroupBox> 0018 #include <QLabel> 0019 #include <QLayout> 0020 #include <QMetaObject> 0021 #include <QMetaProperty> 0022 #include <QRadioButton> 0023 #include <QTimer> 0024 0025 #include <KConfigSkeleton> 0026 0027 typedef QHash<QString, QByteArray> MyHash; 0028 Q_GLOBAL_STATIC(MyHash, s_propertyMap) 0029 Q_GLOBAL_STATIC(MyHash, s_changedMap) 0030 0031 KConfigDialogManager::KConfigDialogManager(QWidget *parent, KCoreConfigSkeleton *conf) 0032 : QObject(parent) 0033 , d(new KConfigDialogManagerPrivate(this)) 0034 { 0035 d->m_conf = conf; 0036 d->m_dialog = parent; 0037 init(true); 0038 } 0039 0040 KConfigDialogManager::~KConfigDialogManager() = default; 0041 0042 // KF6: Drop this and get signals only from metaObject and/or widget's dynamic properties kcfg_property/kcfg_propertyNotify 0043 void KConfigDialogManager::initMaps() 0044 { 0045 if (s_propertyMap()->isEmpty()) { 0046 s_propertyMap()->insert(QStringLiteral("KButtonGroup"), "current"); 0047 s_propertyMap()->insert(QStringLiteral("KColorButton"), "color"); 0048 s_propertyMap()->insert(QStringLiteral("KColorCombo"), "color"); 0049 s_propertyMap()->insert(QStringLiteral("KKeySequenceWidget"), "keySequence"); 0050 } 0051 0052 if (s_changedMap()->isEmpty()) { 0053 // QT 0054 s_changedMap()->insert(QStringLiteral("QCheckBox"), SIGNAL(stateChanged(int))); 0055 s_changedMap()->insert(QStringLiteral("QPushButton"), SIGNAL(clicked(bool))); 0056 s_changedMap()->insert(QStringLiteral("QRadioButton"), SIGNAL(toggled(bool))); 0057 s_changedMap()->insert(QStringLiteral("QGroupBox"), SIGNAL(toggled(bool))); 0058 s_changedMap()->insert(QStringLiteral("QComboBox"), SIGNAL(activated(int))); 0059 s_changedMap()->insert(QStringLiteral("QDateEdit"), SIGNAL(dateChanged(QDate))); 0060 s_changedMap()->insert(QStringLiteral("QTimeEdit"), SIGNAL(timeChanged(QTime))); 0061 s_changedMap()->insert(QStringLiteral("QDateTimeEdit"), SIGNAL(dateTimeChanged(QDateTime))); 0062 s_changedMap()->insert(QStringLiteral("QDial"), SIGNAL(valueChanged(int))); 0063 s_changedMap()->insert(QStringLiteral("QDoubleSpinBox"), SIGNAL(valueChanged(double))); 0064 s_changedMap()->insert(QStringLiteral("QLineEdit"), SIGNAL(textChanged(QString))); 0065 s_changedMap()->insert(QStringLiteral("QSlider"), SIGNAL(valueChanged(int))); 0066 s_changedMap()->insert(QStringLiteral("QSpinBox"), SIGNAL(valueChanged(int))); 0067 s_changedMap()->insert(QStringLiteral("QTextEdit"), SIGNAL(textChanged())); 0068 s_changedMap()->insert(QStringLiteral("QTextBrowser"), SIGNAL(sourceChanged(QString))); 0069 s_changedMap()->insert(QStringLiteral("QPlainTextEdit"), SIGNAL(textChanged())); 0070 s_changedMap()->insert(QStringLiteral("QTabWidget"), SIGNAL(currentChanged(int))); 0071 0072 // KDE 0073 s_changedMap()->insert(QStringLiteral("KComboBox"), SIGNAL(activated(int))); 0074 s_changedMap()->insert(QStringLiteral("KFontComboBox"), SIGNAL(activated(int))); 0075 s_changedMap()->insert(QStringLiteral("KFontRequester"), SIGNAL(fontSelected(QFont))); 0076 s_changedMap()->insert(QStringLiteral("KFontChooser"), SIGNAL(fontSelected(QFont))); 0077 s_changedMap()->insert(QStringLiteral("KColorCombo"), SIGNAL(activated(QColor))); 0078 s_changedMap()->insert(QStringLiteral("KColorButton"), SIGNAL(changed(QColor))); 0079 s_changedMap()->insert(QStringLiteral("KDatePicker"), SIGNAL(dateSelected(QDate))); 0080 s_changedMap()->insert(QStringLiteral("KDateWidget"), SIGNAL(changed(QDate))); 0081 s_changedMap()->insert(QStringLiteral("KDateTimeWidget"), SIGNAL(valueChanged(QDateTime))); 0082 s_changedMap()->insert(QStringLiteral("KEditListWidget"), SIGNAL(changed())); 0083 s_changedMap()->insert(QStringLiteral("KListWidget"), SIGNAL(itemSelectionChanged())); 0084 s_changedMap()->insert(QStringLiteral("KLineEdit"), SIGNAL(textChanged(QString))); 0085 s_changedMap()->insert(QStringLiteral("KRestrictedLine"), SIGNAL(textChanged(QString))); 0086 s_changedMap()->insert(QStringLiteral("KTextEdit"), SIGNAL(textChanged())); 0087 s_changedMap()->insert(QStringLiteral("KUrlRequester"), SIGNAL(textChanged(QString))); 0088 s_changedMap()->insert(QStringLiteral("KUrlComboRequester"), SIGNAL(textChanged(QString))); 0089 s_changedMap()->insert(QStringLiteral("KUrlComboBox"), SIGNAL(urlActivated(QUrl))); 0090 s_changedMap()->insert(QStringLiteral("KButtonGroup"), SIGNAL(changed(int))); 0091 } 0092 } 0093 0094 QHash<QString, QByteArray> *KConfigDialogManager::propertyMap() 0095 { 0096 initMaps(); 0097 return s_propertyMap(); 0098 } 0099 0100 void KConfigDialogManager::init(bool trackChanges) 0101 { 0102 initMaps(); 0103 d->trackChanges = trackChanges; 0104 0105 // Go through all of the children of the widgets and find all known widgets 0106 (void)parseChildren(d->m_dialog, trackChanges); 0107 } 0108 0109 void KConfigDialogManager::addWidget(QWidget *widget) 0110 { 0111 (void)parseChildren(widget, true); 0112 } 0113 0114 void KConfigDialogManager::setupWidget(QWidget *widget, KConfigSkeletonItem *item) 0115 { 0116 QVariant minValue = item->minValue(); 0117 if (minValue.isValid()) { 0118 // KSelector is using this property 0119 if (widget->metaObject()->indexOfProperty("minValue") != -1) { 0120 widget->setProperty("minValue", minValue); 0121 } 0122 if (widget->metaObject()->indexOfProperty("minimum") != -1) { 0123 widget->setProperty("minimum", minValue); 0124 } 0125 } 0126 QVariant maxValue = item->maxValue(); 0127 if (maxValue.isValid()) { 0128 // KSelector is using this property 0129 if (widget->metaObject()->indexOfProperty("maxValue") != -1) { 0130 widget->setProperty("maxValue", maxValue); 0131 } 0132 if (widget->metaObject()->indexOfProperty("maximum") != -1) { 0133 widget->setProperty("maximum", maxValue); 0134 } 0135 } 0136 0137 if (widget->whatsThis().isEmpty()) { 0138 QString whatsThis = item->whatsThis(); 0139 if (!whatsThis.isEmpty()) { 0140 widget->setWhatsThis(whatsThis); 0141 } 0142 } 0143 0144 if (widget->toolTip().isEmpty()) { 0145 QString toolTip = item->toolTip(); 0146 if (!toolTip.isEmpty()) { 0147 widget->setToolTip(toolTip); 0148 } 0149 } 0150 0151 // If it is a QGroupBox with only autoExclusive buttons 0152 // and has no custom property and the config item type 0153 // is an integer, assume we want to save the index like we did with 0154 // KButtonGroup instead of if it is checked or not 0155 QGroupBox *gb = qobject_cast<QGroupBox *>(widget); 0156 if (gb && getCustomProperty(gb).isEmpty()) { 0157 const KConfigSkeletonItem *item = d->m_conf->findItem(widget->objectName().mid(5)); 0158 if (item->property().userType() == QMetaType::Int) { 0159 QObjectList children = gb->children(); 0160 children.removeAll(gb->layout()); 0161 const QList<QAbstractButton *> buttons = gb->findChildren<QAbstractButton *>(); 0162 bool allAutoExclusiveDirectChildren = true; 0163 for (QAbstractButton *button : buttons) { 0164 allAutoExclusiveDirectChildren = allAutoExclusiveDirectChildren && button->autoExclusive() && button->parent() == gb; 0165 } 0166 if (allAutoExclusiveDirectChildren) { 0167 d->allExclusiveGroupBoxes << widget; 0168 } 0169 } 0170 } 0171 0172 if (!item->isEqual(property(widget))) { 0173 setProperty(widget, item->property()); 0174 } 0175 0176 d->updateWidgetIndicator(item->name(), widget); 0177 } 0178 0179 bool KConfigDialogManager::parseChildren(const QWidget *widget, bool trackChanges) 0180 { 0181 bool valueChanged = false; 0182 const QList<QObject *> listOfChildren = widget->children(); 0183 if (listOfChildren.isEmpty()) { //?? XXX 0184 return valueChanged; 0185 } 0186 0187 const QMetaMethod onWidgetModifiedSlot = metaObject()->method(metaObject()->indexOfSlot("onWidgetModified()")); 0188 Q_ASSERT(onWidgetModifiedSlot.isValid() && metaObject()->indexOfSlot("onWidgetModified()") >= 0); 0189 0190 for (QObject *object : listOfChildren) { 0191 if (!object->isWidgetType()) { 0192 continue; // Skip non-widgets 0193 } 0194 0195 QWidget *childWidget = static_cast<QWidget *>(object); 0196 0197 QString widgetName = childWidget->objectName(); 0198 bool bParseChildren = true; 0199 bool bSaveInsideGroupBox = d->insideGroupBox; 0200 0201 if (widgetName.startsWith(QLatin1String("kcfg_"))) { 0202 // This is one of our widgets! 0203 QString configId = widgetName.mid(5); 0204 KConfigSkeletonItem *item = d->m_conf->findItem(configId); 0205 if (item) { 0206 d->knownWidget.insert(configId, childWidget); 0207 0208 setupWidget(childWidget, item); 0209 0210 if (trackChanges) { 0211 bool changeSignalFound = false; 0212 0213 if (d->allExclusiveGroupBoxes.contains(childWidget)) { 0214 const QList<QAbstractButton *> buttons = childWidget->findChildren<QAbstractButton *>(); 0215 for (QAbstractButton *button : buttons) { 0216 connect(button, &QAbstractButton::toggled, this, [this] { 0217 d->onWidgetModified(); 0218 }); 0219 } 0220 } 0221 0222 QByteArray propertyChangeSignal = getCustomPropertyChangedSignal(childWidget); 0223 if (propertyChangeSignal.isEmpty()) { 0224 propertyChangeSignal = getUserPropertyChangedSignal(childWidget); 0225 } 0226 0227 if (propertyChangeSignal.isEmpty()) { 0228 // get the change signal from the meta object 0229 const QMetaObject *metaObject = childWidget->metaObject(); 0230 QByteArray userproperty = getCustomProperty(childWidget); 0231 if (userproperty.isEmpty()) { 0232 userproperty = getUserProperty(childWidget); 0233 } 0234 if (!userproperty.isEmpty()) { 0235 const int indexOfProperty = metaObject->indexOfProperty(userproperty.constData()); 0236 if (indexOfProperty != -1) { 0237 const QMetaProperty property = metaObject->property(indexOfProperty); 0238 const QMetaMethod notifySignal = property.notifySignal(); 0239 if (notifySignal.isValid()) { 0240 connect(childWidget, notifySignal, this, onWidgetModifiedSlot); 0241 changeSignalFound = true; 0242 } 0243 } 0244 } else { 0245 qCWarning(KCONFIG_WIDGETS_LOG) << "Don't know how to monitor widget" << childWidget->metaObject()->className() << "for changes!"; 0246 } 0247 } else { 0248 connect(childWidget, propertyChangeSignal.constData(), this, SLOT(onWidgetModified())); 0249 changeSignalFound = true; 0250 } 0251 0252 if (changeSignalFound) { 0253 QComboBox *cb = qobject_cast<QComboBox *>(childWidget); 0254 if (cb && cb->isEditable()) { 0255 connect(cb, &QComboBox::editTextChanged, this, &KConfigDialogManager::widgetModified); 0256 } 0257 } 0258 } 0259 QGroupBox *gb = qobject_cast<QGroupBox *>(childWidget); 0260 if (!gb) { 0261 bParseChildren = false; 0262 } else { 0263 d->insideGroupBox = true; 0264 } 0265 } else { 0266 qCWarning(KCONFIG_WIDGETS_LOG) << "A widget named" << widgetName << "was found but there is no setting named" << configId; 0267 } 0268 } else if (QLabel *label = qobject_cast<QLabel *>(childWidget)) { 0269 QWidget *buddy = label->buddy(); 0270 if (!buddy) { 0271 continue; 0272 } 0273 QString buddyName = buddy->objectName(); 0274 if (buddyName.startsWith(QLatin1String("kcfg_"))) { 0275 // This is one of our widgets! 0276 QString configId = buddyName.mid(5); 0277 d->buddyWidget.insert(configId, childWidget); 0278 } 0279 } 0280 // kf5: commented out to reduce debug output 0281 // #ifndef NDEBUG 0282 // else if (!widgetName.isEmpty() && trackChanges) 0283 // { 0284 // QHash<QString, QByteArray>::const_iterator changedIt = s_changedMap()->constFind(childWidget->metaObject()->className()); 0285 // if (changedIt != s_changedMap()->constEnd()) 0286 // { 0287 // if ((!d->insideGroupBox || !qobject_cast<QRadioButton*>(childWidget)) && 0288 // !qobject_cast<QGroupBox*>(childWidget) &&!qobject_cast<QTabWidget*>(childWidget) ) 0289 // qCDebug(KCONFIG_WIDGETS_LOG) << "Widget '" << widgetName << "' (" << childWidget->metaObject()->className() << ") remains unmanaged."; 0290 // } 0291 // } 0292 // #endif 0293 0294 if (bParseChildren) { 0295 // this widget is not known as something we can store. 0296 // Maybe we can store one of its children. 0297 valueChanged |= parseChildren(childWidget, trackChanges); 0298 } 0299 d->insideGroupBox = bSaveInsideGroupBox; 0300 } 0301 return valueChanged; 0302 } 0303 0304 void KConfigDialogManager::updateWidgets() 0305 { 0306 bool changed = false; 0307 bool bSignalsBlocked = signalsBlocked(); 0308 blockSignals(true); 0309 0310 QWidget *widget; 0311 QHashIterator<QString, QWidget *> it(d->knownWidget); 0312 while (it.hasNext()) { 0313 it.next(); 0314 widget = it.value(); 0315 0316 KConfigSkeletonItem *item = d->m_conf->findItem(it.key()); 0317 if (!item) { 0318 qCWarning(KCONFIG_WIDGETS_LOG) << "The setting" << it.key() << "has disappeared!"; 0319 continue; 0320 } 0321 0322 if (!item->isEqual(property(widget))) { 0323 setProperty(widget, item->property()); 0324 // qCDebug(KCONFIG_WIDGETS_LOG) << "The setting" << it.key() << "[" << widget->className() << "] has changed"; 0325 changed = true; 0326 } 0327 if (item->isImmutable()) { 0328 widget->setEnabled(false); 0329 QWidget *buddy = d->buddyWidget.value(it.key(), nullptr); 0330 if (buddy) { 0331 buddy->setEnabled(false); 0332 } 0333 } 0334 } 0335 blockSignals(bSignalsBlocked); 0336 0337 if (changed) { 0338 QTimer::singleShot(0, this, &KConfigDialogManager::widgetModified); 0339 d->updateAllWidgetIndicators(); 0340 } 0341 } 0342 0343 void KConfigDialogManager::updateWidgetsDefault() 0344 { 0345 bool bUseDefaults = d->m_conf->useDefaults(true); 0346 updateWidgets(); 0347 d->m_conf->useDefaults(bUseDefaults); 0348 d->updateAllWidgetIndicators(); 0349 } 0350 0351 void KConfigDialogManager::setDefaultsIndicatorsVisible(bool enabled) 0352 { 0353 d->setDefaultsIndicatorsVisible(enabled); 0354 } 0355 0356 void KConfigDialogManager::updateSettings() 0357 { 0358 bool changed = false; 0359 0360 QWidget *widget; 0361 QHashIterator<QString, QWidget *> it(d->knownWidget); 0362 while (it.hasNext()) { 0363 it.next(); 0364 widget = it.value(); 0365 0366 KConfigSkeletonItem *item = d->m_conf->findItem(it.key()); 0367 if (!item) { 0368 qCWarning(KCONFIG_WIDGETS_LOG) << "The setting" << it.key() << "has disappeared!"; 0369 continue; 0370 } 0371 0372 QVariant fromWidget = property(widget); 0373 if (!item->isEqual(fromWidget)) { 0374 item->setProperty(fromWidget); 0375 changed = true; 0376 } 0377 } 0378 if (changed) { 0379 d->m_conf->save(); 0380 Q_EMIT settingsChanged(); 0381 d->updateAllWidgetIndicators(); 0382 } 0383 } 0384 0385 QByteArray KConfigDialogManager::getUserProperty(const QWidget *widget) const 0386 { 0387 MyHash *map = s_propertyMap(); 0388 const QMetaObject *metaObject = widget->metaObject(); 0389 const QString className(QLatin1String(metaObject->className())); 0390 auto it = map->find(className); 0391 if (it == map->end()) { 0392 const QMetaProperty userProp = metaObject->userProperty(); 0393 if (userProp.isValid()) { 0394 it = map->insert(className, userProp.name()); 0395 // qCDebug(KCONFIG_WIDGETS_LOG) << "class name: '" << className 0396 //<< " 's USER property: " << metaProperty.name() << endl; 0397 } else { 0398 return QByteArray(); // no USER property 0399 } 0400 } 0401 0402 const QComboBox *cb = qobject_cast<const QComboBox *>(widget); 0403 if (cb) { 0404 const char *qcomboUserPropertyName = cb->QComboBox::metaObject()->userProperty().name(); 0405 const int qcomboUserPropertyIndex = qcomboUserPropertyName ? cb->QComboBox::metaObject()->indexOfProperty(qcomboUserPropertyName) : -1; 0406 const char *widgetUserPropertyName = metaObject->userProperty().name(); 0407 const int widgetUserPropertyIndex = widgetUserPropertyName ? cb->metaObject()->indexOfProperty(widgetUserPropertyName) : -1; 0408 0409 // no custom user property set on subclass of QComboBox? 0410 if (qcomboUserPropertyIndex == widgetUserPropertyIndex) { 0411 return QByteArray(); // use the q/kcombobox special code 0412 } 0413 } 0414 0415 return it != map->end() ? it.value() : QByteArray{}; 0416 } 0417 0418 QByteArray KConfigDialogManager::getCustomProperty(const QWidget *widget) const 0419 { 0420 QVariant prop(widget->property("kcfg_property")); 0421 if (prop.isValid()) { 0422 if (!prop.canConvert<QByteArray>()) { 0423 qCWarning(KCONFIG_WIDGETS_LOG) << "kcfg_property on" << widget->metaObject()->className() << "is not of type ByteArray"; 0424 } else { 0425 return prop.toByteArray(); 0426 } 0427 } 0428 return QByteArray(); 0429 } 0430 0431 QByteArray KConfigDialogManager::getUserPropertyChangedSignal(const QWidget *widget) const 0432 { 0433 const QString className = QLatin1String(widget->metaObject()->className()); 0434 auto changedIt = s_changedMap()->constFind(className); 0435 0436 if (changedIt == s_changedMap()->constEnd()) { 0437 // If the class name of the widget wasn't in the monitored widgets map, then look for 0438 // it again using the super class name. This fixes a problem with using QtRuby/Korundum 0439 // widgets with KConfigXT where 'Qt::Widget' wasn't being seen a the real deal, even 0440 // though it was a 'QWidget'. 0441 if (widget->metaObject()->superClass()) { 0442 const QString parentClassName = QLatin1String(widget->metaObject()->superClass()->className()); 0443 changedIt = s_changedMap()->constFind(parentClassName); 0444 } 0445 } 0446 0447 return (changedIt == s_changedMap()->constEnd()) ? QByteArray() : *changedIt; 0448 } 0449 0450 QByteArray KConfigDialogManager::getCustomPropertyChangedSignal(const QWidget *widget) const 0451 { 0452 QVariant prop(widget->property("kcfg_propertyNotify")); 0453 if (prop.isValid()) { 0454 if (!prop.canConvert<QByteArray>()) { 0455 qCWarning(KCONFIG_WIDGETS_LOG) << "kcfg_propertyNotify on" << widget->metaObject()->className() << "is not of type ByteArray"; 0456 } else { 0457 return prop.toByteArray(); 0458 } 0459 } 0460 return QByteArray(); 0461 } 0462 0463 void KConfigDialogManager::setProperty(QWidget *w, const QVariant &v) 0464 { 0465 if (d->allExclusiveGroupBoxes.contains(w)) { 0466 const QList<QAbstractButton *> buttons = w->findChildren<QAbstractButton *>(); 0467 if (v.toInt() < buttons.count()) { 0468 buttons[v.toInt()]->setChecked(true); 0469 } 0470 return; 0471 } 0472 0473 QByteArray userproperty = getCustomProperty(w); 0474 if (userproperty.isEmpty()) { 0475 userproperty = getUserProperty(w); 0476 } 0477 if (userproperty.isEmpty()) { 0478 QComboBox *cb = qobject_cast<QComboBox *>(w); 0479 if (cb) { 0480 if (cb->isEditable()) { 0481 int i = cb->findText(v.toString()); 0482 if (i != -1) { 0483 cb->setCurrentIndex(i); 0484 } else { 0485 cb->setEditText(v.toString()); 0486 } 0487 } else { 0488 cb->setCurrentIndex(v.toInt()); 0489 } 0490 return; 0491 } 0492 } 0493 if (userproperty.isEmpty()) { 0494 qCWarning(KCONFIG_WIDGETS_LOG) << w->metaObject()->className() << "widget not handled!"; 0495 return; 0496 } 0497 0498 w->setProperty(userproperty.constData(), v); 0499 } 0500 0501 QVariant KConfigDialogManager::property(QWidget *w) const 0502 { 0503 if (d->allExclusiveGroupBoxes.contains(w)) { 0504 const QList<QAbstractButton *> buttons = w->findChildren<QAbstractButton *>(); 0505 for (int i = 0; i < buttons.count(); ++i) { 0506 if (buttons[i]->isChecked()) { 0507 return i; 0508 } 0509 } 0510 return -1; 0511 } 0512 0513 QByteArray userproperty = getCustomProperty(w); 0514 if (userproperty.isEmpty()) { 0515 userproperty = getUserProperty(w); 0516 } 0517 if (userproperty.isEmpty()) { 0518 QComboBox *cb = qobject_cast<QComboBox *>(w); 0519 if (cb) { 0520 if (cb->isEditable()) { 0521 return QVariant(cb->currentText()); 0522 } else { 0523 return QVariant(cb->currentIndex()); 0524 } 0525 } 0526 } 0527 if (userproperty.isEmpty()) { 0528 qCWarning(KCONFIG_WIDGETS_LOG) << w->metaObject()->className() << "widget not handled!"; 0529 return QVariant(); 0530 } 0531 0532 return w->property(userproperty.constData()); 0533 } 0534 0535 bool KConfigDialogManager::hasChanged() const 0536 { 0537 QWidget *widget; 0538 QHashIterator<QString, QWidget *> it(d->knownWidget); 0539 while (it.hasNext()) { 0540 it.next(); 0541 widget = it.value(); 0542 0543 KConfigSkeletonItem *item = d->m_conf->findItem(it.key()); 0544 if (!item) { 0545 qCWarning(KCONFIG_WIDGETS_LOG) << "The setting" << it.key() << "has disappeared!"; 0546 continue; 0547 } 0548 0549 if (!item->isEqual(property(widget))) { 0550 // qCDebug(KCONFIG_WIDGETS_LOG) << "Widget for '" << it.key() << "' has changed."; 0551 return true; 0552 } 0553 } 0554 return false; 0555 } 0556 0557 bool KConfigDialogManager::isDefault() const 0558 { 0559 QWidget *widget; 0560 QHashIterator<QString, QWidget *> it(d->knownWidget); 0561 while (it.hasNext()) { 0562 it.next(); 0563 widget = it.value(); 0564 0565 KConfigSkeletonItem *item = d->m_conf->findItem(it.key()); 0566 if (!item) { 0567 qCWarning(KCONFIG_WIDGETS_LOG) << "The setting" << it.key() << "has disappeared!"; 0568 continue; 0569 } 0570 0571 if (property(widget) != item->getDefault()) { 0572 return false; 0573 } 0574 } 0575 return true; 0576 } 0577 0578 KConfigDialogManagerPrivate::KConfigDialogManagerPrivate(KConfigDialogManager *qq) 0579 : q(qq) 0580 , insideGroupBox(false) 0581 , defaultsIndicatorsVisible(false) 0582 { 0583 } 0584 0585 void KConfigDialogManagerPrivate::setDefaultsIndicatorsVisible(bool enabled) 0586 { 0587 if (defaultsIndicatorsVisible != enabled) { 0588 defaultsIndicatorsVisible = enabled; 0589 updateAllWidgetIndicators(); 0590 } 0591 } 0592 0593 void KConfigDialogManagerPrivate::onWidgetModified() 0594 { 0595 const auto widget = qobject_cast<QWidget *>(q->sender()); 0596 Q_ASSERT(widget); 0597 0598 const QLatin1String prefix("kcfg_"); 0599 QString configId = widget->objectName(); 0600 if (configId.startsWith(prefix)) { 0601 configId.remove(0, prefix.size()); 0602 updateWidgetIndicator(configId, widget); 0603 } else { 0604 auto *parent = qobject_cast<QWidget *>(widget->parent()); 0605 Q_ASSERT(parent); 0606 configId = parent->objectName(); 0607 Q_ASSERT(configId.startsWith(prefix)); 0608 configId.remove(0, prefix.size()); 0609 updateWidgetIndicator(configId, parent); 0610 } 0611 0612 Q_EMIT q->widgetModified(); 0613 } 0614 0615 void KConfigDialogManagerPrivate::updateWidgetIndicator(const QString &configId, QWidget *widget) 0616 { 0617 const auto item = m_conf->findItem(configId); 0618 Q_ASSERT(item); 0619 0620 const auto widgetValue = q->property(widget); 0621 const auto defaultValue = item->getDefault(); 0622 0623 const auto defaulted = widgetValue == defaultValue; 0624 0625 if (allExclusiveGroupBoxes.contains(widget)) { 0626 const QList<QAbstractButton *> buttons = widget->findChildren<QAbstractButton *>(); 0627 for (int i = 0; i < buttons.count(); i++) { 0628 const auto value = widgetValue.toInt() == i && !defaulted && defaultsIndicatorsVisible; 0629 buttons.at(i)->setProperty("_kde_highlight_neutral", value); 0630 buttons.at(i)->update(); 0631 } 0632 } else { 0633 widget->setProperty("_kde_highlight_neutral", !defaulted && defaultsIndicatorsVisible); 0634 widget->update(); 0635 } 0636 } 0637 0638 void KConfigDialogManagerPrivate::updateAllWidgetIndicators() 0639 { 0640 QHashIterator<QString, QWidget *> it(knownWidget); 0641 while (it.hasNext()) { 0642 it.next(); 0643 updateWidgetIndicator(it.key(), it.value()); 0644 } 0645 } 0646 0647 #include "moc_kconfigdialogmanager.cpp"