1 /*
2     SPDX-FileCopyrightText: 2020 David Redondo <kde@david-redondo.de>
3 
4     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
5 */
6 
7 #include "keysdata.h"
8 
9 #include <KGlobalAccel>
10 #include <KGlobalShortcutInfo>
11 #include <KPluginFactory>
12 #include <KStandardShortcut>
13 #include <kglobalaccel_component_interface.h>
14 #include <kglobalaccel_interface.h>
15 
KeysData(QObject * parent,const QVariantList & args)16 KeysData::KeysData(QObject *parent, const QVariantList &args)
17     : KCModuleData(parent, args)
18 {
19     for (int i = KStandardShortcut::AccelNone + 1; i < KStandardShortcut::StandardShortcutCount; ++i) {
20         const auto id = static_cast<KStandardShortcut::StandardShortcut>(i);
21         const QList<QKeySequence> activeShortcuts = KStandardShortcut::shortcut(id);
22         const QList<QKeySequence> defaultShortcuts = KStandardShortcut::hardcodedDefaultShortcut(id);
23         if (activeShortcuts != defaultShortcuts) {
24             m_isDefault = false;
25             return;
26         }
27     }
28 
29     KGlobalAccelInterface globalAccelInterface(QStringLiteral("org.kde.kglobalaccel"), QStringLiteral("/kglobalaccel"), QDBusConnection::sessionBus());
30     if (!globalAccelInterface.isValid()) {
31         return;
32     }
33 
34     // Default behavior of KCModuleData is to Q_EMIT the 'aboutToLoad' after construction which
35     // triggers the 'loaded' signal. Because we query the data in an async way we Q_EMIT 'loaded'
36     // manually when were are done.
37     disconnect(this, &KCModuleData::aboutToLoad, this, &KCModuleData::loaded);
38 
39     auto componentsWatcher = new QDBusPendingCallWatcher(globalAccelInterface.allComponents());
40     connect(componentsWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) {
41         QDBusPendingReply<QList<QDBusObjectPath>> componentsReply = *watcher;
42         if (componentsReply.isError() || componentsReply.value().isEmpty()) {
43             Q_EMIT loaded();
44             return;
45         }
46         const auto components = componentsReply.value();
47         for (const auto &componentPath : components) {
48             KGlobalAccelComponentInterface component(QStringLiteral("org.kde.kglobalaccel"), componentPath.path(), QDBusConnection::sessionBus());
49             ++m_pendingComponentCalls;
50             auto shortcutsWatcher = new QDBusPendingCallWatcher(component.allShortcutInfos());
51             connect(shortcutsWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) {
52                 QDBusPendingReply<QList<KGlobalShortcutInfo>> shortcutsReply = *watcher;
53                 if (shortcutsReply.isValid()) {
54                     const auto allShortcuts = shortcutsReply.value();
55                     bool isNotDefault = std::any_of(allShortcuts.cbegin(), allShortcuts.cend(), [](const KGlobalShortcutInfo &info) {
56                         return info.defaultKeys() != info.keys();
57                     });
58                     m_isDefault &= isNotDefault;
59                 }
60                 if (--m_pendingComponentCalls == 0) {
61                     Q_EMIT loaded();
62                 }
63             });
64         }
65     });
66 }
67 
isDefaults() const68 bool KeysData::isDefaults() const
69 {
70     return m_isDefault;
71 }
72