/******************************************************************************* * This file is part of the LibreCAD project, a 2D CAD program Copyright (C) 2024 LibreCAD.org Copyright (C) 2024 sand1024 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 "lc_shortcuts_manager.h" #include #include #include "lc_shortcutsstorage.h" #include "rs_debug.h" #include "rs_settings.h" #include "rs_system.h" const char* LC_ShortcutsManager::PROPERTY_SHORTCUT_BACKUP = "tooltip.original"; LC_ShortcutsManager::LC_ShortcutsManager() {} int LC_ShortcutsManager::saveShortcuts( QMap &shortcuts, QMap &actionsMap) const { applyShortcutsMapToActionsMap(shortcuts, actionsMap); updateActionTooltips(actionsMap); QString defaultShortcutsFileName = getDefaultShortcutsFileName(); int saveResult = LC_ShortcutsStorage::saveShortcuts(defaultShortcutsFileName, shortcuts.values(), false); return saveResult; } int LC_ShortcutsManager::loadShortcuts(QMap &actionsMap) const { QString defaultFileName = getDefaultShortcutsFileName(); QMap shortcuts = QMap(); int loadResult = loadShortcuts(defaultFileName, &shortcuts); if (loadResult == LC_ShortcutsStorage::OK){ applyKeySequencesMapToActionsMap(shortcuts, actionsMap); } updateActionTooltips(actionsMap); return loadResult; } int LC_ShortcutsManager::saveShortcuts(const QString &fileName, const QList &shortcutsList) const { int result = LC_ShortcutsStorage::saveShortcuts(fileName, shortcutsList); return result; } int LC_ShortcutsManager::loadShortcuts(const QString &filename, QMap *result) const{ return LC_ShortcutsStorage::loadShortcuts(filename, result); } void LC_ShortcutsManager::updateActionTooltips(const QMap &actionsMap) const { bool showShortcutsInActionsTooltips = LC_GET_ONE_BOOL("Appearance","ShowKeyboardShortcutsInTooltips", true); updateActionShortcutTooltips(actionsMap, showShortcutsInActionsTooltips); } void LC_ShortcutsManager::init() { QString defaultFileName = getDefaultShortcutsFileName(); if (!defaultFileName.isEmpty()) { QFile defaultFile(defaultFileName); if (defaultFile.exists()) { QString backupFileName = defaultFileName + ".bak"; QFile::copy(defaultFileName, backupFileName); } } } void LC_ShortcutsManager::applyShortcutsMapToActionsMap(QMap &shortcuts, QMap &actionsMap) const{ for (auto [key, shortcut] : shortcuts.asKeyValueRange()){ QAction* action = actionsMap[key]; if (action != nullptr){ action->setShortcut(shortcut->getKey()); } } } void LC_ShortcutsManager::applyKeySequencesMapToActionsMap(QMap &shortcuts, QMap &actionsMap) const{ for (auto [name, shortcut] : shortcuts.asKeyValueRange()){ QAction* action = actionsMap[name]; if (action != nullptr){ action->setShortcut(shortcut); action->setShortcutContext(Qt::ApplicationShortcut); } } } void LC_ShortcutsManager::assignShortcutsToActions(const QMap &map, std::vector &shortcutsList) const { for (const LC_ShortcutInfo &a: shortcutsList){ QAction* createdAction = map[a.getName()]; if (createdAction != nullptr){ const QList &list = a.getKeysList(); if (list.isEmpty()) { const QKeySequence &sequence = a.getKey(); if (sequence != QKeySequence::UnknownKey) { createdAction->setShortcut(sequence); } } else { // todo - support for future createdAction->setShortcuts(list); } } } } QString LC_ShortcutsManager::getPlainActionToolTip(QAction* action){ if (action != nullptr) { if (!action->shortcut().isEmpty()) { QString tooltip = action->property(PROPERTY_SHORTCUT_BACKUP).toString(); if (tooltip.isEmpty()) { tooltip = action->toolTip(); } return tooltip; } return action->toolTip(); } return ""; } void LC_ShortcutsManager::updateActionShortcutTooltips(const QMap &map, bool enable) const { if (enable){ for (auto [key, action]: map.asKeyValueRange()) { if (action != nullptr) { if (!action->shortcut().isEmpty()) { // action uses a custom tooltip. Backup so that we can restore it later. QString tooltip = action->property(PROPERTY_SHORTCUT_BACKUP).toString(); if (tooltip.isEmpty()) { tooltip = action->toolTip(); action->setProperty(PROPERTY_SHORTCUT_BACKUP, action->toolTip()); } QColor shortcutTextColor = QApplication::palette().color(QPalette::ToolTipText); QString shortCutTextColorName; if (shortcutTextColor.value() == 0) { shortCutTextColorName = "gray"; // special handling for black because lighter() does not work there [QTBUG-9343]. } else { int factor = (shortcutTextColor.value() < 128) ? 150 : 50; shortCutTextColorName = shortcutTextColor.lighter(factor).name(); } action->setToolTip(QString( "

%1  %3

") .arg(tooltip, shortCutTextColorName, action->shortcut().toString(QKeySequence::NativeText))); } } else{ // if we are here, it means that there is a key for which no action was registered in actions map. // it might be either due to incorrect data in settings file, or if the action was created somewhere in // code that is outside actions factory. // in any case, just ignore that key LC_ERR << "LC_ShortcutsManager::updateActionShortcutTooltips - Action is null in the map, ignored. Key " << key; } } } else{ for (QAction* action: map){ action->setToolTip(action->property(PROPERTY_SHORTCUT_BACKUP).toString()); action->setProperty(PROPERTY_SHORTCUT_BACKUP, QVariant()); // todo - is it really necessary to remove it? } } } /* guesses a descriptive text from a text suited for a menu entry This is equivalent to QActions internal qt_strippedText() */ QString LC_ShortcutsManager::strippedActionText(QString s) const{ s.remove( QString::fromLatin1("...")); for (int i = 0; i < s.size(); ++i) { if (s.at(i) == QLatin1Char('&')) s.remove(i, 1); } return s.trimmed(); } QString LC_ShortcutsManager::getShortcutsMappingsFolder() const { QString settingsDir = LC_GET_ONE_STR("Paths", "OtherSettingsDir", RS_System::instance()->getAppDataDir()).trimmed(); return settingsDir; } QString LC_ShortcutsManager::getDefaultShortcutsFileName() const { QString path = getShortcutsMappingsFolder() + "/shortcuts.lcsc"; return QDir::toNativeSeparators(path); }