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( "KEditListWidget", SIGNAL(changed())); 00140 s_changedMap->insert( "KListWidget", SIGNAL(itemSelectionChanged())); 00141 s_changedMap->insert( "KLineEdit", SIGNAL(textChanged(const QString &))); 00142 s_changedMap->insert( "KPasswordEdit", SIGNAL(textChanged(const QString &))); 00143 s_changedMap->insert( "KRestrictedLine", SIGNAL(textChanged(const QString &))); 00144 s_changedMap->insert( "KTextBrowser", SIGNAL(sourceChanged(const QString &))); 00145 s_changedMap->insert( "KTextEdit", SIGNAL(textChanged())); 00146 s_changedMap->insert( "KUrlRequester", SIGNAL(textChanged (const QString& ))); 00147 s_changedMap->insert( "KUrlComboRequester", SIGNAL(textChanged (const QString& ))); 00148 s_changedMap->insert( "KUrlComboBox", SIGNAL(urlActivated (const KUrl& ))); 00149 s_changedMap->insert( "KIntNumInput", SIGNAL(valueChanged (int))); 00150 s_changedMap->insert( "KIntSpinBox", SIGNAL(valueChanged (int))); 00151 s_changedMap->insert( "KDoubleNumInput", SIGNAL(valueChanged (double))); 00152 s_changedMap->insert( "KButtonGroup", SIGNAL(changed(int))); 00153 } 00154 } 00155 00156 QHash<QString, QByteArray> *KConfigDialogManager::propertyMap() 00157 { 00158 initMaps(); 00159 return s_propertyMap; 00160 } 00161 00162 QHash<QString, QByteArray> *KConfigDialogManager::changedMap() 00163 { 00164 initMaps(); 00165 return s_changedMap; 00166 } 00167 00168 void KConfigDialogManager::init(bool trackChanges) 00169 { 00170 initMaps(); 00171 d->trackChanges = trackChanges; 00172 00173 // Go through all of the children of the widgets and find all known widgets 00174 (void) parseChildren(d->m_dialog, trackChanges); 00175 } 00176 00177 void KConfigDialogManager::addWidget(QWidget *widget) 00178 { 00179 (void) parseChildren(widget, true); 00180 } 00181 00182 void KConfigDialogManager::setupWidget(QWidget *widget, KConfigSkeletonItem *item) 00183 { 00184 QVariant minValue = item->minValue(); 00185 if (minValue.isValid()) 00186 { 00187 // Only q3datetimeedit is using this property we can remove it if we stop supporting Qt3Support 00188 if (widget->metaObject()->indexOfProperty("minValue") != -1) 00189 widget->setProperty("minValue", minValue); 00190 if (widget->metaObject()->indexOfProperty("minimum") != -1) 00191 widget->setProperty("minimum", minValue); 00192 } 00193 QVariant maxValue = item->maxValue(); 00194 if (maxValue.isValid()) 00195 { 00196 // Only q3datetimeedit is using that property we can remove it if we stop supporting Qt3Support 00197 if (widget->metaObject()->indexOfProperty("maxValue") != -1) 00198 widget->setProperty("maxValue", maxValue); 00199 if (widget->metaObject()->indexOfProperty("maximum") != -1) 00200 widget->setProperty("maximum", maxValue); 00201 } 00202 00203 if (widget->whatsThis().isEmpty()) 00204 { 00205 QString whatsThis = item->whatsThis(); 00206 if ( !whatsThis.isEmpty() ) 00207 { 00208 widget->setWhatsThis(whatsThis ); 00209 } 00210 } 00211 00212 if (widget->toolTip().isEmpty()) 00213 { 00214 QString toolTip = item->toolTip(); 00215 if ( !toolTip.isEmpty() ) 00216 { 00217 widget->setToolTip(toolTip); 00218 } 00219 } 00220 00221 if(!item->isEqual( property(widget) )) 00222 setProperty( widget, item->property() ); 00223 } 00224 00225 bool KConfigDialogManager::parseChildren(const QWidget *widget, bool trackChanges) 00226 { 00227 bool valueChanged = false; 00228 const QList<QObject*> listOfChildren = widget->children(); 00229 if(listOfChildren.count()==0) //?? XXX 00230 return valueChanged; 00231 00232 foreach ( QObject *object, listOfChildren ) 00233 { 00234 if(!object->isWidgetType()) 00235 continue; // Skip non-widgets 00236 00237 QWidget *childWidget = static_cast<QWidget *>(object); 00238 00239 QString widgetName = childWidget->objectName(); 00240 bool bParseChildren = true; 00241 bool bSaveInsideGroupBox = d->insideGroupBox; 00242 00243 if (widgetName.startsWith(QLatin1String("kcfg_"))) 00244 { 00245 // This is one of our widgets! 00246 QString configId = widgetName.mid(5); 00247 KConfigSkeletonItem *item = d->m_conf->findItem(configId); 00248 if (item) 00249 { 00250 d->knownWidget.insert(configId, childWidget); 00251 00252 setupWidget(childWidget, item); 00253 00254 if ( d->trackChanges ) { 00255 QHash<QString, QByteArray>::const_iterator changedIt = s_changedMap->constFind(childWidget->metaObject()->className()); 00256 00257 if (changedIt == s_changedMap->constEnd()) 00258 { 00259 // If the class name of the widget wasn't in the monitored widgets map, then look for 00260 // it again using the super class name. This fixes a problem with using QtRuby/Korundum 00261 // widgets with KConfigXT where 'Qt::Widget' wasn't being seen a the real deal, even 00262 // though it was a 'QWidget'. 00263 if ( childWidget->metaObject()->superClass() ) 00264 changedIt = s_changedMap->constFind(childWidget->metaObject()->superClass()->className()); 00265 else 00266 changedIt = s_changedMap->constFind(0); 00267 } 00268 00269 if (changedIt == s_changedMap->constEnd()) 00270 { 00271 kWarning(d->debugArea()) << "Don't know how to monitor widget '" << childWidget->metaObject()->className() << "' for changes!"; 00272 } 00273 else 00274 { 00275 connect(childWidget, *changedIt, 00276 this, SIGNAL(widgetModified())); 00277 00278 QComboBox *cb = qobject_cast<QComboBox *>(childWidget); 00279 if (cb && cb->isEditable()) 00280 connect(cb, SIGNAL(editTextChanged(const QString &)), 00281 this, SIGNAL(widgetModified())); 00282 } 00283 } 00284 QGroupBox *gb = qobject_cast<QGroupBox *>(childWidget); 00285 if (!gb) 00286 bParseChildren = false; 00287 else 00288 d->insideGroupBox = true; 00289 } 00290 else 00291 { 00292 kFatal(d->debugArea()) << "A widget named '" << widgetName << "' was found but there is no setting named '" << configId << "'"; 00293 } 00294 } 00295 else if (QLabel *label = qobject_cast<QLabel*>(childWidget)) 00296 { 00297 QWidget *buddy = label->buddy(); 00298 if (!buddy) 00299 continue; 00300 QString buddyName = buddy->objectName(); 00301 if (buddyName.startsWith(QLatin1String("kcfg_"))) 00302 { 00303 // This is one of our widgets! 00304 QString configId = buddyName.mid(5); 00305 d->buddyWidget.insert(configId, childWidget); 00306 } 00307 } 00308 #ifndef NDEBUG 00309 else if (!widgetName.isEmpty() && d->trackChanges) 00310 { 00311 QHash<QString, QByteArray>::const_iterator changedIt = s_changedMap->constFind(childWidget->metaObject()->className()); 00312 if (changedIt != s_changedMap->constEnd()) 00313 { 00314 if ((!d->insideGroupBox || !qobject_cast<QRadioButton*>(childWidget)) && 00315 !qobject_cast<QGroupBox*>(childWidget) &&!qobject_cast<QTabWidget*>(childWidget) ) 00316 kDebug(d->debugArea()) << "Widget '" << widgetName << "' (" << childWidget->metaObject()->className() << ") remains unmanaged."; 00317 } 00318 } 00319 #endif 00320 00321 if(bParseChildren) 00322 { 00323 // this widget is not known as something we can store. 00324 // Maybe we can store one of its children. 00325 valueChanged |= parseChildren(childWidget, trackChanges); 00326 } 00327 d->insideGroupBox = bSaveInsideGroupBox; 00328 } 00329 return valueChanged; 00330 } 00331 00332 void KConfigDialogManager::updateWidgets() 00333 { 00334 bool changed = false; 00335 bool bSignalsBlocked = signalsBlocked(); 00336 blockSignals(true); 00337 00338 QWidget *widget; 00339 QHashIterator<QString, QWidget *> it( d->knownWidget ); 00340 while(it.hasNext()) { 00341 it.next(); 00342 widget = it.value(); 00343 00344 KConfigSkeletonItem *item = d->m_conf->findItem(it.key()); 00345 if (!item) 00346 { 00347 kWarning(d->debugArea()) << "The setting '" << it.key() << "' has disappeared!"; 00348 continue; 00349 } 00350 00351 if(!item->isEqual( property(widget) )) 00352 { 00353 setProperty( widget, item->property() ); 00354 // kDebug(d->debugArea()) << "The setting '" << it.key() << "' [" << widget->className() << "] has changed"; 00355 changed = true; 00356 } 00357 if (item->isImmutable()) 00358 { 00359 widget->setEnabled(false); 00360 QWidget *buddy = d->buddyWidget.value(it.key(), 0); 00361 if (buddy) 00362 buddy->setEnabled(false); 00363 } 00364 } 00365 blockSignals(bSignalsBlocked); 00366 00367 if (changed) 00368 QTimer::singleShot(0, this, SIGNAL(widgetModified())); 00369 } 00370 00371 void KConfigDialogManager::updateWidgetsDefault() 00372 { 00373 bool bUseDefaults = d->m_conf->useDefaults(true); 00374 updateWidgets(); 00375 d->m_conf->useDefaults(bUseDefaults); 00376 } 00377 00378 void KConfigDialogManager::updateSettings() 00379 { 00380 bool changed = false; 00381 00382 QWidget *widget; 00383 QHashIterator<QString, QWidget *> it( d->knownWidget ); 00384 while(it.hasNext()) { 00385 it.next(); 00386 widget = it.value(); 00387 00388 KConfigSkeletonItem *item = d->m_conf->findItem(it.key()); 00389 if (!item) { 00390 kWarning(d->debugArea()) << "The setting '" << it.key() << "' has disappeared!"; 00391 continue; 00392 } 00393 00394 QVariant fromWidget = property(widget); 00395 if(!item->isEqual( fromWidget )) { 00396 item->setProperty( fromWidget ); 00397 changed = true; 00398 } 00399 } 00400 if (changed) 00401 { 00402 d->m_conf->writeConfig(); 00403 emit settingsChanged(); 00404 } 00405 } 00406 00407 QByteArray KConfigDialogManager::getUserProperty(const QWidget *widget) const 00408 { 00409 if (!s_propertyMap->contains(widget->metaObject()->className())) { 00410 const QMetaObject *metaObject = widget->metaObject(); 00411 const QMetaProperty user = metaObject->userProperty(); 00412 if ( user.isValid() ) { 00413 s_propertyMap->insert( widget->metaObject()->className(), user.name() ); 00414 //kDebug(d->debugArea()) << "class name: '" << widget->metaObject()->className() 00415 //<< " 's USER property: " << metaProperty.name() << endl; 00416 } 00417 else { 00418 return QByteArray(); //no USER property 00419 } 00420 } 00421 return s_propertyMap->value( widget->metaObject()->className() ); 00422 } 00423 00424 QByteArray KConfigDialogManager::getCustomProperty(const QWidget *widget) const 00425 { 00426 QVariant prop(widget->property("kcfg_property")); 00427 if (prop.isValid()) { 00428 if (!prop.canConvert(QVariant::ByteArray)) { 00429 kWarning(d->debugArea()) << "kcfg_property on" << widget->metaObject()->className() 00430 << "is not of type ByteArray"; 00431 } else { 00432 return prop.toByteArray(); 00433 } 00434 } 00435 return QByteArray(); 00436 } 00437 00438 void KConfigDialogManager::setProperty(QWidget *w, const QVariant &v) 00439 { 00440 /* QButtonGroup *bg = qobject_cast<QButtonGroup *>(w); 00441 if (bg) 00442 { 00443 QAbstractButton *b = bg->button(v.toInt()); 00444 if (b) 00445 b->setDown(true); 00446 return; 00447 }*/ 00448 00449 QByteArray userproperty = getCustomProperty(w); 00450 if (userproperty.isEmpty()) { 00451 QComboBox *cb = qobject_cast<QComboBox *>(w); 00452 if (cb) { 00453 if (cb->isEditable()) { 00454 int i = cb->findText(v.toString()); 00455 if (i != -1) { 00456 cb->setCurrentIndex(i); 00457 } else { 00458 cb->setEditText(v.toString()); 00459 } 00460 } else { 00461 cb->setCurrentIndex(v.toInt()); 00462 } 00463 return; 00464 } 00465 } 00466 if (userproperty.isEmpty()) { 00467 userproperty = getUserProperty(w); 00468 } 00469 if (userproperty.isEmpty()) { 00470 kWarning(d->debugArea()) << w->metaObject()->className() << " widget not handled!"; 00471 return; 00472 } 00473 00474 w->setProperty(userproperty, v); 00475 } 00476 00477 QVariant KConfigDialogManager::property(QWidget *w) const 00478 { 00479 /* QButtonGroup *bg = qobject_cast<QButtonGroup *>(w); 00480 if (bg && bg->checkedButton()) 00481 return QVariant(bg->id(bg->checkedButton()));*/ 00482 00483 QByteArray userproperty = getCustomProperty(w); 00484 if (userproperty.isEmpty()) { 00485 QComboBox *cb = qobject_cast<QComboBox *>(w); 00486 if (cb) { 00487 if (cb->isEditable()) { 00488 return QVariant(cb->currentText()); 00489 } else { 00490 return QVariant(cb->currentIndex()); 00491 } 00492 } 00493 } 00494 if (userproperty.isEmpty()) { 00495 userproperty = getUserProperty(w); 00496 } 00497 if (userproperty.isEmpty()) { 00498 kWarning(d->debugArea()) << w->metaObject()->className() << " widget not handled!"; 00499 return QVariant(); 00500 } 00501 00502 return w->property(userproperty); 00503 } 00504 00505 bool KConfigDialogManager::hasChanged() const 00506 { 00507 QWidget *widget; 00508 QHashIterator<QString, QWidget *> it( d->knownWidget) ; 00509 while(it.hasNext()) { 00510 it.next(); 00511 widget = it.value(); 00512 00513 KConfigSkeletonItem *item = d->m_conf->findItem(it.key()); 00514 if (!item) { 00515 kWarning(d->debugArea()) << "The setting '" << it.key() << "' has disappeared!"; 00516 continue; 00517 } 00518 00519 if(!item->isEqual( property(widget) )) { 00520 // kDebug(d->debugArea()) << "Widget for '" << it.key() << "' has changed."; 00521 return true; 00522 } 00523 } 00524 return false; 00525 } 00526 00527 bool KConfigDialogManager::isDefault() const 00528 { 00529 bool bUseDefaults = d->m_conf->useDefaults(true); 00530 bool result = !hasChanged(); 00531 d->m_conf->useDefaults(bUseDefaults); 00532 return result; 00533 } 00534 00535 #include "kconfigdialogmanager.moc" 00536
KDE 4.7 API Reference