Merge pull request #587 from ispyisail/feature-configurable-shortcuts

Add configurable shortcuts: Shortcuts preferences page + app-wide registry
This commit is contained in:
Laurent Trinques
2026-08-01 07:23:56 +02:00
committed by GitHub
14 changed files with 665 additions and 96 deletions
+4
View File
@@ -248,6 +248,8 @@ set(QET_SRC_FILES
${QET_DIR}/sources/qtextorientationwidget.h
${QET_DIR}/sources/recentfiles.cpp
${QET_DIR}/sources/recentfiles.h
${QET_DIR}/sources/shortcutmanager.cpp
${QET_DIR}/sources/shortcutmanager.h
${QET_DIR}/sources/titleblockcell.cpp
${QET_DIR}/sources/titleblockcell.h
${QET_DIR}/sources/titleblockproperties.cpp
@@ -732,6 +734,8 @@ set(QET_SRC_FILES
${QET_DIR}/sources/ui/configpage/projectconfigpages.h
${QET_DIR}/sources/ui/configpage/guidespropertieswidget.cpp
${QET_DIR}/sources/ui/configpage/guidespropertieswidget.h
${QET_DIR}/sources/ui/configpage/shortcutsconfigpage.cpp
${QET_DIR}/sources/ui/configpage/shortcutsconfigpage.h
${QET_DIR}/sources/undocommand/addelementtextcommand.cpp
${QET_DIR}/sources/undocommand/addelementtextcommand.h
@@ -20,6 +20,7 @@
#include "../../diagram.h"
#include "../../diagramview.h"
#include "../../qetapp.h"
#include "../../shortcutmanager.h"
#include "../../titleblockproperties.h"
#include "../../ui/projectpropertiesdialog.h"
#include "../numerotationcontext.h"
@@ -151,7 +152,8 @@ void AutoNumberingDockWidget::setProject(QETProject *project,
//Set Combobox Context
setContext();
ui->m_configure_pb->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_P);
ShortcutManager::instance().registerAction(ui->m_configure_pb, "autonum.configure",
tr("Autonumérotation"), Qt::CTRL | Qt::SHIFT | Qt::Key_P);
}
/**
+29 -28
View File
@@ -19,6 +19,7 @@
#include "ui_qetelementeditor.h"
#include "../elementscene.h"
#include "../../qeticons.h"
#include "../../shortcutmanager.h"
#include "../elementview.h"
#include "../../qetmessagebox.h"
#include "../../qetapp.h"
@@ -978,32 +979,32 @@ void QETElementEditor::setupActions()
m_redo_action = m_elmt_scene -> undoStack().createRedoAction(this, tr("Refaire"));
m_undo_action -> setIcon(QET::Icons::EditUndo);
m_redo_action -> setIcon(QET::Icons::EditRedo);
m_undo_action -> setShortcuts(QKeySequence::Undo);
m_redo_action -> setShortcuts(QKeySequence::Redo);
ShortcutManager::instance().registerAction(m_undo_action, "elementeditor.undo", tr("Éditeur d'élément"), QKeySequence::Undo);
ShortcutManager::instance().registerAction(m_redo_action, "elementeditor.redo", tr("Éditeur d'élément"), QKeySequence::Redo);
ui->m_undo_toolbar->addAction(m_undo_action);
ui->m_undo_toolbar->addAction(m_redo_action);
ui->m_new_action -> setShortcut(QKeySequence::New);
ui->m_open_action -> setShortcut(QKeySequence::Open);
ui->m_open_from_file_action -> setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_O);
ui->m_save_action -> setShortcut(QKeySequence::Save);
ui->m_save_as_file_action -> setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_S);
ui->m_select_all_act -> setShortcut(QKeySequence::SelectAll);
ui->m_deselect_all_action -> setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_A);
ui->m_revert_selection_action -> setShortcut(Qt::CTRL | Qt::Key_I);
ui->m_cut_action -> setShortcut(QKeySequence::Cut);
ui->m_copy_action -> setShortcut(QKeySequence::Copy);
ui->m_paste_action -> setShortcut(QKeySequence::Paste);
ui->m_paste_in_area_action -> setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_V);
ui->m_edit_names_action -> setShortcut(Qt::CTRL | Qt::Key_E);
ui->m_edit_author_action -> setShortcut(Qt::CTRL | Qt::Key_Y);
ShortcutManager::instance().registerAction(ui->m_new_action, "elementeditor.new", tr("Éditeur d'élément"), QKeySequence::New);
ShortcutManager::instance().registerAction(ui->m_open_action, "elementeditor.open", tr("Éditeur d'élément"), QKeySequence::Open);
ShortcutManager::instance().registerAction(ui->m_open_from_file_action, "elementeditor.open_from_file", tr("Éditeur d'élément"), Qt::CTRL | Qt::SHIFT | Qt::Key_O);
ShortcutManager::instance().registerAction(ui->m_save_action, "elementeditor.save", tr("Éditeur d'élément"), QKeySequence::Save);
ShortcutManager::instance().registerAction(ui->m_save_as_file_action, "elementeditor.save_as_file", tr("Éditeur d'élément"), Qt::CTRL | Qt::SHIFT | Qt::Key_S);
ShortcutManager::instance().registerAction(ui->m_select_all_act, "elementeditor.select_all", tr("Éditeur d'élément"), QKeySequence::SelectAll);
ShortcutManager::instance().registerAction(ui->m_deselect_all_action, "elementeditor.deselect_all", tr("Éditeur d'élément"), Qt::CTRL | Qt::SHIFT | Qt::Key_A);
ShortcutManager::instance().registerAction(ui->m_revert_selection_action, "elementeditor.revert_selection", tr("Éditeur d'élément"), Qt::CTRL | Qt::Key_I);
ShortcutManager::instance().registerAction(ui->m_cut_action, "elementeditor.cut", tr("Éditeur d'élément"), QKeySequence::Cut);
ShortcutManager::instance().registerAction(ui->m_copy_action, "elementeditor.copy", tr("Éditeur d'élément"), QKeySequence::Copy);
ShortcutManager::instance().registerAction(ui->m_paste_action, "elementeditor.paste", tr("Éditeur d'élément"), QKeySequence::Paste);
ShortcutManager::instance().registerAction(ui->m_paste_in_area_action, "elementeditor.paste_in_area", tr("Éditeur d'élément"), Qt::CTRL | Qt::SHIFT | Qt::Key_V);
ShortcutManager::instance().registerAction(ui->m_edit_names_action, "elementeditor.edit_names", tr("Éditeur d'élément"), Qt::CTRL | Qt::Key_E);
ShortcutManager::instance().registerAction(ui->m_edit_author_action, "elementeditor.edit_author", tr("Éditeur d'élément"), Qt::CTRL | Qt::Key_Y);
#ifdef Q_OS_MAC
ui->m_delete_action -> setShortcut(Qt::Key_Backspace);
ui->m_quit_action -> setShortcut(Qt::CTRL | Qt::Key_W);
ShortcutManager::instance().registerAction(ui->m_delete_action, "elementeditor.delete", tr("Éditeur d'élément"), Qt::Key_Backspace);
ShortcutManager::instance().registerAction(ui->m_quit_action, "elementeditor.quit", tr("Éditeur d'élément"), Qt::CTRL | Qt::Key_W);
#else
ui->m_delete_action -> setShortcut(Qt::Key_Delete);
ui->m_quit_action -> setShortcut(Qt::CTRL | Qt::Key_Q);
ShortcutManager::instance().registerAction(ui->m_delete_action, "elementeditor.delete", tr("Éditeur d'élément"), Qt::Key_Delete);
ShortcutManager::instance().registerAction(ui->m_quit_action, "elementeditor.quit", tr("Éditeur d'élément"), Qt::CTRL | Qt::Key_Q);
#endif
//Depth action
@@ -1019,27 +1020,27 @@ void QETElementEditor::setupActions()
addToolBar(Qt::TopToolBarArea, depth_toolbar);
//Rotate action
ui->m_rotate_action -> setShortcut(Qt::Key_Space);
ShortcutManager::instance().registerAction(ui->m_rotate_action, "elementeditor.rotate", tr("Éditeur d'élément"), Qt::Key_Space);
connect(ui->m_rotate_action, &QAction::triggered, [this]() {this -> elementScene() -> undoStack().push(new RotateElementsCommand(this->elementScene()));});
//Rotate Fine action = rotate with smaller inkrement
ui->m_rotateFine_action -> setShortcut(Qt::CTRL | Qt::Key_Space);
ShortcutManager::instance().registerAction(ui->m_rotateFine_action, "elementeditor.rotate_fine", tr("Éditeur d'élément"), Qt::CTRL | Qt::Key_Space);
connect(ui->m_rotateFine_action, &QAction::triggered, [this]() {this -> elementScene() -> undoStack().push(new RotateFineElementsCommand(this->elementScene()));});
//Flip action
ui->m_flip_action -> setShortcut(Qt::Key_F);
ShortcutManager::instance().registerAction(ui->m_flip_action, "elementeditor.flip", tr("Éditeur d'élément"), Qt::Key_F);
connect(ui->m_flip_action, &QAction::triggered, [this]() {this -> elementScene() -> undoStack().push(new FlipElementsCommand(this->elementScene()));});
//Mirror action
ui->m_mirror_action -> setShortcut(Qt::Key_M);
ShortcutManager::instance().registerAction(ui->m_mirror_action, "elementeditor.mirror", tr("Éditeur d'élément"), Qt::Key_M);
connect(ui->m_mirror_action, &QAction::triggered, [this]() {this -> elementScene() -> undoStack().push(new MirrorElementsCommand(this->elementScene()));});
//Zoom action
ui->m_zoom_in_action -> setShortcut(QKeySequence::ZoomIn);
ui->m_zoom_out_action -> setShortcut(QKeySequence::ZoomOut);
ui->m_zoom_fit_best_action -> setShortcut(Qt::CTRL | Qt::Key_9);
ui->m_zoom_original_action -> setShortcut(Qt::CTRL | Qt::Key_0);
ShortcutManager::instance().registerAction(ui->m_zoom_in_action, "elementeditor.zoom_in", tr("Éditeur d'élément"), QKeySequence::ZoomIn);
ShortcutManager::instance().registerAction(ui->m_zoom_out_action, "elementeditor.zoom_out", tr("Éditeur d'élément"), QKeySequence::ZoomOut);
ShortcutManager::instance().registerAction(ui->m_zoom_fit_best_action, "elementeditor.zoom_fit_best", tr("Éditeur d'élément"), Qt::CTRL | Qt::Key_9);
ShortcutManager::instance().registerAction(ui->m_zoom_original_action, "elementeditor.zoom_original", tr("Éditeur d'élément"), Qt::CTRL | Qt::Key_0);
//Add primitive actions
m_add_part_action_grp = new QActionGroup(this);
+9 -8
View File
@@ -22,6 +22,7 @@
#include "qetapp.h"
#include "qeticons.h"
#include "qetproject.h"
#include "shortcutmanager.h"
#include "titleblock/templatedeleter.h"
#include <QFileInfo>
#include <QMessageBox>
@@ -74,14 +75,14 @@ ElementsPanelWidget::ElementsPanelWidget(QWidget *parent) : QWidget(parent) {
tbt_remove = new QAction(QET::Icons::TitleBlock, tr("Supprimer ce modèle"), this);
prj_del_diagram -> setShortcut(QKeySequence(Qt::Key_Delete));
prj_move_diagram_up -> setShortcut(QKeySequence(Qt::Key_F3));
prj_move_diagram_down -> setShortcut(QKeySequence(Qt::Key_F4));
prj_move_diagram_top -> setShortcut(QKeySequence(Qt::Key_F5));
prj_move_diagram_downx10 -> setShortcut(QKeySequence(Qt::Key_F6));
prj_move_diagram_downx100 -> setShortcut(QKeySequence(Qt::Key_F7));
prj_move_diagram_upx10 -> setShortcut(QKeySequence(Qt::Key_F8));
prj_move_diagram_upx100 -> setShortcut(QKeySequence(Qt::Key_F9));
ShortcutManager::instance().registerAction(prj_del_diagram, "panel.delete_diagram", tr("Panneau des éléments"), QKeySequence(Qt::Key_Delete));
ShortcutManager::instance().registerAction(prj_move_diagram_up, "panel.move_diagram_up", tr("Panneau des éléments"), QKeySequence(Qt::Key_F3));
ShortcutManager::instance().registerAction(prj_move_diagram_down, "panel.move_diagram_down", tr("Panneau des éléments"), QKeySequence(Qt::Key_F4));
ShortcutManager::instance().registerAction(prj_move_diagram_top, "panel.move_diagram_top", tr("Panneau des éléments"), QKeySequence(Qt::Key_F5));
ShortcutManager::instance().registerAction(prj_move_diagram_downx10, "panel.move_diagram_downx10", tr("Panneau des éléments"), QKeySequence(Qt::Key_F6));
ShortcutManager::instance().registerAction(prj_move_diagram_downx100, "panel.move_diagram_downx100", tr("Panneau des éléments"), QKeySequence(Qt::Key_F7));
ShortcutManager::instance().registerAction(prj_move_diagram_upx10, "panel.move_diagram_upx10", tr("Panneau des éléments"), QKeySequence(Qt::Key_F8));
ShortcutManager::instance().registerAction(prj_move_diagram_upx100, "panel.move_diagram_upx100", tr("Panneau des éléments"), QKeySequence(Qt::Key_F9));
+5 -4
View File
@@ -17,6 +17,7 @@
*/
#include "qet.h"
#include "qeticons.h"
#include "shortcutmanager.h"
#include <limits>
#include <QGraphicsSceneContextMenuEvent>
@@ -785,10 +786,10 @@ QActionGroup *QET::depthActionGroup(QObject *parent)
edit_lower ->setStatusTip(QObject::tr("Éloigne la ou les sélections"));
edit_backward->setStatusTip(QObject::tr("Envoie en arrière plan la ou les sélections"));
edit_raise ->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Up);
edit_lower ->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Down);
edit_backward->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_End);
edit_forward ->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Home);
ShortcutManager::instance().registerAction(edit_raise, "depth.raise", QObject::tr("Profondeur"), Qt::CTRL | Qt::SHIFT | Qt::Key_Up);
ShortcutManager::instance().registerAction(edit_lower, "depth.lower", QObject::tr("Profondeur"), Qt::CTRL | Qt::SHIFT | Qt::Key_Down);
ShortcutManager::instance().registerAction(edit_backward, "depth.backward", QObject::tr("Profondeur"), Qt::CTRL | Qt::SHIFT | Qt::Key_End);
ShortcutManager::instance().registerAction(edit_forward, "depth.forward", QObject::tr("Profondeur"), Qt::CTRL | Qt::SHIFT | Qt::Key_Home);
edit_forward ->setData(QET::BringForward);
edit_raise ->setData(QET::Raise);
+2
View File
@@ -36,6 +36,7 @@
#include "titleblocktemplate.h"
#include "ui/aboutqetdialog.h"
#include "ui/configpage/generalconfigurationpage.h"
#include "ui/configpage/shortcutsconfigpage.h"
#include "machine_info.h"
#include "TerminalStrip/ui/terminalstripeditorwindow.h"
#include "qetversion.h"
@@ -2051,6 +2052,7 @@ void QETApp::configureQET()
cd.addPage(new NewDiagramPage());
cd.addPage(new ExportConfigPage());
cd.addPage(new PrintConfigPage());
cd.addPage(new ShortcutsConfigPage());
// associates the dialog with a possible parent widget
// associe le dialogue a un eventuel widget parent
+32 -31
View File
@@ -38,6 +38,7 @@
#include "qeticons.h"
#include "qetmessagebox.h"
#include "recentfiles.h"
#include "shortcutmanager.h"
#include "ui/bomexportdialog.h"
#include "ui/diagrampropertieseditordockwidget.h"
#include "ui/backupdialog.h"
@@ -275,7 +276,7 @@ void QETDiagramEditor::setUpActions()
{
//Export to another file type (jpeg, dxf etc...)
m_export_to_images = new QAction(QET::Icons::DocumentExport, tr("E&xporter"), this);
m_export_to_images->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_X);
ShortcutManager::instance().registerAction(m_export_to_images, "diagrameditor.export_to_images", tr("Éditeur de schémas"), Qt::CTRL | Qt::SHIFT | Qt::Key_X);
m_export_to_images->setStatusTip(tr("Exporte le folio courant dans un autre format", "status bar tip"));
connect(m_export_to_images, &QAction::triggered, [this]() {
ProjectView *current_project = currentProjectView();
@@ -286,7 +287,7 @@ void QETDiagramEditor::setUpActions()
//Print
m_print = new QAction(QET::Icons::DocumentPrint, tr("Imprimer"), this);
m_print->setShortcut(QKeySequence::Print);
ShortcutManager::instance().registerAction(m_print, "diagrameditor.print", tr("Éditeur de schémas"), QKeySequence::Print);
m_print->setStatusTip(tr("Imprime un ou plusieurs folios du projet courant", "status bar tip"));
connect(m_print, &QAction::triggered, [this]() {
auto project = currentProject();
@@ -307,19 +308,19 @@ void QETDiagramEditor::setUpActions()
//Quit editor
m_quit_editor = new QAction(QET::Icons::ApplicationExit, tr("&Quitter"), this);
m_quit_editor->setShortcut(Qt::CTRL | Qt::Key_Q);
ShortcutManager::instance().registerAction(m_quit_editor, "diagrameditor.quit", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_Q);
m_quit_editor->setStatusTip(tr("Ferme l'application QElectroTech", "status bar tip"));
connect(m_quit_editor, &QAction::triggered, this, &QETDiagramEditor::close);
//Undo
undo = undo_group.createUndoAction(this, tr("Annuler"));
undo->setIcon(QET::Icons::EditUndo);
undo->setShortcut(QKeySequence::Undo);
ShortcutManager::instance().registerAction(undo, "diagrameditor.undo", tr("Éditeur de schémas"), QKeySequence::Undo);
undo->setStatusTip(tr("Annule l'action précédente", "status bar tip"));
//Redo
redo = undo_group.createRedoAction(this, tr("Refaire"));
redo->setIcon(QET::Icons::EditRedo);
redo->setShortcut(QKeySequence::Redo);
ShortcutManager::instance().registerAction(redo, "diagrameditor.redo", tr("Éditeur de schémas"), QKeySequence::Redo);
redo->setStatusTip(tr("Restaure l'action annulée", "status bar tip"));
//cut copy past
@@ -327,9 +328,9 @@ void QETDiagramEditor::setUpActions()
m_copy = new QAction(QET::Icons::EditCopy, tr("Cop&ier"), this);
m_paste = new QAction(QET::Icons::EditPaste, tr("C&oller"), this);
m_cut -> setShortcut(QKeySequence::Cut);
m_copy -> setShortcut(QKeySequence::Copy);
m_paste -> setShortcut(QKeySequence::Paste);
ShortcutManager::instance().registerAction(m_cut, "diagrameditor.cut", tr("Éditeur de schémas"), QKeySequence::Cut);
ShortcutManager::instance().registerAction(m_copy, "diagrameditor.copy", tr("Éditeur de schémas"), QKeySequence::Copy);
ShortcutManager::instance().registerAction(m_paste, "diagrameditor.paste", tr("Éditeur de schémas"), QKeySequence::Paste);
m_cut -> setStatusTip(tr("Transfère les éléments sélectionnés dans le presse-papier", "status bar tip"));
m_copy -> setStatusTip(tr("Copie les éléments sélectionnés dans le presse-papier", "status bar tip"));
@@ -350,7 +351,7 @@ void QETDiagramEditor::setUpActions()
//Reset conductor path
m_conductor_reset = new QAction(QET::Icons::ConductorSettings, tr("Réinitialiser les conducteurs"), this);
m_conductor_reset->setShortcut(Qt::CTRL | Qt::Key_K);
ShortcutManager::instance().registerAction(m_conductor_reset, "diagrameditor.conductor_reset", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_K);
m_conductor_reset->setStatusTip(tr("Recalcule les chemins des conducteurs sans tenir compte des modifications", "status bar tip"));
connect(m_conductor_reset, &QAction::triggered, [this]() {
if (DiagramView *dv = currentDiagramView())
@@ -404,7 +405,7 @@ void QETDiagramEditor::setUpActions()
//Edit current diagram properties
m_edit_diagram_properties = new QAction(QET::Icons::DialogInformation, tr("Propriétés du folio"), this);
m_edit_diagram_properties->setShortcut(Qt::CTRL | Qt::Key_L);
ShortcutManager::instance().registerAction(m_edit_diagram_properties, "diagrameditor.edit_diagram_properties", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_L);
m_edit_diagram_properties -> setStatusTip(tr("Édite les propriétés du folio (dimensions, informations du cartouche, propriétés des conducteurs...)", "status bar tip"));
connect(m_edit_diagram_properties, &QAction::triggered, [this]() {
if (ProjectView *project_view = currentProjectView())
@@ -422,7 +423,7 @@ void QETDiagramEditor::setUpActions()
//Add new folio to current project
m_project_add_diagram = new QAction(QET::Icons::DiagramAdd, tr("Ajouter un folio"), this);
m_project_add_diagram->setShortcut(Qt::CTRL | Qt::Key_T);
ShortcutManager::instance().registerAction(m_project_add_diagram, "diagrameditor.project_add_diagram", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_T);
connect(m_project_add_diagram, &QAction::triggered, [this]() {
if (ProjectView *current_project = currentProjectView()) {
current_project->project()->addNewDiagram();
@@ -566,12 +567,12 @@ void QETDiagramEditor::setUpActions()
//Navigate next/previous project
m_next_window = new QAction(tr("Projet suivant"), this);
m_next_window->setShortcut(QKeySequence::NextChild);
ShortcutManager::instance().registerAction(m_next_window, "diagrameditor.next_window", tr("Éditeur de schémas"), QKeySequence::NextChild);
m_next_window->setStatusTip(tr("Active le projet suivant", "status bar tip"));
connect(m_next_window, &QAction::triggered, &m_workspace, &QMdiArea::activateNextSubWindow);
m_previous_window = new QAction(tr("Projet précédent"), this);
m_previous_window->setShortcut(QKeySequence::PreviousChild);
ShortcutManager::instance().registerAction(m_previous_window, "diagrameditor.previous_window", tr("Éditeur de schémas"), QKeySequence::PreviousChild);
m_previous_window->setStatusTip(tr("Active le projet précédent", "status bar tip"));
connect(m_previous_window, &QAction::triggered, &m_workspace, &QMdiArea::activatePreviousSubWindow);
@@ -582,11 +583,11 @@ void QETDiagramEditor::setUpActions()
m_save_file_as = m_file_actions_group.addAction(QET::Icons::DocumentSaveAs, tr("Enregistrer sous"));
m_close_file = m_file_actions_group.addAction(QET::Icons::ProjectClose, tr("&Fermer"));
new_file ->setShortcut(QKeySequence::New);
open_file ->setShortcut(QKeySequence::Open);
m_close_file ->setShortcut(QKeySequence::Close);
m_save_file ->setShortcut(QKeySequence::Save);
m_save_file_as ->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_S);
ShortcutManager::instance().registerAction(new_file, "diagrameditor.new_file", tr("Éditeur de schémas"), QKeySequence::New);
ShortcutManager::instance().registerAction(open_file, "diagrameditor.open_file", tr("Éditeur de schémas"), QKeySequence::Open);
ShortcutManager::instance().registerAction(m_close_file, "diagrameditor.close_file", tr("Éditeur de schémas"), QKeySequence::Close);
ShortcutManager::instance().registerAction(m_save_file, "diagrameditor.save_file", tr("Éditeur de schémas"), QKeySequence::Save);
ShortcutManager::instance().registerAction(m_save_file_as, "diagrameditor.save_file_as", tr("Éditeur de schémas"), Qt::CTRL | Qt::SHIFT | Qt::Key_S);
new_file ->setStatusTip( tr("Crée un nouveau projet", "status bar tip") );
open_file ->setStatusTip( tr("Ouvre un projet existant", "status bar tip") );
@@ -630,10 +631,10 @@ void QETDiagramEditor::setUpActions()
m_edit_selection = m_selection_actions_group.addAction( QET::Icons::ElementEdit, tr("Éditer l'item sélectionné") );
m_group_selected_texts = m_selection_actions_group.addAction( QET::Icons::textGroup, tr("Grouper les textes sélectionnés"));
m_delete_selection->setShortcut(Qt::Key_Delete);
m_rotate_selection->setShortcut(Qt::Key_Space);
m_rotate_texts ->setShortcut(Qt::CTRL | Qt::Key_Space);
m_edit_selection ->setShortcut(Qt::CTRL | Qt::Key_E);
ShortcutManager::instance().registerAction(m_delete_selection, "diagrameditor.delete_selection", tr("Éditeur de schémas"), Qt::Key_Delete);
ShortcutManager::instance().registerAction(m_rotate_selection, "diagrameditor.rotate_selection", tr("Éditeur de schémas"), Qt::Key_Space);
ShortcutManager::instance().registerAction(m_rotate_texts, "diagrameditor.rotate_texts", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_Space);
ShortcutManager::instance().registerAction(m_edit_selection, "diagrameditor.edit_selection", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_E);
m_delete_selection->setStatusTip( tr("Enlève les éléments sélectionnés du folio", "status bar tip"));
m_rotate_selection->setStatusTip( tr("Pivote les éléments et textes sélectionnés", "status bar tip"));
@@ -654,9 +655,9 @@ void QETDiagramEditor::setUpActions()
QAction *select_nothing = m_select_actions_group.addAction( QET::Icons::EditSelectNone, tr("Désélectionner tout") );
QAction *select_invert = m_select_actions_group.addAction( QET::Icons::EditSelectInvert, tr("Inverser la sélection") );
select_all ->setShortcut(QKeySequence::SelectAll);
select_nothing->setShortcut(QKeySequence::Deselect);
select_invert ->setShortcut(Qt::CTRL | Qt::Key_I);
ShortcutManager::instance().registerAction(select_all, "diagrameditor.select_all", tr("Éditeur de schémas"), QKeySequence::SelectAll);
ShortcutManager::instance().registerAction(select_nothing, "diagrameditor.select_nothing", tr("Éditeur de schémas"), QKeySequence::Deselect);
ShortcutManager::instance().registerAction(select_invert, "diagrameditor.select_invert", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_I);
select_all ->setStatusTip( tr("Sélectionne tous les éléments du folio", "status bar tip") );
select_nothing->setStatusTip( tr("Désélectionne tous les éléments du folio", "status bar tip") );
@@ -676,11 +677,11 @@ void QETDiagramEditor::setUpActions()
QAction *zoom_reset = m_zoom_actions_group.addAction( QET::Icons::ZoomOriginal, tr("Pas de zoom"));
m_zoom_action_toolBar << zoom_content << zoom_fit << zoom_reset;
zoom_in ->setShortcut(QKeySequence::ZoomIn);
zoom_out ->setShortcut(QKeySequence::ZoomOut);
zoom_content->setShortcut(Qt::CTRL | Qt::Key_8);
zoom_fit ->setShortcut(Qt::CTRL | Qt::Key_9);
zoom_reset ->setShortcut(Qt::CTRL | Qt::Key_0);
ShortcutManager::instance().registerAction(zoom_in, "diagrameditor.zoom_in", tr("Éditeur de schémas"), QKeySequence::ZoomIn);
ShortcutManager::instance().registerAction(zoom_out, "diagrameditor.zoom_out", tr("Éditeur de schémas"), QKeySequence::ZoomOut);
ShortcutManager::instance().registerAction(zoom_content, "diagrameditor.zoom_content", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_8);
ShortcutManager::instance().registerAction(zoom_fit, "diagrameditor.zoom_fit", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_9);
ShortcutManager::instance().registerAction(zoom_reset, "diagrameditor.zoom_reset", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_0);
zoom_in ->setStatusTip(tr("Agrandit le folio", "status bar tip"));
zoom_out ->setStatusTip(tr("Rétrécit le folio", "status bar tip"));
@@ -738,7 +739,7 @@ void QETDiagramEditor::setUpActions()
});
m_find = new QAction(tr("Chercher/remplacer"), this);
m_find->setShortcut(QKeySequence::Find);
ShortcutManager::instance().registerAction(m_find, "diagrameditor.find", tr("Éditeur de schémas"), QKeySequence::Find);
connect(m_find, &QAction::triggered, [this]()
{
if (auto animator = m_search_and_replace_widget.findChild<QWidgetAnimation *>("search and replace animator")) {
+3 -2
View File
@@ -24,6 +24,7 @@
#include "qetmainwindow.h"
#include "qeticons.h"
#include "shortcutmanager.h"
#include "qetapp.h"
#include "qetdiagrameditor.h"
#include "projectview.h"
@@ -98,7 +99,7 @@ void QETMainWindow::initCommonActions()
QDesktopServices::openUrl(QUrl(link));
});
manual_online_ -> setShortcut(Qt::Key_F1);
ShortcutManager::instance().registerAction(manual_online_, "mainwindow.manual_online", tr("Général"), Qt::Key_F1);
youtube_ = new QAction(QET::Icons::QETVideo, tr("Chaine Youtube"), this);
youtube_ -> setStatusTip(tr("Lance le navigateur par défaut vers la chaine Youtube de QElectroTech", "status bar tip"));
@@ -220,7 +221,7 @@ void QETMainWindow::updateFullScreenAction()
fullscreen_action_ -> setIcon(QET::Icons::FullScreenEnter);
fullscreen_action_ -> setStatusTip(tr("Affiche QElectroTech en mode plein écran", "status bar tip"));
}
fullscreen_action_ -> setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_F);
ShortcutManager::instance().registerAction(fullscreen_action_, "mainwindow.fullscreen", tr("Général"), Qt::CTRL | Qt::SHIFT | Qt::Key_F);
}
/**
+4 -3
View File
@@ -47,6 +47,7 @@
#include "richtexteditor_p.h"
#include "ui_addlinkdialog.h"
#include "../shortcutmanager.h"
//#include <QtDesigner/QDesignerFormEditorInterface>
@@ -461,19 +462,19 @@ RichTextEditorToolBar::RichTextEditorToolBar(RichTextEditor *editor,
m_bold_action = createCheckableAction(
QIcon(":/ico/32x32/format-text-bold.png"),
tr("Texte en gras"), editor, SLOT(setFontBold(bool)), this);
m_bold_action->setShortcut(Qt::CTRL | Qt::Key_B);
ShortcutManager::instance().registerAction(m_bold_action, "richtext.bold", tr("Éditeur de texte"), Qt::CTRL | Qt::Key_B);
addAction(m_bold_action);
m_italic_action = createCheckableAction(
QIcon(":/ico/32x32/format-text-italic.png"),
tr("Texte en italique"), editor, SLOT(setFontItalic(bool)), this);
m_italic_action->setShortcut(Qt::CTRL | Qt::Key_I);
ShortcutManager::instance().registerAction(m_italic_action, "richtext.italic", tr("Éditeur de texte"), Qt::CTRL | Qt::Key_I);
addAction(m_italic_action);
m_underline_action = createCheckableAction(
QIcon(":/ico/32x32/format-text-underline.png"),
tr("Texte souligé"), editor, SLOT(setFontUnderline(bool)), this);
m_underline_action->setShortcut(Qt::CTRL | Qt::Key_U);
ShortcutManager::instance().registerAction(m_underline_action, "richtext.underline", tr("Éditeur de texte"), Qt::CTRL | Qt::Key_U);
addAction(m_underline_action);
+167
View File
@@ -0,0 +1,167 @@
/*
Copyright 2006-2026 The QElectroTech Team
This file is part of QElectroTech.
QElectroTech 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.
QElectroTech 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 QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "shortcutmanager.h"
#include <QObject>
#include <QSettings>
#include <QVariant>
#include <algorithm>
namespace {
const QString SETTINGS_GROUP = QStringLiteral("shortcuts/");
}
ShortcutManager &ShortcutManager::instance()
{
static ShortcutManager manager;
return manager;
}
/**
@brief ShortcutManager::savedSequence
@param id
@param default_sequence
@return the user-overridden sequence stored for \a id, or \a default_sequence
if the user never overrode it. A stored-but-empty sequence (the user
cleared the shortcut) is returned as an empty QKeySequence, not the default.
*/
QKeySequence ShortcutManager::savedSequence(const QString &id, const QKeySequence &default_sequence) const
{
QSettings settings;
const QString key = SETTINGS_GROUP + id;
if (!settings.contains(key)) {
return default_sequence;
}
return QKeySequence::fromString(settings.value(key).toString());
}
/**
@brief ShortcutManager::registerAction
Register \a target under \a id, applying the user's saved override (if
any) or \a default_sequence otherwise. \a target must be a QAction or a
QAbstractButton -- both declare a "shortcut" QKeySequence property, which
is what's actually read/written here, so this works for either without a
separate code path. Safe to call once per instance that shares this id
(e.g. once per open window of the same kind) -- the first call to reach a
given id fixes its category, description (taken from the target's current
"text" property) and default sequence for the lifetime of the
application; later calls just register another live target to update.
*/
void ShortcutManager::registerAction(QObject *target, const QString &id,
const QString &category,
const QKeySequence &default_sequence)
{
if (!target) {
return;
}
auto it = m_entries.find(id);
if (it == m_entries.end()) {
Entry entry;
entry.category = category;
entry.description = target->property("text").toString();
entry.description.remove(QLatin1Char('&'));
entry.default_sequence = default_sequence;
it = m_entries.insert(id, entry);
m_order << id;
}
QList<QPointer<QObject>> &targets = it->targets;
targets.erase(std::remove_if(targets.begin(), targets.end(),
[](const QPointer<QObject> &t) { return t.isNull(); }),
targets.end());
if (!targets.contains(target)) {
targets << target;
}
target->setProperty("shortcut", QVariant::fromValue(savedSequence(id, it->default_sequence)));
}
/**
@return every registered shortcut, in registration order, along with its
currently effective sequence -- for display in the Shortcuts config page.
*/
QList<ShortcutManager::ShortcutInfo> ShortcutManager::allShortcuts() const
{
QList<ShortcutInfo> list;
for (const QString &id : m_order) {
const Entry &entry = m_entries.value(id);
ShortcutInfo info;
info.id = id;
info.category = entry.category;
info.description = entry.description;
info.default_sequence = entry.default_sequence;
info.current_sequence = savedSequence(id, entry.default_sequence);
list << info;
}
return list;
}
QKeySequence ShortcutManager::currentSequence(const QString &id) const
{
auto it = m_entries.find(id);
if (it == m_entries.end()) {
return QKeySequence();
}
return savedSequence(id, it->default_sequence);
}
/**
@brief ShortcutManager::setSequence
Persist \a sequence as the binding for \a id and apply it immediately to
every currently live QAction registered under that id. Persisted as "no
override" when \a sequence matches the id's default, so a future QET
version raising that default takes effect for users who never customized it.
*/
void ShortcutManager::setSequence(const QString &id, const QKeySequence &sequence)
{
auto it = m_entries.find(id);
if (it == m_entries.end()) {
return;
}
QSettings settings;
const QString key = SETTINGS_GROUP + id;
if (sequence == it->default_sequence) {
settings.remove(key);
} else {
settings.setValue(key, sequence.toString());
}
for (const QPointer<QObject> &target : qAsConst(it->targets)) {
if (target) {
target->setProperty("shortcut", QVariant::fromValue(sequence));
}
}
}
void ShortcutManager::resetToDefault(const QString &id)
{
auto it = m_entries.find(id);
if (it == m_entries.end()) {
return;
}
setSequence(id, it->default_sequence);
}
void ShortcutManager::resetAllToDefaults()
{
for (const QString &id : m_order) {
resetToDefault(id);
}
}
+92
View File
@@ -0,0 +1,92 @@
/*
Copyright 2006-2026 The QElectroTech Team
This file is part of QElectroTech.
QElectroTech 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.
QElectroTech 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 QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SHORTCUTMANAGER_H
#define SHORTCUTMANAGER_H
#include <QHash>
#include <QKeySequence>
#include <QList>
#include <QPointer>
#include <QString>
#include <QStringList>
class QObject;
/**
@brief The ShortcutManager class
App-wide registry of every rebindable shortcut, carried by either a
QAction or a QAbstractButton -- both declare an identical "shortcut"
Q_PROPERTY of type QKeySequence, which this class targets generically via
QObject so it doesn't need a separate code path for the handful of
QAbstractButton-based shortcuts (e.g. a QPushButton acting as a shortcut-
only trigger).
Every place in the code that used to call setShortcut() directly now
calls registerAction() instead, giving each shortcut a stable string id, a
category (for grouping in the UI) and a hardcoded default sequence.
registerAction() applies the user's saved override for that id (if any),
falling back to the default, and remembers the target so the Shortcuts
configuration page can list, edit and persist it.
Several targets can share the same id at once, since QET allows several
windows of the same kind (diagram editor, element editor...) to be open
simultaneously, each with its own QAction. setSequence() updates every
live target for a given id in one call.
*/
class ShortcutManager
{
public:
static ShortcutManager &instance();
struct ShortcutInfo {
QString id;
QString category;
QString description;
QKeySequence default_sequence;
QKeySequence current_sequence;
};
void registerAction(QObject *target, const QString &id,
const QString &category,
const QKeySequence &default_sequence);
QList<ShortcutInfo> allShortcuts() const;
QKeySequence currentSequence(const QString &id) const;
void setSequence(const QString &id, const QKeySequence &sequence);
void resetToDefault(const QString &id);
void resetAllToDefaults();
private:
ShortcutManager() = default;
ShortcutManager(const ShortcutManager &) = delete;
void operator=(const ShortcutManager &) = delete;
struct Entry {
QString category;
QString description;
QKeySequence default_sequence;
QList<QPointer<QObject>> targets;
};
QKeySequence savedSequence(const QString &id, const QKeySequence &default_sequence) const;
QHash<QString, Entry> m_entries;
QStringList m_order;
};
#endif // SHORTCUTMANAGER_H
+20 -19
View File
@@ -19,6 +19,7 @@
#include "../qetapp.h"
#include "../qeticons.h"
#include "../shortcutmanager.h"
#include "../qetmessagebox.h"
#include "../qetproject.h"
#include "templatecellwidget.h"
@@ -390,25 +391,25 @@ void QETTitleBlockTemplateEditor::initActions()
undo_ -> setIcon(QET::Icons::EditUndo);
redo_ -> setIcon(QET::Icons::EditRedo);
new_ -> setShortcut(QKeySequence::New);
open_ -> setShortcut(QKeySequence::Open);
open_from_file_ -> setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_O);
save_ -> setShortcut(QKeySequence::Save);
save_as_file_ -> setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_S);
quit_ -> setShortcut(Qt::CTRL | Qt::Key_Q);
undo_ -> setShortcut(QKeySequence::Undo);
redo_ -> setShortcut(QKeySequence::Redo);
cut_ -> setShortcut(QKeySequence::Cut);
copy_ -> setShortcut(QKeySequence::Copy);
paste_ -> setShortcut(QKeySequence::Paste);
edit_logos_ -> setShortcut(Qt::CTRL | Qt::Key_T);
edit_info_ -> setShortcut(Qt::CTRL | Qt::Key_Y);
merge_cells_ -> setShortcut(Qt::CTRL | Qt::Key_J);
split_cell_ -> setShortcut(Qt::CTRL | Qt::Key_K);
zoom_in_ -> setShortcut(QKeySequence::ZoomIn);
zoom_out_ -> setShortcut(QKeySequence::ZoomOut);
zoom_fit_ -> setShortcut(Qt::CTRL | Qt::Key_9);
zoom_reset_ -> setShortcut(Qt::CTRL | Qt::Key_0);
ShortcutManager::instance().registerAction(new_, "titleblockeditor.new", tr("Éditeur de cartouche"), QKeySequence::New);
ShortcutManager::instance().registerAction(open_, "titleblockeditor.open", tr("Éditeur de cartouche"), QKeySequence::Open);
ShortcutManager::instance().registerAction(open_from_file_, "titleblockeditor.open_from_file", tr("Éditeur de cartouche"), Qt::CTRL | Qt::SHIFT | Qt::Key_O);
ShortcutManager::instance().registerAction(save_, "titleblockeditor.save", tr("Éditeur de cartouche"), QKeySequence::Save);
ShortcutManager::instance().registerAction(save_as_file_, "titleblockeditor.save_as_file", tr("Éditeur de cartouche"), Qt::CTRL | Qt::SHIFT | Qt::Key_S);
ShortcutManager::instance().registerAction(quit_, "titleblockeditor.quit", tr("Éditeur de cartouche"), Qt::CTRL | Qt::Key_Q);
ShortcutManager::instance().registerAction(undo_, "titleblockeditor.undo", tr("Éditeur de cartouche"), QKeySequence::Undo);
ShortcutManager::instance().registerAction(redo_, "titleblockeditor.redo", tr("Éditeur de cartouche"), QKeySequence::Redo);
ShortcutManager::instance().registerAction(cut_, "titleblockeditor.cut", tr("Éditeur de cartouche"), QKeySequence::Cut);
ShortcutManager::instance().registerAction(copy_, "titleblockeditor.copy", tr("Éditeur de cartouche"), QKeySequence::Copy);
ShortcutManager::instance().registerAction(paste_, "titleblockeditor.paste", tr("Éditeur de cartouche"), QKeySequence::Paste);
ShortcutManager::instance().registerAction(edit_logos_, "titleblockeditor.edit_logos", tr("Éditeur de cartouche"), Qt::CTRL | Qt::Key_T);
ShortcutManager::instance().registerAction(edit_info_, "titleblockeditor.edit_info", tr("Éditeur de cartouche"), Qt::CTRL | Qt::Key_Y);
ShortcutManager::instance().registerAction(merge_cells_, "titleblockeditor.merge_cells", tr("Éditeur de cartouche"), Qt::CTRL | Qt::Key_J);
ShortcutManager::instance().registerAction(split_cell_, "titleblockeditor.split_cell", tr("Éditeur de cartouche"), Qt::CTRL | Qt::Key_K);
ShortcutManager::instance().registerAction(zoom_in_, "titleblockeditor.zoom_in", tr("Éditeur de cartouche"), QKeySequence::ZoomIn);
ShortcutManager::instance().registerAction(zoom_out_, "titleblockeditor.zoom_out", tr("Éditeur de cartouche"), QKeySequence::ZoomOut);
ShortcutManager::instance().registerAction(zoom_fit_, "titleblockeditor.zoom_fit", tr("Éditeur de cartouche"), Qt::CTRL | Qt::Key_9);
ShortcutManager::instance().registerAction(zoom_reset_, "titleblockeditor.zoom_reset", tr("Éditeur de cartouche"), Qt::CTRL | Qt::Key_0);
connect(new_, SIGNAL(triggered()), this, SLOT(newTemplate()));
connect(open_, SIGNAL(triggered()), this, SLOT(open()));
@@ -0,0 +1,227 @@
/*
Copyright 2006-2026 The QElectroTech Team
This file is part of QElectroTech.
QElectroTech 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.
QElectroTech 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 QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "shortcutsconfigpage.h"
#include "../../qeticons.h"
#include "../../shortcutmanager.h"
#include <QFrame>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QKeySequenceEdit>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QTableWidget>
#include <QToolButton>
#include <QVBoxLayout>
#include <algorithm>
/**
@brief ShortcutsConfigPage::ShortcutsConfigPage
@param parent
*/
ShortcutsConfigPage::ShortcutsConfigPage(QWidget *parent) :
ConfigPage(parent)
{
auto *vlayout = new QVBoxLayout();
QLabel *title_label = new QLabel(this->title());
vlayout->addWidget(title_label);
QFrame *horiz_line = new QFrame();
horiz_line->setFrameShape(QFrame::HLine);
vlayout->addWidget(horiz_line);
m_filter_edit = new QLineEdit(this);
m_filter_edit->setPlaceholderText(tr("Filtrer les raccourcis…"));
connect(m_filter_edit, &QLineEdit::textChanged, this, &ShortcutsConfigPage::filterRows);
vlayout->addWidget(m_filter_edit);
m_table = new QTableWidget(0, 4, this);
m_table->setHorizontalHeaderLabels({tr("Catégorie"), tr("Action"), tr("Raccourci"), QString()});
m_table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
m_table->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
m_table->horizontalHeader()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
m_table->horizontalHeader()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
m_table->verticalHeader()->setVisible(false);
m_table->setEditTriggers(QAbstractItemView::NoEditTriggers);
m_table->setSelectionMode(QAbstractItemView::NoSelection);
vlayout->addWidget(m_table);
auto *reset_all_button = new QPushButton(tr("Tout réinitialiser"), this);
connect(reset_all_button, &QPushButton::clicked, this, &ShortcutsConfigPage::resetAllRows);
auto *bottom_layout = new QHBoxLayout();
bottom_layout->addStretch();
bottom_layout->addWidget(reset_all_button);
vlayout->addLayout(bottom_layout);
setLayout(vlayout);
populateTable();
}
ShortcutsConfigPage::~ShortcutsConfigPage()
{
}
/**
@brief ShortcutsConfigPage::populateTable
Fill the table with one row per shortcut known to ShortcutManager, sorted
by category then action name.
*/
void ShortcutsConfigPage::populateTable()
{
QList<ShortcutManager::ShortcutInfo> shortcuts = ShortcutManager::instance().allShortcuts();
std::sort(shortcuts.begin(), shortcuts.end(),
[](const ShortcutManager::ShortcutInfo &a, const ShortcutManager::ShortcutInfo &b) {
if (a.category != b.category) {
return a.category < b.category;
}
return a.description < b.description;
});
m_table->setRowCount(shortcuts.size());
m_rows.clear();
m_rows.reserve(shortcuts.size());
for (int row = 0; row < shortcuts.size(); ++row) {
const ShortcutManager::ShortcutInfo &info = shortcuts.at(row);
auto *category_item = new QTableWidgetItem(info.category);
category_item->setFlags(category_item->flags() & ~Qt::ItemIsEditable);
m_table->setItem(row, 0, category_item);
auto *description_item = new QTableWidgetItem(info.description);
description_item->setFlags(description_item->flags() & ~Qt::ItemIsEditable);
m_table->setItem(row, 1, description_item);
auto *edit = new QKeySequenceEdit(info.current_sequence, m_table);
connect(edit, &QKeySequenceEdit::editingFinished, this, &ShortcutsConfigPage::checkConflicts);
m_table->setCellWidget(row, 2, edit);
auto *reset_button = new QToolButton(m_table);
reset_button->setIcon(QET::Icons::EditUndo);
reset_button->setToolTip(tr("Réinitialiser ce raccourci"));
reset_button->setAutoRaise(true);
connect(reset_button, &QToolButton::clicked, this, [this, row]() { resetRow(row); });
m_table->setCellWidget(row, 3, reset_button);
m_rows << Row{info.id, info.default_sequence, edit};
}
checkConflicts();
}
/**
@brief ShortcutsConfigPage::filterRows
Hide every row whose category or action name doesn't contain \a filter_text.
*/
void ShortcutsConfigPage::filterRows(const QString &filter_text)
{
const QString needle = filter_text.trimmed();
for (int row = 0; row < m_table->rowCount(); ++row) {
const bool matches = needle.isEmpty()
|| m_table->item(row, 0)->text().contains(needle, Qt::CaseInsensitive)
|| m_table->item(row, 1)->text().contains(needle, Qt::CaseInsensitive);
m_table->setRowHidden(row, !matches);
}
}
/**
@brief ShortcutsConfigPage::checkConflicts
Highlight every row whose currently-edited sequence is shared, non-empty,
with another row, and explain the conflict in the shortcut editor's tooltip.
*/
void ShortcutsConfigPage::checkConflicts()
{
QHash<QString, QList<int>> sequence_to_rows;
for (int row = 0; row < m_rows.size(); ++row) {
const QString sequence_text = m_rows.at(row).edit->keySequence().toString();
if (!sequence_text.isEmpty()) {
sequence_to_rows[sequence_text] << row;
}
}
for (int row = 0; row < m_rows.size(); ++row) {
const Row &current_row = m_rows.at(row);
const QString sequence_text = current_row.edit->keySequence().toString();
const QList<int> &conflicting_rows = sequence_to_rows.value(sequence_text);
const bool conflicted = !sequence_text.isEmpty() && conflicting_rows.size() > 1;
QTableWidgetItem *description_item = m_table->item(row, 1);
if (conflicted) {
QStringList other_descriptions;
for (int other_row : conflicting_rows) {
if (other_row != row) {
other_descriptions << m_table->item(other_row, 1)->text();
}
}
description_item->setBackground(QColor(255, 205, 205));
current_row.edit->setToolTip(
tr("Ce raccourci est aussi utilisé par : %1").arg(other_descriptions.join(QStringLiteral(", "))));
} else {
description_item->setBackground(Qt::NoBrush);
current_row.edit->setToolTip(QString());
}
}
}
/**
@brief ShortcutsConfigPage::resetRow
Reset the shortcut editor at \a row_index to its default sequence.
*/
void ShortcutsConfigPage::resetRow(int row_index)
{
if (row_index < 0 || row_index >= m_rows.size()) {
return;
}
m_rows.at(row_index).edit->setKeySequence(m_rows.at(row_index).default_sequence);
checkConflicts();
}
void ShortcutsConfigPage::resetAllRows()
{
for (const Row &row : qAsConst(m_rows)) {
row.edit->setKeySequence(row.default_sequence);
}
checkConflicts();
}
/**
@brief ShortcutsConfigPage::applyConf
Persist every row's shortcut edit through ShortcutManager, which also
applies it immediately to every currently live QAction sharing that id.
*/
void ShortcutsConfigPage::applyConf()
{
for (const Row &row : qAsConst(m_rows)) {
ShortcutManager::instance().setSequence(row.id, row.edit->keySequence());
}
}
QString ShortcutsConfigPage::title() const
{
return tr("Raccourcis", "configuration page title");
}
QIcon ShortcutsConfigPage::icon() const
{
return QET::Icons::ConfigureToolbars;
}
@@ -0,0 +1,68 @@
/*
Copyright 2006-2026 The QElectroTech Team
This file is part of QElectroTech.
QElectroTech 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.
QElectroTech 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 QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SHORTCUTSCONFIGPAGE_H
#define SHORTCUTSCONFIGPAGE_H
#include "configpage.h"
#include <QKeySequence>
class QKeySequenceEdit;
class QLineEdit;
class QTableWidget;
/**
@brief The ShortcutsConfigPage class
Configuration page listing every shortcut registered with ShortcutManager,
letting the user rebind, reset and search them. Bindings are only
persisted (via ShortcutManager::setSequence()) when applyConf() runs, i.e.
when the user validates the surrounding ConfigDialog.
*/
class ShortcutsConfigPage : public ConfigPage
{
Q_OBJECT
public:
explicit ShortcutsConfigPage(QWidget *parent = nullptr);
~ShortcutsConfigPage() override;
void applyConf() override;
QString title() const override;
QIcon icon() const override;
private slots:
void filterRows(const QString &filter_text);
void checkConflicts();
void resetAllRows();
private:
struct Row {
QString id;
QKeySequence default_sequence;
QKeySequenceEdit *edit;
};
void populateTable();
void resetRow(int row_index);
QLineEdit *m_filter_edit;
QTableWidget *m_table;
QList<Row> m_rows;
};
#endif // SHORTCUTSCONFIGPAGE_H