diff --git a/globalaccel.cpp b/globalaccel.cpp index a1fc99d..57a97d7 100644 --- a/globalaccel.cpp +++ b/globalaccel.cpp @@ -1,61 +1,59 @@ /* * Copyright (C) 2019 David Redondo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "globalaccel.h" #include #include #include #include #include #include -void GlobalAccel::changeMenuEntryShortcut(const QString &storageId, const QKeySequence &shortcut) +void GlobalAccel::changeMenuEntryShortcut(const KService::Ptr service, const QKeySequence &shortcut) { - const KService::Ptr service = KService::serviceByStorageId(storageId); const QString desktopFile = QStringLiteral("%1.desktop").arg(service->desktopEntryName()); if (!KGlobalAccel::isComponentActive(desktopFile)) { const QString destination = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/kglobalaccel/") + desktopFile; QFile::copy(service->entryPath(), destination); } QAction action(i18n("Launch %1", service->name())); action.setProperty("componentName", desktopFile); action.setProperty("componentDisplayName", service->name()); action.setObjectName(QStringLiteral("_launch")); //Make sure that the action is marked active KGlobalAccel::self()->setShortcut(&action, {shortcut}); action.setProperty("isConfigurationAction", true); KGlobalAccel::self()->setShortcut(&action, {shortcut}, KGlobalAccel::NoAutoloading); } -QKeySequence GlobalAccel::getMenuEntryShortcut(const QString &storageId) +QKeySequence GlobalAccel::getMenuEntryShortcut(const KService::Ptr service) { - const KService::Ptr service = KService::serviceByStorageId(storageId); const QString desktopFile = QStringLiteral("%1.desktop").arg(service->desktopEntryName()); const QList shortcut = KGlobalAccel::self()->globalShortcut(desktopFile, QStringLiteral("_launch")); if (!shortcut.isEmpty()) { return shortcut[0]; } return QKeySequence(); } diff --git a/globalaccel.h b/globalaccel.h index 547185d..f4f41b0 100644 --- a/globalaccel.h +++ b/globalaccel.h @@ -1,31 +1,31 @@ /* * Copyright (C) 2019 David Redondo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef GLOBALACCEL_H #define GLOBALACCEL_H -#include +#include #include class GlobalAccel { public: - static QKeySequence getMenuEntryShortcut(const QString &storageId); - static void changeMenuEntryShortcut(const QString &storageId, const QKeySequence &shortcut); + static QKeySequence getMenuEntryShortcut(const KService::Ptr service); + static void changeMenuEntryShortcut(const KService::Ptr service, const QKeySequence &shortcut); }; #endif // GLOBALACCEL_H diff --git a/kconf_update/globalaccel.cpp b/kconf_update/globalaccel.cpp index 9b0bf08..db8f82a 100644 --- a/kconf_update/globalaccel.cpp +++ b/kconf_update/globalaccel.cpp @@ -1,79 +1,79 @@ /* * Copyright (C) 2019 David Redondo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include "../globalaccel.h" int main(int argc, char **argv) { QCoreApplication app(argc, argv); QDBusInterface khotkeys(QStringLiteral("org.kde.kded5"), QStringLiteral("/modules/khotkeys"), QStringLiteral("org.kde.khotkeys")); khotkeys.call(QStringLiteral("declareConfigOutDated")); KConfig khotkeysrc(QStringLiteral("khotkeysrc"), KConfig::SimpleConfig); const int dataCount = KConfigGroup(&khotkeysrc, "Data").readEntry("DataCount", 0); bool foundKmenuedit = false; int kmenueditIndex; KConfigGroup kmenueditGroup; for (int i = 1; i <= dataCount; ++i) { kmenueditGroup = KConfigGroup(&khotkeysrc, QStringLiteral("Data_%1").arg(i)); if (kmenueditGroup.readEntry("Name", QString()) == QLatin1String("KMenuEdit")) { foundKmenuedit = true; kmenueditIndex = i; break; } } if (!foundKmenuedit) { return 0; } const int numShortcuts = kmenueditGroup.readEntry("DataCount", 0); for (int i = 1; i <= numShortcuts; ++i) { const QString groupName = QStringLiteral("Data_%1_%2").arg(kmenueditIndex).arg(i); // only migrate the launch actions for now, not the default search action if (KConfigGroup(&khotkeysrc, groupName).readEntry("Type") != QLatin1String("MENUENTRY_SHORTCUT_ACTION_DATA")) { continue; } const QString storageId = KConfigGroup(&khotkeysrc, groupName + QStringLiteral("Actions0")).readEntry("CommandURL"); const QString id = KConfigGroup(&khotkeysrc, groupName + QStringLiteral("Triggers0")).readEntry("Uuid"); //ask globalaccel about the current shortcut rather than parsing it ourselves const QList shortcut = KGlobalAccel::self()->globalShortcut(QStringLiteral("khotkeys"), id); QAction action; action.setObjectName(id); action.setProperty("componentName", QStringLiteral("khotkeys")); KGlobalAccel::self()->setShortcut(&action, {}); KGlobalAccel::self()->removeAllShortcuts(&action); if (!shortcut.isEmpty() && !shortcut[0].isEmpty()) { - GlobalAccel::changeMenuEntryShortcut(storageId, shortcut[0]); + GlobalAccel::changeMenuEntryShortcut(KService::serviceByStorageId(storageId), shortcut[0]); } khotkeysrc.deleteGroup(groupName); khotkeysrc.deleteGroup(groupName + QStringLiteral("Actions")); khotkeysrc.deleteGroup(groupName + QStringLiteral("Actions0")); khotkeysrc.deleteGroup(groupName + QStringLiteral("Conditions")); khotkeysrc.deleteGroup(groupName + QStringLiteral("Triggers")); khotkeysrc.deleteGroup(groupName + QStringLiteral("Triggers0")); } khotkeysrc.sync(); khotkeys.call(QStringLiteral("reread_configuration")); } diff --git a/menuinfo.cpp b/menuinfo.cpp index 4d43c5f..b81fee4 100644 --- a/menuinfo.cpp +++ b/menuinfo.cpp @@ -1,465 +1,465 @@ /* * Copyright (C) 2003 Waldo Bastian * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "menuinfo.h" #include #include #include #include #include "globalaccel.h" #include "menufile.h" // // MenuFolderInfo // static QStringList *s_newShortcuts = nullptr; static QStringList *s_freeShortcuts = nullptr; static QStringList *s_deletedApps = nullptr; // Add separator MenuFolderInfo::~MenuFolderInfo() { qDeleteAll(subFolders); subFolders.clear(); } void MenuFolderInfo::add(MenuSeparatorInfo *info, bool initial) { if (initial) { initialLayout.append(info); } } // Add sub menu void MenuFolderInfo::add(MenuFolderInfo *info, bool initial) { subFolders.append(info); if (initial) { initialLayout.append(info); } } // Remove sub menu (without deleting it) void MenuFolderInfo::take(MenuFolderInfo *info) { subFolders.removeAll(info); } // Remove sub menu (without deleting it) bool MenuFolderInfo::takeRecursive(MenuFolderInfo *info) { if (subFolders.removeAll(info) > 0) { return true; } foreach (MenuFolderInfo *subFolderInfo, subFolders) { if (subFolderInfo->takeRecursive(info)) { return true; } } return false; } // Recursively update all fullIds void MenuFolderInfo::updateFullId(const QString &parentId) { fullId = parentId + id; foreach (MenuFolderInfo *subFolderInfo, subFolders) { subFolderInfo->updateFullId(fullId); } } // Add entry void MenuFolderInfo::add(MenuEntryInfo *entry, bool initial) { entries.append(entry); if (initial) { initialLayout.append(entry); } } // Remove entry void MenuFolderInfo::take(MenuEntryInfo *entry) { entries.removeAll(entry); } // Return a unique sub-menu caption inspired by @p caption QString MenuFolderInfo::uniqueMenuCaption(const QString &caption) { QRegExp r(QStringLiteral("(.*)(?=-\\d+)")); QString cap = (r.indexIn(caption) > -1) ? r.cap(1) : caption; QString result = caption; for (int n = 1; ++n;) { bool ok = true; foreach (MenuFolderInfo *subFolderInfo, subFolders) { if (subFolderInfo->caption == result) { ok = false; break; } } if (ok) { return result; } result = cap + QStringLiteral("-%1").arg(n); } return QString(); // Never reached } // Return a unique item caption inspired by @p caption QString MenuFolderInfo::uniqueItemCaption(const QString &caption, const QString &exclude) { QRegExp r(QStringLiteral("(.*)(?=-\\d+)")); QString cap = (r.indexIn(caption) > -1) ? r.cap(1) : caption; QString result = caption; for (int n = 1; ++n;) { bool ok = true; if (result == exclude) { ok = false; } foreach (MenuEntryInfo *entryInfo, entries) { if (entryInfo->caption == result) { ok = false; break; } } if (ok) { return result; } result = cap + QStringLiteral("-%1").arg(n); } return QString(); // Never reached } // Return a list of existing submenu ids QStringList MenuFolderInfo::existingMenuIds() { QStringList result; foreach (MenuFolderInfo *subFolderInfo, subFolders) { result.append(subFolderInfo->id); } return result; } void MenuFolderInfo::setDirty() { dirty = true; } void MenuFolderInfo::save(MenuFile *menuFile) { if (s_deletedApps) { // Remove hotkeys for applications that have been deleted for (QStringList::ConstIterator it = s_deletedApps->constBegin(); it != s_deletedApps->constEnd(); ++it) { // The shorcut is deleted if we set a empty sequence - GlobalAccel::changeMenuEntryShortcut(*it, QKeySequence()); + GlobalAccel::changeMenuEntryShortcut(KService::serviceByStorageId(*it), QKeySequence()); } delete s_deletedApps; s_deletedApps = nullptr; } if (dirty) { QString local = KDesktopFile::locateLocal(directoryFile); KDesktopFile *df = nullptr; if (directoryFile != local) { KDesktopFile orig(QStandardPaths::ApplicationsLocation, directoryFile); df = orig.copyTo(local); } else { df = new KDesktopFile(QStandardPaths::ApplicationsLocation, directoryFile); } KConfigGroup dg(df->desktopGroup()); dg.writeEntry("Name", caption); dg.writeEntry("GenericName", genericname); dg.writeEntry("Comment", comment); dg.writeEntry("Icon", icon); dg.sync(); delete df; dirty = false; } // Save sub-menus foreach (MenuFolderInfo *subFolderInfo, subFolders) { subFolderInfo->save(menuFile); } // Save entries foreach (MenuEntryInfo *entryInfo, entries) { if (entryInfo->needInsertion()) { menuFile->addEntry(fullId, entryInfo->menuId()); } entryInfo->save(); } } bool MenuFolderInfo::hasDirt() { if (dirty) { return true; } // Check sub-menus foreach (MenuFolderInfo *subFolderInfo, subFolders) { if (subFolderInfo->hasDirt()) { return true; } } // Check entries foreach (MenuEntryInfo *entryInfo, entries) { if (entryInfo->dirty || entryInfo->shortcutDirty) { return true; } } return false; } KService::Ptr MenuFolderInfo::findServiceShortcut(const QKeySequence &cut) { KService::Ptr result; // Check sub-menus foreach (MenuFolderInfo *subFolderInfo, subFolders) { result = subFolderInfo->findServiceShortcut(cut); if (result) { return result; } } // Check entries foreach (MenuEntryInfo *entryInfo, entries) { if (entryInfo->shortCut == cut) { return entryInfo->service; } } return KService::Ptr(); } void MenuFolderInfo::setInUse(bool inUse) { // Propagate to sub-menus foreach (MenuFolderInfo *subFolderInfo, subFolders) { subFolderInfo->setInUse(inUse); } // Propagate to entries foreach (MenuEntryInfo *entryInfo, entries) { entryInfo->setInUse(inUse); } } // // MenuEntryInfo // MenuEntryInfo::~MenuEntryInfo() { m_desktopFile->markAsClean(); delete m_desktopFile; } KDesktopFile *MenuEntryInfo::desktopFile() { if (!m_desktopFile) { m_desktopFile = new KDesktopFile(service->entryPath()); } return m_desktopFile; } void MenuEntryInfo::setDirty() { if (dirty) { return; } dirty = true; QString local = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + QLatin1Char('/') + service->menuId(); if (local != service->entryPath()) { KDesktopFile *oldDf = desktopFile(); m_desktopFile = oldDf->copyTo(local); delete oldDf; } } bool MenuEntryInfo::needInsertion() { // If entry is dirty and previously stored under applnk, then we need to be added explicitly return dirty && !service->entryPath().startsWith(QLatin1Char('/')); } void MenuEntryInfo::save() { if (dirty) { m_desktopFile->sync(); dirty = false; } if (shortcutDirty) { - GlobalAccel::changeMenuEntryShortcut(service->storageId(), shortCut); + GlobalAccel::changeMenuEntryShortcut(service, shortCut); shortcutDirty = false; } } void MenuEntryInfo::setCaption(const QString &_caption) { if (caption == _caption) { return; } caption = _caption; setDirty(); desktopFile()->desktopGroup().writeEntry("Name", caption); } void MenuEntryInfo::setDescription(const QString &_description) { if (description == _description) { return; } description = _description; setDirty(); desktopFile()->desktopGroup().writeEntry("GenericName", description); } void MenuEntryInfo::setIcon(const QString &_icon) { if (icon == _icon) { return; } icon = _icon; setDirty(); desktopFile()->desktopGroup().writeEntry("Icon", icon); } QKeySequence MenuEntryInfo::shortcut() { if (!shortcutLoaded) { shortcutLoaded = true; - shortCut = GlobalAccel::getMenuEntryShortcut(service->storageId()); + shortCut = GlobalAccel::getMenuEntryShortcut(service); } return shortCut; } static void freeShortcut(const QKeySequence &shortCut) { if (!shortCut.isEmpty()) { QString shortcutKey = shortCut.toString(); if (s_newShortcuts) { s_newShortcuts->removeAll(shortcutKey); } if (!s_freeShortcuts) { s_freeShortcuts = new QStringList; } s_freeShortcuts->append(shortcutKey); } } static void allocateShortcut(const QKeySequence &shortCut) { if (!shortCut.isEmpty()) { QString shortcutKey = shortCut.toString(); if (s_freeShortcuts) { s_freeShortcuts->removeAll(shortcutKey); } if (!s_newShortcuts) { s_newShortcuts = new QStringList; } s_newShortcuts->append(shortcutKey); } } void MenuEntryInfo::setShortcut(const QKeySequence &_shortcut) { if (shortCut == _shortcut) { return; } freeShortcut(shortCut); allocateShortcut(_shortcut); shortCut = _shortcut; if (shortCut.isEmpty()) { shortCut = QKeySequence(); // Normalize } shortcutLoaded = true; shortcutDirty = true; } void MenuEntryInfo::setInUse(bool inUse) { if (inUse) { QKeySequence temp = shortcut(); shortCut = QKeySequence(); if (isShortcutAvailable(temp)) { shortCut = temp; } else { shortcutDirty = true; } allocateShortcut(shortCut); if (s_deletedApps) { s_deletedApps->removeAll(service->storageId()); } } else { freeShortcut(shortcut()); // Add to list of deleted apps if (!s_deletedApps) { s_deletedApps = new QStringList; } s_deletedApps->append(service->storageId()); } } bool MenuEntryInfo::isShortcutAvailable(const QKeySequence &_shortcut) { // We only have to check agains not saved local shortcuts. // KKeySequenceWidget checks against all other registered shortcuts. if (shortCut == _shortcut) { return true; } QString shortcutKey = _shortcut.toString(); bool available = true; if (available && s_newShortcuts) { available = !s_newShortcuts->contains(shortcutKey); } if (!available && s_freeShortcuts) { available = s_freeShortcuts->contains(shortcutKey); } return available; }