app/CommandRegistry.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <QFlags> | ||
| 4 | #include <QHash> | ||
| 5 | #include <QKeySequence> | ||
| 6 | #include <QList> | ||
| 7 | #include <QObject> | ||
| 8 | #include <QPointer> | ||
| 9 | #include <QString> | ||
| 10 | |||
| 11 | class QAction; | ||
| 12 | |||
| 13 | enum class CommandContext : quint32 { | ||
| 14 | None = 0, | ||
| 15 | MainMail = 1U << 0, | ||
| 16 | MailTab = 1U << 1, | ||
| 17 | Calendar = 1U << 2, | ||
| 18 | Task = 1U << 3, | ||
| 19 | TextInput = 1U << 4, | ||
| 20 | Modal = 1U << 5, | ||
| 21 | Contact = 1U << 6, | ||
| 22 | Rules = 1U << 7, // Sprint 95: the rule manager page of the mail area | ||
| 23 | // Sprint 101 CB-06: a search tab — the selected result(s) are the subject | ||
| 24 | // of mail commands; commands about tab 0's folder are not available. | ||
| 25 | Search = 1U << 8, | ||
| 26 | Settings = 1U << 9, // Sprint 100: the settings area (no single-letter keys) | ||
| 27 | // Sprint 105 S105.9.2/S105.9.4: focus contexts. They apply in addition to | ||
| 28 | // the area context while the focus is inside an element that declares them | ||
| 29 | // (KeyHint.context); their commands win over the area's for the same key. | ||
| 30 | Agenda = 1U << 10, // the agenda beside the mail | ||
| 31 | SettingsPages = 1U << 11, // the page list of the settings | ||
| 32 | Compose = 1U << 12, // a message being written (S105.9.4) | ||
| 33 | Resolver = 1U << 13, // Sprint 107: the conflict resolver sheet | ||
| 34 | }; | ||
| 35 | Q_DECLARE_FLAGS(CommandContexts, CommandContext) | ||
| 36 | 4 | Q_DECLARE_OPERATORS_FOR_FLAGS(CommandContexts) | |
| 37 | |||
| 38 | struct CommandSpec { | ||
| 39 | // Sprint 105 (keys.md §2): how often the action is used; decides the | ||
| 40 | // badge priority in the keys overlay. | ||
| 41 | enum Frequency { Rare = 1, Weekly = 2, Daily = 3 }; | ||
| 42 | |||
| 43 | QString id; | ||
| 44 | QList<QKeySequence> defaultKeys; | ||
| 45 | CommandContexts contexts; | ||
| 46 | const char *category = nullptr; | ||
| 47 | const char *description = nullptr; | ||
| 48 | bool showInHelp = true; | ||
| 49 | // S105.6.4 (D-17): what the key does when its name does not say it | ||
| 50 | // (one sentence, at most 70 characters; untranslated source text). | ||
| 51 | const char *explanation = nullptr; | ||
| 52 | // S105.7.4 (K-11): acts even while a text field has focus (the key types | ||
| 53 | // nothing: F-keys and Ctrl combinations). | ||
| 54 | bool whileTyping = false; | ||
| 55 | Frequency frequency = Weekly; | ||
| 56 | // S105.9.5: the key changed in 1.0 — `?` marks it "new" for one release. | ||
| 57 | // test_command_registry checks it against the inventory taken before. | ||
| 58 | bool changedKey = false; | ||
| 59 | |||
| 60 | // Builders for the table in CommandRegistry.cpp. | ||
| 61 | 812 | CommandSpec &explain(const char *text) { explanation = text; return *this; } | |
| 62 | 1508 | CommandSpec &typing() { whileTyping = true; return *this; } | |
| 63 | 1015 | CommandSpec &daily() { frequency = Daily; return *this; } | |
| 64 | 928 | CommandSpec &rare() { frequency = Rare; return *this; } | |
| 65 | CommandSpec &hidden() { showInHelp = false; return *this; } | ||
| 66 | 2204 | CommandSpec &changed() { changedKey = true; return *this; } | |
| 67 | }; | ||
| 68 | |||
| 69 | // Single source of truth for shortcut identity, keys, scope, help text and | ||
| 70 | // explanations (Sprint 105 rule 2). The router, the help popup, the keys | ||
| 71 | // overlay, tooltips and docs/user/KEYBOARD.md all read this table. | ||
| 72 | class CommandRegistry : public QObject { | ||
| 73 | Q_OBJECT | ||
| 74 | |||
| 75 | public: | ||
| 76 | explicit CommandRegistry(QObject *parent = nullptr); | ||
| 77 | |||
| 78 | static const QList<CommandSpec> &specs(); | ||
| 79 | static const CommandSpec *find(const QString &id); | ||
| 80 | static QString translatedCategory(const CommandSpec &spec); | ||
| 81 | static QString translatedDescription(const CommandSpec &spec); | ||
| 82 | static QString translatedExplanation(const CommandSpec &spec); | ||
| 83 | // Portable key text ("Ctrl+R", "g i"); single letters in lower case. | ||
| 84 | static QString keyText(const CommandSpec &spec); | ||
| 85 | static QString keyText(const QKeySequence &key); | ||
| 86 | // The same in the interface language ("Strg+R" in German). | ||
| 87 | static QString nativeKeyText(const QKeySequence &key); | ||
| 88 | // Markdown body of docs/user/KEYBOARD.md between the keyboard-reference | ||
| 89 | // markers (scripts/update_keyboard_reference.py writes the same text). | ||
| 90 | static QString keyboardReference(); | ||
| 91 | static QStringList duplicateSequences(); | ||
| 92 | // S105.7.7: fixed keys on Alt + letter/digit (reserved for the overlay, | ||
| 93 | // D-11); Alt+Up and Alt+Down are allowed. | ||
| 94 | static QStringList altLetterViolations(); | ||
| 95 | |||
| 96 | bool bind(const QString &id, QAction *action); | ||
| 97 | void setContext(CommandContext context); | ||
| 98 | CommandContext context() const { return m_context; } | ||
| 99 | QAction *action(const QString &id) const; | ||
| 100 | |||
| 101 | private: | ||
| 102 | void applyContext(); | ||
| 103 | |||
| 104 | QHash<QString, QPointer<QAction>> m_actions; | ||
| 105 | CommandContext m_context = CommandContext::MainMail; | ||
| 106 | }; | ||
| 107 |