Add a command search: type part of a command's name, press Enter

Ctrl+Shift+M (Édition → "Rechercher une commande…") opens a small
search box at the cursor listing every command of the diagram editor
window, as SolidWorks' "Search Commands" and the command palette of
many editors do. Typing narrows it, best match first: name starting
with the text, then a word starting with it, then containing it.
Matching ignores case, accents and mnemonic "&", so "editer" finds
"Éditer l'item sélectionné". Each row shows the command's key when it
has one, which also teaches the keys. Disabled commands are listed,
greyed, and cannot be run. Enter runs the highlighted one after
closing the box; Esc closes.

The list is ShortcutManager's registry, restricted to the actions this
window owns (ShortcutManager::action(id, owner)), so a second editor
window's commands never appear and nothing has to be listed by hand.

Ctrl+Shift+P, the usual key for this, is already the autonumbering
dock's.

tst_commandsearch covers the folding, the ranking, that another
window's commands are left out and that a disabled command does not
run; both behaviours were checked to fail the test when broken.

Discussion #1033.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG
This commit is contained in:
ispyisail
2026-09-26 13:37:51 +12:00
parent 923367d2a8
commit 86cb7e430e
9 changed files with 494 additions and 0 deletions
+33
View File
@@ -197,3 +197,36 @@ bool ShortcutManager::trigger(const QString &id) const
}
return false;
}
/**
@return the QAction registered under @a id that belongs to @a owner --
that is, has @a owner among its ancestors -- or nullptr. Several windows
of the same kind each register their own action under one id, so a
window asking for "its" action has to say which window it is.
@param id
@param owner : the window, or nullptr for the first live action
*/
QAction *ShortcutManager::action(const QString &id, const QObject *owner) const
{
auto it = m_entries.find(id);
if (it == m_entries.end()) {
return nullptr;
}
for (const QPointer<QObject> &target : qAsConst(it->targets))
{
auto *action = qobject_cast<QAction *>(target.data());
if (!action) {
continue;
}
if (!owner) {
return action;
}
for (const QObject *o = action->parent(); o; o = o->parent()) {
if (o == owner) {
return action;
}
}
}
return nullptr;
}