1
/***************************************************************************
2
* Copyright (C) 2008-2010 by Dario Freddi <drf@kde.org> *
4
* This program is free software; you can redistribute it and/or modify *
5
* it under the terms of the GNU General Public License as published by *
6
* the Free Software Foundation; either version 2 of the License, or *
7
* (at your option) any later version. *
9
* This program is distributed in the hope that it will be useful, *
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12
* GNU General Public License for more details. *
14
* You should have received a copy of the GNU General Public License *
15
* along with this program; if not, write to the *
16
* Free Software Foundation, Inc., *
17
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
18
***************************************************************************/
22
#include "actionconfigwidget.h"
24
#include <daemon/powerdevilactionconfig.h>
25
#include <daemon/powerdevilprofilegenerator.h>
27
#include <config-workspace.h>
29
#include <QtGui/QCheckBox>
30
#include <QtGui/QFormLayout>
31
#include <QtGui/QLabel>
33
#include <QtDBus/QDBusMessage>
34
#include <QtDBus/QDBusReply>
35
#include <QtDBus/QDBusConnection>
36
#include <QtDBus/QDBusMetaType>
38
#include <KConfigGroup>
42
#include <KFileDialog>
43
#include <KMessageBox>
44
#include <KIconButton>
47
#include <KPluginFactory>
48
#include <KServiceTypeTrader>
49
#include <KStandardDirs>
52
K_PLUGIN_FACTORY(PowerDevilProfilesKCMFactory,
53
registerPlugin<EditPage>();
55
K_EXPORT_PLUGIN(PowerDevilProfilesKCMFactory("powerdevilprofilesconfig","powerdevil"))
57
typedef QMap< QString, QString > StringStringMap;
58
Q_DECLARE_METATYPE(StringStringMap)
60
EditPage::EditPage(QWidget *parent, const QVariantList &args)
61
: KCModule(PowerDevilProfilesKCMFactory::componentData(), parent, args)
62
, m_profileEdited(false)
64
qDBusRegisterMetaType< StringStringMap >();
66
setButtons(Apply | Help | Default);
69
new KAboutData("powerdevilprofilesconfig", "powerdevilprofilesconfig", ki18n("Power Profiles Configuration"),
70
"", ki18n("A profile configurator for KDE Power Management System"),
71
KAboutData::License_GPL, ki18n("(c), 2010 Dario Freddi"),
72
ki18n("From this module, you can manage KDE Power Management System's power profiles, by tweaking "
73
"existing ones or creating new ones."));
75
about->addAuthor(ki18n("Dario Freddi"), ki18n("Maintainer") , "drf@kde.org",
76
"http://drfav.wordpress.com");
82
m_profilesConfig = KSharedConfig::openConfig("powerdevil2profilesrc", KConfig::SimpleConfig);
84
if (m_profilesConfig->groupList().isEmpty()) {
86
PowerDevil::ProfileGenerator::generateProfiles();
87
m_profilesConfig->reparseConfiguration();
90
m_toolBar = new KToolBar(this);
91
listLayout->addWidget(m_toolBar);
93
m_toolBar->addAction(actionNewProfile);
94
m_toolBar->addAction(actionEditProfile);
95
m_toolBar->addAction(actionDeleteProfile);
96
m_toolBar->addSeparator();
97
m_toolBar->addAction(actionImportProfiles);
98
m_toolBar->addAction(actionExportProfiles);
99
m_toolBar->addAction(actionRestoreDefaultProfiles);
100
m_toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
102
actionNewProfile->setIcon(KIcon("document-new"));
103
actionEditProfile->setIcon(KIcon("document-edit"));
104
actionDeleteProfile->setIcon(KIcon("edit-delete-page"));
105
actionImportProfiles->setIcon(KIcon("document-import"));
106
actionExportProfiles->setIcon(KIcon("document-export"));
107
actionRestoreDefaultProfiles->setIcon(KIcon("document-revert"));
109
connect(profilesList, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
110
SLOT(switchProfile(QListWidgetItem*, QListWidgetItem*)));
111
connect(this, SIGNAL(changed(bool)),
112
this, SLOT(onChanged(bool)));
114
connect(actionDeleteProfile, SIGNAL(triggered()), SLOT(deleteCurrentProfile()));
115
connect(actionEditProfile, SIGNAL(triggered(bool)), SLOT(editProfile()));
116
connect(actionNewProfile, SIGNAL(triggered()), SLOT(createProfile()));
117
connect(actionImportProfiles, SIGNAL(triggered()), SLOT(importProfiles()));
118
connect(actionExportProfiles, SIGNAL(triggered()), SLOT(exportProfiles()));
119
connect(actionRestoreDefaultProfiles, SIGNAL(triggered(bool)), SLOT(restoreDefaultProfiles()));
121
reloadAvailableProfiles();
122
ActionConfigWidget *actionConfigWidget = new ActionConfigWidget(0);
123
QMap< int, QList<QPair<QString, QWidget*> > > widgets;
125
// Load all the services
126
KService::List offers = KServiceTypeTrader::self()->query("PowerDevil/Action", "(Type == 'Service')");
128
foreach (const KService::Ptr &offer, offers) {
129
//try to load the specified library
130
KPluginFactory *factory = KPluginLoader(offer->property("X-KDE-PowerDevil-Action-UIComponentLibrary",
131
QVariant::String).toString()).factory();
134
kError() << "KPluginFactory could not load the plugin:" << offer->property("X-KDE-PowerDevil-Action-UIComponentLibrary",
135
QVariant::String).toString();
139
PowerDevil::ActionConfig *actionConfig = factory->create<PowerDevil::ActionConfig>();
141
kError() << "KPluginFactory could not load the plugin:" << offer->property("X-KDE-PowerDevil-Action-UIComponentLibrary",
142
QVariant::String).toString();
146
connect(actionConfig, SIGNAL(changed()), this, SLOT(changed()));
148
QCheckBox *checkbox = new QCheckBox(offer->name());
149
if (!offer->icon().isEmpty()) {
150
checkbox->setIcon(KIcon(offer->icon()));
152
connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(changed()));
153
m_actionsHash.insert(offer->property("X-KDE-PowerDevil-Action-ID", QVariant::String).toString(), checkbox);
154
m_actionsConfigHash.insert(offer->property("X-KDE-PowerDevil-Action-ID", QVariant::String).toString(), actionConfig);
156
QList<QPair<QString, QWidget*> > offerWidgets = actionConfig->buildUi();
157
offerWidgets.prepend(qMakePair<QString,QWidget*>(QString(), checkbox));
158
widgets.insertMulti(100 - offer->property("X-KDE-PowerDevil-Action-ConfigPriority", QVariant::Int).toInt(),
162
for (QMap< int, QList<QPair<QString, QWidget*> > >::const_iterator i = widgets.constBegin(); i != widgets.constEnd(); ++i) {
163
actionConfigWidget->addWidgets(i.value());
166
// Add a proxy widget to prevent vertical fuck ups
167
QWidget *tw = new QWidget;
168
QVBoxLayout *lay = new QVBoxLayout;
169
lay->addWidget(actionConfigWidget);
172
scrollArea->setWidget(tw);
175
EditPage::~EditPage()
179
void EditPage::onChanged(bool changed)
181
m_profileEdited = changed;
184
void EditPage::load()
189
void EditPage::save()
191
if (!profilesList->currentItem()) {
195
QString profile = profilesList->currentItem()->data(Qt::UserRole).toString();
196
saveProfile(profile);
198
notifyDaemon(profile);
201
void EditPage::notifyDaemon(const QString &editedProfile)
204
if (!editedProfile.isNull()) {
205
call = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", "/org/kde/Solid/PowerManagement",
206
"org.kde.Solid.PowerManagement", "currentProfile");
207
QDBusPendingReply< QString > reply = QDBusConnection::sessionBus().asyncCall(call);
208
reply.waitForFinished();
210
if (reply.isValid()) {
211
if (reply.value() == editedProfile) {
212
// Ask to reload the profile
213
kDebug() << "Active profile edited, reloading profile";
214
call = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", "/org/kde/Solid/PowerManagement",
215
"org.kde.Solid.PowerManagement", "reloadCurrentProfile");
217
// Ask to reparse config
218
kDebug() << "Inactive profile edited, reparsing configuration";
219
call = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", "/org/kde/Solid/PowerManagement",
220
"org.kde.Solid.PowerManagement", "reparseConfiguration");
223
kWarning() << "Invalid reply from daemon when asking for current profile!";
224
// To be sure, reload profile
225
call = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", "/org/kde/Solid/PowerManagement",
226
"org.kde.Solid.PowerManagement", "reloadCurrentProfile");
230
call = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", "/org/kde/Solid/PowerManagement",
231
"org.kde.Solid.PowerManagement", "refreshStatus");
235
QDBusConnection::sessionBus().asyncCall(call);
238
void EditPage::loadProfile()
240
kDebug() << "Loading a profile";
242
if (!profilesList->currentItem()) {
246
// Check if the profile is not reserved
247
QString profileId = profilesList->currentItem()->data(Qt::UserRole).toString();
248
if (profileId == "Performance" || profileId == "Powersave" || profileId == "Aggressive powersave") {
249
actionDeleteProfile->setEnabled(false);
250
actionEditProfile->setEnabled(false);
252
actionDeleteProfile->setEnabled(true);
253
actionEditProfile->setEnabled(true);
256
kDebug() << profileId;
258
KConfigGroup group(m_profilesConfig, profileId);
260
if (!group.isValid()) {
263
kDebug() << "Ok, KConfigGroup ready";
265
// Iterate over the possible actions
266
for (QHash< QString, QCheckBox* >::const_iterator i = m_actionsHash.constBegin(); i != m_actionsHash.constEnd(); ++i) {
267
i.value()->setChecked(group.groupList().contains(i.key()));
269
KConfigGroup actionGroup = group.group(i.key());
270
m_actionsConfigHash[i.key()]->setConfigGroup(actionGroup);
271
m_actionsConfigHash[i.key()]->load();
277
void EditPage::saveProfile(const QString &p)
279
if (!profilesList->currentItem() && p.isEmpty()) {
280
kDebug() << "Could not perform a save operation";
287
profile = profilesList->currentItem()->data(Qt::UserRole).toString();
292
KConfigGroup group(m_profilesConfig, profile);
294
if (!group.isValid()) {
295
kDebug() << "Could not perform a save operation, group is not valid!";
299
// Iterate over the possible actions
300
for (QHash< QString, QCheckBox* >::const_iterator i = m_actionsHash.constBegin(); i != m_actionsHash.constEnd(); ++i) {
301
if (i.value()->isChecked()) {
302
// Perform the actual save
303
m_actionsConfigHash[i.key()]->save();
306
group.deleteGroup(i.key());
312
// After saving, reload the config to make sure we'll pick up changes.
313
m_profilesConfig.data()->reparseConfiguration();
318
void EditPage::reloadAvailableProfiles()
320
profilesList->clear();
322
// Request profiles to the daemon
323
QDBusMessage call = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", "/org/kde/Solid/PowerManagement",
324
"org.kde.Solid.PowerManagement", "availableProfiles");
325
QDBusPendingReply< StringStringMap > reply = QDBusConnection::sessionBus().asyncCall(call);
326
reply.waitForFinished();
328
if (!reply.isValid()) {
329
kDebug() << "Error contacting the daemon!";
333
StringStringMap profiles = reply.value();
335
if (profiles.isEmpty()) {
336
kDebug() << "No available profiles!";
340
m_profilesConfig->reparseConfiguration();
342
for (StringStringMap::const_iterator i = profiles.constBegin(); i != profiles.constEnd(); ++i) {
343
KConfigGroup group(m_profilesConfig, i.key());
344
QListWidgetItem *itm = new QListWidgetItem(KIcon(group.readEntry("icon")), i.value());
345
itm->setData(Qt::UserRole, i.key());
346
profilesList->addItem(itm);
349
profilesList->setCurrentRow(0);
352
void EditPage::deleteCurrentProfile()
354
if (!profilesList->currentItem()) {
358
// We're deleting it, we don't care anymore
361
m_profilesConfig->deleteGroup(profilesList->currentItem()->data(Qt::UserRole).toString());
362
m_profilesConfig->sync();
365
QDBusMessage call = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", "/org/kde/Solid/PowerManagement",
366
"org.kde.Solid.PowerManagement", "reparseConfiguration");
367
QDBusConnection::sessionBus().asyncCall(call);
369
reloadAvailableProfiles();
372
void EditPage::createProfile(const QString &name, const QString &icon)
374
if (name.isEmpty()) {
377
KConfigGroup group(m_profilesConfig, name);
378
group.writeEntry("icon", icon);
379
group.writeEntry("name", name);
384
QDBusMessage call = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", "/org/kde/Solid/PowerManagement",
385
"org.kde.Solid.PowerManagement", "reparseConfiguration");
386
QDBusConnection::sessionBus().asyncCall(call);
388
reloadAvailableProfiles();
391
void EditPage::createProfile()
393
KDialog *dialog = new KDialog(this);
394
QWidget *wg = new QWidget();
395
KLineEdit *ed = new KLineEdit(wg);
396
QLabel *lb = new QLabel(wg);
397
QFormLayout *lay = new QFormLayout();
398
KIconButton *ibt = new KIconButton(wg);
400
ibt->setIconSize(KIconLoader::SizeSmall);
402
lb->setText(i18n("Please enter a name for the new profile:"));
404
lb->setToolTip(i18n("The name for the new profile"));
405
lb->setWhatsThis(i18n("Enter here the name for the profile you are creating"));
407
ed->setToolTip(i18n("The name for the new profile"));
408
ed->setWhatsThis(i18n("Enter here the name for the profile you are creating"));
411
lay->addRow(ibt, ed);
415
dialog->setMainWidget(wg);
418
if (dialog->exec() == KDialog::Accepted) {
419
createProfile(ed->text(), ibt->icon());
424
void EditPage::editProfile(const QString &id, const QString &name, const QString &icon)
426
if (id.isEmpty() || !m_profilesConfig->hasGroup(id)) {
430
KConfigGroup group(m_profilesConfig, id);
432
group.writeEntry("icon", icon);
433
group.writeEntry("name", name);
440
reloadAvailableProfiles();
443
void EditPage::editProfile()
445
if (!profilesList->currentItem()) {
449
KDialog *dialog = new KDialog(this);
450
QWidget *wg = new QWidget();
451
KLineEdit *ed = new KLineEdit(wg);
452
QLabel *lb = new QLabel(wg);
453
QFormLayout *lay = new QFormLayout();
454
KIconButton *ibt = new KIconButton(wg);
456
ibt->setIconSize(KIconLoader::SizeSmall);
458
lb->setText(i18n("Please enter a name for this profile:"));
460
lb->setToolTip(i18n("The name for the new profile"));
461
lb->setWhatsThis(i18n("Enter here the name for the profile you are creating"));
463
ed->setToolTip(i18n("The name for the new profile"));
464
ed->setWhatsThis(i18n("Enter here the name for the profile you are creating"));
466
KConfigGroup group(m_profilesConfig, profilesList->currentItem()->data(Qt::UserRole).toString());
468
ibt->setIcon(group.readEntry("icon"));
469
ed->setText(group.readEntry("name"));
472
lay->addRow(ibt, ed);
476
dialog->setMainWidget(wg);
479
if (dialog->exec() == KDialog::Accepted) {
480
editProfile(profilesList->currentItem()->data(Qt::UserRole).toString(), ed->text(), ibt->icon());
486
void EditPage::importProfiles()
488
QString fileName = KFileDialog::getOpenFileName(KUrl(), "*.kpmsprofiles|KDE Power Management System Profiles "
489
"(*.kpmsprofiles)", this, i18n("Import Power Management Profiles"));
491
if (fileName.isEmpty()) {
495
KConfig toImport(fileName, KConfig::SimpleConfig);
497
foreach(const QString &ent, toImport.groupList()) {
498
KConfigGroup copyFrom(&toImport, ent);
499
KConfigGroup copyTo(m_profilesConfig, ent);
501
copyFrom.copyTo(©To);
504
m_profilesConfig->sync();
507
QDBusMessage call = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement", "/org/kde/Solid/PowerManagement",
508
"org.kde.Solid.PowerManagement", "reparseConfiguration");
509
QDBusConnection::sessionBus().asyncCall(call);
511
reloadAvailableProfiles();
514
void EditPage::exportProfiles()
516
QString fileName = KFileDialog::getSaveFileName(KUrl(), "*.kpmsprofiles|KDE Power Management System Profiles "
517
"(*.kpmsprofiles)", this, i18n("Export Power Management Profiles"));
519
if (fileName.isEmpty()) {
523
kDebug() << "Filename is" << fileName;
525
KConfig *toExport = m_profilesConfig->copyTo(fileName);
532
void EditPage::restoreDefaultProfiles()
535
int ret = KMessageBox::warningContinueCancel(this, i18n("The KDE Power Management System will now generate a set of default "
536
"profiles based on your computer's capabilities. This will also erase "
537
"all existing profiles. "
538
"Are you sure you want to continue?"), i18n("Restore Default Profiles"));
539
if (ret == KMessageBox::Continue) {
540
kDebug() << "Restoring defaults.";
541
PowerDevil::ProfileGenerator::generateProfiles();
546
reloadAvailableProfiles();
550
void EditPage::switchProfile(QListWidgetItem *current, QListWidgetItem *previous)
554
if (!m_profileEdited) {
555
kDebug() << "Profile has not been edited, switch";
559
// Pass by, the profile has probably been deleted
560
kDebug() << "No previous profile";
563
} else if (!m_profilesConfig.data()->groupList().contains(previous->text())) {
564
// Pass by, the profile has probably been deleted
565
kDebug() << "No previous profile saved";
570
int result = KMessageBox::warningYesNoCancel(this, i18n("The current profile has not been saved.\n"
571
"Do you want to save it?"), i18n("Save Profile"));
573
if (result == KMessageBox::Yes) {
574
saveProfile(previous->data(Qt::UserRole).toString());
576
} else if (result == KMessageBox::No) {
578
} else if (result == KMessageBox::Cancel) {
579
disconnect(profilesList, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
580
this, SLOT(switchProfile(QListWidgetItem*, QListWidgetItem*)));
581
profilesList->setCurrentItem(previous);
582
connect(profilesList, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
583
SLOT(switchProfile(QListWidgetItem*, QListWidgetItem*)));
588
void EditPage::openUrl(const QString &url)
590
new KRun(KUrl(url), this);
593
void EditPage::defaults()
595
restoreDefaultProfiles();
598
#include "EditPage.moc"