File indexing completed on 2024-05-12 17:07:19

0001 /*
0002     SPDX-FileCopyrightText: 2020 David Redondo <kde@david-redondo.de>
0003 
0004     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #include "standardshortcutsmodel.h"
0008 
0009 #include <QCollator>
0010 #include <QMetaEnum>
0011 
0012 #include <KConfigBase>
0013 #include <KConfigGroup>
0014 #include <KLocalizedString>
0015 #include <KStandardShortcut>
0016 
0017 #include "basemodel.h"
0018 #include "kcmkeys_debug.h"
0019 
0020 StandardShortcutsModel::StandardShortcutsModel(QObject *parent)
0021     : BaseModel(parent)
0022 {
0023 }
0024 
0025 void StandardShortcutsModel::load()
0026 {
0027     beginResetModel();
0028     m_components.clear();
0029     m_components.resize(6);
0030     const ComponentType sectionName = ComponentType::CommonAction;
0031     auto index = [](KStandardShortcut::Category category) {
0032         return static_cast<int>(category);
0033     };
0034     m_components[index(KStandardShortcut::Category::File)] = Component{"File", i18n("File"), sectionName, "document-multiple", {}, false, false};
0035     m_components[index(KStandardShortcut::Category::Edit)] = Component{"Edit", i18n("Edit"), sectionName, "edittext", {}, false, false};
0036     m_components[index(KStandardShortcut::Category::Navigation)] =
0037         Component{"Navigation", i18n("Navigation"), sectionName, "preferences-desktop-navigation", {}, false, false};
0038     m_components[index(KStandardShortcut::Category::View)] = Component{"View", i18n("View"), sectionName, "view-preview", {}, false, false};
0039     m_components[index(KStandardShortcut::Category::Settings)] = Component{"Settings", i18n("Settings"), sectionName, "settings-configure", {}, false, false};
0040     m_components[index(KStandardShortcut::Category::Help)] = Component{"Help", i18n("Help"), sectionName, "system-help", {}, false, false};
0041     for (int i = KStandardShortcut::AccelNone + 1; i < KStandardShortcut::StandardShortcutCount; ++i) {
0042         const auto id = static_cast<KStandardShortcut::StandardShortcut>(i);
0043         const QList<QKeySequence> activeShortcuts = KStandardShortcut::shortcut(id);
0044         const QList<QKeySequence> defaultShortcuts = KStandardShortcut::hardcodedDefaultShortcut(id);
0045         auto listToSet = [](const QList<QKeySequence> &list) {
0046             return QSet<QKeySequence>{list.cbegin(), list.cend()};
0047         };
0048         const Action a{KStandardShortcut::name(id),
0049                        KStandardShortcut::label(id),
0050                        listToSet(activeShortcuts),
0051                        listToSet(defaultShortcuts),
0052                        listToSet(activeShortcuts)};
0053         m_components[static_cast<int>(category(id))].actions.append(a);
0054     }
0055     QCollator collator;
0056     collator.setCaseSensitivity(Qt::CaseInsensitive);
0057     collator.setNumericMode(true);
0058     std::for_each(m_components.begin(), m_components.end(), [&](Component &c) {
0059         std::sort(c.actions.begin(), c.actions.end(), [&](const Action &a1, const Action &a2) {
0060             return collator.compare(a1.displayName, a2.displayName) < 0;
0061         });
0062     });
0063     std::sort(m_components.begin(), m_components.end(), [&](Component &c1, Component &c2) {
0064         return collator.compare(c1.displayName, c2.displayName) < 0;
0065     });
0066     endResetModel();
0067 }
0068 
0069 void StandardShortcutsModel::exportToConfig(const KConfigBase &config)
0070 {
0071     KConfigGroup group(&config, "StandardShortcuts");
0072     for (const auto &component : qAsConst(m_components)) {
0073         if (component.checked) {
0074             for (const auto &action : component.actions) {
0075                 const QList<QKeySequence> shortcutsList(action.activeShortcuts.cbegin(), action.activeShortcuts.cend());
0076                 group.writeEntry(action.id, QKeySequence::listToString(shortcutsList));
0077             }
0078         }
0079     }
0080 }
0081 
0082 void StandardShortcutsModel::importConfig(const KConfigBase &config)
0083 {
0084     if (!config.hasGroup("StandardShortcuts")) {
0085         qCDebug(KCMKEYS) << "Config has no StandardShortcuts group";
0086         return;
0087     }
0088     const KConfigGroup group = config.group("StandardShortcuts");
0089     const QStringList keys = group.keyList();
0090     for (const auto &key : keys) {
0091         KStandardShortcut::StandardShortcut id = KStandardShortcut::findByName(key);
0092         if (id == KStandardShortcut::AccelNone) {
0093             qCWarning(KCMKEYS) << "Unknown standard shortcut" << key;
0094             continue;
0095         }
0096         QString name;
0097         switch (category(id)) {
0098         case KStandardShortcut::Category::File:
0099             name = "File";
0100             break;
0101         case KStandardShortcut::Category::Edit:
0102             name = "Edit";
0103             break;
0104         case KStandardShortcut::Category::Navigation:
0105             name = "Navigation";
0106             break;
0107         case KStandardShortcut::Category::View:
0108             name = "View";
0109             break;
0110         case KStandardShortcut::Category::Settings:
0111             name = "Settings";
0112             break;
0113         case KStandardShortcut::Category::Help:
0114             name = "Help";
0115             break;
0116         }
0117         auto cat = std::find_if(m_components.begin(), m_components.end(), [&name](const Component &c) {
0118             return c.id == name;
0119         });
0120         if (cat == m_components.end()) {
0121             qCWarning(KCMKEYS) << "No category for standard shortcut" << key;
0122             continue;
0123         }
0124         auto action = std::find_if(cat->actions.begin(), cat->actions.end(), [&](const Action &a) {
0125             return a.id == key;
0126         });
0127         if (action == cat->actions.end()) {
0128             qCWarning(KCMKEYS) << "Model doesn't include action" << key;
0129             continue;
0130         }
0131         const auto shortcuts = QKeySequence::listFromString(group.readEntry(key));
0132         const QSet<QKeySequence> shortcutsSet(shortcuts.cbegin(), shortcuts.cend());
0133         if (shortcutsSet != action->activeShortcuts) {
0134             action->activeShortcuts = shortcutsSet;
0135             const QModelIndex i = index(action - cat->actions.begin(), 0, index(cat - m_components.begin(), 0));
0136             Q_EMIT dataChanged(i, i, {CustomShortcutsRole, ActiveShortcutsRole});
0137         }
0138     }
0139 }
0140 
0141 void StandardShortcutsModel::save()
0142 {
0143     for (auto &component : m_components) {
0144         for (auto &action : component.actions) {
0145             if (action.initialShortcuts != action.activeShortcuts) {
0146                 QList<QKeySequence> keys(action.activeShortcuts.cbegin(), action.activeShortcuts.cend());
0147                 KStandardShortcut::saveShortcut(KStandardShortcut::findByName(action.id), keys);
0148                 action.initialShortcuts = action.activeShortcuts;
0149             }
0150         }
0151     }
0152 }