1 // vim: noexpandtab shiftwidth=4 tabstop=4
2 /* This file is part of the KDE project
3 Copyright (C) 2002 Daniel Molkentin <molkentin@kde.org>
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
24 #include <QtDBus/QtDBus>
26 #include <QHeaderView>
27 #include <QPushButton>
29 #include <QTreeWidget>
30 #include <QVBoxLayout>
32 #include <kaboutdata.h>
33 #include <kdialogbuttonbox.h>
35 #include <kdesktopfile.h>
37 #include <kmessagebox.h>
39 #include <kstandarddirs.h>
41 #include <KPluginFactory>
42 #include <KPluginLoader>
43 #include "kcmkded.moc"
45 K_PLUGIN_FACTORY(KDEDFactory
,
46 registerPlugin
<KDEDConfig
>();
48 K_EXPORT_PLUGIN(KDEDFactory("kcmkded"))
54 OnDemandDescription
= 2
62 StartupDescription
= 3
67 static const int LibraryRole
= Qt::UserRole
+ 1;
69 KDEDConfig::KDEDConfig(QWidget
* parent
, const QVariantList
&) :
70 KCModule( KDEDFactory::componentData(), parent
)
73 new KAboutData( I18N_NOOP( "kcmkded" ), 0, ki18n( "KDE Service Manager" ),
74 0, KLocalizedString(), KAboutData::License_GPL
,
75 ki18n( "(c) 2002 Daniel Molkentin" ) );
76 about
->addAuthor(ki18n("Daniel Molkentin"),KLocalizedString(),"molkentin@kde.org");
77 setAboutData( about
);
78 setButtons(Apply
|Default
);
79 setQuickHelp( i18n("<h1>Service Manager</h1><p>This module allows you to have an overview of all plugins of the "
80 "KDE Daemon, also referred to as KDE Services. Generally, there are two types of service:</p>"
81 "<ul><li>Services invoked at startup</li><li>Services called on demand</li></ul>"
82 "<p>The latter are only listed for convenience. The startup services can be started and stopped. "
83 "In Administrator mode, you can also define whether services should be loaded at startup.</p>"
84 "<p><b> Use this with care: some services are vital for KDE; do not deactivate services if you"
85 " do not know what you are doing.</b></p>"));
87 RUNNING
= i18n("Running")+' ';
88 NOT_RUNNING
= i18n("Not running")+' ';
90 QVBoxLayout
*lay
= new QVBoxLayout( this );
92 lay
->setSpacing( KDialog::spacingHint() );
94 QGroupBox
*gb
= new QGroupBox( i18n("Load-on-Demand Services"), this );
95 gb
->setWhatsThis( i18n("This is a list of available KDE services which will "
96 "be started on demand. They are only listed for convenience, as you "
97 "cannot manipulate these services."));
100 QVBoxLayout
*gblay
= new QVBoxLayout( gb
);
102 _lvLoD
= new QTreeWidget( gb
);
104 cols
.append( i18n("Service") );
105 cols
.append( i18n("Status") );
106 cols
.append( i18n("Description") );
107 _lvLoD
->setHeaderLabels( cols
);
108 _lvLoD
->setAllColumnsShowFocus(true);
109 _lvLoD
->setRootIsDecorated( false );
110 _lvLoD
->header()->setStretchLastSection(true);
111 gblay
->addWidget( _lvLoD
);
113 gb
= new QGroupBox( i18n("Startup Services"), this );
114 gb
->setWhatsThis( i18n("This shows all KDE services that can be loaded "
115 "on KDE startup. Checked services will be invoked on next startup. "
116 "Be careful with deactivation of unknown services."));
117 lay
->addWidget( gb
);
119 gblay
= new QVBoxLayout( gb
);
121 _lvStartup
= new QTreeWidget( gb
);
123 cols
.append( i18n("Use") );
124 cols
.append( i18n("Service") );
125 cols
.append( i18n("Status") );
126 cols
.append( i18n("Description") );
127 _lvStartup
->setHeaderLabels( cols
);
128 _lvStartup
->setAllColumnsShowFocus(true);
129 _lvStartup
->setRootIsDecorated( false );
130 _lvStartup
->header()->setStretchLastSection(true);
131 gblay
->addWidget( _lvStartup
);
133 KDialogButtonBox
*buttonBox
= new KDialogButtonBox( gb
, Qt::Horizontal
);
134 _pbStart
= buttonBox
->addButton( i18n("Start") , QDialogButtonBox::ActionRole
);
135 _pbStop
= buttonBox
->addButton( i18n("Stop") , QDialogButtonBox::ActionRole
);
136 gblay
->addWidget( buttonBox
);
138 _pbStart
->setEnabled( false );
139 _pbStop
->setEnabled( false );
141 connect(_pbStart
, SIGNAL(clicked()), SLOT(slotStartService()));
142 connect(_pbStop
, SIGNAL(clicked()), SLOT(slotStopService()));
143 connect(_lvLoD
, SIGNAL(itemClicked(QTreeWidgetItem
*, int)), SLOT(slotLodItemSelected(QTreeWidgetItem
*)) );
144 connect(_lvStartup
, SIGNAL(itemClicked(QTreeWidgetItem
*, int)), SLOT(slotEvalItem(QTreeWidgetItem
*)) );
145 connect(_lvStartup
, SIGNAL(itemChanged(QTreeWidgetItem
*, int)), SLOT(slotItemChecked(QTreeWidgetItem
*, int)) );
149 QString
setModuleGroup(const QString
&filename
)
151 QString module
= filename
;
152 int i
= module
.lastIndexOf('/');
154 module
= module
.mid(i
+1);
155 i
= module
.lastIndexOf('.');
157 module
= module
.left(i
);
159 return QString("Module-%1").arg(module
);
162 bool KDEDConfig::autoloadEnabled(KConfig
*config
, const QString
&filename
)
164 KConfigGroup
cg(config
, setModuleGroup(filename
));
165 return cg
.readEntry("autoload", true);
168 void KDEDConfig::setAutoloadEnabled(KConfig
*config
, const QString
&filename
, bool b
)
170 KConfigGroup
cg(config
, setModuleGroup(filename
));
171 return cg
.writeEntry("autoload", b
);
174 void KDEDConfig::load() {
175 KConfig
kdedrc( "kdedrc", KConfig::NoGlobals
);
181 KGlobal::dirs()->findAllResources( "services",
182 QLatin1String( "kded/*.desktop" ),
183 KStandardDirs::Recursive
| KStandardDirs::NoDuplicates
,
186 QTreeWidgetItem
* treeitem
= 0L;
187 for ( QStringList::ConstIterator it
= files
.constBegin(); it
!= files
.constEnd(); ++it
) {
190 if ( KDesktopFile::isDesktopFile( *it
) ) {
191 KDesktopFile
file( "services", *it
);
192 Q_ASSERT( file
.desktopGroup().readEntry("X-KDE-ServiceTypes") == "KDEDModule" );
193 // The logic has to be identical to Kded::initModules.
194 // They interpret X-KDE-Kded-autoload as false if not specified
195 // X-KDE-Kded-load-on-demand as true if not specified
196 if ( file
.desktopGroup().readEntry("X-KDE-Kded-autoload", false) ) {
197 treeitem
= new QTreeWidgetItem();
198 treeitem
->setCheckState( StartupUse
, autoloadEnabled(&kdedrc
, *it
) ? Qt::Checked
: Qt::Unchecked
);
199 treeitem
->setText( StartupService
, file
.readName() );
200 treeitem
->setText( StartupDescription
, file
.readComment() );
201 treeitem
->setText( StartupStatus
, NOT_RUNNING
);
202 if (file
.desktopGroup().hasKey("X-KDE-DBus-ModuleName")) {
203 treeitem
->setData( StartupService
, LibraryRole
, file
.desktopGroup().readEntry("X-KDE-DBus-ModuleName") );
205 kWarning() << "X-KDE-DBUS-ModuleName not set for module " << file
.readName();
206 treeitem
->setData( StartupService
, LibraryRole
, file
.desktopGroup().readEntry("X-KDE-Library") );
208 _lvStartup
->addTopLevelItem( treeitem
);
210 else if ( file
.desktopGroup().readEntry("X-KDE-Kded-load-on-demand", true) ) {
211 treeitem
= new QTreeWidgetItem();
212 treeitem
->setText( OnDemandService
, file
.readName() );
213 treeitem
->setText( OnDemandDescription
, file
.readComment() );
214 treeitem
->setText( OnDemandStatus
, NOT_RUNNING
);
215 if (file
.desktopGroup().hasKey("X-KDE-DBus-ModuleName")) {
216 treeitem
->setData( OnDemandService
, LibraryRole
, file
.desktopGroup().readEntry("X-KDE-DBus-ModuleName") );
218 kWarning() << "X-KDE-DBUS-ModuleName not set for module " << file
.readName();
219 treeitem
->setData( OnDemandService
, LibraryRole
, file
.desktopGroup().readEntry("X-KDE-Library") );
221 _lvLoD
->addTopLevelItem( treeitem
);
224 kWarning() << "kcmkded: Module " << file
.readName() << " not loaded on demand or startup! Skipping.";
229 _lvStartup
->resizeColumnToContents(StartupUse
);
230 _lvStartup
->resizeColumnToContents(StartupService
);
231 _lvStartup
->resizeColumnToContents(StartupStatus
);
233 _lvLoD
->resizeColumnToContents(OnDemandService
);
234 _lvLoD
->resizeColumnToContents(OnDemandStatus
);
241 void KDEDConfig::save() {
243 KGlobal::dirs()->findAllResources( "services",
244 QLatin1String( "kded/*.desktop" ),
245 KStandardDirs::Recursive
| KStandardDirs::NoDuplicates
,
248 KConfig
kdedrc("kdedrc", KConfig::NoGlobals
);
250 for ( QStringList::ConstIterator it
= files
.constBegin(); it
!= files
.constEnd(); ++it
) {
252 if ( KDesktopFile::isDesktopFile( *it
) ) {
254 KConfig
_file( *it
, KConfig::NoGlobals
, "services" );
255 KConfigGroup
file(&_file
, "Desktop Entry");
257 if (file
.readEntry("X-KDE-Kded-autoload", false)){
259 QString libraryName
= file
.readEntry( "X-KDE-Library" );
260 int count
= _lvStartup
->topLevelItemCount();
261 for( int i
= 0; i
< count
; ++i
)
263 QTreeWidgetItem
*treeitem
= _lvStartup
->topLevelItem( i
);
264 if ( treeitem
->data( StartupService
, LibraryRole
).toString() == libraryName
)
266 // we found a match, now compare and see what changed
267 setAutoloadEnabled( &kdedrc
, *it
, treeitem
->checkState( StartupUse
) == Qt::Checked
);
278 QDBusInterface
kdedInterface( "org.kde.kded", "/kded", "org.kde.kded" );
279 kdedInterface
.call( "reconfigure" );
280 QTimer::singleShot(0, this, SLOT(slotServiceRunningToggled()));
284 void KDEDConfig::defaults()
286 int count
= _lvStartup
->topLevelItemCount();
287 for( int i
= 0; i
< count
; ++i
)
289 _lvStartup
->topLevelItem( i
)->setCheckState( StartupUse
, Qt::Unchecked
);
298 void KDEDConfig::getServiceStatus()
301 QDBusInterface
kdedInterface( "org.kde.kded", "/kded", "org.kde.kded" );
302 QDBusReply
<QStringList
> reply
= kdedInterface
.call( "loadedModules" );
304 if ( reply
.isValid() ) {
305 modules
= reply
.value();
308 _lvLoD
->setEnabled( false );
309 _lvStartup
->setEnabled( false );
310 KMessageBox::error(this, i18n("Unable to contact KDED."));
315 int count
= _lvLoD
->topLevelItemCount();
316 for( int i
= 0; i
< count
; ++i
)
317 _lvLoD
->topLevelItem( i
)->setText( OnDemandStatus
, NOT_RUNNING
);
318 count
= _lvStartup
->topLevelItemCount();
319 for( int i
= 0; i
< count
; ++i
)
320 _lvStartup
->topLevelItem( i
)->setText( StartupStatus
, NOT_RUNNING
);
323 foreach( const QString
& module
, modules
)
327 count
= _lvLoD
->topLevelItemCount();
328 for( int i
= 0; i
< count
; ++i
)
330 QTreeWidgetItem
*treeitem
= _lvLoD
->topLevelItem( i
);
331 if ( treeitem
->data( OnDemandService
, LibraryRole
).toString() == module
)
333 treeitem
->setText( OnDemandStatus
, RUNNING
);
339 count
= _lvStartup
->topLevelItemCount();
340 for( int i
= 0; i
< count
; ++i
)
342 QTreeWidgetItem
*treeitem
= _lvStartup
->topLevelItem( i
);
343 if ( treeitem
->data( StartupService
, LibraryRole
).toString() == module
)
345 treeitem
->setText( StartupStatus
, RUNNING
);
353 kDebug() << "Could not relate module " << module
;
355 kDebug() << "Candidates were:";
356 count
= _lvLoD
->topLevelItemCount();
357 for( int i
= 0; i
< count
; ++i
)
359 QTreeWidgetItem
*treeitem
= _lvLoD
->topLevelItem( i
);
360 kDebug() << treeitem
->data( OnDemandService
, LibraryRole
).toString();
363 count
= _lvStartup
->topLevelItemCount();
364 for( int i
= 0; i
< count
; ++i
)
366 QTreeWidgetItem
*treeitem
= _lvStartup
->topLevelItem( i
);
367 kDebug() << treeitem
->data( StartupService
, LibraryRole
).toString();
376 void KDEDConfig::slotReload()
379 if ( _lvStartup
->currentItem() )
380 current
= _lvStartup
->currentItem()->data( StartupService
, LibraryRole
).toString();
382 if ( !current
.isEmpty() )
384 int count
= _lvStartup
->topLevelItemCount();
385 for( int i
= 0; !i
< count
; ++i
)
387 QTreeWidgetItem
*treeitem
= _lvStartup
->topLevelItem( i
);
388 if ( treeitem
->data( StartupService
, LibraryRole
).toString() == current
)
390 _lvStartup
->setCurrentItem( treeitem
);
397 void KDEDConfig::slotEvalItem(QTreeWidgetItem
* item
)
400 // Disable the buttons
401 _pbStart
->setEnabled( false );
402 _pbStop
->setEnabled( false );
406 // Deselect a currently selected element in the "load on demand" treeview
407 _lvLoD
->setCurrentItem(NULL
);
409 if ( item
->text(StartupStatus
) == RUNNING
) {
410 _pbStart
->setEnabled( false );
411 _pbStop
->setEnabled( true );
413 else if ( item
->text(StartupStatus
) == NOT_RUNNING
) {
414 _pbStart
->setEnabled( true );
415 _pbStop
->setEnabled( false );
417 else // Error handling, better do nothing
419 _pbStart
->setEnabled( false );
420 _pbStop
->setEnabled( false );
426 void KDEDConfig::slotLodItemSelected(QTreeWidgetItem
* item
)
431 // Deselect a currently selected element in the "load on startup" treeview
432 _lvStartup
->setCurrentItem(NULL
);
433 // The above line doesn't trigger itemClicked. So call that handler
438 void KDEDConfig::slotServiceRunningToggled()
441 slotEvalItem(_lvStartup
->currentItem());
444 void KDEDConfig::slotStartService()
446 QString service
= _lvStartup
->currentItem()->data( StartupService
, LibraryRole
).toString();
448 QDBusInterface
kdedInterface( "org.kde.kded", "/kded","org.kde.kded" );
449 QDBusReply
<bool> reply
= kdedInterface
.call( "loadModule", service
);
451 if ( reply
.isValid() ) {
453 slotServiceRunningToggled();
455 KMessageBox::error(this, "<qt>" + i18n("Unable to start server <em>%1</em>.", service
) + "</qt>");
458 KMessageBox::error(this, "<qt>" + i18n("Unable to start service <em>%1</em>.<br /><br /><i>Error: %2</i>",
459 service
, reply
.error().message()) + "</qt>" );
463 void KDEDConfig::slotStopService()
465 QString service
= _lvStartup
->currentItem()->data( StartupService
, LibraryRole
).toString();
466 kDebug() << "Stopping: " << service
;
468 QDBusInterface
kdedInterface( "org.kde.kded", "/kded", "org.kde.kded" );
469 QDBusReply
<bool> reply
= kdedInterface
.call( "unloadModule", service
);
471 if ( reply
.isValid() ) {
473 slotServiceRunningToggled();
475 KMessageBox::error(this, "<qt>" + i18n("Unable to stop server <em>%1</em>.", service
) + "</qt>");
478 KMessageBox::error(this, "<qt>" + i18n("Unable to stop service <em>%1</em>.<br /><br /><i>Error: %2</i>",
479 service
, reply
.error().message()) + "</qt>" );
483 void KDEDConfig::slotItemChecked(QTreeWidgetItem
*, int column
)
485 // We only listen to changes the user did.
486 if (column
==StartupUse
) {