• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KUtils

dialog.cpp

Go to the documentation of this file.
00001 /*  This file is part of the KDE project
00002     Copyright (C) 2003 Matthias Kretz <kretz@kde.org>
00003 
00004     This library is free software; you can redistribute it and/or
00005     modify it under the terms of the GNU Library General Public
00006     License version 2 as published by the Free Software Foundation.
00007 
00008     This library is distributed in the hope that it will be useful,
00009     but WITHOUT ANY WARRANTY; without even the implied warranty of
00010     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011     Library General Public License for more details.
00012 
00013     You should have received a copy of the GNU Library General Public License
00014     along with this library; see the file COPYING.LIB.  If not, write to
00015     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016     Boston, MA 02110-1301, USA.
00017 
00018 */
00019 
00020 #include "dialog.h"
00021 #include "dialog_p.h"
00022 
00023 #include "dispatcher.h"
00024 //#include "componentsdialog_p.h"
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     // The plugin, when disabled, disables all the KCMs described by kcmServices().
00096     // - Normally they are grouped using a .setdlg file so that the group parent can get a
00097     // checkbox to enable/disable the plugin.
00098     // - If the plugin does not belong to a group and has only one KCM the checkbox can be
00099     // used with this KCM.
00100     // - If the plugin belongs to a group but there are other modules in the group that do not
00101     // belong to this plugin we give a kError and show no checkbox
00102     // - If the plugin belongs to multiple groups we give a kError and show no checkbox
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     //kDebug(700) ;
00135     QString componentName = KGlobal::mainComponent().componentName();
00136     registeredComponents.append(componentName);
00137     //kDebug(700) << "calling KServiceGroup::childGroup( " << componentName << " )";
00138     KServiceGroup::Ptr service = KServiceGroup::childGroup( componentName );
00139 
00140     QSet<KCModuleInfo> ret;
00141 
00142     if( service && service->isValid() )
00143     {
00144         //kDebug(700) << "call was successful";
00145         const 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                 //kDebug( 700 ) << "found service";
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     //kDebug(700) << "constraint = " << constraint;
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     // if the user of this class requested to hide disabled modules
00182     // we check whether it should be enabled or not
00183     bool enabled = true;
00184     //kDebug(700) << "check whether the '" << moduleinfo->moduleName() << "' KCM should be shown";
00185     // for all parent components
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         // if the parentComponent is not registered ignore it
00192         if (!registeredComponents.contains(*pcit)) {
00193             continue;
00194         }
00195 
00196         // we check if the parent component is a plugin
00197         // if not the KCModule must be enabled
00198         enabled = true;
00199         if (pinfo.pluginName() == *pcit) {
00200             // it is a plugin: we check whether the plugin is enabled
00201             pinfo.load();
00202             enabled = pinfo.isPluginEnabled();
00203             //kDebug(700) << "parent " << *pcit << " is " << (enabled ? "enabled" : "disabled");
00204         }
00205         // if it is enabled we're done for this KCModuleInfo
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                     // the item we found is heavier than the new module
00262                     q->insertPage(siblingItem, item);
00263                     break;
00264                 }
00265             }
00266             if (row == siblingCount) {
00267                 // the new module is either the first or the heaviest item
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                     // the item we found is heavier than the new module
00277                     q->insertPage(siblingItem, item);
00278                     break;
00279                 }
00280             }
00281             if (row == siblingCount) {
00282                 // the new module is either the first or the heaviest item
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     // read .setdlg files
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     //kDebug(700) << kcmInfos.count();
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                 // this KCM belongs to a plugin
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                         // else everything is fine
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     // now that the KCMs are in, check for empty groups and remove them again
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                 // no children, and it's not allowed => remove this item
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     // TODO: Don't show the reset button until the issue with the
00406     // KPluginSelector::load() method is solved.
00407     // Problem:
00408     // KCMultiDialog::show() call KCModule::load() to reset all KCMs
00409     // (KPluginSelector::load() resets all plugin selections and all plugin
00410     // KCMs).
00411     // The reset button calls KCModule::load(), too but in this case we want the
00412     // KPluginSelector to only reset the current visible plugin KCM and not
00413     // touch the plugin selections.
00414     // I have no idea how to check that in KPluginSelector::load()...
00415     //q->showButton(KDialog::User1, true);
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 void DialogPrivate::_k_configureTree()
00448 {
00449     kDebug( 700 ) ;
00450     QObject::connect(subdlg, SIGNAL(okClicked()), q, SLOT(_k_updateTreeList()));
00451     QObject::connect(subdlg, SIGNAL(applyClicked()), q, SLOT(_k_updateTreeList()));
00452     QObject::connect(subdlg, SIGNAL(okClicked()), q, SIGNAL(pluginSelectionChanged()));
00453     QObject::connect(subdlg, SIGNAL(applyClicked()), q, SIGNAL(pluginSelectionChanged()));
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     // iterate over all child KPageWidgetItem objects and check whether they need to be enabled/disabled
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     //kDebug(700) ;
00500 
00501     QModelIndex firstborn = index.child(0, 0);
00502     if (firstborn.isValid()) {
00503         //kDebug(700) << "iterating over children";
00504         // change all children
00505         index = firstborn;
00506         QStack<QModelIndex> stack;
00507         while (index.isValid()) {
00508             //kDebug(700) << index;
00509             KPageWidgetItem *item = model->item(index);
00510             //kDebug(700) << "item->setEnabled(" << enabled << ')';
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 } //namespace
00528 
00529 #include "dialog.moc"
00530 
00531 // vim: ts=4

KUtils

Skip menu "KUtils"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal