// vim: noexpandtab shiftwidth=4 tabstop=4 /* This file is part of the KDE project Copyright (C) 2002 Daniel Molkentin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kcmkded.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "moc_kcmkded.cpp" K_PLUGIN_FACTORY(KDEDFactory, registerPlugin(); ) K_EXPORT_PLUGIN(KDEDFactory("kcmkded")) enum OnDemandColumns { OnDemandService = 0, OnDemandStatus = 1, OnDemandDescription = 2 }; enum StartupColumns { StartupUse = 0, StartupService = 1, StartupStatus = 2, StartupDescription = 3 }; static const int LibraryRole = Qt::UserRole + 1; KDEDConfig::KDEDConfig(QWidget* parent, const QVariantList &) : KCModule( KDEDFactory::componentData(), parent ) { KAboutData *about = new KAboutData( I18N_NOOP( "kcmkded" ), 0, ki18n( "KDE Service Manager" ), 0, KLocalizedString(), KAboutData::License_GPL, ki18n( "(c) 2002 Daniel Molkentin" ) ); about->addAuthor(ki18n("Daniel Molkentin"),KLocalizedString(),"molkentin@kde.org"); setAboutData( about ); setButtons(Apply|Default|Help); setQuickHelp( i18n("

Service Manager

This module allows you to have an overview of all plugins of the " "KDE Daemon, also referred to as KDE Services. Generally, there are two types of service:

" "
  • Services invoked at startup
  • Services called on demand
" "

The latter are only listed for convenience. The startup services can be started and stopped. " "In Administrator mode, you can also define whether services should be loaded at startup.

" "

Use this with care: some services are vital for KDE; do not deactivate services if you" " do not know what you are doing.

