KDEUI
kconfigdialogmanager.cpp
Go to the documentation of this file.
00001 /* 00002 * This file is part of the KDE libraries 00003 * Copyright (C) 2003 Benjamin C Meyer (ben+kdelibs at meyerhome dot net) 00004 * Copyright (C) 2003 Waldo Bastian <bastian@kde.org> 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Library General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Library General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Library General Public License 00017 * along with this library; see the file COPYING.LIB. If not, write to 00018 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 * Boston, MA 02110-1301, USA. 00020 */ 00021 00022 #include "kconfigdialogmanager.h" 00023 00024 #include <QComboBox> 00025 #include <QGroupBox> 00026 #include <QLabel> 00027 #include <QMetaObject> 00028 #include <QMetaProperty> 00029 #include <QTimer> 00030 #include <QRadioButton> 00031 //#include <QButtonGroup> 00032 00033 #include <kconfigskeleton.h> 00034 #include <kdebug.h> 00035 #include <kglobal.h> 00036 00037 #include <assert.h> 00038 00039 typedef QHash<QString, QByteArray> MyHash; 00040 K_GLOBAL_STATIC(MyHash, s_propertyMap) 00041 K_GLOBAL_STATIC(MyHash, s_changedMap) 00042 00043 class KConfigDialogManager::Private { 00044 00045 public: 00046 Private(KConfigDialogManager *q) : q(q), insideGroupBox(false) { } 00047 00048 public: 00049 KConfigDialogManager *q; 00050 00051 static int debugArea() { static int s_area = KDebug::registerArea("kdeui (KConfigDialogManager)"); return s_area; } 00052 00056 KCoreConfigSkeleton *m_conf; 00057 00061 QWidget *m_dialog; 00062 00063 QHash<QString, QWidget *> knownWidget; 00064 QHash<QString, QWidget *> buddyWidget; 00065 bool insideGroupBox : 1; 00066 bool trackChanges : 1; 00067 }; 00068 00069 KConfigDialogManager::KConfigDialogManager(QWidget *parent, KCoreConfigSkeleton *conf) 00070 : QObject(parent), d(new Private(this)) 00071 { 00072 d->m_conf = conf; 00073 d->m_dialog = parent; 00074 init(true); 00075 } 00076 00077 KConfigDialogManager::KConfigDialogManager(QWidget *parent, KConfigSkeleton *conf) 00078 : QObject(parent), d(new Private(this)) 00079 { 00080 d->m_conf = conf; 00081 d->m_dialog = parent; 00082 init(true); 00083 } 00084 00085 KConfigDialogManager::~KConfigDialogManager() 00086 { 00087 delete d; 00088 } 00089 00090 void KConfigDialogManager::initMaps() 00091 { 00092 if ( s_propertyMap->isEmpty() ) { 00093 s_propertyMap->insert( "KButtonGroup", "current" ); 00094 s_propertyMap->insert( "KColorButton", "color" ); 00095 s_propertyMap->insert( "KColorCombo", "color" ); 00096 //s_propertyMap->insert( "KUrlRequester", "url" ); 00097 //s_propertyMap->insert( "KUrlComboRequester", "url" ); 00098 } 00099 00100 if( s_changedMap->isEmpty() ) 00101 { 00102 // QT 00103 s_changedMap->insert("QCheckBox", SIGNAL(stateChanged(int))); 00104 s_changedMap->insert("QPushButton", SIGNAL(clicked(bool))); 00105 s_changedMap->insert("QRadioButton", SIGNAL(toggled(bool))); 00106 // We can only store one thing, so you can't have 00107 // a ButtonGroup that is checkable. 00108 // s_changedMap->insert("QButtonGroup", SIGNAL(buttonClicked(int))); 00109 s_changedMap->insert("QGroupBox", SIGNAL(toggled(bool))); 00110 s_changedMap->insert("QComboBox", SIGNAL(activated (int))); 00111 //qsqlproperty map doesn't store the text, but the value! 00112 //s_changedMap->insert("QComboBox", SIGNAL(textChanged(const QString &))); 00113 s_changedMap->insert("QDateEdit", SIGNAL(dateChanged(const QDate &))); 00114 s_changedMap->insert("QTimeEdit", SIGNAL(timeChanged(const QTime &))); 00115 s_changedMap->insert("QDateTimeEdit", SIGNAL(dateTimeChanged(const QDateTime &))); 00116 s_changedMap->insert("QDial", SIGNAL(valueChanged (int))); 00117 s_changedMap->insert("QDoubleSpinBox", SIGNAL(valueChanged(double))); 00118 s_changedMap->insert("QLineEdit", SIGNAL(textChanged(const QString &))); 00119 s_changedMap->insert("QSlider", SIGNAL(valueChanged(int))); 00120 s_changedMap->insert("QSpinBox", SIGNAL(valueChanged(int))); 00121 s_changedMap->insert("QTextEdit", SIGNAL(textChanged())); 00122 s_changedMap->insert("QTextBrowser", SIGNAL(sourceChanged(const QString &))); 00123 s_changedMap->insert("QPlainTextEdit", SIGNAL(textChanged())); 00124 s_changedMap->insert("QTabWidget", SIGNAL(currentChanged(int))); 00125 00126 // KDE 00127 s_changedMap->insert( "KComboBox", SIGNAL(activated (int))); 00128 s_changedMap->insert( "KFontComboBox", SIGNAL(activated (int))); 00129 s_changedMap->insert( "KFontRequester", SIGNAL(fontSelected(const QFont &))); 00130 s_changedMap->insert( "KFontChooser", SIGNAL(fontSelected(const QFont &))); 00131 s_changedMap->insert( "KHistoryCombo", SIGNAL(activated (int))); 00132 s_changedMap->insert( "KColorCombo", SIGNAL(activated (const QColor &))); 00133 00134 s_changedMap->insert( "KColorButton", SIGNAL(changed(const QColor &))); 00135 s_changedMap->insert( "KDatePicker", SIGNAL(dateSelected (QDate))); 00136 s_changedMap->insert( "KDateWidget", SIGNAL(changed (QDate))); 00137 s_changedMap->insert( "KDateTimeWidget", SIGNAL(valueChanged (const QDateTime &))); 00138 s_changedMap->insert( "KEditListBox", SIGNAL(changed())); 00139 s_changedMap->insert( "KListWidget", SIGNAL(itemSelectionChanged())); 00140 s_changedMap->insert( "KLineEdit", SIGNAL(textChanged(const QString &))); 00141 s_changedMap->insert( "KPasswordEdit", SIGNAL(textChanged(const QString &))); 00142 s_changedMap->insert( "KRestrictedLine", SIGNAL(textChanged(const QString &))); 00143 s_changedMap->insert( "KTextBrowser", SIGNAL(sourceChanged(const QString &))); 00144 s_changedMap->insert( "KTextEdit", SIGNAL(textChanged())); 00145 s_changedMap->insert( "KUrlRequester", SIGNAL(textChanged (const QString& ))); 00146 s_changedMap->insert( "KUrlComboRequester", SIGNAL(textChanged (const QString& ))); 00147 s_changedMap->insert( "KUrlComboBox", SIGNAL(urlActivated (const KUrl& ))); 00148 s_changedMap->insert( "KIntNumInput", SIGNAL(valueChanged (int))); 00149 s_changedMap->insert( "KIntSpinBox", SIGNAL(valueChanged (int))); 00150 s_changedMap->insert( "KDoubleNumInput", SIGNAL(valueChanged (double))); 00151 s_changedMap->insert( "KButtonGroup", SIGNAL(changed(int))); 00152 } 00153 } 00154 00155 QHash<QString, QByteArray> *KConfigDialogManager::propertyMap() 00156 { 00157 initMaps(); 00158 return s_propertyMap; 00159 } 00160 00161 QHash<QString, QByteArray> *KConfigDialogManager::changedMap() 00162 { 00163 initMaps(); 00164 return s_changedMap; 00165 } 00166 00167 void KConfigDialogManager::init(bool trackChanges) 00168 { 00169 initMaps(); 00170 d->trackChanges = trackChanges; 00171 00172 // Go through all of the children of the widgets and find all known widgets 00173 (void) parseChildren(d->m_dialog, trackChanges); 00174 } 00175 00176 void KConfigDialogManager::addWidget(QWidget *widget) 00177 { 00178 (void) parseChildren(widget, true); 00179 } 00180 00181 void KConfigDialogManager::setupWidget(QWidget *widget, KConfigSkeletonItem *item) 00182 { 00183 QVariant minValue = item->minValue(); 00184 if (minValue.isValid()) 00185 { 00186 // Only q3datetimeedit is using this property we can remove it if we stop supporting Qt3Support 00187 if (widget->metaObject()->indexOfProperty("minValue") != -1) 00188 widget->setProperty("minValue", minValue); 00189 if (widget->metaObject()->indexOfProperty("minimum") != -1) 00190 widget->setProperty("minimum", minValue); 00191 } 00192 QVariant maxValue = item->maxValue(); 00193 if (maxValue.isValid()) 00194 { 00195 // Only q3datetimeedit is using that property we can remove it if we stop supporting Qt3Support 00196 if (widget->metaObject()->indexOfProperty("maxValue") != -1) 00197 widget->setProperty("maxValue", maxValue); 00198 if (widget->metaObject()->indexOfProperty("maximum") != -1) 00199 widget->setProperty("maximum", maxValue); 00200 } 00201 00202 if (widget->whatsThis().isEmpty()) 00203 { 00204 QString whatsThis = item->whatsThis(); 00205 if ( !whatsThis.isEmpty() ) 00206 { 00207 widget->setWhatsThis(whatsThis ); 00208 } 00209 } 00210 00211 if (widget->toolTip().isEmpty()) 00212 { 00213 QString toolTip = item->toolTip(); 00214 if ( !toolTip.isEmpty() ) 00215 { 00216 widget->setToolTip(toolTip); 00217 } 00218 } 00219 00220 if(!item->isEqual( property(widget) )) 00221 setProperty( widget, item->property() ); 00222 } 00223 00224 bool KConfigDialogManager::parseChildren(const QWidget *widget, bool trackChanges) 00225 { 00226 bool valueChanged = false; 00227 const QList<QObject*> listOfChildren = widget->children(); 00228 if(listOfChildren.count()==0) //?? XXX 00229 return valueChanged; 00230 00231 foreach ( QObject *object, listOfChildren ) 00232 { 00233 if(!object->isWidgetType()) 00234 continue; // Skip non-widgets 00235 00236 QWidget *childWidget = static_cast<QWidget *>(object); 00237 00238 QString widgetName = childWidget->objectName(); 00239 bool bParseChildren = true; 00240 bool bSaveInsideGroupBox = d->insideGroupBox; 00241 00242 if (widgetName.startsWith(QLatin1String("kcfg_"))) 00243 { 00244 // This is one of our widgets! 00245 QString configId = widgetName.mid(5); 00246 KConfigSkeletonItem *item = d->m_conf->findItem(configId); 00247 if (item) 00248 { 00249 d->knownWidget.insert(configId, childWidget); 00250 00251 setupWidget(childWidget, item); 00252 00253 if ( d->trackChanges ) { 00254 QHash<QString, QByteArray>::const_iterator changedIt = s_changedMap->constFind(childWidget->metaObject()->className()); 00255 00256 if (changedIt == s_changedMap->constEnd()) 00257 { 00258 // If the class name of the widget wasn't in the monitored widgets map, then look for 00259 // it again using the super class name. This fixes a problem with using QtRuby/Korundum 00260 // widgets with KConfigXT where 'Qt::Widget' wasn't being seen a the real deal, even 00261 // though it was a 'QWidget'. 00262 if ( childWidget->metaObject()->superClass() ) 00263 changedIt = s_changedMap->constFind(childWidget->metaObject()->superClass()->className()); 00264 else 00265 changedIt = s_changedMap->constFind(0); 00266 } 00267 00268 if (changedIt == s_changedMap->constEnd()) 00269 { 00270 kWarning(d->debugArea()) << "Don't know how to monitor widget '" << childWidget->metaObject()->className() << "' for changes!"; 00271 } 00272 else 00273 { 00274 connect(childWidget, *changedIt, 00275 this, SIGNAL(widgetModified())); 00276 00277 QComboBox *cb = qobject_cast<QComboBox *>(childWidget); 00278 if (cb && cb->isEditable()) 00279 connect(cb, SIGNAL(editTextChanged(const QString &)), 00280 this, SIGNAL(widgetModified())); 00281 } 00282 } 00283 QGroupBox *gb = qobject_cast<QGroupBox *>(childWidget); 00284 if (!gb) 00285 bParseChildren = false; 00286 else 00287 d->insideGroupBox = true; 00288 } 00289 else 00290 { 00291 kFatal(d->debugArea()) << "A widget named '" << widgetName << "' was found but there is no setting named '" << configId << "'"; 00292 } 00293 } 00294 else if (QLabel *label = qobject_cast<QLabel*>(childWidget)) 00295 { 00296 QWidget *buddy = label->buddy(); 00297 if (!buddy) 00298 continue; 00299 QString buddyName = buddy->objectName(); 00300 if (buddyName.startsWith(QLatin1String("kcfg_"))) 00301 { 00302 // This is one of our widgets! 00303 QString configId = buddyName.mid(5); 00304 d->buddyWidget.insert(configId, childWidget); 00305 } 00306 } 00307 #ifndef NDEBUG 00308 else if (!widgetName.isEmpty() && d->trackChanges) 00309 { 00310 QHash<QString, QByteArray>::const_iterator changedIt = s_changedMap->constFind(childWidget->metaObject()->className()); 00311 if (changedIt != s_changedMap->constEnd()) 00312 { 00313 if ((!d->insideGroupBox || !qobject_cast<QRadioButton*>(childWidget)) && 00314 !qobject_cast<QGroupBox*>(childWidget) &&!qobject_cast<QTabWidget*>(childWidget) ) 00315 kDebug(d->debugArea()) << "Widget '" << widgetName << "' (" << childWidget->metaObject()->className() << ") remains unmanaged."; 00316 } 00317 } 00318 #endif 00319 00320 if(bParseChildren) 00321 { 00322 // this widget is not known as something we can store. 00323 // Maybe we can store one of its children. 00324 valueChanged |= parseChildren(childWidget, trackChanges); 00325 } 00326 d->insideGroupBox = bSaveInsideGroupBox; 00327 } 00328 return valueChanged; 00329 } 00330 00331 void KConfigDialogManager::updateWidgets() 00332 { 00333 bool changed = false; 00334 bool bSignalsBlocked = signalsBlocked(); 00335 blockSignals(true); 00336 00337 QWidget *widget; 00338 QHashIterator<QString, QWidget *> it( d->knownWidget ); 00339 while(it.hasNext()) { 00340 it.next(); 00341 widget = it.value(); 00342 00343 KConfigSkeletonItem *item = d->m_conf->findItem(it.key()); 00344 if (!item) 00345 { 00346 kWarning(d->debugArea()) << "The setting '" << it.key() << "' has disappeared!"; 00347 continue; 00348 } 00349 00350 if(!item->isEqual( property(widget) )) 00351 { 00352 setProperty( widget, item->property() ); 00353 // kDebug(d->debugArea()) << "The setting '" << it.key() << "' [" << widget->className() << "] has changed"; 00354 changed = true; 00355 } 00356 if (item->isImmutable()) 00357 { 00358 widget->setEnabled(false); 00359 QWidget *buddy = d->buddyWidget.value(it.key(), 0); 00360 if (buddy) 00361 buddy->setEnabled(false); 00362 } 00363 } 00364 blockSignals(bSignalsBlocked); 00365 00366 if (changed) 00367 QTimer::singleShot(0, this, SIGNAL(widgetModified())); 00368 } 00369 00370 void KConfigDialogManager::updateWidgetsDefault() 00371 { 00372 bool bUseDefaults = d->m_conf->useDefaults(true); 00373 updateWidgets(); 00374 d->m_conf->useDefaults(bUseDefaults); 00375 } 00376 00377 void KConfigDialogManager::updateSettings() 00378 { 00379 bool changed = false; 00380 00381 QWidget *widget; 00382 QHashIterator<QString, QWidget *> it( d->knownWidget ); 00383 while(it.hasNext()) { 00384 it.next(); 00385 widget = it.value(); 00386 00387 KConfigSkeletonItem *item = d->m_conf->findItem(it.key()); 00388 if (!item) { 00389 kWarning(d->debugArea()) << "The setting '" << it.key() << "' has disappeared!"; 00390 continue; 00391 } 00392 00393 QVariant fromWidget = property(widget); 00394 if(!item->isEqual( fromWidget )) { 00395 item->setProperty( fromWidget ); 00396 changed = true; 00397 } 00398 } 00399 if (changed) 00400 { 00401 d->m_conf->writeConfig(); 00402 emit settingsChanged(); 00403 } 00404 } 00405 00406 QByteArray KConfigDialogManager::getUserProperty(const QWidget *widget) const 00407 { 00408 if (!s_propertyMap->contains(widget->metaObject()->className())) { 00409 const QMetaObject *metaObject = widget->metaObject(); 00410 const QMetaProperty user = metaObject->userProperty(); 00411 if ( user.isValid() ) { 00412 s_propertyMap->insert( widget->metaObject()->className(), user.name() ); 00413 //kDebug(d->debugArea()) << "class name: '" << widget->metaObject()->className() 00414 //<< " 's USER property: " << metaProperty.name() << endl; 00415 } 00416 else { 00417 return QByteArray(); //no USER property 00418 } 00419 } 00420 return s_propertyMap->value( widget->metaObject()->className() ); 00421 } 00422 00423 QByteArray KConfigDialogManager::getCustomProperty(const QWidget *widget) const 00424 { 00425 QVariant prop(widget->property("kcfg_property")); 00426 if (prop.isValid()) { 00427 if (!prop.canConvert(QVariant::ByteArray)) { 00428 kWarning(d->debugArea()) << "kcfg_property on" << widget->metaObject()->className() 00429 << "is not of type ByteArray"; 00430 } else { 00431 return prop.toByteArray(); 00432 } 00433 } 00434 return QByteArray(); 00435 } 00436 00437 void KConfigDialogManager::setProperty(QWidget *w, const QVariant &v) 00438 { 00439 /* QButtonGroup *bg = qobject_cast<QButtonGroup *>(w); 00440 if (bg) 00441 { 00442 QAbstractButton *b = bg->button(v.toInt()); 00443 if (b) 00444 b->setDown(true); 00445 return; 00446 }*/ 00447 00448 QByteArray userproperty = getCustomProperty(w); 00449 if (userproperty.isEmpty()) { 00450 userproperty = getUserProperty(w); 00451 } 00452 if (userproperty.isEmpty()) { 00453 QComboBox *cb = qobject_cast<QComboBox *>(w); 00454 if (cb) { 00455 if (cb->isEditable()) { 00456 int i = cb->findText(v.toString()); 00457 if (i != -1) { 00458 cb->setCurrentIndex(i); 00459 } else { 00460 cb->setEditText(v.toString()); 00461 } 00462 } else { 00463 cb->setCurrentIndex(v.toInt()); 00464 } 00465 return; 00466 } 00467 kWarning(d->debugArea()) << w->metaObject()->className() << " widget not handled!"; 00468 return; 00469 } 00470 w->setProperty(userproperty, v); 00471 } 00472 00473 QVariant KConfigDialogManager::property(QWidget *w) const 00474 { 00475 /* QButtonGroup *bg = qobject_cast<QButtonGroup *>(w); 00476 if (bg && bg->checkedButton()) 00477 return QVariant(bg->id(bg->checkedButton()));*/ 00478 00479 QByteArray userproperty = getCustomProperty(w); 00480 if (userproperty.isEmpty()) { 00481 userproperty = getUserProperty(w); 00482 } 00483 if (userproperty.isEmpty()) { 00484 QComboBox *cb = qobject_cast<QComboBox *>(w); 00485 if (cb) { 00486 if (cb->isEditable()) { 00487 return QVariant(cb->currentText()); 00488 } else { 00489 return QVariant(cb->currentIndex()); 00490 } 00491 } 00492 kWarning(d->debugArea()) << w->metaObject()->className() << " widget not handled!"; 00493 return QVariant(); 00494 } 00495 00496 return w->property(userproperty); 00497 } 00498 00499 bool KConfigDialogManager::hasChanged() const 00500 { 00501 QWidget *widget; 00502 QHashIterator<QString, QWidget *> it( d->knownWidget) ; 00503 while(it.hasNext()) { 00504 it.next(); 00505 widget = it.value(); 00506 00507 KConfigSkeletonItem *item = d->m_conf->findItem(it.key()); 00508 if (!item) { 00509 kWarning(d->debugArea()) << "The setting '" << it.key() << "' has disappeared!"; 00510 continue; 00511 } 00512 00513 if(!item->isEqual( property(widget) )) { 00514 // kDebug(d->debugArea()) << "Widget for '" << it.key() << "' has changed."; 00515 return true; 00516 } 00517 } 00518 return false; 00519 } 00520 00521 bool KConfigDialogManager::isDefault() const 00522 { 00523 bool bUseDefaults = d->m_conf->useDefaults(true); 00524 bool result = !hasChanged(); 00525 d->m_conf->useDefaults(bUseDefaults); 00526 return result; 00527 } 00528 00529 #include "kconfigdialogmanager.moc" 00530
KDE 4.6 API Reference