summaryrefslogtreecommitdiffstats
path: root/examples/widgets/widgets/shortcuteditor
diff options
context:
space:
mode:
Diffstat (limited to 'examples/widgets/widgets/shortcuteditor')
-rw-r--r--examples/widgets/widgets/shortcuteditor/CMakeLists.txt40
-rw-r--r--examples/widgets/widgets/shortcuteditor/actionmanager.cpp57
-rw-r--r--examples/widgets/widgets/shortcuteditor/actionmanager.h33
-rw-r--r--examples/widgets/widgets/shortcuteditor/application.cpp15
-rw-r--r--examples/widgets/widgets/shortcuteditor/application.h27
-rw-r--r--examples/widgets/widgets/shortcuteditor/main.cpp13
-rw-r--r--examples/widgets/widgets/shortcuteditor/mainwindow.cpp46
-rw-r--r--examples/widgets/widgets/shortcuteditor/mainwindow.h22
-rw-r--r--examples/widgets/widgets/shortcuteditor/shortcuteditordelegate.cpp71
-rw-r--r--examples/widgets/widgets/shortcuteditor/shortcuteditordelegate.h34
-rw-r--r--examples/widgets/widgets/shortcuteditor/shortcuteditormodel.cpp273
-rw-r--r--examples/widgets/widgets/shortcuteditor/shortcuteditormodel.h71
-rw-r--r--examples/widgets/widgets/shortcuteditor/shortcuteditorwidget.cpp33
-rw-r--r--examples/widgets/widgets/shortcuteditor/shortcuteditorwidget.h32
14 files changed, 767 insertions, 0 deletions
diff --git a/examples/widgets/widgets/shortcuteditor/CMakeLists.txt b/examples/widgets/widgets/shortcuteditor/CMakeLists.txt
new file mode 100644
index 0000000000..5d1c4a8dc1
--- /dev/null
+++ b/examples/widgets/widgets/shortcuteditor/CMakeLists.txt
@@ -0,0 +1,40 @@
+cmake_minimum_required(VERSION 3.16)
+project(shortcuteditor LANGUAGES CXX)
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
+
+qt_standard_project_setup()
+
+qt_add_executable(shortcuteditor
+ actionmanager.cpp actionmanager.h
+ application.cpp application.h
+ main.cpp
+ mainwindow.cpp mainwindow.h
+ shortcuteditordelegate.cpp shortcuteditordelegate.h
+ shortcuteditormodel.cpp shortcuteditormodel.h
+ shortcuteditorwidget.cpp shortcuteditorwidget.h
+)
+
+set_target_properties(shortcuteditor PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(shortcuteditor PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Widgets
+)
+
+install(TARGETS shortcuteditor
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_app_script(
+ TARGET shortcuteditor
+ OUTPUT_SCRIPT deploy_script
+ NO_UNSUPPORTED_PLATFORM_ERROR
+)
+install(SCRIPT ${deploy_script})
diff --git a/examples/widgets/widgets/shortcuteditor/actionmanager.cpp b/examples/widgets/widgets/shortcuteditor/actionmanager.cpp
new file mode 100644
index 0000000000..cfe5f42674
--- /dev/null
+++ b/examples/widgets/widgets/shortcuteditor/actionmanager.cpp
@@ -0,0 +1,57 @@
+// Copyright (C) 2022 Laszlo Papp <lpapp@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "actionmanager.h"
+
+#include <QAction>
+#include <QApplication>
+#include <QString>
+#include <QVariant>
+
+static const char *kDefaultShortcutPropertyName = "defaultShortcuts";
+static const char *kIdPropertyName = "id";
+static const char *kAuthorName = "qt";
+
+struct ActionIdentifier {
+ QString author;
+ QString context;
+ QString category;
+ QString name;
+};
+
+QList<QAction *> ActionManager::registeredActions() const
+{
+ return m_actions;
+}
+
+void ActionManager::registerAction(QAction *action)
+{
+ action->setProperty(kDefaultShortcutPropertyName, QVariant::fromValue(action->shortcut()));
+ m_actions.append(action);
+}
+
+void ActionManager::registerAction(QAction *action, const QString &context, const QString &category)
+{
+ action->setProperty(kIdPropertyName, QVariant::fromValue(ActionIdentifier{
+ kAuthorName, context, category, action->text()
+ }));
+ registerAction(action);
+}
+
+QAction *ActionManager::registerAction(const QString &name, const QString &shortcut, const QString &context, const QString &category)
+{
+ QAction *action = new QAction(name, qApp);
+ action->setShortcut(QKeySequence(shortcut));
+ registerAction(action, context, category);
+ return action;
+}
+
+QString ActionManager::contextForAction(QAction *action)
+{
+ return action->property(kIdPropertyName).value<ActionIdentifier>().context;
+}
+
+QString ActionManager::categoryForAction(QAction *action)
+{
+ return action->property(kIdPropertyName).value<ActionIdentifier>().category;
+}
diff --git a/examples/widgets/widgets/shortcuteditor/actionmanager.h b/examples/widgets/widgets/shortcuteditor/actionmanager.h
new file mode 100644
index 0000000000..da20cd8840
--- /dev/null
+++ b/examples/widgets/widgets/shortcuteditor/actionmanager.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2022 Laszlo Papp <lpapp@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef ACTIONMANAGER_H
+#define ACTIONMANAGER_H
+
+#include <QList>
+#include <QString>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+QT_END_NAMESPACE
+
+class ActionManager
+{
+public:
+ ActionManager() = default;
+ ~ActionManager() = default;
+
+ QList<QAction*> registeredActions() const;
+
+ void registerAction(QAction *action);
+ void registerAction(QAction *action, const QString &context, const QString &category);
+ QAction *registerAction(const QString &name, const QString &shortcut, const QString &context, const QString &category);
+
+ QString contextForAction(QAction *action);
+ QString categoryForAction(QAction *action);
+
+private:
+ QList<QAction *> m_actions;
+};
+
+#endif
diff --git a/examples/widgets/widgets/shortcuteditor/application.cpp b/examples/widgets/widgets/shortcuteditor/application.cpp
new file mode 100644
index 0000000000..4ac76682d0
--- /dev/null
+++ b/examples/widgets/widgets/shortcuteditor/application.cpp
@@ -0,0 +1,15 @@
+// Copyright (C) 2022 Laszlo Papp <lpapp@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "application.h"
+
+Application::Application(int &argc, char **argv)
+ : QApplication(argc, argv)
+{
+ m_actionManager = std::make_unique<ActionManager>();
+}
+
+ActionManager *Application::actionManager() const
+{
+ return m_actionManager.get();
+}
diff --git a/examples/widgets/widgets/shortcuteditor/application.h b/examples/widgets/widgets/shortcuteditor/application.h
new file mode 100644
index 0000000000..38808c3ad2
--- /dev/null
+++ b/examples/widgets/widgets/shortcuteditor/application.h
@@ -0,0 +1,27 @@
+// Copyright (C) 2022 Laszlo Papp <lpapp@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef APPLICATION_H
+#define APPLICATION_H
+
+#include "actionmanager.h"
+
+#include <QApplication>
+
+#include <memory>
+
+class Application : public QApplication
+{
+ Q_OBJECT
+
+public:
+ Application(int &argc, char **argv);
+ ~Application() override = default;
+
+ ActionManager *actionManager() const;
+
+private:
+ std::unique_ptr<ActionManager> m_actionManager;
+};
+
+#endif
diff --git a/examples/widgets/widgets/shortcuteditor/main.cpp b/examples/widgets/widgets/shortcuteditor/main.cpp
new file mode 100644
index 0000000000..029f7a351a
--- /dev/null
+++ b/examples/widgets/widgets/shortcuteditor/main.cpp
@@ -0,0 +1,13 @@
+// Copyright (C) 2022 Laszlo Papp <lpapp@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "application.h"
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ Application app(argc, argv);
+ MainWindow window;
+ window.show();
+ return app.exec();
+}
diff --git a/examples/widgets/widgets/shortcuteditor/mainwindow.cpp b/examples/widgets/widgets/shortcuteditor/mainwindow.cpp
new file mode 100644
index 0000000000..587dbbc5b5
--- /dev/null
+++ b/examples/widgets/widgets/shortcuteditor/mainwindow.cpp
@@ -0,0 +1,46 @@
+// Copyright (C) 2022 Laszlo Papp <lpapp@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "mainwindow.h"
+
+#include "actionmanager.h"
+#include "application.h"
+#include "shortcuteditorwidget.h"
+
+#include <QAction>
+#include <QHBoxLayout>
+#include <QPushButton>
+#include <QVBoxLayout>
+
+MainWindow::MainWindow()
+{
+ QPushButton *topPushButton = new QPushButton("Left");
+ QPushButton *bottomPushButton = new QPushButton("Right");
+ for (auto nameShortcut : std::vector<std::vector<const char *>>{{"red", "r", "shift+r"}, {"green", "g", "shift+g"}, {"blue", "b", "shift+b"}}) {
+ Application *application = static_cast<Application *>(QCoreApplication::instance());
+ ActionManager *actionManager = application->actionManager();
+ QAction *action = actionManager->registerAction(nameShortcut[0], nameShortcut[1], "top", "color");
+ topPushButton->addAction(action);
+ connect(action, &QAction::triggered, this, [topPushButton, nameShortcut]() {
+ topPushButton->setText(nameShortcut[0]);
+ });
+
+ action = actionManager->registerAction(nameShortcut[0], nameShortcut[2], "bottom", "color");
+ bottomPushButton->addAction(action);
+ connect(action, &QAction::triggered, this, [bottomPushButton, nameShortcut]() {
+ bottomPushButton->setText(nameShortcut[0]);
+ });
+ }
+
+ QVBoxLayout *vBoxLayout = new QVBoxLayout;
+ vBoxLayout->addWidget(topPushButton);
+ vBoxLayout->addWidget(bottomPushButton);
+
+ QHBoxLayout *hBoxLayout = new QHBoxLayout;
+ hBoxLayout->addWidget(new ShortcutEditorWidget);
+ hBoxLayout->addLayout(vBoxLayout);
+
+ QWidget *centralWidget = new QWidget;
+ centralWidget->setLayout(hBoxLayout);
+ setCentralWidget(centralWidget);
+}
diff --git a/examples/widgets/widgets/shortcuteditor/mainwindow.h b/examples/widgets/widgets/shortcuteditor/mainwindow.h
new file mode 100644
index 0000000000..702b3f2d87
--- /dev/null
+++ b/examples/widgets/widgets/shortcuteditor/mainwindow.h
@@ -0,0 +1,22 @@
+// Copyright (C) 2022 Laszlo Papp <lpapp@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+
+QT_BEGIN_NAMESPACE
+class QPushButton;
+QT_END_NAMESPACE
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow();
+ ~MainWindow() override = default;
+};
+
+#endif
diff --git a/examples/widgets/widgets/shortcuteditor/shortcuteditordelegate.cpp b/examples/widgets/widgets/shortcuteditor/shortcuteditordelegate.cpp
new file mode 100644
index 0000000000..a8b32bc06a
--- /dev/null
+++ b/examples/widgets/widgets/shortcuteditor/shortcuteditordelegate.cpp
@@ -0,0 +1,71 @@
+// Copyright (C) 2022 Laszlo Papp <lpapp@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "shortcuteditordelegate.h"
+
+#include <QAbstractItemModel>
+#include <QKeySequenceEdit>
+
+//! [0]
+ShortcutEditorDelegate::ShortcutEditorDelegate(QObject *parent)
+ : QStyledItemDelegate(parent)
+{
+}
+//! [0]
+
+//! [1]
+QWidget *ShortcutEditorDelegate::createEditor(QWidget *parent,
+ const QStyleOptionViewItem &/*option*/,
+ const QModelIndex &/*index*/) const
+{
+ QKeySequenceEdit *editor = new QKeySequenceEdit(parent);
+ connect(editor, &QKeySequenceEdit::editingFinished, this, &ShortcutEditorDelegate::commitAndCloseEditor);
+ return editor;
+}
+//! [1]
+
+//! [2]
+void ShortcutEditorDelegate::commitAndCloseEditor()
+{
+ QKeySequenceEdit *editor = static_cast<QKeySequenceEdit *>(sender());
+ Q_EMIT commitData(editor);
+ Q_EMIT closeEditor(editor);
+}
+//! [2]
+
+//! [3]
+void ShortcutEditorDelegate::setEditorData(QWidget *editor,
+ const QModelIndex &index) const
+{
+ if (!editor || !index.isValid())
+ return;
+
+ QString value = index.model()->data(index, Qt::EditRole).toString();
+
+ QKeySequenceEdit *keySequenceEdit = static_cast<QKeySequenceEdit *>(editor);
+ keySequenceEdit->setKeySequence(value);
+}
+//! [3]
+
+//! [4]
+void ShortcutEditorDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
+ const QModelIndex &index) const
+{
+ if (!editor || !model || !index.isValid())
+ return;
+
+ const QKeySequenceEdit *keySequenceEdit = static_cast<QKeySequenceEdit *>(editor);
+ const QKeySequence keySequence = keySequenceEdit->keySequence();
+ QString keySequenceString = keySequence.toString(QKeySequence::NativeText);
+ model->setData(index, keySequenceString);
+}
+//! [4]
+
+//! [5]
+void ShortcutEditorDelegate::updateEditorGeometry(QWidget *editor,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &/*index*/) const
+{
+ editor->setGeometry(option.rect);
+}
+//! [5]
diff --git a/examples/widgets/widgets/shortcuteditor/shortcuteditordelegate.h b/examples/widgets/widgets/shortcuteditor/shortcuteditordelegate.h
new file mode 100644
index 0000000000..2818438db3
--- /dev/null
+++ b/examples/widgets/widgets/shortcuteditor/shortcuteditordelegate.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2022 Laszlo Papp <lpapp@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef SHORTCUTEDITORDELEGATE_H
+#define SHORTCUTEDITORDELEGATE_H
+
+#include <QStyledItemDelegate>
+
+//! [0]
+class ShortcutEditorDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+
+public:
+ explicit ShortcutEditorDelegate(QObject *parent = nullptr);
+ ~ShortcutEditorDelegate() override = default;
+
+protected:
+ QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const override;
+
+ void setEditorData(QWidget *editor, const QModelIndex &index) const override;
+ void setModelData(QWidget *editor, QAbstractItemModel *model,
+ const QModelIndex &index) const override;
+
+ void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const override;
+
+private:
+ void commitAndCloseEditor();
+};
+//! [0]
+
+#endif
diff --git a/examples/widgets/widgets/shortcuteditor/shortcuteditormodel.cpp b/examples/widgets/widgets/shortcuteditor/shortcuteditormodel.cpp
new file mode 100644
index 0000000000..612f1fb726
--- /dev/null
+++ b/examples/widgets/widgets/shortcuteditor/shortcuteditormodel.cpp
@@ -0,0 +1,273 @@
+// Copyright (C) 2022 Laszlo Papp <lpapp@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "shortcuteditormodel.h"
+
+#include "actionmanager.h"
+#include "application.h"
+
+#include <QAction>
+#include <QModelIndex>
+
+// List of actions for all categories
+using CategoryActionsMap = QMap<QString, QList<QAction *>>;
+
+// List of categories for all contexts
+using ActionsMap = QMap<QString, CategoryActionsMap>;
+
+
+ShortcutEditorModel::ShortcutEditorModelItem::ShortcutEditorModelItem(const QList<QVariant> &data, ShortcutEditorModelItem *parent)
+ : m_itemData(data)
+ , m_parentItem(parent)
+{
+}
+
+ShortcutEditorModel::ShortcutEditorModelItem::~ShortcutEditorModelItem()
+{
+ qDeleteAll(m_childItems);
+}
+
+void ShortcutEditorModel::ShortcutEditorModelItem::appendChild(ShortcutEditorModelItem *item)
+{
+ m_childItems.push_back(item);
+}
+
+ShortcutEditorModel::ShortcutEditorModelItem *ShortcutEditorModel::ShortcutEditorModelItem::child(int row) const
+{
+ if (row < 0 || row >= m_childItems.size())
+ return nullptr;
+
+ return m_childItems.at(row);
+}
+
+int ShortcutEditorModel::ShortcutEditorModelItem::childCount() const
+{
+ return m_childItems.count();
+}
+
+int ShortcutEditorModel::ShortcutEditorModelItem::columnCount() const
+{
+ return m_itemData.count();
+}
+
+QVariant ShortcutEditorModel::ShortcutEditorModelItem::data(int column) const
+{
+ if (column < 0 || column >= m_itemData.size())
+ return QVariant();
+
+ QVariant columnVariant = m_itemData.at(column);
+ if (column != static_cast<int>(Column::Shortcut) || columnVariant.canConvert<QString>())
+ return columnVariant;
+
+ QAction *action = static_cast<QAction *>(columnVariant.value<void *>());
+ if (!action)
+ return QVariant();
+
+ QKeySequence keySequence = action->shortcut();
+ QString keySequenceString = keySequence.toString(QKeySequence::NativeText);
+ return keySequenceString;
+}
+
+ShortcutEditorModel::ShortcutEditorModelItem *ShortcutEditorModel::ShortcutEditorModelItem::parentItem() const
+{
+ return m_parentItem;
+}
+
+int ShortcutEditorModel::ShortcutEditorModelItem::row() const
+{
+ if (m_parentItem)
+ return m_parentItem->m_childItems.indexOf(const_cast<ShortcutEditorModelItem*>(this));
+
+ return 0;
+}
+
+QAction *ShortcutEditorModel::ShortcutEditorModelItem::action() const
+{
+ QVariant actionVariant = m_itemData.at(static_cast<int>(Column::Shortcut));
+ return static_cast<QAction*>(actionVariant.value<void *>());
+}
+
+
+//! [0]
+ShortcutEditorModel::ShortcutEditorModel(QObject *parent)
+ : QAbstractItemModel(parent)
+{
+ m_rootItem = new ShortcutEditorModelItem({tr("Name"), tr("Shortcut")});
+}
+//! [0]
+
+//! [1]
+ShortcutEditorModel::~ShortcutEditorModel()
+{
+ delete m_rootItem;
+}
+//! [1]
+
+//! [2]
+void ShortcutEditorModel::setActions()
+{
+ beginResetModel();
+ setupModelData(m_rootItem);
+ endResetModel();
+}
+//! [2]
+
+//! [3]
+QModelIndex ShortcutEditorModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (!hasIndex(row, column, parent))
+ return QModelIndex();
+
+ ShortcutEditorModelItem *parentItem;
+ if (!parent.isValid())
+ parentItem = m_rootItem;
+ else
+ parentItem = static_cast<ShortcutEditorModelItem*>(parent.internalPointer());
+
+ ShortcutEditorModelItem *childItem = parentItem->child(row);
+ if (childItem)
+ return createIndex(row, column, childItem);
+
+ return QModelIndex();
+}
+//! [3]
+
+//! [4]
+QModelIndex ShortcutEditorModel::parent(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return QModelIndex();
+
+ ShortcutEditorModelItem *childItem = static_cast<ShortcutEditorModelItem*>(index.internalPointer());
+ ShortcutEditorModelItem *parentItem = childItem->parentItem();
+
+ if (parentItem == m_rootItem)
+ return QModelIndex();
+
+ return createIndex(parentItem->row(), 0, parentItem);
+}
+//! [4]
+
+//! [5]
+int ShortcutEditorModel::rowCount(const QModelIndex &parent) const
+{
+ ShortcutEditorModelItem *parentItem;
+ if (parent.column() > 0)
+ return 0;
+
+ if (!parent.isValid())
+ parentItem = m_rootItem;
+ else
+ parentItem = static_cast<ShortcutEditorModelItem*>(parent.internalPointer());
+
+ return parentItem->childCount();
+}
+//! [5]
+
+//! [6]
+int ShortcutEditorModel::columnCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return static_cast<ShortcutEditorModelItem*>(parent.internalPointer())->columnCount();
+
+ return m_rootItem->columnCount();
+}
+//! [6]
+
+//! [7]
+QVariant ShortcutEditorModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (role != Qt::DisplayRole && role != Qt::EditRole)
+ return QVariant();
+
+ ShortcutEditorModelItem *item = static_cast<ShortcutEditorModelItem*>(index.internalPointer());
+ return item->data(index.column());
+}
+//! [7]
+
+//! [8]
+Qt::ItemFlags ShortcutEditorModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return Qt::NoItemFlags;
+
+ Qt::ItemFlags modelFlags = QAbstractItemModel::flags(index);
+ if (index.column() == static_cast<int>(Column::Shortcut))
+ modelFlags |= Qt::ItemIsEditable;
+
+ return modelFlags;
+}
+//! [8]
+
+//! [9]
+QVariant ShortcutEditorModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+ return m_rootItem->data(section);
+ }
+
+ return QVariant();
+}
+//! [9]
+
+//! [10]
+void ShortcutEditorModel::setupModelData(ShortcutEditorModelItem *parent)
+{
+ ActionsMap actionsMap;
+ Application *application = static_cast<Application *>(QCoreApplication::instance());
+ ActionManager *actionManager = application->actionManager();
+ const QList<QAction *> registeredActions = actionManager->registeredActions();
+ for (QAction *action : registeredActions) {
+ QString context = actionManager->contextForAction(action);
+ QString category = actionManager->categoryForAction(action);
+ actionsMap[context][category].append(action);
+ }
+
+ QAction *nullAction = nullptr;
+ const QString contextIdPrefix = "root";
+ // Go through each context, one context - many categories each iteration
+ for (const auto &contextLevel : actionsMap.keys()) {
+ ShortcutEditorModelItem *contextLevelItem = new ShortcutEditorModelItem({contextLevel, QVariant::fromValue(nullAction)}, parent);
+ parent->appendChild(contextLevelItem);
+
+ // Go through each category, one category - many actions each iteration
+ for (const auto &categoryLevel : actionsMap[contextLevel].keys()) {
+ ShortcutEditorModelItem *categoryLevelItem = new ShortcutEditorModelItem({categoryLevel, QVariant::fromValue(nullAction)}, contextLevelItem);
+ contextLevelItem->appendChild(categoryLevelItem);
+ for (QAction *action : actionsMap[contextLevel][categoryLevel]) {
+ QString name = action->text();
+ if (name.isEmpty() || !action)
+ continue;
+
+ ShortcutEditorModelItem *actionLevelItem = new ShortcutEditorModelItem({name, QVariant::fromValue(reinterpret_cast<void *>(action))}, categoryLevelItem);
+ categoryLevelItem->appendChild(actionLevelItem);
+ }
+ }
+ }
+}
+//! [10]
+
+//! [11]
+bool ShortcutEditorModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (role == Qt::EditRole && index.column() == static_cast<int>(Column::Shortcut)) {
+ QString keySequenceString = value.toString();
+ ShortcutEditorModelItem *item = static_cast<ShortcutEditorModelItem *>(index.internalPointer());
+ QAction *itemAction = item->action();
+ if (itemAction) {
+ if (keySequenceString == itemAction->shortcut().toString(QKeySequence::NativeText))
+ return true;
+ itemAction->setShortcut(keySequenceString);
+ }
+ Q_EMIT dataChanged(index, index);
+
+ if (keySequenceString.isEmpty())
+ return true;
+ }
+
+ return QAbstractItemModel::setData(index, value, role);
+}
+//! [11]
diff --git a/examples/widgets/widgets/shortcuteditor/shortcuteditormodel.h b/examples/widgets/widgets/shortcuteditor/shortcuteditormodel.h
new file mode 100644
index 0000000000..c687bb4129
--- /dev/null
+++ b/examples/widgets/widgets/shortcuteditor/shortcuteditormodel.h
@@ -0,0 +1,71 @@
+// Copyright (C) 2022 Laszlo Papp <lpapp@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef SHORTCUTEDITORMODEL_H
+#define SHORTCUTEDITORMODEL_H
+
+#include <QAbstractItemModel>
+#include <QList>
+#include <QVariant>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+QT_END_NAMESPACE
+
+enum class Column : uint8_t {
+ Name,
+ Shortcut
+};
+
+//! [0]
+class ShortcutEditorModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+ class ShortcutEditorModelItem
+ {
+ public:
+ explicit ShortcutEditorModelItem(const QList<QVariant> &data,
+ ShortcutEditorModelItem *parentItem = nullptr);
+ ~ShortcutEditorModelItem();
+
+ void appendChild(ShortcutEditorModelItem *child);
+
+ ShortcutEditorModelItem *child(int row) const;
+ int childCount() const;
+ int columnCount() const;
+ QVariant data(int column) const;
+ int row() const;
+ ShortcutEditorModelItem *parentItem() const;
+ QAction *action() const;
+
+ private:
+ QList<ShortcutEditorModelItem *> m_childItems;
+ QList<QVariant> m_itemData;
+ ShortcutEditorModelItem *m_parentItem;
+ };
+
+public:
+ explicit ShortcutEditorModel(QObject *parent = nullptr);
+ ~ShortcutEditorModel() override;
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
+ QModelIndex parent(const QModelIndex &index) const override;
+ int rowCount(const QModelIndex &index = QModelIndex()) const override;
+ int columnCount(const QModelIndex &index = QModelIndex()) const override;
+
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
+
+ void setActions();
+
+private:
+ void setupModelData(ShortcutEditorModelItem *parent);
+
+ ShortcutEditorModelItem *m_rootItem;
+};
+//! [0]
+
+#endif
diff --git a/examples/widgets/widgets/shortcuteditor/shortcuteditorwidget.cpp b/examples/widgets/widgets/shortcuteditor/shortcuteditorwidget.cpp
new file mode 100644
index 0000000000..3e8a027f38
--- /dev/null
+++ b/examples/widgets/widgets/shortcuteditor/shortcuteditorwidget.cpp
@@ -0,0 +1,33 @@
+// Copyright (C) 2022 Laszlo Papp <lpapp@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "shortcuteditorwidget.h"
+
+#include "shortcuteditordelegate.h"
+#include "shortcuteditormodel.h"
+
+#include <QHeaderView>
+#include <QTreeView>
+#include <QVBoxLayout>
+
+//! [0]
+ShortcutEditorWidget::ShortcutEditorWidget(QWidget *parent)
+ : QWidget(parent)
+{
+ m_model = new ShortcutEditorModel(this);
+ m_delegate = new ShortcutEditorDelegate(this);
+ m_view = new QTreeView(this);
+ m_view->setModel(m_model);
+ m_view->setItemDelegateForColumn(static_cast<int>(Column::Shortcut), m_delegate);
+ m_view->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
+ m_view->setAllColumnsShowFocus(true);
+ m_view->header()->resizeSection(0, 250);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->addWidget(m_view);
+ setLayout(layout);
+
+ m_model->setActions();
+}
+//! [0]
diff --git a/examples/widgets/widgets/shortcuteditor/shortcuteditorwidget.h b/examples/widgets/widgets/shortcuteditor/shortcuteditorwidget.h
new file mode 100644
index 0000000000..44735e65e2
--- /dev/null
+++ b/examples/widgets/widgets/shortcuteditor/shortcuteditorwidget.h
@@ -0,0 +1,32 @@
+// Copyright (C) 2022 Laszlo Papp <lpapp@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef SHORTCUTEDITORWIDGET_H
+#define SHORTCUTEDITORWIDGET_H
+
+#include <QWidget>
+
+class ShortcutEditorDelegate;
+class ShortcutEditorModel;
+
+QT_BEGIN_NAMESPACE
+class QTreeView;
+QT_END_NAMESPACE
+
+//! [0]
+class ShortcutEditorWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit ShortcutEditorWidget(QWidget *parent = nullptr);
+ ~ShortcutEditorWidget() override = default;
+
+private:
+ ShortcutEditorDelegate *m_delegate;
+ ShortcutEditorModel *m_model;
+ QTreeView *m_view;
+};
+//! [0]
+
+#endif