")); RUNNING = i18n("Running")+' '; NOT_RUNNING = i18n("Not running")+' '; QVBoxLayout *lay = new QVBoxLayout( this ); lay->setMargin( 0 ); QGroupBox *gb = new QGroupBox( i18n("Load-on-Demand Services"), this ); gb->setWhatsThis( i18n("This is a list of available KDE services which will " "be started on demand. They are only listed for convenience, as you " "cannot manipulate these services.")); lay->addWidget( gb ); QVBoxLayout *gblay = new QVBoxLayout( gb ); _lvLoD = new QTreeWidget( gb ); QStringList cols; cols.append( i18n("Service") ); cols.append( i18n("Status") ); cols.append( i18n("Description") ); _lvLoD->setHeaderLabels( cols ); _lvLoD->setAllColumnsShowFocus(true); _lvLoD->setRootIsDecorated( false ); _lvLoD->setSortingEnabled(true); _lvLoD->sortByColumn(OnDemandService, Qt::AscendingOrder); _lvLoD->header()->setStretchLastSection(true); gblay->addWidget( _lvLoD ); gb = new QGroupBox( i18n("Startup Services"), this ); gb->setWhatsThis( i18n("This shows all KDE services that can be loaded " "on KDE startup. Checked services will be invoked on next startup. " "Be careful with deactivation of unknown services.")); lay->addWidget( gb ); gblay = new QVBoxLayout( gb ); _lvStartup = new QTreeWidget( gb ); cols.clear(); cols.append( i18n("Use") ); cols.append( i18n("Service") ); cols.append( i18n("Status") ); cols.append( i18n("Description") ); _lvStartup->setHeaderLabels( cols ); _lvStartup->setAllColumnsShowFocus(true); _lvStartup->setRootIsDecorated( false ); _lvStartup->setSortingEnabled(true); _lvStartup->sortByColumn(StartupService, Qt::AscendingOrder); _lvStartup->header()->setStretchLastSection(true); gblay->addWidget( _lvStartup ); KDialogButtonBox *buttonBox = new KDialogButtonBox( gb, Qt::Horizontal); _pbStart = buttonBox->addButton( i18n("Start") , QDialogButtonBox::ActionRole ); _pbStop = buttonBox->addButton( i18n("Stop") , QDialogButtonBox::ActionRole ); gblay->addWidget( buttonBox ); _pbStart->setEnabled( false ); _pbStop->setEnabled( false ); connect(_pbStart, SIGNAL(clicked()), SLOT(slotStartService())); connect(_pbStop, SIGNAL(clicked()), SLOT(slotStopService())); connect(_lvLoD, SIGNAL(itemSelectionChanged()), SLOT(slotLodItemSelected())); connect(_lvStartup, SIGNAL(itemSelectionChanged()), SLOT(slotStartupItemSelected())); connect(_lvStartup, SIGNAL(itemChanged(QTreeWidgetItem*, int)), SLOT(slotItemChecked(QTreeWidgetItem*, int)) ); } QString setModuleGroup(const QString &filename) { QString module = filename; int i = module.lastIndexOf('/'); if (i != -1) module = module.mid(i+1); i = module.lastIndexOf('.'); if (i != -1) module = module.left(i); return QString("Module-%1").arg(module); } bool KDEDConfig::autoloadEnabled(KConfig *config, const QString &filename) { KConfigGroup cg(config, setModuleGroup(filename)); return cg.readEntry("autoload", true); } void KDEDConfig::setAutoloadEnabled(KConfig *config, const QString &filename, bool b) { KConfigGroup cg(config, setModuleGroup(filename)); return cg.writeEntry("autoload", b); } void KDEDConfig::load() { KConfig kdedrc( "kdedrc", KConfig::NoGlobals ); _lvStartup->clear(); _lvLoD->clear(); KService::List offers = KServiceTypeTrader::self()->query( "KDEDModule" ); QTreeWidgetItem* treeitem = 0L; for ( KService::List::const_iterator it = offers.constBegin(); it != offers.constEnd(); ++it) { QString servicePath = (*it)->entryPath(); kDebug() << servicePath; const KDesktopFile file( "services", servicePath ); const KConfigGroup grp = file.desktopGroup(); // The logic has to be identical to Kded::initModules. // They interpret X-KDE-Kded-autoload as false if not specified // X-KDE-Kded-load-on-demand as true if not specified if ( grp.readEntry("X-KDE-Kded-autoload", false) ) { treeitem = new QTreeWidgetItem(); treeitem->setCheckState( StartupUse, autoloadEnabled(&kdedrc, file.name()) ? Qt::Checked : Qt::Unchecked ); treeitem->setText( StartupService, file.readName() ); treeitem->setText( StartupDescription, file.readComment() ); treeitem->setText( StartupStatus, NOT_RUNNING ); if (grp.hasKey("X-KDE-DBus-ModuleName")) { treeitem->setData( StartupService, LibraryRole, grp.readEntry("X-KDE-DBus-ModuleName") ); } else { kWarning() << "X-KDE-DBUS-ModuleName not set for module " << file.readName(); treeitem->setData( StartupService, LibraryRole, grp.readEntry("X-KDE-Library") ); } _lvStartup->addTopLevelItem( treeitem ); } else if ( grp.readEntry("X-KDE-Kded-load-on-demand", true) ) { treeitem = new QTreeWidgetItem(); treeitem->setText( OnDemandService, file.readName() ); treeitem->setText( OnDemandDescription, file.readComment() ); treeitem->setText( OnDemandStatus, NOT_RUNNING ); if (grp.hasKey("X-KDE-DBus-ModuleName")) { treeitem->setData( OnDemandService, LibraryRole, grp.readEntry("X-KDE-DBus-ModuleName") ); } else { kWarning() << "X-KDE-DBUS-ModuleName not set for module " << file.readName(); treeitem->setData( OnDemandService, LibraryRole, grp.readEntry("X-KDE-Library") ); } _lvLoD->addTopLevelItem( treeitem ); } else { kWarning() << "kcmkded: Module " << file.readName() << " not loaded on demand or startup! Skipping."; } } _lvStartup->resizeColumnToContents(StartupUse); _lvStartup->resizeColumnToContents(StartupService); _lvStartup->resizeColumnToContents(StartupStatus); _lvLoD->resizeColumnToContents(OnDemandService); _lvLoD->resizeColumnToContents(OnDemandStatus); getServiceStatus(); emit changed(false); } void KDEDConfig::save() { KConfig kdedrc("kdedrc", KConfig::NoGlobals); KService::List offers = KServiceTypeTrader::self()->query( "KDEDModule" ); for ( KService::List::const_iterator it = offers.constBegin(); it != offers.constEnd(); ++it) { QString servicePath = (*it)->entryPath(); kDebug() << servicePath; const KDesktopFile file( "services", servicePath ); const KConfigGroup grp = file.desktopGroup(); if (grp.readEntry("X-KDE-Kded-autoload", false)){ QString libraryName = grp.readEntry( "X-KDE-Library" ); int count = _lvStartup->topLevelItemCount(); for( int i = 0; i < count; ++i ) { QTreeWidgetItem *treeitem = _lvStartup->topLevelItem( i ); if ( treeitem->data( StartupService, LibraryRole ).toString() == libraryName ) { // we found a match, now compare and see what changed setAutoloadEnabled( &kdedrc, servicePath, treeitem->checkState( StartupUse ) == Qt::Checked); break; } } } } kdedrc.sync(); emit changed(false); QDBusInterface kdedInterface( "org.kde.kded", "/kded", "org.kde.kded" ); kdedInterface.call( "reconfigure" ); QTimer::singleShot(0, this, SLOT(slotServiceRunningToggled())); } void KDEDConfig::defaults() { int count = _lvStartup->topLevelItemCount(); for( int i = 0; i < count; ++i ) { _lvStartup->topLevelItem( i )->setCheckState( StartupUse, Qt::Checked ); } getServiceStatus(); emit changed(true); } void KDEDConfig::getServiceStatus() { QStringList modules; QDBusInterface kdedInterface( "org.kde.kded", "/kded", "org.kde.kded" ); QDBusReply reply = kdedInterface.call( "loadedModules" ); if ( reply.isValid() ) { modules = reply.value(); } else { _lvLoD->setEnabled( false ); _lvStartup->setEnabled( false ); KMessageBox::error(this, i18n("Unable to contact KDED.")); return; } // Initialize int count = _lvLoD->topLevelItemCount(); for( int i = 0; i < count; ++i ) _lvLoD->topLevelItem( i )->setText( OnDemandStatus, NOT_RUNNING ); count = _lvStartup->topLevelItemCount(); for( int i = 0; i < count; ++i ) _lvStartup->topLevelItem( i )->setText( StartupStatus, NOT_RUNNING ); // Fill foreach( const QString& module, modules ) { bool found = false; count = _lvLoD->topLevelItemCount(); for( int i = 0; i < count; ++i ) { QTreeWidgetItem *treeitem = _lvLoD->topLevelItem( i ); if ( treeitem->data( OnDemandService, LibraryRole ).toString() == module ) { treeitem->setText( OnDemandStatus, RUNNING ); found = true; break; } } count = _lvStartup->topLevelItemCount(); for( int i = 0; i < count; ++i ) { QTreeWidgetItem *treeitem = _lvStartup->topLevelItem( i ); if ( treeitem->data( StartupService, LibraryRole ).toString() == module ) { treeitem->setText( StartupStatus, RUNNING ); found = true; break; } } if (!found) { kDebug() << "Could not relate module " << module; #ifndef NDEBUG kDebug() << "Candidates were:"; count = _lvLoD->topLevelItemCount(); for( int i = 0; i < count; ++i ) { QTreeWidgetItem *treeitem = _lvLoD->topLevelItem( i ); kDebug() << treeitem->data( OnDemandService, LibraryRole ).toString(); } count = _lvStartup->topLevelItemCount(); for( int i = 0; i < count; ++i ) { QTreeWidgetItem *treeitem = _lvStartup->topLevelItem( i ); kDebug() << treeitem->data( StartupService, LibraryRole ).toString(); } #endif } } } void KDEDConfig::slotReload() { QString current; if ( !_lvStartup->selectedItems().isEmpty() ) current = _lvStartup->selectedItems().at(0)->data( StartupService, LibraryRole ).toString(); load(); if ( !current.isEmpty() ) { int count = _lvStartup->topLevelItemCount(); for( int i = 0; i < count; ++i ) { QTreeWidgetItem *treeitem = _lvStartup->topLevelItem( i ); if ( treeitem->data( StartupService, LibraryRole ).toString() == current ) { _lvStartup->setCurrentItem( treeitem, 0, QItemSelectionModel::ClearAndSelect ); break; } } } } void KDEDConfig::slotStartupItemSelected() { if ( _lvStartup->selectedItems().isEmpty() ) { // Disable the buttons _pbStart->setEnabled( false ); _pbStop->setEnabled( false ); return; } // Deselect a currently selected element in the "load on demand" treeview _lvLoD->setCurrentItem(NULL, 0, QItemSelectionModel::Clear); QTreeWidgetItem *item = _lvStartup->selectedItems().at(0); if ( item->text(StartupStatus) == RUNNING ) { _pbStart->setEnabled( false ); _pbStop->setEnabled( true ); } else if ( item->text(StartupStatus) == NOT_RUNNING ) { _pbStart->setEnabled( true ); _pbStop->setEnabled( false ); } else // Error handling, better do nothing { _pbStart->setEnabled( false ); _pbStop->setEnabled( false ); } getServiceStatus(); } void KDEDConfig::slotLodItemSelected() { if ( _lvLoD->selectedItems().isEmpty() ) return; // Deselect a currently selected element in the "load on startup" treeview _lvStartup->setCurrentItem(NULL, 0, QItemSelectionModel::Clear); } void KDEDConfig::slotServiceRunningToggled() { getServiceStatus(); slotStartupItemSelected(); } void KDEDConfig::slotStartService() { QString service = _lvStartup->selectedItems().at(0)->data( StartupService, LibraryRole ).toString(); QDBusInterface kdedInterface( "org.kde.kded", "/kded","org.kde.kded" ); QDBusReply reply = kdedInterface.call( "loadModule", service ); if ( reply.isValid() ) { if ( reply.value() ) slotServiceRunningToggled(); else KMessageBox::error(this, "" + i18n("Unable to start server %1.", service) + ""); } else { KMessageBox::error(this, "" + i18n("Unable to start service %1.

Error: %2", service, reply.error().message()) + "
" ); } } void KDEDConfig::slotStopService() { QString service = _lvStartup->selectedItems().at(0)->data( StartupService, LibraryRole ).toString(); kDebug() << "Stopping: " << service; QDBusInterface kdedInterface( "org.kde.kded", "/kded", "org.kde.kded" ); QDBusReply reply = kdedInterface.call( "unloadModule", service ); if ( reply.isValid() ) { if ( reply.value() ) slotServiceRunningToggled(); else KMessageBox::error(this, "" + i18n("Unable to stop server %1.", service) + ""); } else { KMessageBox::error(this, "" + i18n("Unable to stop service %1.

Error: %2", service, reply.error().message()) + "
" ); } } void KDEDConfig::slotItemChecked(QTreeWidgetItem*, int column) { // We only listen to changes the user did. if (column==StartupUse) { emit changed(true); } }