presentation/QuickCommandRouterKeys.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // QuickCommandRouter: key resolution and the window's event filter | ||
| 2 | // (Sprint 105 S105.7.3, S105.7.4, S105.7.6, S105.8.6, S105.9.11). | ||
| 3 | #include "QuickCommandRouter.h" | ||
| 4 | |||
| 5 | #include "KeyHint.h" | ||
| 6 | #include "WorkspaceState.h" | ||
| 7 | |||
| 8 | #include <QCoreApplication> | ||
| 9 | #include <QKeyEvent> | ||
| 10 | #include <QLoggingCategory> | ||
| 11 | #include <QQuickItem> | ||
| 12 | #include <QQuickWindow> | ||
| 13 | #include <algorithm> | ||
| 14 | |||
| 15 | Q_DECLARE_LOGGING_CATEGORY(lcKeys) | ||
| 16 | |||
| 17 | namespace { | ||
| 18 | 76 | QString keysTr(const char *text) { return QCoreApplication::translate("QuickCommandRouter", text); } | |
| 19 | |||
| 20 | 7710 | bool isModifierKey(int key) { | |
| 21 |
5/6✓ Branch 3 → 4 taken 7686 times.
✗ Branch 3 → 9 not taken.
✓ Branch 4 → 5 taken 7523 times.
✓ Branch 4 → 9 taken 163 times.
✓ Branch 5 → 6 taken 6944 times.
✓ Branch 5 → 9 taken 579 times.
|
7686 | return key == Qt::Key_Alt || key == Qt::Key_AltGr || key == Qt::Key_Shift || key == Qt::Key_Control |
| 22 |
5/8✓ Branch 2 → 3 taken 7686 times.
✓ Branch 2 → 9 taken 24 times.
✓ Branch 6 → 7 taken 6944 times.
✗ Branch 6 → 9 not taken.
✓ Branch 7 → 8 taken 6944 times.
✗ Branch 7 → 9 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 6944 times.
|
15396 | || key == Qt::Key_Meta || key == Qt::Key_Super_L || key == Qt::Key_Super_R; |
| 23 | } | ||
| 24 | |||
| 25 | // The visible focus item (a hidden page can keep active focus for a moment, | ||
| 26 | // e.g. the rule manager that just closed — it must not claim the keys). | ||
| 27 | 95749 | QQuickItem *visibleFocus(QQuickWindow *window) { | |
| 28 |
2/2✓ Branch 2 → 3 taken 89307 times.
✓ Branch 2 → 5 taken 6442 times.
|
95749 | QQuickItem *focus = window ? window->activeFocusItem() : nullptr; |
| 29 |
4/4✓ Branch 6 → 7 taken 87855 times.
✓ Branch 6 → 10 taken 7894 times.
✓ Branch 8 → 9 taken 81535 times.
✓ Branch 8 → 10 taken 6320 times.
|
95749 | return focus && focus->isVisible() ? focus : nullptr; |
| 30 | } | ||
| 31 | |||
| 32 | 12843 | bool ancestorHas(QQuickItem *item, const char *property) { | |
| 33 |
2/2✓ Branch 10 → 3 taken 170951 times.
✓ Branch 10 → 11 taken 12748 times.
|
183699 | for (; item; item = item->parentItem()) |
| 34 |
4/4✓ Branch 3 → 4 taken 170951 times.
✓ Branch 4 → 5 taken 170951 times.
✓ Branch 6 → 7 taken 95 times.
✓ Branch 6 → 8 taken 170856 times.
|
170951 | if (item->property(property).toBool()) return true; |
| 35 | 12748 | return false; | |
| 36 | } | ||
| 37 | |||
| 38 | // The area a command belongs to, for the wrong-key hint (D-23). | ||
| 39 | 4 | QString areaOf(const CommandSpec &spec) { | |
| 40 |
2/2✓ Branch 6 → 7 taken 3 times.
✓ Branch 6 → 8 taken 1 time.
|
4 | if (spec.contexts & (CommandContext::MainMail | CommandContext::MailTab | CommandContext::Search)) |
| 41 | 3 | return keysTr("the mail list"); | |
| 42 |
1/2✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 1 time.
|
1 | if (spec.contexts & CommandContext::Calendar) return keysTr("the calendar"); |
| 43 |
1/2✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 1 time.
|
1 | if (spec.contexts & CommandContext::Task) return keysTr("the tasks"); |
| 44 |
1/2✓ Branch 18 → 19 taken 1 time.
✗ Branch 18 → 20 not taken.
|
1 | if (spec.contexts & CommandContext::Contact) return keysTr("the contacts"); |
| 45 | ✗ | if (spec.contexts & CommandContext::Rules) return keysTr("the rules"); | |
| 46 | ✗ | if (spec.contexts & CommandContext::Agenda) return keysTr("the agenda beside the mail"); | |
| 47 | ✗ | return keysTr("another place"); | |
| 48 | } | ||
| 49 | } // namespace | ||
| 50 | |||
| 51 | 144 | QQuickWindow *QuickCommandRouter::window() const { return m_window; } | |
| 52 | |||
| 53 | 78469 | bool QuickCommandRouter::typingFocus() const { | |
| 54 | 78469 | QQuickItem *focus = visibleFocus(m_window); | |
| 55 |
7/7✓ Branch 4 → 5 taken 64601 times.
✓ Branch 4 → 8 taken 13868 times.
✓ Branch 5 → 6 taken 64601 times.
✓ Branch 7 → 8 taken 58692 times.
✓ Branch 7 → 9 taken 5909 times.
✓ Branch 10 → 11 taken 72560 times.
✓ Branch 10 → 12 taken 5909 times.
|
78469 | if (!focus || !focus->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)) return false; |
| 56 | // An explicitly read-only reader keeps the mail keys (mailReaderShortcuts). | ||
| 57 |
1/2✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 5909 times.
|
5909 | if (ancestorHas(focus, "mailReaderShortcuts")) return false; |
| 58 |
2/2✓ Branch 15 → 16 taken 5909 times.
✓ Branch 16 → 17 taken 5909 times.
|
5909 | return !focus->property("readOnly").toBool(); |
| 59 | } | ||
| 60 | |||
| 61 | 78242 | const CommandSpec *QuickCommandRouter::commandFor(const QKeySequence &sequence, bool typing) const { | |
| 62 | // Focus contexts (the agenda, the settings' page list) win over the area; | ||
| 63 | // an exclusive one (the resolver sheet) hides the area's keys. | ||
| 64 |
2/2✓ Branch 3 → 4 taken 57 times.
✓ Branch 3 → 5 taken 78185 times.
|
78242 | const CommandContexts area = exclusiveContext(m_focusContext) ? CommandContexts() : CommandContexts(m_context); |
| 65 |
2/2✓ Branch 35 → 8 taken 152983 times.
✓ Branch 35 → 36 taken 6037 times.
|
159020 | for (const CommandContexts scope : {m_focusContext, area}) { |
| 66 |
2/2✓ Branch 9 → 10 taken 72208 times.
✓ Branch 9 → 11 taken 80775 times.
|
152983 | if (!scope) continue; |
| 67 |
3/3✓ Branch 11 → 12 taken 80775 times.
✓ Branch 31 → 14 taken 6768528 times.
✓ Branch 31 → 32 taken 8570 times.
|
6777098 | for (const CommandSpec &spec : CommandRegistry::specs()) { |
| 68 |
10/10✓ Branch 17 → 18 taken 3065743 times.
✓ Branch 17 → 22 taken 3702785 times.
✓ Branch 19 → 20 taken 3015575 times.
✓ Branch 19 → 22 taken 50168 times.
✓ Branch 20 → 21 taken 260439 times.
✓ Branch 20 → 23 taken 2755136 times.
✓ Branch 21 → 22 taken 119387 times.
✓ Branch 21 → 23 taken 141052 times.
✓ Branch 24 → 25 taken 3872340 times.
✓ Branch 24 → 26 taken 2896188 times.
|
6768528 | if (!(spec.contexts & scope) || !m_supported.contains(spec.id) || (typing && !spec.whileTyping)) continue; |
| 69 |
2/2✓ Branch 27 → 28 taken 72205 times.
✓ Branch 27 → 29 taken 2823983 times.
|
2896188 | if (spec.defaultKeys.contains(sequence)) return &spec; |
| 70 | } | ||
| 71 | } | ||
| 72 | 6037 | return nullptr; | |
| 73 | } | ||
| 74 | |||
| 75 | 4796 | bool QuickCommandRouter::isPrefix(const QKeySequence &sequence) const { | |
| 76 |
3/3✓ Branch 2 → 3 taken 4796 times.
✓ Branch 29 → 5 taken 975566 times.
✓ Branch 29 → 30 taken 4715 times.
|
980281 | for (const CommandSpec &spec : CommandRegistry::specs()) { |
| 77 |
3/3✓ Branch 6 → 7 taken 975566 times.
✓ Branch 7 → 8 taken 737337 times.
✓ Branch 7 → 9 taken 238229 times.
|
975566 | if (!isAvailable(spec.id)) continue; |
| 78 |
2/2✓ Branch 24 → 11 taken 253375 times.
✓ Branch 24 → 25 taken 238148 times.
|
491523 | for (const QKeySequence &key : spec.defaultKeys) |
| 79 |
9/9✓ Branch 12 → 13 taken 253375 times.
✓ Branch 13 → 14 taken 12602 times.
✓ Branch 13 → 19 taken 240773 times.
✓ Branch 14 → 15 taken 12602 times.
✓ Branch 15 → 16 taken 12602 times.
✓ Branch 17 → 18 taken 81 times.
✓ Branch 17 → 19 taken 12521 times.
✓ Branch 20 → 21 taken 81 times.
✓ Branch 20 → 22 taken 253294 times.
|
253375 | if (key.count() > 1 && key[0] == sequence[0]) return true; |
| 80 | } | ||
| 81 | 4715 | return false; | |
| 82 | } | ||
| 83 | |||
| 84 | 268632 | QKeySequence QuickCommandRouter::effectiveKey(const QString &id) const { | |
| 85 | 268632 | const CommandSpec *spec = CommandRegistry::find(id); | |
| 86 |
6/6✓ Branch 3 → 4 taken 268619 times.
✓ Branch 3 → 6 taken 13 times.
✓ Branch 5 → 6 taken 197123 times.
✓ Branch 5 → 7 taken 71496 times.
✓ Branch 8 → 9 taken 197136 times.
✓ Branch 8 → 10 taken 71496 times.
|
268632 | if (!spec || !isAvailable(id)) return {}; |
| 87 | 71496 | const bool typing = typingFocus(); | |
| 88 |
2/2✓ Branch 28 → 13 taken 71496 times.
✓ Branch 28 → 29 taken 1669 times.
|
73165 | for (const QKeySequence &key : spec->defaultKeys) { |
| 89 |
7/7✓ Branch 14 → 15 taken 71496 times.
✓ Branch 15 → 16 taken 620 times.
✓ Branch 15 → 21 taken 70876 times.
✓ Branch 16 → 17 taken 13 times.
✓ Branch 16 → 18 taken 607 times.
✓ Branch 18 → 19 taken 607 times.
✓ Branch 21 → 22 taken 70876 times.
|
71496 | const CommandSpec *runs = key.count() > 1 ? (typing ? nullptr : commandFor(key, false)) : commandFor(key, typing); |
| 90 |
3/3✓ Branch 23 → 24 taken 69827 times.
✓ Branch 23 → 26 taken 1669 times.
✓ Branch 24 → 25 taken 69827 times.
|
71496 | if (runs == spec) return key; |
| 91 | } | ||
| 92 | 1669 | return {}; | |
| 93 | } | ||
| 94 | |||
| 95 | 80888 | QString QuickCommandRouter::effectiveKeyText(const QString &id) const { | |
| 96 |
1/1✓ Branch 2 → 3 taken 80888 times.
|
80888 | const QKeySequence key = effectiveKey(id); |
| 97 |
4/4✓ Branch 3 → 4 taken 80888 times.
✓ Branch 4 → 5 taken 18333 times.
✓ Branch 4 → 6 taken 62555 times.
✓ Branch 6 → 7 taken 62555 times.
|
161776 | return key.isEmpty() ? QString() : CommandRegistry::nativeKeyText(key); |
| 98 | 80888 | } | |
| 99 | |||
| 100 | 45022 | bool QuickCommandRouter::filtersWindow(QObject *window) const { | |
| 101 |
4/4✓ Branch 2 → 3 taken 44350 times.
✓ Branch 2 → 6 taken 672 times.
✓ Branch 4 → 5 taken 8768 times.
✓ Branch 4 → 6 taken 35582 times.
|
45022 | return window && window == m_window; |
| 102 | } | ||
| 103 | |||
| 104 | 36255 | QString QuickCommandRouter::keyTextOf(const QString &id) const { | |
| 105 | 36255 | const CommandSpec *spec = CommandRegistry::find(id); | |
| 106 |
2/4✓ Branch 3 → 4 taken 36255 times.
✗ Branch 3 → 8 not taken.
✓ Branch 5 → 6 taken 36255 times.
✗ Branch 5 → 8 not taken.
|
36255 | return spec && !spec->defaultKeys.isEmpty() ? CommandRegistry::nativeKeyText(spec->defaultKeys.first()) : QString(); |
| 107 | } | ||
| 108 | |||
| 109 | 38195 | QString QuickCommandRouter::explanationFor(const QString &id) const { | |
| 110 | 38195 | const CommandSpec *spec = CommandRegistry::find(id); | |
| 111 |
1/2✓ Branch 3 → 4 taken 38195 times.
✗ Branch 3 → 5 not taken.
|
38195 | return spec ? CommandRegistry::translatedExplanation(*spec) : QString(); |
| 112 | } | ||
| 113 | |||
| 114 | 248 | QString QuickCommandRouter::pendingPrefix() const { | |
| 115 |
2/2✓ Branch 3 → 4 taken 78 times.
✓ Branch 3 → 5 taken 170 times.
|
248 | return m_prefix.isEmpty() ? QString() : CommandRegistry::keyText(m_prefix); |
| 116 | } | ||
| 117 | |||
| 118 | 347 | QVariantList QuickCommandRouter::prefixChoices() const { | |
| 119 | 347 | QVariantList choices; | |
| 120 |
2/3✓ Branch 2 → 3 taken 347 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 347 times.
|
347 | if (m_prefix.isEmpty()) return choices; |
| 121 |
3/3✓ Branch 5 → 6 taken 347 times.
✓ Branch 61 → 8 taken 71135 times.
✓ Branch 61 → 62 taken 347 times.
|
71482 | for (const CommandSpec &spec : CommandRegistry::specs()) { |
| 122 |
3/3✓ Branch 9 → 10 taken 71135 times.
✓ Branch 10 → 11 taken 48036 times.
✓ Branch 10 → 12 taken 23099 times.
|
71135 | if (!isAvailable(spec.id)) continue; |
| 123 |
2/2✓ Branch 57 → 14 taken 24225 times.
✓ Branch 57 → 58 taken 23099 times.
|
47324 | for (const QKeySequence &key : spec.defaultKeys) |
| 124 |
8/9✓ Branch 15 → 16 taken 24225 times.
✓ Branch 16 → 17 taken 1578 times.
✓ Branch 16 → 22 taken 22647 times.
✓ Branch 17 → 18 taken 1578 times.
✓ Branch 18 → 19 taken 1578 times.
✓ Branch 20 → 21 taken 1578 times.
✗ Branch 20 → 22 not taken.
✓ Branch 23 → 24 taken 1578 times.
✓ Branch 23 → 55 taken 22647 times.
|
24225 | if (key.count() == 2 && key[0] == m_prefix[0]) |
| 125 |
4/4✓ Branch 30 → 31 taken 1578 times.
✓ Branch 31 → 32 taken 1578 times.
✓ Branch 32 → 33 taken 1578 times.
✓ Branch 41 → 42 taken 1578 times.
|
4734 | choices.append(QVariantMap{{QStringLiteral("key"), CommandRegistry::keyText(QKeySequence(key[1]))}, |
| 126 |
3/5✓ Branch 37 → 38 taken 1578 times.
✓ Branch 45 → 46 taken 3156 times.
✓ Branch 45 → 47 taken 1578 times.
✗ Branch 71 → 72 not taken.
✗ Branch 71 → 73 not taken.
|
7890 | {QStringLiteral("text"), CommandRegistry::translatedDescription(spec)}}); |
| 127 | } | ||
| 128 | 347 | return choices; | |
| 129 | 4734 | } | |
| 130 | |||
| 131 | 68 | QString QuickCommandRouter::contextTitle() const { | |
| 132 |
8/9✓ Branch 2 → 3 taken 17 times.
✓ Branch 2 → 4 taken 4 times.
✓ Branch 2 → 5 taken 4 times.
✓ Branch 2 → 6 taken 17 times.
✓ Branch 2 → 7 taken 4 times.
✓ Branch 2 → 8 taken 13 times.
✓ Branch 2 → 9 taken 4 times.
✓ Branch 2 → 10 taken 5 times.
✗ Branch 2 → 11 not taken.
|
68 | switch (m_context) { |
| 133 | 17 | case CommandContext::MainMail: return keysTr("Mail list"); | |
| 134 | 4 | case CommandContext::MailTab: return keysTr("Mail"); | |
| 135 | 4 | case CommandContext::Search: return keysTr("Search results"); | |
| 136 | 17 | case CommandContext::Calendar: return keysTr("Calendar"); | |
| 137 | 4 | case CommandContext::Task: return keysTr("Tasks"); | |
| 138 | 13 | case CommandContext::Contact: return keysTr("Contacts"); | |
| 139 | 4 | case CommandContext::Rules: return keysTr("Rules"); | |
| 140 | 5 | case CommandContext::Settings: return keysTr("Settings"); | |
| 141 | ✗ | default: return {}; | |
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | 502 | CommandContexts QuickCommandRouter::focusContextOf(const QString &name) { | |
| 146 |
2/2✓ Branch 4 → 5 taken 11 times.
✓ Branch 4 → 8 taken 491 times.
|
502 | if (name == QLatin1String("agenda")) return CommandContext::Agenda; |
| 147 |
2/2✓ Branch 10 → 11 taken 96 times.
✓ Branch 10 → 14 taken 395 times.
|
491 | if (name == QLatin1String("settingsPages")) return CommandContext::SettingsPages; |
| 148 |
2/2✓ Branch 16 → 17 taken 268 times.
✓ Branch 16 → 20 taken 127 times.
|
395 | if (name == QLatin1String("compose")) return CommandContext::Compose; |
| 149 |
2/2✓ Branch 22 → 23 taken 126 times.
✓ Branch 22 → 26 taken 1 time.
|
127 | if (name == QLatin1String("resolver")) return CommandContext::Resolver; |
| 150 | 1 | return {}; | |
| 151 | } | ||
| 152 | |||
| 153 | 72 | QQuickItem *QuickCommandRouter::exclusiveScope() const { | |
| 154 |
2/2✓ Branch 3 → 4 taken 71 times.
✓ Branch 3 → 5 taken 1 time.
|
72 | if (!exclusiveContext(m_focusContext)) return nullptr; |
| 155 |
1/2✓ Branch 22 → 8 taken 8 times.
✗ Branch 22 → 23 not taken.
|
8 | for (QQuickItem *item = visibleFocus(m_window); item; item = item->parentItem()) { |
| 156 | 8 | const KeyHint *hint = KeyHint::of(item); | |
| 157 |
7/8✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 15 taken 7 times.
✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 15 not taken.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 16 → 18 taken 7 times.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 18 → 20 taken 7 times.
|
8 | if (hint && exclusiveContext(focusContextOf(hint->context()))) return item; |
| 158 | } | ||
| 159 | ✗ | return nullptr; | |
| 160 | } | ||
| 161 | |||
| 162 | 173 | QString QuickCommandRouter::paneCommand(int order) { | |
| 163 | 4 | static const QStringList commands = {QStringLiteral("app.pane_sidebar"), QStringLiteral("app.pane_main"), | |
| 164 |
5/10✓ Branch 2 → 3 taken 4 times.
✓ Branch 2 → 28 taken 169 times.
✓ Branch 4 → 5 taken 4 times.
✗ Branch 4 → 28 not taken.
✓ Branch 21 → 22 taken 16 times.
✓ Branch 21 → 23 taken 4 times.
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 39 not taken.
✗ Branch 58 → 59 not taken.
✗ Branch 58 → 60 not taken.
|
197 | QStringLiteral("app.pane_detail"), QStringLiteral("app.pane_side")}; |
| 165 |
3/4✓ Branch 28 → 29 taken 173 times.
✗ Branch 28 → 33 not taken.
✓ Branch 30 → 31 taken 161 times.
✓ Branch 30 → 33 taken 12 times.
|
173 | return order >= 0 && order < commands.size() ? commands.at(order) : QString(); |
| 166 | 20 | } | |
| 167 | |||
| 168 | 9 | QList<const CommandSpec *> QuickCommandRouter::paneCommands(const QString &context) const { | |
| 169 | 9 | const CommandContexts scope = focusContextOf(context); | |
| 170 | 9 | QList<const CommandSpec *> commands; | |
| 171 |
6/6✓ Branch 4 → 5 taken 8 times.
✓ Branch 4 → 8 taken 1 time.
✓ Branch 7 → 8 taken 7 times.
✓ Branch 7 → 9 taken 1 time.
✓ Branch 10 → 11 taken 8 times.
✓ Branch 10 → 12 taken 1 time.
|
9 | if (!scope || (scope & m_focusContext)) return commands; |
| 172 |
3/3✓ Branch 12 → 13 taken 1 time.
✓ Branch 30 → 15 taken 205 times.
✓ Branch 30 → 31 taken 1 time.
|
206 | for (const CommandSpec &spec : CommandRegistry::specs()) |
| 173 |
7/10✓ Branch 18 → 19 taken 3 times.
✓ Branch 18 → 25 taken 202 times.
✓ Branch 19 → 20 taken 3 times.
✗ Branch 19 → 25 not taken.
✓ Branch 21 → 22 taken 3 times.
✗ Branch 21 → 25 not taken.
✓ Branch 23 → 24 taken 3 times.
✗ Branch 23 → 25 not taken.
✓ Branch 26 → 27 taken 3 times.
✓ Branch 26 → 28 taken 202 times.
|
205 | if ((spec.contexts & scope) && spec.showInHelp && m_supported.contains(spec.id) && !spec.defaultKeys.isEmpty()) |
| 174 |
1/1✓ Branch 27 → 28 taken 3 times.
|
3 | commands.append(&spec); |
| 175 | 1 | return commands; | |
| 176 | ✗ | } | |
| 177 | |||
| 178 | 9498 | void QuickCommandRouter::updateFocusContext() { | |
| 179 | 9498 | CommandContexts context; | |
| 180 |
4/4✓ Branch 3 → 4 taken 9498 times.
✓ Branch 20 → 21 taken 110682 times.
✓ Branch 22 → 5 taken 111174 times.
✓ Branch 22 → 23 taken 9006 times.
|
120180 | for (QQuickItem *item = visibleFocus(m_window); item; item = item->parentItem()) { |
| 181 |
1/1✓ Branch 5 → 6 taken 111174 times.
|
111174 | const KeyHint *hint = KeyHint::of(item); |
| 182 |
8/8✓ Branch 6 → 7 taken 10111 times.
✓ Branch 6 → 10 taken 101063 times.
✓ Branch 9 → 10 taken 9619 times.
✓ Branch 9 → 11 taken 492 times.
✓ Branch 12 → 13 taken 10111 times.
✓ Branch 12 → 14 taken 101063 times.
✓ Branch 14 → 15 taken 110682 times.
✓ Branch 14 → 16 taken 492 times.
|
111174 | if (!hint || hint->context().isEmpty()) continue; |
| 183 | 492 | context = focusContextOf(hint->context()); | |
| 184 | 492 | break; | |
| 185 | } | ||
| 186 |
2/2✓ Branch 24 → 25 taken 9037 times.
✓ Branch 24 → 26 taken 461 times.
|
9498 | if (context == m_focusContext) return; |
| 187 | 461 | m_focusContext = context; | |
| 188 |
1/1✓ Branch 26 → 27 taken 461 times.
|
461 | notifyAvailability(); |
| 189 | } | ||
| 190 | |||
| 191 | 62 | bool QuickCommandRouter::focusPane(int delta) { | |
| 192 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 62 times.
|
62 | if (!m_window) return false; |
| 193 | struct Pane { KeyHint *hint; int order; qreal x; }; | ||
| 194 | 62 | QList<Pane> panes; | |
| 195 |
5/5✓ Branch 5 → 6 taken 62 times.
✓ Branch 6 → 7 taken 62 times.
✓ Branch 7 → 8 taken 62 times.
✓ Branch 36 → 9 taken 18547 times.
✓ Branch 36 → 37 taken 62 times.
|
18609 | for (KeyHint *hint : KeyHint::all()) { |
| 196 | 18547 | QQuickItem *item = hint->item(); | |
| 197 |
12/18✓ Branch 13 → 14 taken 543 times.
✓ Branch 13 → 22 taken 18004 times.
✓ Branch 14 → 15 taken 543 times.
✗ Branch 14 → 22 not taken.
✓ Branch 15 → 16 taken 543 times.
✓ Branch 17 → 18 taken 543 times.
✗ Branch 17 → 22 not taken.
✓ Branch 18 → 19 taken 543 times.
✓ Branch 19 → 20 taken 152 times.
✓ Branch 19 → 22 taken 391 times.
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 152 times.
✓ Branch 24 → 25 taken 18547 times.
✗ Branch 24 → 26 not taken.
✓ Branch 26 → 27 taken 18395 times.
✓ Branch 26 → 28 taken 152 times.
✗ Branch 97 → 98 not taken.
✗ Branch 97 → 99 not taken.
|
18547 | if (hint->pane().isEmpty() || !item || item->window() != m_window || !item->isVisible() || !hint->enabled()) continue; |
| 198 |
2/2✓ Branch 30 → 31 taken 152 times.
✓ Branch 32 → 33 taken 152 times.
|
152 | panes.append({hint, hint->paneOrder(), item->mapToScene(QPointF()).x()}); |
| 199 | 62 | } | |
| 200 |
1/2✗ Branch 39 → 40 not taken.
✓ Branch 39 → 41 taken 62 times.
|
62 | if (panes.isEmpty()) return false; |
| 201 |
3/3✓ Branch 41 → 42 taken 62 times.
✓ Branch 42 → 43 taken 62 times.
✓ Branch 43 → 44 taken 62 times.
|
62 | std::stable_sort(panes.begin(), panes.end(), [](const Pane &a, const Pane &b) { |
| 202 |
1/2✓ Branch 2 → 3 taken 126 times.
✗ Branch 2 → 4 not taken.
|
126 | return a.order != b.order ? a.order < b.order : a.x < b.x; |
| 203 | }); | ||
| 204 | 62 | int current = -1; | |
| 205 |
5/6✓ Branch 45 → 46 taken 62 times.
✓ Branch 61 → 62 taken 224 times.
✓ Branch 63 → 64 taken 286 times.
✗ Branch 63 → 65 not taken.
✓ Branch 64 → 47 taken 224 times.
✓ Branch 64 → 65 taken 62 times.
|
286 | for (QQuickItem *item = visibleFocus(m_window); item && current < 0; item = item->parentItem()) |
| 206 |
2/2✓ Branch 60 → 48 taken 482 times.
✓ Branch 60 → 61 taken 162 times.
|
644 | for (int index = 0; index < panes.size(); ++index) |
| 207 |
8/8✓ Branch 48 → 49 taken 482 times.
✓ Branch 50 → 51 taken 435 times.
✓ Branch 50 → 54 taken 47 times.
✓ Branch 51 → 52 taken 435 times.
✓ Branch 53 → 54 taken 15 times.
✓ Branch 53 → 55 taken 420 times.
✓ Branch 56 → 57 taken 62 times.
✓ Branch 56 → 58 taken 420 times.
|
482 | if (panes[index].hint->item() == item || panes[index].hint->focusTarget() == item) { current = index; break; } |
| 208 | 62 | const int count = int(panes.size()); | |
| 209 |
1/4✗ Branch 66 → 67 not taken.
✓ Branch 66 → 71 taken 62 times.
✗ Branch 67 → 68 not taken.
✗ Branch 67 → 69 not taken.
|
62 | const int next = current < 0 ? (delta > 0 ? 0 : count - 1) : ((current + delta) % count + count) % count; |
| 210 |
2/2✓ Branch 72 → 73 taken 62 times.
✓ Branch 73 → 74 taken 62 times.
|
62 | panes[next].hint->focusPane(); |
| 211 |
2/7✓ Branch 74 → 75 taken 62 times.
✗ Branch 78 → 79 not taken.
✗ Branch 79 → 80 not taken.
✗ Branch 80 → 81 not taken.
✗ Branch 82 → 83 not taken.
✗ Branch 87 → 76 not taken.
✓ Branch 87 → 88 taken 62 times.
|
62 | qCInfo(lcKeys) << "pane" << panes[next].hint->pane(); |
| 212 |
2/2✓ Branch 88 → 89 taken 62 times.
✓ Branch 90 → 91 taken 62 times.
|
62 | emit paneFocused(panes[next].hint->pane()); |
| 213 | 62 | return true; | |
| 214 | 62 | } | |
| 215 | |||
| 216 | 519 | bool QuickCommandRouter::focusPaneAt(int order) { | |
| 217 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 519 times.
|
519 | if (!m_window) return false; |
| 218 | 519 | KeyHint *target = nullptr; | |
| 219 | 519 | qreal targetX = 0; | |
| 220 |
5/5✓ Branch 5 → 6 taken 519 times.
✓ Branch 6 → 7 taken 519 times.
✓ Branch 7 → 8 taken 519 times.
✓ Branch 38 → 9 taken 176357 times.
✓ Branch 38 → 39 taken 519 times.
|
176876 | for (KeyHint *hint : KeyHint::all()) { |
| 221 | 176357 | QQuickItem *item = hint->item(); | |
| 222 |
8/11✓ Branch 15 → 16 taken 1181 times.
✓ Branch 15 → 24 taken 3691 times.
✓ Branch 16 → 17 taken 1181 times.
✗ Branch 16 → 24 not taken.
✓ Branch 17 → 18 taken 1181 times.
✓ Branch 19 → 20 taken 1178 times.
✓ Branch 19 → 24 taken 3 times.
✓ Branch 28 → 29 taken 175928 times.
✓ Branch 28 → 30 taken 429 times.
✗ Branch 62 → 63 not taken.
✗ Branch 62 → 64 not taken.
|
181229 | if (hint->pane().isEmpty() || hint->paneOrder() != order || !item || item->window() != m_window |
| 223 |
7/9✓ Branch 13 → 14 taken 4872 times.
✓ Branch 13 → 24 taken 171485 times.
✓ Branch 20 → 21 taken 1178 times.
✓ Branch 21 → 22 taken 429 times.
✓ Branch 21 → 24 taken 749 times.
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 429 times.
✓ Branch 26 → 27 taken 176357 times.
✗ Branch 26 → 28 not taken.
|
181229 | || !item->isVisible() || !hint->enabled()) |
| 224 | 175928 | continue; | |
| 225 |
1/1✓ Branch 31 → 32 taken 429 times.
|
429 | const qreal x = item->mapToScene(QPointF()).x(); |
| 226 |
1/4✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 429 times.
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 36 not taken.
|
429 | if (!target || x < targetX) { target = hint; targetX = x; } |
| 227 | 519 | } | |
| 228 |
2/2✓ Branch 40 → 41 taken 90 times.
✓ Branch 40 → 42 taken 429 times.
|
519 | if (!target) return false; |
| 229 | 429 | target->focusPane(); | |
| 230 |
2/6✓ Branch 43 → 44 taken 429 times.
✗ Branch 47 → 48 not taken.
✗ Branch 48 → 49 not taken.
✗ Branch 50 → 51 not taken.
✗ Branch 55 → 45 not taken.
✓ Branch 55 → 56 taken 429 times.
|
429 | qCInfo(lcKeys) << "pane" << target->pane(); |
| 231 |
1/1✓ Branch 57 → 58 taken 429 times.
|
429 | emit paneFocused(target->pane()); |
| 232 | 429 | return true; | |
| 233 | } | ||
| 234 | |||
| 235 | 2713 | void QuickCommandRouter::showWrongKeyHint(const QKeySequence &sequence) { | |
| 236 |
1/1✓ Branch 2 → 3 taken 2713 times.
|
2713 | const QKeyCombination combination = sequence[0]; |
| 237 | // In an exclusive sheet the area's keys are off on purpose: no hint. | ||
| 238 |
6/6✓ Branch 5 → 6 taken 2686 times.
✓ Branch 5 → 8 taken 27 times.
✓ Branch 7 → 8 taken 9 times.
✓ Branch 7 → 9 taken 2677 times.
✓ Branch 10 → 11 taken 36 times.
✓ Branch 10 → 12 taken 2677 times.
|
5390 | if (combination.keyboardModifiers() != Qt::NoModifier || exclusiveContext(m_focusContext)) return; |
| 239 | 2677 | const int code = int(combination.key()); | |
| 240 |
8/8✓ Branch 13 → 14 taken 2649 times.
✓ Branch 13 → 17 taken 28 times.
✓ Branch 14 → 15 taken 5 times.
✓ Branch 14 → 17 taken 2644 times.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 16 → 18 taken 4 times.
✓ Branch 19 → 20 taken 2673 times.
✓ Branch 19 → 21 taken 4 times.
|
2677 | if (!(code >= Qt::Key_A && code <= Qt::Key_Z) || m_hintedKeys.contains(code)) return; |
| 241 |
2/3✓ Branch 21 → 22 taken 4 times.
✓ Branch 49 → 24 taken 281 times.
✗ Branch 49 → 50 not taken.
|
281 | for (const CommandSpec &spec : CommandRegistry::specs()) { |
| 242 |
5/6✓ Branch 26 → 27 taken 281 times.
✗ Branch 26 → 29 not taken.
✓ Branch 28 → 29 taken 277 times.
✓ Branch 28 → 30 taken 4 times.
✓ Branch 31 → 32 taken 277 times.
✓ Branch 31 → 33 taken 4 times.
|
281 | if (!m_supported.contains(spec.id) || !spec.defaultKeys.contains(sequence)) continue; |
| 243 |
1/1✓ Branch 33 → 34 taken 4 times.
|
4 | m_hintedKeys.insert(code); |
| 244 |
1/1✓ Branch 34 → 35 taken 4 times.
|
4 | const QString key = CommandRegistry::keyText(sequence); |
| 245 |
2/2✓ Branch 35 → 36 taken 4 times.
✓ Branch 39 → 40 taken 4 times.
|
8 | emit keyHintRequested(keysTr("“%1” means “%2” in %3 — hold Alt to see the keys here.") |
| 246 |
3/3✓ Branch 36 → 37 taken 4 times.
✓ Branch 37 → 38 taken 4 times.
✓ Branch 38 → 39 taken 4 times.
|
8 | .arg(key, CommandRegistry::translatedDescription(spec), areaOf(spec))); |
| 247 | 4 | return; | |
| 248 | 4 | } | |
| 249 | } | ||
| 250 | |||
| 251 | // The active focus item can be a QtWebEngine delegate item; QtWebEngine is | ||
| 252 | // built without RTTI, so UBSan's vptr check cannot type it and reports | ||
| 253 | // every member call on it (Sprint 102 S102.4.1, docs/TESTING.md#sanitizers). | ||
| 254 | __attribute__((no_sanitize("vptr"))) | ||
| 255 | 51874 | bool QuickCommandRouter::eventFilter(QObject *watched, QEvent *event) { | |
| 256 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 51874 times.
|
51874 | if (watched != m_window) return false; |
| 257 |
5/5✓ Branch 6 → 7 taken 7241 times.
✓ Branch 6 → 9 taken 489 times.
✓ Branch 6 → 11 taken 1021 times.
✓ Branch 6 → 13 taken 7723 times.
✓ Branch 6 → 21 taken 35400 times.
|
51874 | switch (event->type()) { |
| 258 | 7241 | case QEvent::KeyRelease: | |
| 259 | 7241 | m_overlay->keyRelease(static_cast<QKeyEvent *>(event)); | |
| 260 | 7241 | return false; | |
| 261 | 489 | case QEvent::MouseButtonPress: | |
| 262 | case QEvent::TouchBegin: | ||
| 263 | 489 | m_overlay->pointerPress(); | |
| 264 | 489 | return false; | |
| 265 | 1021 | case QEvent::Resize: | |
| 266 | 1021 | m_overlay->cancel(); // badge positions would lie (ux.md §11) | |
| 267 | 1021 | return false; | |
| 268 | 7723 | case QEvent::KeyPress: | |
| 269 |
4/4✓ Branch 15 → 16 taken 7719 times.
✓ Branch 15 → 19 taken 4 times.
✓ Branch 17 → 18 taken 2300 times.
✓ Branch 17 → 19 taken 5419 times.
|
7723 | return m_window->isActive() && handleKeyPress(static_cast<QKeyEvent *>(event)); |
| 270 | 35400 | default: | |
| 271 | 35400 | return false; | |
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | __attribute__((no_sanitize("vptr"))) | ||
| 276 | 7719 | bool QuickCommandRouter::handleKeyPress(QKeyEvent *key) { | |
| 277 |
1/1✓ Branch 3 → 4 taken 7719 times.
|
7719 | QQuickItem *focus = visibleFocus(m_window); |
| 278 | // An input method composing text owns every key (ux.md §11). | ||
| 279 |
10/16✓ Branch 4 → 5 taken 7690 times.
✓ Branch 4 → 10 taken 29 times.
✓ Branch 5 → 6 taken 7690 times.
✓ Branch 6 → 7 taken 7690 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 7690 times.
✓ Branch 11 → 12 taken 7690 times.
✓ Branch 11 → 13 taken 29 times.
✓ Branch 13 → 14 taken 7690 times.
✓ Branch 13 → 15 taken 29 times.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 18 taken 7719 times.
✗ Branch 103 → 104 not taken.
✗ Branch 103 → 105 not taken.
✗ Branch 107 → 108 not taken.
✗ Branch 107 → 109 not taken.
|
7719 | if (focus && !focus->property("preeditText").toString().isEmpty()) { |
| 280 | ✗ | m_overlay->cancel(); | |
| 281 | ✗ | return false; | |
| 282 | } | ||
| 283 |
3/3✓ Branch 18 → 19 taken 7719 times.
✓ Branch 19 → 20 taken 9 times.
✓ Branch 19 → 22 taken 7710 times.
|
7719 | if (m_overlay->keyPress(key)) { key->accept(); return true; } |
| 284 |
2/2✓ Branch 24 → 25 taken 766 times.
✓ Branch 24 → 26 taken 6944 times.
|
7710 | if (isModifierKey(key->key())) return false; |
| 285 |
5/5✓ Branch 27 → 28 taken 6944 times.
✓ Branch 28 → 29 taken 6944 times.
✓ Branch 30 → 31 taken 176 times.
✓ Branch 30 → 33 taken 6768 times.
✓ Branch 31 → 32 taken 176 times.
|
6944 | if (m_window->property("modalDepth").toInt() > 0) { cancelSequence(); return false; } |
| 286 | // Editors and sheets that own their keys (rule editor, script editor, | ||
| 287 | // out of office, create sheet; the task editor) keep every key except | ||
| 288 | // the ones that type nothing (S105.7.4). | ||
| 289 |
1/1✓ Branch 33 → 34 taken 6768 times.
|
6768 | const bool owned = ancestorHas(focus, "ownShortcuts") |
| 290 |
7/7✓ Branch 34 → 35 taken 6688 times.
✓ Branch 34 → 38 taken 80 times.
✓ Branch 35 → 36 taken 166 times.
✓ Branch 35 → 39 taken 6522 times.
✓ Branch 36 → 37 taken 166 times.
✓ Branch 37 → 38 taken 15 times.
✓ Branch 37 → 39 taken 151 times.
|
6768 | || (m_context == CommandContext::Task && ancestorHas(focus, "taskEditorShortcuts")); |
| 291 |
1/1✓ Branch 40 → 41 taken 6768 times.
|
6768 | const bool typing = typingFocus(); |
| 292 |
1/1✓ Branch 41 → 42 taken 6768 times.
|
6768 | const QKeySequence sequence = normalizedShortcut(key); |
| 293 |
4/4✓ Branch 42 → 43 taken 6673 times.
✓ Branch 42 → 44 taken 95 times.
✓ Branch 43 → 44 taken 1794 times.
✓ Branch 43 → 55 taken 4879 times.
|
6768 | if (owned || typing) { |
| 294 |
1/1✓ Branch 44 → 45 taken 1889 times.
|
1889 | cancelSequence(); |
| 295 |
1/1✓ Branch 45 → 46 taken 1889 times.
|
1889 | const CommandSpec *spec = commandFor(sequence, true); |
| 296 |
6/7✓ Branch 46 → 47 taken 125 times.
✓ Branch 46 → 50 taken 1764 times.
✓ Branch 47 → 48 taken 125 times.
✓ Branch 48 → 49 taken 125 times.
✗ Branch 48 → 50 not taken.
✓ Branch 51 → 52 taken 125 times.
✓ Branch 51 → 54 taken 1764 times.
|
1889 | if (spec && invokeFromKeyboard(spec->id)) { key->accept(); return true; } |
| 297 | 1764 | return false; | |
| 298 | } | ||
| 299 |
3/3✓ Branch 55 → 56 taken 4879 times.
✓ Branch 56 → 57 taken 85 times.
✓ Branch 56 → 79 taken 4794 times.
|
4879 | if (!m_prefix.isEmpty()) { |
| 300 | // A held prefix key is not a second press (the old 500 ms guard of g g). | ||
| 301 |
2/2✓ Branch 58 → 59 taken 11 times.
✓ Branch 58 → 61 taken 74 times.
|
157 | if (key->isAutoRepeat()) { key->accept(); return true; } |
| 302 |
3/3✓ Branch 63 → 64 taken 74 times.
✓ Branch 64 → 65 taken 74 times.
✓ Branch 65 → 66 taken 74 times.
|
74 | const QKeySequence combined(m_prefix[0], sequence[0]); |
| 303 |
1/1✓ Branch 66 → 67 taken 74 times.
|
74 | cancelSequence(); |
| 304 |
3/3✓ Branch 67 → 68 taken 74 times.
✓ Branch 68 → 69 taken 72 times.
✓ Branch 68 → 73 taken 2 times.
|
74 | if (const CommandSpec *spec = commandFor(combined, false)) { |
| 305 |
2/3✓ Branch 69 → 70 taken 72 times.
✓ Branch 70 → 71 taken 72 times.
✗ Branch 70 → 73 not taken.
|
72 | if (invokeFromKeyboard(spec->id)) { key->accept(); return true; } |
| 306 | } | ||
| 307 | // Not a sequence: the key keeps its own meaning below. | ||
| 308 | 74 | } | |
| 309 |
7/8✓ Branch 79 → 80 taken 4796 times.
✓ Branch 80 → 81 taken 81 times.
✓ Branch 80 → 84 taken 4715 times.
✓ Branch 81 → 82 taken 81 times.
✓ Branch 82 → 83 taken 81 times.
✗ Branch 82 → 84 not taken.
✓ Branch 85 → 86 taken 81 times.
✓ Branch 85 → 91 taken 4715 times.
|
4796 | if (isPrefix(sequence) && !commandFor(sequence, false)) { |
| 310 |
1/1✓ Branch 86 → 87 taken 81 times.
|
81 | m_prefix = sequence; |
| 311 |
1/1✓ Branch 87 → 88 taken 81 times.
|
81 | m_prefixTimeout.start(); |
| 312 |
1/1✓ Branch 88 → 89 taken 81 times.
|
81 | emit prefixChanged(); |
| 313 | 81 | key->accept(); | |
| 314 | 81 | return true; | |
| 315 | } | ||
| 316 |
3/3✓ Branch 91 → 92 taken 4715 times.
✓ Branch 92 → 93 taken 2002 times.
✓ Branch 92 → 98 taken 2713 times.
|
4715 | if (const CommandSpec *spec = commandFor(sequence, false)) { |
| 317 |
2/3✓ Branch 93 → 94 taken 2002 times.
✓ Branch 94 → 95 taken 2002 times.
✗ Branch 94 → 97 not taken.
|
2002 | if (invokeFromKeyboard(spec->id)) { key->accept(); return true; } |
| 318 | ✗ | return false; | |
| 319 | } | ||
| 320 |
1/1✓ Branch 98 → 99 taken 2713 times.
|
2713 | showWrongKeyHint(sequence); |
| 321 | 2713 | return false; | |
| 322 | 6768 | } | |
| 323 |