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