2 * Copyright 2007 Andreas Pakulat <apaku@gmx.de>
3 * Copyright 2008 Michael Jansen <kde@michael-jansen.biz>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (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
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include "globalshortcuts.h"
20 #include "kglobalshortcutseditor.h"
21 #include "select_scheme_dialog.h"
22 #include "kdedglobalaccel_interface.h"
23 #include "kdedglobalaccel_component_interface.h"
26 #include <QCoreApplication>
27 #include <QDBusConnection>
29 #include <QDBusInterface>
31 #include <QDBusMetaType>
36 #include <KActionCollection>
38 #include <KConfigGroup>
39 #include <KFileDialog>
41 #include <KMessageBox>
42 #include <KPluginFactory>
43 #include <KPushButton>
45 K_PLUGIN_FACTORY(GlobalShortcutsModuleFactory
, registerPlugin
<GlobalShortcutsModule
>();)
46 K_EXPORT_PLUGIN(GlobalShortcutsModuleFactory("kcmkeys"))
48 GlobalShortcutsModule::GlobalShortcutsModule(QWidget
*parent
, const QVariantList
&args
)
49 : KCModule(GlobalShortcutsModuleFactory::componentData(), parent
, args
),
52 KCModule::setButtons(KCModule::Buttons(KCModule::Default
| KCModule::Apply
));
54 // Add import scheme button
55 KPushButton
*importButton
= new KPushButton(this);
56 importButton
->setText(i18n("Import Scheme..."));
57 connect(importButton
, SIGNAL(clicked()), this, SLOT(importScheme()));
59 // Add export scheme button
60 KPushButton
*exportButton
= new KPushButton(this);
61 exportButton
->setText(i18n("Export Scheme..."));
62 connect(exportButton
, SIGNAL(clicked()), this, SLOT(exportScheme()));
64 // Layout for the buttons
65 QHBoxLayout
*hbox
= new QHBoxLayout
;
66 hbox
->addWidget(exportButton
);
67 hbox
->addWidget(importButton
);
69 // Create the kglobaleditor
70 editor
= new KGlobalShortcutsEditor(this, KShortcutsEditor::GlobalAction
);
71 connect(editor
, SIGNAL(changed(bool)), this, SIGNAL(changed(bool)));
73 // Layout the hole bunch
74 QVBoxLayout
*global
= new QVBoxLayout
;
75 global
->addLayout(hbox
);
76 global
->addWidget(editor
);
80 GlobalShortcutsModule::~GlobalShortcutsModule()
84 void GlobalShortcutsModule::load()
86 // Connect to kdedglobalaccel. If that fails there is no need to continue.
87 qRegisterMetaType
<QList
<int> >();
88 qDBusRegisterMetaType
<QList
<int> >();
89 qDBusRegisterMetaType
<QList
<KGlobalShortcutInfo
> >();
90 qDBusRegisterMetaType
<KGlobalShortcutInfo
>();
91 QDBusConnection bus
= QDBusConnection::sessionBus();
92 org::kde::KdedGlobalAccel
kdedglobalaccel(
94 "/modules/kdedglobalaccel",
97 if (!kdedglobalaccel
.isValid()) {
99 QDBusError error
= kdedglobalaccel
.lastError();
100 // The global shortcuts DBus service manages all global shortcuts and we
101 // can't do anything useful without it.
102 if (error
.isValid()) {
103 errorString
= i18n("Message: %1\nError: %2", error
.message(), error
.name());
108 i18n("Failed to contact the KDE global shortcuts daemon\n")
113 // Undo all changes not yet applied
116 QDBusReply
< QList
<QDBusObjectPath
> > componentsRc
= kdedglobalaccel
.allComponents();
117 if (!componentsRc
.isValid())
119 kDebug() << "allComponents() failed!";
122 QList
<QDBusObjectPath
> components
= componentsRc
;
124 Q_FOREACH(QDBusObjectPath componentPath
, components
) {
127 org::kde::kdedglobalaccel::Component
component(
129 componentPath
.path(),
131 if (!component
.isValid()) {
132 kDebug() << "Component " << componentPath
.path() << "not valid! Skipping!";
136 // Get the shortcut contexts.
137 QDBusReply
<QStringList
> shortcutContextsRc
= component
.getShortcutContexts();
138 if (!shortcutContextsRc
.isValid()) {
139 kDebug() << "Failed to get contexts for component "
140 << componentPath
.path() <<"! Skipping!";
143 QStringList shortcutContexts
= shortcutContextsRc
;
145 // We add shortcut all shortcut context to the editor. Thias way the
146 // user keep full control of it's shortcuts.
147 Q_FOREACH (QString shortcutContext
, shortcutContexts
) {
149 QDBusReply
< QList
<KGlobalShortcutInfo
> > shortcutsRc
=
150 component
.allShortcutInfos(shortcutContext
);
151 if (!shortcutsRc
.isValid())
153 kDebug() << "allShortcutInfos() failed for " << componentPath
.path() << shortcutContext
;
156 QList
<KGlobalShortcutInfo
> shortcuts
= shortcutsRc
;
157 // Shouldn't happen. But you never know
158 if (shortcuts
.isEmpty()) {
159 kDebug() << "Got shortcut context" << shortcutContext
<< "without shortcuts for"
160 << componentPath
.path();
165 const QString componentUnique
= shortcuts
[0].componentUniqueName();
166 QString componentContextId
= componentUnique
;
167 // kdedglobalaccel knows that '|' is our separator between
168 // component and context
169 if (shortcutContext
!= "default") {
170 componentContextId
+= QString("|") + shortcutContext
;
173 // Create a action collection for our current component:context
174 KActionCollection
* col
= new KActionCollection(
176 KComponentData(componentContextId
.toAscii()));
178 // Now add the shortcuts.
179 foreach (const KGlobalShortcutInfo
&shortcut
, shortcuts
) {
181 const QString
&objectName
= shortcut
.uniqueName();
182 KAction
*action
= col
->addAction(objectName
);
183 action
->setProperty("isConfigurationAction", QVariant(true)); // see KAction::~KAction
184 action
->setText(shortcut
.friendlyName());
186 // Always call this to enable global shortcuts for the action. The editor widget
188 // Also actually loads the shortcut using the KAction::Autoloading mechanism.
189 // Avoid setting the default shortcut; it would just be written to the global
190 // configuration so we would not get the real one below.
191 action
->setGlobalShortcut(KShortcut(), KAction::ActiveShortcut
);
193 // The default shortcut will never be loaded because it's pointless in a real
194 // application. There are no scarce resources [i.e. physical keys] to manage
195 // so applications can set them at will and there's no autoloading.
196 QList
<QKeySequence
> sc
= shortcut
.defaultKeys();
198 action
->setGlobalShortcut(KShortcut(sc
[0]), KAction::DefaultShortcut
);
200 } // Q_FOREACH(shortcut)
202 QString componentFriendlyName
= shortcuts
[0].componentFriendlyName();
204 if (shortcuts
[0].contextUniqueName() != "default")
206 componentFriendlyName
+=
207 QString('[') + shortcuts
[0].contextFriendlyName() + QString(']');
210 editor
->addCollection(col
, componentContextId
, componentFriendlyName
);
212 } // Q_FOREACH(context)
213 } // Q_FOREACH(component)
216 void GlobalShortcutsModule::defaults()
218 editor
->allDefault();
222 void GlobalShortcutsModule::save()
228 void GlobalShortcutsModule::importScheme()
230 // Check for unsaved modifications
231 if (editor
->isModified()) {
232 int choice
= KMessageBox::warningContinueCancel(
234 i18n("Your current changes will be lost if you load another scheme before saving this one"),
235 i18n("Load Shortcurt Scheme"),
236 KGuiItem(i18n("Load")));
237 if (choice
!= KMessageBox::Continue
) {
242 SelectSchemeDialog
dialog(this);
243 if (dialog
.exec() != KDialog::Accepted
) {
247 KUrl url
= dialog
.selectedScheme();
248 if (!url
.isLocalFile()) {
249 KMessageBox::sorry(this, i18n("This file (%1) does not exist. You can only select local files.",
253 kDebug() << url
.path();
254 KConfig
config(url
.path());
255 editor
->importConfiguration(&config
);
259 void GlobalShortcutsModule::exportScheme()
261 KUrl url
= KFileDialog::getSaveFileName(KUrl(), "*.kksrc", parentWidget());
262 if (!url
.isEmpty()) {
263 KConfig
config(url
.path());
264 config
.deleteGroup("Shortcuts");
265 config
.deleteGroup("Global Shortcuts");
266 editor
->exportConfiguration(&config
);
270 #include "globalshortcuts.moc"