123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include "EditorDefs.h"
- #include "CustomizeKeyboardDialog.h"
- // Qt
- #include <QMenu>
- #include <QMenuBar>
- #include <QMessageBox>
- // AzQtComponents
- #include <AzQtComponents/Components/WindowDecorationWrapper.h>
- AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
- #include "ui_CustomizeKeyboardDialog.h"
- AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
- using namespace AzQtComponents;
- namespace
- {
- enum CustomRole
- {
- ActionRole = Qt::UserRole,
- KeySequenceRole
- };
- }
- class NestedQAction
- {
- public:
- NestedQAction()
- : m_action(nullptr)
- {
- }
- NestedQAction(const QString& path, QAction* action)
- : m_path(path)
- , m_action(action)
- {
- }
- QString Path() const { return m_path; }
- QAction* Action() const { return m_action; }
- private:
- QString m_path;
- QAction* m_action;
- };
- QVector<NestedQAction> GetAllActionsForMenu(const QMenu* menu, const QString& path)
- {
- QList<QAction*> menuActions = menu->actions();
- QVector<NestedQAction> actions;
- actions.reserve(menuActions.size());
- foreach(QAction * action, menuActions)
- {
- if (action->menu() != nullptr)
- {
- QString newPath = path + action->text() + QStringLiteral(" | ");
- newPath = RemoveAcceleratorAmpersands(newPath);
- QVector<NestedQAction> subMenuActions = GetAllActionsForMenu(action->menu(), newPath);
- actions.reserve(actions.size() + subMenuActions.size());
- actions += subMenuActions;
- }
- else if (!action->isSeparator())
- {
- actions.push_back(NestedQAction(path + RemoveAcceleratorAmpersands(action->text()), action));
- }
- }
- return actions;
- }
- class MenuActionsModel
- : public QAbstractListModel
- {
- public:
- MenuActionsModel(QObject* parent = nullptr)
- : QAbstractListModel(parent)
- {
- }
- ~MenuActionsModel() override {}
- int rowCount([[maybe_unused]] const QModelIndex& parent = QModelIndex()) const override
- {
- return m_actions.size();
- }
- QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override
- {
- if (index.row() < 0 || index.row() >= m_actions.size())
- {
- return {};
- }
- switch (role)
- {
- case Qt::DisplayRole:
- {
- return m_actions[index.row()].Path();
- }
- case ActionRole:
- return QVariant::fromValue(m_actions[index.row()].Action());
- }
- return {};
- }
- void Reset(const QVector<NestedQAction>& actions)
- {
- beginResetModel();
- m_actions = actions;
- endResetModel();
- }
- private:
- QVector<NestedQAction> m_actions;
- };
- class ActionShortcutsModel
- : public QAbstractListModel
- {
- public:
- ActionShortcutsModel(QObject* parent = nullptr)
- : QAbstractListModel(parent)
- , m_action(nullptr)
- {
- }
- ~ActionShortcutsModel() override {}
- int rowCount([[maybe_unused]] const QModelIndex& parent = QModelIndex()) const override
- {
- if (m_action)
- {
- return m_action->shortcuts().size();
- }
- else
- {
- return 0;
- }
- }
- QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override
- {
- auto shortcuts = m_action->shortcuts();
- if (index.row() < 0 || index.row() >= shortcuts.size())
- {
- return {};
- }
- switch (role)
- {
- case Qt::DisplayRole:
- return shortcuts.at(index.row()).toString();
- case KeySequenceRole:
- return QVariant::fromValue(shortcuts.at(index.row()));
- }
- return {};
- }
- void RemoveAll()
- {
- auto shortcuts = m_action->shortcuts();
- beginRemoveRows({}, 0, shortcuts.size() - 1);
- shortcuts.clear();
- m_action->setShortcuts(shortcuts);
- endRemoveRows();
- }
- void Remove(const QKeySequence& sequence)
- {
- auto shortcuts = m_action->shortcuts();
- int index = shortcuts.indexOf(sequence);
- if (index >= 0)
- {
- beginRemoveRows({}, index, index);
- shortcuts.removeAll(sequence);
- m_action->setShortcuts(shortcuts);
- endRemoveRows();
- }
- }
- QModelIndex Add(const QKeySequence& sequence)
- {
- auto shortcuts = m_action->shortcuts();
- int position = shortcuts.indexOf(sequence);
- if (-1 == position)
- {
- position = shortcuts.size();
- beginInsertRows({}, position, position);
- shortcuts.append(sequence);
- m_action->setShortcuts(shortcuts);
- endInsertRows();
- }
- return index(position);
- }
- bool Contains(const QKeySequence& sequence) const
- {
- return m_action->shortcuts().contains(sequence);
- }
- void Reset(QAction& action)
- {
- beginResetModel();
- m_action = &action;
- endResetModel();
- }
- private:
- QAction* m_action;
- };
- CustomizeKeyboardDialog::CustomizeKeyboardDialog(KeyboardCustomizationSettings& settings, QWidget* parent /* = nullptr */)
- : QDialog(new WindowDecorationWrapper(WindowDecorationWrapper::OptionAutoAttach | WindowDecorationWrapper::OptionAutoTitleBarButtons, parent))
- , m_ui(new Ui::CustomizeKeyboardDialog)
- , m_settings(settings)
- , m_settingsSnapshot(m_settings.CreateSnapshot())
- {
- m_ui->setupUi(this);
- m_menuActionsModel = new MenuActionsModel(this);
- m_actionShortcutsModel = new ActionShortcutsModel(this);
- m_ui->commandsView->setModel(m_menuActionsModel);
- m_ui->shortcutsView->setModel(m_actionShortcutsModel);
- QStringList categories = BuildModels(parent);
- connect(m_ui->categories, &QComboBox::currentTextChanged, this, &CustomizeKeyboardDialog::CategoryChanged);
- connect(m_ui->commandsView->selectionModel(), &QItemSelectionModel::currentChanged, this, &CustomizeKeyboardDialog::CommandSelectionChanged);
- connect(m_ui->shortcutsView->selectionModel(), &QItemSelectionModel::currentChanged, this, &CustomizeKeyboardDialog::ShortcutsViewSelectionChanged);
- connect(m_actionShortcutsModel, &QAbstractItemModel::rowsRemoved, this, &CustomizeKeyboardDialog::ShortcutsViewDataChanged);
- connect(m_actionShortcutsModel, &QAbstractItemModel::rowsInserted, this, &CustomizeKeyboardDialog::ShortcutsViewDataChanged);
- connect(m_ui->keySequenceEdit, &QKeySequenceEdit::editingFinished, this, &CustomizeKeyboardDialog::KeySequenceEditingFinished);
- connect(m_ui->assignButton, &QPushButton::clicked, this, &CustomizeKeyboardDialog::AssignButtonClicked);
- connect(m_ui->removeButton, &QPushButton::clicked, this, &CustomizeKeyboardDialog::ShortcutRemoved);
- connect(m_ui->clearButton, &QPushButton::clicked, m_actionShortcutsModel, &ActionShortcutsModel::RemoveAll);
- connect(m_ui->buttonBox, &QDialogButtonBox::clicked, this, &CustomizeKeyboardDialog::DialogButtonClicked);
- connect(this, &QDialog::rejected, this, [&]() { m_settings.Load(m_settingsSnapshot); });
- m_ui->categories->addItems(categories);
- }
- CustomizeKeyboardDialog::~CustomizeKeyboardDialog()
- {
- }
- QStringList CustomizeKeyboardDialog::BuildModels(QWidget* parent)
- {
- QMenuBar* menuBar = parent->findChild<QMenuBar*>();
- QList<QAction*> menuBarActions = menuBar->actions();
- QStringList categories;
- foreach(QAction * menuAction, menuBarActions)
- {
- QString category = RemoveAcceleratorAmpersands(menuAction->text());
- categories.append(category);
- QMenu* menu = menuAction->menu();
- m_menuActions[category] = GetAllActionsForMenu(menu, QString());
- }
- return categories;
- }
- void CustomizeKeyboardDialog::CategoryChanged(const QString& category)
- {
- m_menuActionsModel->Reset(m_menuActions[category]);
- // Must reset the shortcut sequence text box back to disabled state
- // if the category is changed
- m_ui->keySequenceEdit->setEnabled(false);
- m_ui->commandsView->scrollToTop();
- }
- void CustomizeKeyboardDialog::CommandSelectionChanged(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous)
- {
- QAction* action = current.data(ActionRole).value<QAction*>();
- m_actionShortcutsModel->Reset(*action);
- m_ui->removeButton->setEnabled(false);
- m_ui->clearButton->setEnabled(m_actionShortcutsModel->rowCount() > 0);
- m_ui->keySequenceEdit->setEnabled(true);
- const auto& description = action->statusTip().size() > 0 ? action->statusTip() : action->toolTip();
- m_ui->descriptionLabel->setText(description);
- m_ui->keySequenceEdit->clear();
- }
- void CustomizeKeyboardDialog::ShortcutsViewSelectionChanged(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous)
- {
- m_ui->removeButton->setEnabled(current.isValid());
- }
- void CustomizeKeyboardDialog::ShortcutsViewDataChanged()
- {
- m_ui->clearButton->setEnabled(m_actionShortcutsModel->rowCount() > 0);
- }
- void CustomizeKeyboardDialog::ShortcutRemoved()
- {
- auto index = m_ui->shortcutsView->selectionModel()->selectedIndexes().first();
- m_actionShortcutsModel->Remove(index.data(KeySequenceRole).value<QKeySequence>());
- }
- void CustomizeKeyboardDialog::KeySequenceEditingFinished()
- {
- auto keySequence = m_ui->keySequenceEdit->keySequence();
- m_ui->assignButton->setEnabled(!keySequence.isEmpty() && !m_actionShortcutsModel->Contains(keySequence));
- }
- void CustomizeKeyboardDialog::AssignButtonClicked()
- {
- auto sequence = m_ui->keySequenceEdit->keySequence();
- m_ui->keySequenceEdit->clear();
- auto currentAction = m_settings.FindActionForShortcut(sequence);
- if (currentAction)
- {
- auto result = QMessageBox::warning(
- this,
- tr("Shortcut already in use"),
- tr("%1 is currently assigned to '%2'.\n\nAssign and replace?")
- .arg(sequence.toString()).arg(RemoveAcceleratorAmpersands(currentAction->text())),
- QMessageBox::Yes | QMessageBox::No,
- QMessageBox::No);
- if (result == QMessageBox::No)
- {
- m_ui->keySequenceEdit->setFocus();
- return;
- }
- //remove this sequence from the current shortcut
- auto shortcuts = currentAction->shortcuts();
- shortcuts.removeAll(sequence);
- currentAction->setShortcuts(shortcuts);
- }
- QModelIndex index = m_actionShortcutsModel->Add(sequence);
- m_ui->shortcutsView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Clear | QItemSelectionModel::SelectCurrent);
- m_ui->assignButton->setEnabled(false);
- m_ui->removeButton->setFocus();
- }
- void CustomizeKeyboardDialog::DialogButtonClicked(const QAbstractButton* button)
- {
- if (button == m_ui->buttonBox->button(QDialogButtonBox::RestoreDefaults))
- {
- auto result = QMessageBox::question(
- this,
- tr("Restore Default Keyboard Shortcuts"),
- tr("Are you sure you wish to restore all keyboard shortcuts to factory defaults?"));
- if (result == QMessageBox::Yes)
- {
- m_settings.LoadDefaults();
- }
- }
- else if (button == m_ui->buttonBox->button(QDialogButtonBox::Close))
- {
- m_settings.Save();
- accept();
- }
- else if (button == m_ui->buttonBox->button(QDialogButtonBox::Cancel))
- {
- m_settings.Load(m_settingsSnapshot);
- reject();
- }
- }
- #include <moc_CustomizeKeyboardDialog.cpp>
|