00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "dialog.h"
00021 #include "dialog_p.h"
00022
00023 #include "dispatcher.h"
00024
00025
00026 #include <klocale.h>
00027 #include <kservicegroup.h>
00028 #include <kdebug.h>
00029 #include <kservicetypetrader.h>
00030 #include <kconfig.h>
00031 #include <kstandarddirs.h>
00032 #include <kcomponentdata.h>
00033 #include <kiconloader.h>
00034 #include <QtCore/QFile>
00035 #include <QtGui/QCheckBox>
00036 #include <QtCore/QStack>
00037
00038 uint qHash(const KCModuleInfo &info)
00039 {
00040 return qHash(info.fileName());
00041 }
00042
00043 namespace KSettings
00044 {
00045
00046 Dialog::Dialog(QWidget *parent)
00047 : KCMultiDialog(*new DialogPrivate, new KPageWidget, parent)
00048 {
00049 }
00050
00051 Dialog::Dialog(const QStringList &components, QWidget *parent)
00052 : KCMultiDialog(*new DialogPrivate, new KPageWidget, parent)
00053 {
00054 Q_D(Dialog);
00055 d->components = components;
00056 }
00057
00058 Dialog::~Dialog()
00059 {
00060 }
00061
00062 void Dialog::setAllowComponentSelection(bool selection)
00063 {
00064 d_func()->staticlistview = !selection;
00065 }
00066
00067 bool Dialog::allowComponentSelection() const
00068 {
00069 return !d_func()->staticlistview;
00070 }
00071
00072 void Dialog::setKCMArguments(const QStringList& arguments)
00073 {
00074 Q_D(Dialog);
00075 d->arguments = arguments;
00076 }
00077
00078 void Dialog::setComponentBlacklist(const QStringList& blacklist)
00079 {
00080 Q_D(Dialog);
00081 d->componentBlacklist = blacklist;
00082 }
00083
00084 void Dialog::addPluginInfos(const KPluginInfo::List &plugininfos)
00085 {
00086 Q_D(Dialog);
00087 for (KPluginInfo::List::ConstIterator it = plugininfos.begin();
00088 it != plugininfos.end(); ++it ) {
00089 d->registeredComponents.append(it->pluginName());
00090 foreach (const KService::Ptr &service, it->kcmServices()) {
00091 d->kcmInfos << KCModuleInfo(service);
00092 }
00093 }
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 d->plugininfos = plugininfos;
00104 }
00105
00106 KPluginInfo::List Dialog::pluginInfos() const
00107 {
00108 return d_func()->plugininfos;
00109 }
00110
00111 void Dialog::showEvent(QShowEvent *)
00112 {
00113 Q_D(Dialog);
00114 if (d->firstshow) {
00115 setUpdatesEnabled(false);
00116 d->kcmInfos += d->instanceServices();
00117 if (!d->components.isEmpty()) {
00118 d->kcmInfos += d->parentComponentsServices(d->components);
00119 }
00120 d->createDialogFromServices();
00121 d->firstshow = false;
00122 setUpdatesEnabled(true);
00123 }
00124 Dispatcher::syncConfiguration();
00125 }
00126
00127 DialogPrivate::DialogPrivate()
00128 : staticlistview(true), firstshow(true), pluginStateDirty(0)
00129 {
00130 }
00131
00132 QSet<KCModuleInfo> DialogPrivate::instanceServices()
00133 {
00134
00135 QString componentName = KGlobal::mainComponent().componentName();
00136 registeredComponents.append(componentName);
00137
00138 KServiceGroup::Ptr service = KServiceGroup::childGroup( componentName );
00139
00140 QSet<KCModuleInfo> ret;
00141
00142 if( service && service->isValid() )
00143 {
00144
00145 KServiceGroup::List list = service->entries();
00146 for( KServiceGroup::List::ConstIterator it = list.begin();
00147 it != list.end(); ++it )
00148 {
00149 KSycocaEntry::Ptr p = (*it);
00150 if( p->isType( KST_KService ) )
00151 {
00152
00153 ret << KCModuleInfo(KService::Ptr::staticCast(p));
00154 }
00155 else
00156 kWarning( 700 ) << "KServiceGroup::childGroup returned"
00157 " something else than a KService" << endl;
00158 }
00159 }
00160
00161 return ret;
00162 }
00163
00164 QSet<KCModuleInfo> DialogPrivate::parentComponentsServices(const QStringList &kcdparents)
00165 {
00166 registeredComponents += kcdparents;
00167 QString constraint = kcdparents.join("' in [X-KDE-ParentComponents]) or ('");
00168 constraint = "('" + constraint + "' in [X-KDE-ParentComponents])";
00169
00170
00171 const QList<KService::Ptr> services = KServiceTypeTrader::self()->query("KCModule", constraint);
00172 QSet<KCModuleInfo> ret;
00173 foreach (const KService::Ptr &service, services) {
00174 ret << KCModuleInfo(service);
00175 }
00176 return ret;
00177 }
00178
00179 bool DialogPrivate::isPluginForKCMEnabled(const KCModuleInfo *moduleinfo, KPluginInfo &pinfo) const
00180 {
00181
00182
00183 bool enabled = true;
00184
00185
00186 const QStringList parentComponents = moduleinfo->service()->property(
00187 "X-KDE-ParentComponents" ).toStringList();
00188 for( QStringList::ConstIterator pcit = parentComponents.begin();
00189 pcit != parentComponents.end(); ++pcit )
00190 {
00191
00192 if (!registeredComponents.contains(*pcit)) {
00193 continue;
00194 }
00195
00196
00197
00198 enabled = true;
00199 if (pinfo.pluginName() == *pcit) {
00200
00201 pinfo.load();
00202 enabled = pinfo.isPluginEnabled();
00203
00204 }
00205
00206 if (enabled) {
00207 return true;
00208 }
00209 }
00210 return enabled;
00211 }
00212
00213 bool DialogPrivate::isPluginImmutable(const KPluginInfo &pinfo) const
00214 {
00215 return pinfo.property("X-KDE-PluginInfo-Immutable").toBool();
00216 }
00217
00218 void DialogPrivate::parseGroupFile( const QString & filename )
00219 {
00220 Q_Q(Dialog);
00221 KConfig file( filename, KConfig::SimpleConfig );
00222 const QStringList groups = file.groupList();
00223 foreach (const QString &group, groups) {
00224 if (group.isEmpty()) {
00225 continue;
00226 }
00227 KConfigGroup conf(&file, group);
00228
00229 QWidget * page = new QWidget( q );
00230
00231 const QString iconName = conf.readEntry("Icon");
00232 QCheckBox *checkBox = new QCheckBox(i18n("Enable component"), page);
00233 QLabel *iconLabel = new QLabel(page);
00234 QLabel *comment = new QLabel(conf.readEntry("Comment"), page);
00235 comment->setTextFormat(Qt::RichText);
00236 QVBoxLayout * layout = new QVBoxLayout(page);
00237 layout->addWidget(checkBox);
00238 layout->addWidget(iconLabel);
00239 layout->addWidget(comment);
00240 layout->addStretch();
00241 page->setLayout(layout);
00242
00243 KPageWidgetItem *item = new KPageWidgetItem(page, conf.readEntry("Name"));
00244 item->setIcon(KIcon(iconName));
00245 iconLabel->setPixmap(item->icon().pixmap(128, 128));
00246 const int weight = conf.readEntry("Weight", 100);
00247 item->setProperty("_k_weight", weight);
00248 checkBoxForItem.insert(item, checkBox);
00249
00250 const KPageWidgetModel *model = qobject_cast<const KPageWidgetModel *>(q->pageWidget()->model());
00251 Q_ASSERT(model);
00252 const QString parentId = conf.readEntry("Parent");
00253 KPageWidgetItem *parentItem = pageItemForGroupId.value(parentId);
00254 if (parentItem) {
00255 const QModelIndex parentIndex = model->index(parentItem);
00256 const int siblingCount = model->rowCount(parentIndex);
00257 int row = 0;
00258 for (; row < siblingCount; ++row) {
00259 KPageWidgetItem *siblingItem = model->item(parentIndex.child(row, 0));
00260 if (siblingItem->property("_k_weight").toInt() > weight) {
00261
00262 q->insertPage(siblingItem, item);
00263 break;
00264 }
00265 }
00266 if (row == siblingCount) {
00267
00268 q->addSubPage(parentItem, item);
00269 }
00270 } else {
00271 const int siblingCount = model->rowCount();
00272 int row = 0;
00273 for (; row < siblingCount; ++row) {
00274 KPageWidgetItem *siblingItem = model->item(model->index(row, 0));
00275 if (siblingItem->property("_k_weight").toInt() > weight) {
00276
00277 q->insertPage(siblingItem, item);
00278 break;
00279 }
00280 }
00281 if (row == siblingCount) {
00282
00283 q->addPage(item);
00284 }
00285 }
00286
00287 pageItemForGroupId.insert(group, item);
00288 }
00289 }
00290
00291 void DialogPrivate::createDialogFromServices()
00292 {
00293 Q_Q(Dialog);
00294
00295 QString setdlgpath = KStandardDirs::locate( "appdata",
00296 KGlobal::mainComponent().componentName() + ".setdlg" );
00297 const QStringList setdlgaddon = KGlobal::dirs()->findAllResources( "appdata",
00298 "ksettingsdialog/*.setdlg" );
00299 if (!setdlgpath.isNull()) {
00300 parseGroupFile(setdlgpath);
00301 }
00302 if (setdlgaddon.size() > 0) {
00303 for (QStringList::ConstIterator it = setdlgaddon.begin(); it != setdlgaddon.end(); ++it) {
00304 parseGroupFile(*it);
00305 }
00306 }
00307
00308
00309 foreach (const KCModuleInfo &info, kcmInfos) {
00310 const QStringList parentComponents = info.service()->property("X-KDE-ParentComponents").toStringList();
00311 bool blacklisted = false;
00312 foreach (const QString &parentComponent, parentComponents) {
00313 if (componentBlacklist.contains(parentComponent)) {
00314 blacklisted = true;
00315 break;
00316 }
00317 }
00318 if (blacklisted) {
00319 continue;
00320 }
00321 const QString parentId = info.service()->property("X-KDE-CfgDlgHierarchy", QVariant::String).toString();
00322 KPageWidgetItem *parent = pageItemForGroupId.value(parentId);
00323 KPageWidgetItem *item = q->addModule(info, parent, arguments);
00324 kDebug(700) << "added KCM '" << info.moduleName() << "'";
00325 foreach (KPluginInfo pinfo, plugininfos) {
00326 kDebug(700) << pinfo.pluginName();
00327 if (pinfo.kcmServices().contains(info.service())) {
00328 const bool isEnabled = isPluginForKCMEnabled(&info, pinfo);
00329 item->setEnabled(isEnabled);
00330 kDebug(700) << "correct KPluginInfo for this KCM";
00331
00332 if (parent && pinfo.kcmServices().count() > 1) {
00333 const KPluginInfo &plugin = pluginForItem.value(parent);
00334 if (plugin.isValid()) {
00335 if (plugin != pinfo) {
00336 kError(700) << "A group contains more than one plugin: '"
00337 << plugin.pluginName() << "' and '" << pinfo.pluginName()
00338 << "'. Now it won't be possible to enable/disable the plugin."
00339 << endl;
00340 parent->setCheckable(false);
00341 q->disconnect(parent, SIGNAL(toggled(bool)), q, SLOT(_k_updateEnabledState(bool)));
00342 }
00343
00344 } else {
00345 QCheckBox *checkBox = checkBoxForItem.value(parent);
00346 Q_ASSERT(checkBox);
00347 pluginForItem.insert(parent, pinfo);
00348 parent->setCheckable(!isPluginImmutable(pinfo));
00349 parent->setChecked(isEnabled);
00350 checkBox->setVisible(!isPluginImmutable(pinfo));
00351 checkBox->setChecked(isEnabled);
00352 q->connect(parent, SIGNAL(toggled(bool)), q, SLOT(_k_updateEnabledState(bool)));
00353 q->connect(parent, SIGNAL(toggled(bool)), checkBox, SLOT(setChecked(bool)));
00354 q->connect(checkBox, SIGNAL(clicked(bool)), parent, SLOT(setChecked(bool)));
00355 }
00356 } else {
00357 pluginForItem.insert(item, pinfo);
00358 item->setCheckable(!isPluginImmutable(pinfo));
00359 item->setChecked(isEnabled);
00360 q->connect(item, SIGNAL(toggled(bool)), q, SLOT(_k_updateEnabledState(bool)));
00361 }
00362 break;
00363 }
00364 }
00365 }
00366
00367 {
00368 const KPageWidgetModel *model = qobject_cast<const KPageWidgetModel *>(q->pageWidget()->model());
00369 const QHash<QString, KPageWidgetItem *>::ConstIterator end = pageItemForGroupId.constEnd();
00370 QHash<QString, KPageWidgetItem *>::ConstIterator it = pageItemForGroupId.constBegin();
00371 for (; it != end; ++it) {
00372 const QModelIndex index = model->index(it.value());
00373 KPluginInfo pinfo;
00374 foreach (const KPluginInfo &p, plugininfos) {
00375 if (p.name()==it.key()) {
00376 pinfo = p;
00377 break;
00378 }
00379 }
00380 bool allowEmpty = false;
00381 if (pinfo.isValid()) {
00382 allowEmpty = pinfo.property("X-KDE-PluginInfo-AllowEmptySettings").toBool();
00383 }
00384
00385 if (!index.child(0, 0).isValid()) {
00386
00387 if (!allowEmpty) {
00388 q->removePage(it.value());
00389 } else {
00390 QCheckBox *checkBox = checkBoxForItem.value(it.value());
00391 Q_ASSERT(checkBox);
00392 pluginForItem.insert(it.value(), pinfo);
00393 it.value()->setCheckable(!isPluginImmutable(pinfo));
00394 it.value()->setChecked(pinfo.isPluginEnabled());
00395 checkBox->setVisible(!isPluginImmutable(pinfo));
00396 checkBox->setChecked(pinfo.isPluginEnabled());
00397 q->connect(it.value(), SIGNAL(toggled(bool)), q, SLOT(_k_updateEnabledState(bool)));
00398 q->connect(it.value(), SIGNAL(toggled(bool)), checkBox, SLOT(setChecked(bool)));
00399 q->connect(checkBox, SIGNAL(clicked(bool)), it.value(), SLOT(setChecked(bool)));
00400 }
00401 }
00402 }
00403 }
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417 QObject::connect(q, SIGNAL(okClicked()), q, SLOT(_k_syncConfiguration()));
00418 QObject::connect(q, SIGNAL(applyClicked()), q, SLOT(_k_syncConfiguration()));
00419 QObject::connect(q, SIGNAL(configCommitted(const QByteArray &)), q,
00420 SLOT(_k_reparseConfiguration(const QByteArray &)));
00421 }
00422
00423 void DialogPrivate::_k_syncConfiguration()
00424 {
00425 Q_Q(Dialog);
00426 const QHash<KPageWidgetItem *, KPluginInfo>::Iterator endIt = pluginForItem.end();
00427 QHash<KPageWidgetItem *, KPluginInfo>::Iterator it = pluginForItem.begin();
00428 for (; it != endIt; ++it) {
00429 KPageWidgetItem *item = it.key();
00430 KPluginInfo pinfo = it.value();
00431 pinfo.setPluginEnabled(item->isChecked());
00432 pinfo.save();
00433 }
00434 if (pluginStateDirty > 0) {
00435 emit q->pluginSelectionChanged();
00436 pluginStateDirty = 0;
00437 }
00438 Dispatcher::syncConfiguration();
00439 }
00440
00441 void DialogPrivate::_k_reparseConfiguration(const QByteArray &a)
00442 {
00443 Dispatcher::reparseConfiguration(a);
00444 }
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457 void DialogPrivate::_k_clientChanged()
00458 {
00459 if (pluginStateDirty > 0) {
00460 Q_Q(Dialog);
00461 q->enableButton(KDialog::Apply, true);
00462 } else {
00463 KCMultiDialogPrivate::_k_clientChanged();
00464 }
00465 }
00466
00467 void DialogPrivate::_k_updateEnabledState(bool enabled)
00468 {
00469 Q_Q(Dialog);
00470 KPageWidgetItem *item = qobject_cast<KPageWidgetItem *>(q->sender());
00471 if (!item) {
00472 kWarning(700) << "invalid sender";
00473 return;
00474 }
00475
00476
00477 const KPageWidgetModel *model = qobject_cast<const KPageWidgetModel *>(q->pageWidget()->model());
00478 Q_ASSERT(model);
00479 QModelIndex index = model->index(item);
00480 if (!index.isValid()) {
00481 kWarning(700) << "could not find item in model";
00482 return;
00483 }
00484
00485 const KPluginInfo &pinfo = pluginForItem.value(item);
00486 if (!pinfo.isValid()) {
00487 kWarning(700) << "could not find KPluginInfo in item";
00488 return;
00489 }
00490 if (pinfo.isPluginEnabled() != enabled) {
00491 ++pluginStateDirty;
00492 } else {
00493 --pluginStateDirty;
00494 }
00495 if (pluginStateDirty < 2) {
00496 _k_clientChanged();
00497 }
00498
00499
00500
00501 QModelIndex firstborn = index.child(0, 0);
00502 if (firstborn.isValid()) {
00503
00504
00505 index = firstborn;
00506 QStack<QModelIndex> stack;
00507 while (index.isValid()) {
00508
00509 KPageWidgetItem *item = model->item(index);
00510
00511 item->setEnabled(enabled);
00512 firstborn = index.child(0, 0);
00513 if (firstborn.isValid()) {
00514 stack.push(index);
00515 index = firstborn;
00516 } else {
00517 index = index.sibling(index.row() + 1, 0);
00518 while (!index.isValid() && !stack.isEmpty()) {
00519 index = stack.pop();
00520 index = index.sibling(index.row() + 1, 0);
00521 }
00522 }
00523 }
00524 }
00525 }
00526
00527 }
00528
00529 #include "dialog.moc"
00530
00531