/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include "StdAfx.h" #include "KeyboardCustomizationSettings.h" #include "LogFile.h" #include #include #include #include #include #include #include #include #include QString RemoveAcceleratorAmpersands(const QString& original) { static const QRegularExpression expression(QStringLiteral("&(.)")); QString updated = original; updated.replace(expression, QStringLiteral("\\1")); return updated; } QVector GetAllActionsForMenu(const QMenu* menu) { QList menuActions = menu->actions(); QVector actions; actions.reserve(menuActions.size()); foreach(QAction * action, menuActions) { if (action->menu() != nullptr) { QVector subMenuActions = GetAllActionsForMenu(action->menu()); actions.reserve(actions.size() + subMenuActions.size()); actions += subMenuActions; } else if (!action->isSeparator()) { actions.push_back(action); } } return actions; } void ProcessAllActions(const QWidget* parent, const std::function& processor) { QMenuBar* menuBar = parent->findChild(); QList menuBarActions = menuBar->actions(); foreach(QAction * menuAction, menuBarActions) { processor(menuAction); auto actions = GetAllActionsForMenu(menuAction->menu()); foreach(QAction * action, actions) { if (Q_UNLIKELY(processor(action))) { return; } } } } QString GetName(const QAction* action) { if (action->data().isValid()) { return action->data().toString(); } else { return action->objectName(); } } QVector KeyboardCustomizationSettings::m_instances; KeyboardCustomizationSettings::KeyboardCustomizationSettings(const QString& group, QWidget* parent) : m_parent(parent) , m_group(group) , m_defaults(CreateSnapshot()) , m_shortcutsEnabled(true) { m_instances.append(this); Load(); } KeyboardCustomizationSettings::~KeyboardCustomizationSettings() { m_instances.remove(m_instances.indexOf(this)); } void KeyboardCustomizationSettings::LoadDefaults() { LoadFromSnapshot(m_defaults); } void KeyboardCustomizationSettings::Load() { QSettings settings(QStringLiteral("Amazon"), QStringLiteral("Lumberyard")); settings.beginGroup(QStringLiteral("Keyboard Shortcuts")); settings.beginGroup(m_group); QStringList groups = settings.childGroups(); ProcessAllActions(m_parent, [&](QAction* action) { auto groupName = GetName(action); if (groups.contains(groupName)) { settings.beginGroup(groupName); auto sequence = QKeySequence::listFromString(settings.value("shortcuts").toString()); action->setShortcuts(sequence); settings.endGroup(); } return false; }); settings.endGroup(); // m_group settings.endGroup(); // Keyboard Shortcuts } void KeyboardCustomizationSettings::Load(const Snapshot& snapshot) { LoadFromSnapshot(snapshot); } void KeyboardCustomizationSettings::LoadFromSnapshot(const Snapshot& snapshot) { ProcessAllActions(m_parent, [&](QAction* action) { auto entry = snapshot.constFind(action); if (entry != snapshot.constEnd()) { const Shortcut& s = entry.value(); action->setText(s.text); action->setShortcuts(s.keySequence); } return false; }); } void KeyboardCustomizationSettings::Save() { QSettings settings(QStringLiteral("Amazon"), QStringLiteral("Lumberyard")); settings.beginGroup(QStringLiteral("Keyboard Shortcuts")); settings.beginGroup(m_group); ProcessAllActions(m_parent, [&](QAction* action) { auto groupName = GetName(action); settings.beginGroup(groupName); settings.setValue("shortcuts", QKeySequence::listToString(action->shortcuts())); settings.endGroup(); return false; }); settings.endGroup(); // m_group settings.endGroup(); // Keyboard Shortcuts } KeyboardCustomizationSettings::Snapshot KeyboardCustomizationSettings::CreateSnapshot() { Snapshot result; ProcessAllActions(m_parent, [&](QAction* action) { Shortcut s = { action->text(), action->shortcuts() }; result[action] = s; return false; }); return result; } void KeyboardCustomizationSettings::ExportToFile(QWidget* parent) { QString fileName = QFileDialog::getSaveFileName(parent, QObject::tr("Export Keyboard Shortcuts"), QStringLiteral("lumberyard.keys"), QObject::tr("Keyboard Settings (*.keys)")); if (fileName.isEmpty()) { return; } QFile file(fileName); if (!file.open(QIODevice::WriteOnly)) { QMessageBox::critical(parent, QObject::tr("Shortcut Export Error"), QObject::tr("Couldn't open \"%1\": %2").arg(fileName).arg(file.errorString())); return; } QJsonObject store; store.insert("version", "1.0"); store.insert("Content-Type", "application/x-lumberyard-sdk-keyboard-settings+json"); QJsonObject groups; for (auto instance = m_instances.constBegin(); instance != m_instances.constEnd(); instance++) { groups.insert((*instance)->m_group, QJsonValue((*instance)->ExportGroup())); } store.insert("groups", groups); QJsonDocument exported(store); if (-1 == file.write(exported.toJson())) { QMessageBox::critical(parent, QObject::tr("Shortcut Export Error"), QObject::tr("Couldn't write settings to \"%1\": %2").arg(fileName).arg(file.errorString())); return; } file.close(); } QJsonObject KeyboardCustomizationSettings::ExportGroup() { QJsonObject group; group.insert("name", m_group); ProcessAllActions(m_parent, [&](QAction* action) { QJsonObject entry; entry.insert("label", RemoveAcceleratorAmpersands(action->text())); entry.insert("shortcuts", QKeySequence::listToString(action->shortcuts())); group.insert(GetName(action), QJsonValue(entry)); return false; }); return group; } void KeyboardCustomizationSettings::ImportFromFile(QWidget* parent) { QString fileName = QFileDialog::getOpenFileName(parent, QObject::tr("Export Keyboard Shortcuts"), QStringLiteral(""), QObject::tr("Keyboard Settings (*.keys)")); if (fileName.isEmpty()) { return; } QFile file(fileName); if (!file.open(QIODevice::ReadOnly)) { QMessageBox::critical(parent, QObject::tr("Shortcut Import Error"), QObject::tr("Couldn't open \"%1\": %2").arg(fileName).arg(file.errorString())); return; } QByteArray rawData = file.readAll(); QJsonDocument imported(QJsonDocument::fromJson(rawData)); QJsonObject store = imported.object(); if (store.value("Content-Type") != "application/x-lumberyard-sdk-keyboard-settings+json" || store.value("version") != "1.0") { QMessageBox::critical(parent, QObject::tr("Shortcut Import Error"), QObject::tr("\"%1\" doesn't appear to contain keyboard settings").arg(fileName)); return; } QJsonObject groups = store.value("groups").toObject(); if (QJsonObject() == groups) { QMessageBox::critical(parent, QObject::tr("Shortcut Import Error"), QObject::tr("\"%1\" contains no keyboard settings").arg(fileName)); return; } for (auto instance = m_instances.begin(); instance != m_instances.end(); instance++) { QJsonValue rawGroup = groups.value((*instance)->m_group); if (!rawGroup.isUndefined()) { QJsonObject group = rawGroup.toObject(); if (QJsonObject() != group && group.value("name").toString() == (*instance)->m_group) { (*instance)->ImportGroup(group); } } } file.close(); } void KeyboardCustomizationSettings::ImportGroup(const QJsonObject& group) { ProcessAllActions(m_parent, [&](QAction* action) { auto position = group.constFind(GetName(action)); if (position != group.constEnd()) { QJsonObject entry = position.value().toObject(); if (QJsonObject() != entry) { QString value = entry.value("shortcuts").toString(); action->setShortcuts(QKeySequence::listFromString(value)); } else { action->setShortcuts({}); } } return false; }); } QAction* KeyboardCustomizationSettings::FindActionForShortcut(QKeySequence shortcut) const { QAction* result { nullptr }; ProcessAllActions(m_parent, [&](QAction* action) { bool found { false }; if (action->shortcuts().contains(shortcut)) { result = action; found = true; } return found; }); return result; } void KeyboardCustomizationSettings::ClearShortcutsAndAccelerators() { ProcessAllActions(m_parent, [&](QAction* action) { action->setText(RemoveAcceleratorAmpersands(action->text())); action->setShortcut({}); return false; }); } /** static */ void KeyboardCustomizationSettings::EnableShortcutsGlobally(bool enable) { for (auto it : m_instances) { it->EnableShortcuts(enable); } } void KeyboardCustomizationSettings::EnableShortcuts(bool enabled) { if (enabled != m_shortcutsEnabled) { m_shortcutsEnabled = enabled; if (enabled) { LoadFromSnapshot(m_lastEnabledShortcuts); CLogFile::WriteLine("Enable Accelerators"); } else { m_lastEnabledShortcuts = CreateSnapshot(); ClearShortcutsAndAccelerators(); CLogFile::WriteLine("Disable Accelerators"); } } } /** static */ void KeyboardCustomizationSettings::LoadDefaultsGlobally() { for (auto it : m_instances) { it->LoadDefaults(); } } /** static */ void KeyboardCustomizationSettings::SaveGlobally() { for (auto it : m_instances) { it->Save(); } }