kconfigdialogmanager.cpp
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 <qbuttongroup.h> 00025 #include <qcombobox.h> 00026 #include <qlabel.h> 00027 #include <qmetaobject.h> 00028 #include <qobjectlist.h> 00029 #include <qsqlpropertymap.h> 00030 #include <qtimer.h> 00031 #include <qwhatsthis.h> 00032 00033 #include <kapplication.h> 00034 #include <kconfigskeleton.h> 00035 #include <kdebug.h> 00036 #include <kglobal.h> 00037 00038 #include <assert.h> 00039 00040 class KConfigDialogManager::Private { 00041 00042 public: 00043 Private() : insideGroupBox(false) { } 00044 00045 public: 00046 QDict<QWidget> knownWidget; 00047 QDict<QWidget> buddyWidget; 00048 bool insideGroupBox; 00049 }; 00050 00051 KConfigDialogManager::KConfigDialogManager(QWidget *parent, KConfigSkeleton *conf, const char *name) 00052 : QObject(parent, name), m_conf(conf), m_dialog(parent) 00053 { 00054 d = new Private(); 00055 00056 kapp->installKDEPropertyMap(); 00057 propertyMap = QSqlPropertyMap::defaultMap(); 00058 00059 init(true); 00060 } 00061 00062 KConfigDialogManager::~KConfigDialogManager() 00063 { 00064 delete d; 00065 } 00066 00067 void KConfigDialogManager::init(bool trackChanges) 00068 { 00069 if(trackChanges) 00070 { 00071 // QT 00072 changedMap.insert("QButton", SIGNAL(stateChanged(int))); 00073 changedMap.insert("QCheckBox", SIGNAL(stateChanged(int))); 00074 changedMap.insert("QPushButton", SIGNAL(stateChanged(int))); 00075 changedMap.insert("QRadioButton", SIGNAL(stateChanged(int))); 00076 // We can only store one thing, so you can't have 00077 // a ButtonGroup that is checkable. 00078 changedMap.insert("QButtonGroup", SIGNAL(clicked(int))); 00079 changedMap.insert("QGroupBox", SIGNAL(toggled(bool))); 00080 changedMap.insert("QComboBox", SIGNAL(activated (int))); 00081 //qsqlproperty map doesn't store the text, but the value! 00082 //changedMap.insert("QComboBox", SIGNAL(textChanged(const QString &))); 00083 changedMap.insert("QDateEdit", SIGNAL(valueChanged(const QDate &))); 00084 changedMap.insert("QDateTimeEdit", SIGNAL(valueChanged(const QDateTime &))); 00085 changedMap.insert("QDial", SIGNAL(valueChanged (int))); 00086 changedMap.insert("QLineEdit", SIGNAL(textChanged(const QString &))); 00087 changedMap.insert("QSlider", SIGNAL(valueChanged(int))); 00088 changedMap.insert("QSpinBox", SIGNAL(valueChanged(int))); 00089 changedMap.insert("QTimeEdit", SIGNAL(valueChanged(const QTime &))); 00090 changedMap.insert("QTextEdit", SIGNAL(textChanged())); 00091 changedMap.insert("QTextBrowser", SIGNAL(sourceChanged(const QString &))); 00092 changedMap.insert("QMultiLineEdit", SIGNAL(textChanged())); 00093 changedMap.insert("QListBox", SIGNAL(selectionChanged())); 00094 changedMap.insert("QTabWidget", SIGNAL(currentChanged(QWidget *))); 00095 00096 // KDE 00097 changedMap.insert( "KComboBox", SIGNAL(activated (int))); 00098 changedMap.insert( "KFontCombo", SIGNAL(activated (int))); 00099 changedMap.insert( "KFontRequester", SIGNAL(fontSelected(const QFont &))); 00100 changedMap.insert( "KFontChooser", SIGNAL(fontSelected(const QFont &))); 00101 changedMap.insert( "KHistoryCombo", SIGNAL(activated (int))); 00102 00103 changedMap.insert( "KColorButton", SIGNAL(changed(const QColor &))); 00104 changedMap.insert( "KDatePicker", SIGNAL(dateSelected (QDate))); 00105 changedMap.insert( "KDateWidget", SIGNAL(changed (QDate))); 00106 changedMap.insert( "KDateTimeWidget", SIGNAL(valueChanged (const QDateTime &))); 00107 changedMap.insert( "KEditListBox", SIGNAL(changed())); 00108 changedMap.insert( "KListBox", SIGNAL(selectionChanged())); 00109 changedMap.insert( "KLineEdit", SIGNAL(textChanged(const QString &))); 00110 changedMap.insert( "KPasswordEdit", SIGNAL(textChanged(const QString &))); 00111 changedMap.insert( "KRestrictedLine", SIGNAL(textChanged(const QString &))); 00112 changedMap.insert( "KTextBrowser", SIGNAL(sourceChanged(const QString &))); 00113 changedMap.insert( "KTextEdit", SIGNAL(textChanged())); 00114 changedMap.insert( "KURLRequester", SIGNAL(textChanged (const QString& ))); 00115 changedMap.insert( "KIntNumInput", SIGNAL(valueChanged (int))); 00116 changedMap.insert( "KIntSpinBox", SIGNAL(valueChanged (int))); 00117 changedMap.insert( "KDoubleNumInput", SIGNAL(valueChanged (double))); 00118 } 00119 00120 // Go through all of the children of the widgets and find all known widgets 00121 (void) parseChildren(m_dialog, trackChanges); 00122 } 00123 00124 void KConfigDialogManager::addWidget(QWidget *widget) 00125 { 00126 (void) parseChildren(widget, true); 00127 } 00128 00129 void KConfigDialogManager::setupWidget(QWidget *widget, KConfigSkeletonItem *item) 00130 { 00131 QVariant minValue = item->minValue(); 00132 if (minValue.isValid()) 00133 { 00134 if (widget->metaObject()->findProperty("minValue", true) != -1) 00135 widget->setProperty("minValue", minValue); 00136 } 00137 QVariant maxValue = item->maxValue(); 00138 if (maxValue.isValid()) 00139 { 00140 if (widget->metaObject()->findProperty("maxValue", true) != -1) 00141 widget->setProperty("maxValue", maxValue); 00142 } 00143 if (QWhatsThis::textFor( widget ).isEmpty()) 00144 { 00145 QString whatsThis = item->whatsThis(); 00146 if ( !whatsThis.isEmpty() ) 00147 { 00148 QWhatsThis::add( widget, whatsThis ); 00149 } 00150 } 00151 } 00152 00153 bool KConfigDialogManager::parseChildren(const QWidget *widget, bool trackChanges) 00154 { 00155 bool valueChanged = false; 00156 const QObjectList *listOfChildren = widget->children(); 00157 if(!listOfChildren) 00158 return valueChanged; 00159 00160 QObject *object; 00161 for( QPtrListIterator<QObject> it( *listOfChildren ); 00162 (object = it.current()); ++it ) 00163 { 00164 if(!object->isWidgetType()) 00165 continue; // Skip non-widgets 00166 00167 QWidget *childWidget = (QWidget *)object; 00168 00169 const char *widgetName = childWidget->name(0); 00170 bool bParseChildren = true; 00171 bool bSaveInsideGroupBox = d->insideGroupBox; 00172 00173 if (widgetName && (strncmp(widgetName, "kcfg_", 5) == 0)) 00174 { 00175 // This is one of our widgets! 00176 QString configId = widgetName+5; 00177 KConfigSkeletonItem *item = m_conf->findItem(configId); 00178 if (item) 00179 { 00180 d->knownWidget.insert(configId, childWidget); 00181 00182 setupWidget(childWidget, item); 00183 00184 QMap<QString, QCString>::const_iterator changedIt = changedMap.find(childWidget->className()); 00185 00186 if (changedIt == changedMap.end()) 00187 { 00188 // If the class name of the widget wasn't in the monitored widgets map, then look for 00189 // it again using the super class name. This fixes a problem with using QtRuby/Korundum 00190 // widgets with KConfigXT where 'Qt::Widget' wasn't being seen a the real deal, even 00191 // though it was a 'QWidget'. 00192 changedIt = changedMap.find(childWidget->metaObject()->superClassName()); 00193 } 00194 00195 if (changedIt == changedMap.end()) 00196 { 00197 kdWarning(178) << "Don't know how to monitor widget '" << childWidget->className() << "' for changes!" << endl; 00198 } 00199 else 00200 { 00201 connect(childWidget, *changedIt, 00202 this, SIGNAL(widgetModified())); 00203 00204 QGroupBox *gb = dynamic_cast<QGroupBox *>(childWidget); 00205 if (!gb) 00206 bParseChildren = false; 00207 else 00208 d->insideGroupBox = true; 00209 00210 QComboBox *cb = dynamic_cast<QComboBox *>(childWidget); 00211 if (cb && cb->editable()) 00212 connect(cb, SIGNAL(textChanged(const QString &)), 00213 this, SIGNAL(widgetModified())); 00214 } 00215 } 00216 else 00217 { 00218 kdWarning(178) << "A widget named '" << widgetName << "' was found but there is no setting named '" << configId << "'" << endl; 00219 assert(false); 00220 } 00221 } 00222 else if (childWidget->inherits("QLabel")) 00223 { 00224 QLabel *label = static_cast<QLabel *>(childWidget); 00225 QWidget *buddy = label->buddy(); 00226 if (!buddy) 00227 continue; 00228 const char *buddyName = buddy->name(0); 00229 if (buddyName && (strncmp(buddyName, "kcfg_", 5) == 0)) 00230 { 00231 // This is one of our widgets! 00232 QString configId = buddyName+5; 00233 d->buddyWidget.insert(configId, childWidget); 00234 } 00235 } 00236 #ifndef NDEBUG 00237 else if (widgetName) 00238 { 00239 QMap<QString, QCString>::const_iterator changedIt = changedMap.find(childWidget->className()); 00240 if (changedIt != changedMap.end()) 00241 { 00242 if ((!d->insideGroupBox || !childWidget->inherits("QRadioButton")) && 00243 !childWidget->inherits("QGroupBox")) 00244 kdDebug(178) << "Widget '" << widgetName << "' (" << childWidget->className() << ") remains unmanaged." << endl; 00245 } 00246 } 00247 #endif 00248 00249 if(bParseChildren) 00250 { 00251 // this widget is not known as something we can store. 00252 // Maybe we can store one of its children. 00253 valueChanged |= parseChildren(childWidget, trackChanges); 00254 } 00255 d->insideGroupBox = bSaveInsideGroupBox; 00256 } 00257 return valueChanged; 00258 } 00259 00260 void KConfigDialogManager::updateWidgets() 00261 { 00262 bool changed = false; 00263 bool bSignalsBlocked = signalsBlocked(); 00264 blockSignals(true); 00265 00266 QWidget *widget; 00267 for( QDictIterator<QWidget> it( d->knownWidget ); 00268 (widget = it.current()); ++it ) 00269 { 00270 KConfigSkeletonItem *item = m_conf->findItem(it.currentKey()); 00271 if (!item) 00272 { 00273 kdWarning(178) << "The setting '" << it.currentKey() << "' has disappeared!" << endl; 00274 continue; 00275 } 00276 00277 QVariant p = item->property(); 00278 if (p != property(widget)) 00279 { 00280 setProperty(widget, p); 00281 // kdDebug(178) << "The setting '" << it.currentKey() << "' [" << widget->className() << "] has changed" << endl; 00282 changed = true; 00283 } 00284 if (item->isImmutable()) 00285 { 00286 widget->setEnabled(false); 00287 QWidget *buddy = d->buddyWidget.find(it.currentKey()); 00288 if (buddy) 00289 buddy->setEnabled(false); 00290 } 00291 } 00292 blockSignals(bSignalsBlocked); 00293 00294 if (changed) 00295 QTimer::singleShot(0, this, SIGNAL(widgetModified())); 00296 } 00297 00298 void KConfigDialogManager::updateWidgetsDefault() 00299 { 00300 bool bUseDefaults = m_conf->useDefaults(true); 00301 updateWidgets(); 00302 m_conf->useDefaults(bUseDefaults); 00303 } 00304 00305 void KConfigDialogManager::updateSettings() 00306 { 00307 bool changed = false; 00308 00309 QWidget *widget; 00310 for( QDictIterator<QWidget> it( d->knownWidget ); 00311 (widget = it.current()); ++it ) 00312 { 00313 KConfigSkeletonItem *item = m_conf->findItem(it.currentKey()); 00314 if (!item) 00315 { 00316 kdWarning(178) << "The setting '" << it.currentKey() << "' has disappeared!" << endl; 00317 continue; 00318 } 00319 00320 QVariant p = property(widget); 00321 if (p != item->property()) 00322 { 00323 item->setProperty(p); 00324 changed = true; 00325 } 00326 } 00327 if (changed) 00328 { 00329 m_conf->writeConfig(); 00330 emit settingsChanged(); 00331 } 00332 } 00333 00334 void KConfigDialogManager::setProperty(QWidget *w, const QVariant &v) 00335 { 00336 QButtonGroup *bg = dynamic_cast<QButtonGroup *>(w); 00337 if (bg) 00338 { 00339 bg->setButton(v.toInt()); 00340 return; 00341 } 00342 00343 QComboBox *cb = dynamic_cast<QComboBox *>(w); 00344 if (cb && cb->editable()) 00345 { 00346 cb->setCurrentText(v.toString()); 00347 return; 00348 } 00349 00350 propertyMap->setProperty(w, v); 00351 } 00352 00353 QVariant KConfigDialogManager::property(QWidget *w) 00354 { 00355 QButtonGroup *bg = dynamic_cast<QButtonGroup *>(w); 00356 if (bg) 00357 return QVariant(bg->selectedId()); 00358 00359 QComboBox *cb = dynamic_cast<QComboBox *>(w); 00360 if (cb && cb->editable()) 00361 return QVariant(cb->currentText()); 00362 00363 return propertyMap->property(w); 00364 } 00365 00366 bool KConfigDialogManager::hasChanged() 00367 { 00368 00369 QWidget *widget; 00370 for( QDictIterator<QWidget> it( d->knownWidget ); 00371 (widget = it.current()); ++it ) 00372 { 00373 KConfigSkeletonItem *item = m_conf->findItem(it.currentKey()); 00374 if (!item) 00375 { 00376 kdWarning(178) << "The setting '" << it.currentKey() << "' has disappeared!" << endl; 00377 continue; 00378 } 00379 00380 QVariant p = property(widget); 00381 if (p != item->property()) 00382 { 00383 // kdDebug(178) << "Widget for '" << it.currentKey() << "' has changed." << endl; 00384 return true; 00385 } 00386 } 00387 return false; 00388 } 00389 00390 bool KConfigDialogManager::isDefault() 00391 { 00392 bool bUseDefaults = m_conf->useDefaults(true); 00393 bool result = !hasChanged(); 00394 m_conf->useDefaults(bUseDefaults); 00395 return result; 00396 } 00397 00398 #include "kconfigdialogmanager.moc" 00399