File indexing completed on 2024-12-01 03:44:34
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2008 Alexander Dymo <adymo@kdevelop.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "kshortcutschemeshelper_p.h" 0009 0010 #include <QAction> 0011 #include <QCoreApplication> 0012 #include <QDomDocument> 0013 #include <QFile> 0014 #include <QStandardPaths> 0015 #include <QTextStream> 0016 0017 #include <KConfigGroup> 0018 #include <KSharedConfig> 0019 #include <QDir> 0020 0021 #include "debug.h" 0022 #include "kactioncollection.h" 0023 #include "kxmlguiclient.h" 0024 0025 bool KShortcutSchemesHelper::saveShortcutScheme(const QList<KActionCollection *> &collections, const QString &schemeName) 0026 { 0027 // Every action collection is associated with a KXMLGUIClient 0028 // (at least if it was added by KXMLGUIFactory::configureShortcuts() 0029 // or KXMLGUIFactory::showConfigureShortcutsDialog()) 0030 0031 // Some GUI clients have the same name (e.g. the child client for a mainwindow 0032 // holding the actions for hiding/showing toolbars), so we need to save them 0033 // together, otherwise they will overwrite each other's files on disk. 0034 0035 // For cases like kdevelop (many guiclients not reused in other apps) it's simpler 0036 // to even save all shortcuts to a single shortcuts file -> set the boolean below to true 0037 // to create an all-in-one scheme. 0038 // Maybe we need a checkbox for this? Or an env var for contributors to set, rather? End users don't care. 0039 const bool saveToApplicationFile = false; 0040 0041 QMultiMap<QString, KActionCollection *> collectionsByClientName; 0042 for (KActionCollection *coll : collections) { 0043 const KXMLGUIClient *client = coll->parentGUIClient(); 0044 if (client) { 0045 const QString key = saveToApplicationFile ? QCoreApplication::applicationName() : client->componentName(); 0046 collectionsByClientName.insert(key, coll); 0047 } 0048 } 0049 const auto componentNames = collectionsByClientName.uniqueKeys(); 0050 for (const QString &componentName : componentNames) { 0051 qCDebug(DEBUG_KXMLGUI) << "Considering component" << componentName; 0052 QDomDocument doc; 0053 QDomElement docElem = doc.createElement(QStringLiteral("gui")); 0054 docElem.setAttribute(QStringLiteral("version"), QStringLiteral("1")); 0055 docElem.setAttribute(QStringLiteral("name"), componentName); 0056 doc.appendChild(docElem); 0057 QDomElement elem = doc.createElement(QStringLiteral("ActionProperties")); 0058 docElem.appendChild(elem); 0059 0060 const auto componentCollections = collectionsByClientName.values(componentName); 0061 for (KActionCollection *collection : componentCollections) { 0062 qCDebug(DEBUG_KXMLGUI) << "Saving shortcut scheme for action collection with" << collection->actions().count() << "actions"; 0063 0064 const auto collectionActions = collection->actions(); 0065 for (QAction *action : collectionActions) { 0066 if (!action) { 0067 continue; 0068 } 0069 0070 const QString actionName = action->objectName(); 0071 const QString shortcut = QKeySequence::listToString(action->shortcuts()); 0072 // qCDebug(DEBUG_KXMLGUI) << "action" << actionName << "has shortcut" << shortcut; 0073 if (!shortcut.isEmpty()) { 0074 QDomElement act_elem = doc.createElement(QStringLiteral("Action")); 0075 act_elem.setAttribute(QStringLiteral("name"), actionName); 0076 act_elem.setAttribute(QStringLiteral("shortcut"), shortcut); 0077 elem.appendChild(act_elem); 0078 } 0079 } 0080 } 0081 0082 const QString schemeFileName = writableShortcutSchemeFileName(componentName, schemeName); 0083 if (elem.childNodes().isEmpty()) { 0084 QFile::remove(schemeFileName); 0085 } else { 0086 qCDebug(DEBUG_KXMLGUI) << "saving to" << schemeFileName; 0087 QDir().mkpath(QFileInfo(schemeFileName).absolutePath()); 0088 QFile schemeFile(schemeFileName); 0089 if (!schemeFile.open(QFile::WriteOnly | QFile::Truncate)) { 0090 qCDebug(DEBUG_KXMLGUI) << "COULD NOT WRITE" << schemeFileName; 0091 return false; 0092 } 0093 0094 QTextStream out(&schemeFile); 0095 out << doc.toString(2); 0096 } 0097 } 0098 return true; 0099 } 0100 0101 QString KShortcutSchemesHelper::currentShortcutSchemeName() 0102 { 0103 return KSharedConfig::openConfig()->group(QStringLiteral("Shortcut Schemes")).readEntry("Current Scheme", "Default"); 0104 } 0105 0106 QString KShortcutSchemesHelper::writableShortcutSchemeFileName(const QString &componentName, const QString &schemeName) 0107 { 0108 return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/%1/shortcuts/%2").arg(componentName, schemeName); 0109 } 0110 0111 QString KShortcutSchemesHelper::writableApplicationShortcutSchemeFileName(const QString &schemeName) 0112 { 0113 return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) 0114 + QLatin1String("/%1/shortcuts/%2").arg(QCoreApplication::applicationName(), schemeName); 0115 } 0116 0117 QString KShortcutSchemesHelper::shortcutSchemeFileName(const QString &componentName, const QString &schemeName) 0118 { 0119 return QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("%1/shortcuts/%2").arg(componentName, schemeName)); 0120 } 0121 0122 QString KShortcutSchemesHelper::applicationShortcutSchemeFileName(const QString &schemeName) 0123 { 0124 return QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("%1/shortcuts/%2").arg(QCoreApplication::applicationName(), schemeName)); 0125 }