Salome HOME
[bos #35160][EDF](2023-T1) Keyboard shortcuts.
authordish <Dmitrii.SHVYDKOI@opencascade.com>
Thu, 7 Dec 2023 06:55:48 +0000 (06:55 +0000)
committerdish <dmitrii.shvydkoi@opencascade.com>
Thu, 25 Jan 2024 10:50:35 +0000 (10:50 +0000)
Add ReadMe and an auxiliary for DevTools file.

src/SUIT/SUIT_ShortcutMgr. ReadMe.md [new file with mode: 0644]
tools/DevTools/ShortcutMgr/ShortcutMgr. Resource generator.xlsx [new file with mode: 0644]

diff --git a/src/SUIT/SUIT_ShortcutMgr. ReadMe.md b/src/SUIT/SUIT_ShortcutMgr. ReadMe.md
new file mode 100644 (file)
index 0000000..65702e7
--- /dev/null
@@ -0,0 +1,82 @@
+ # ShortcutMgr ReadMe
+
+Hot keys must be considered as resources, being shared between all components of an application. E.g. it is unacceptable to have 'Close file' and 'Redo' actions being assigned to the same key sequence. When the SHAPER module is active, the application desktop is active too. The desktop has own hot keys, and they must not interfere with ones of SHAPER. Since the task implies granting users a right to assign shortcuts on their will, the application must track all assigned shortcuts of all modules, prevent intolerable user shortcut modifications and govern actual binding of QActions with key sequences.
+
+`SUIT_ShortcutMgr` handles shortcuts of SALOME desktop and all modules. It is solely responsible and capable to dynamically bind actions with key sequences and (de)serialize shortcut preferences using `SUIT_ResourceMgr`. `SUIT_ShortcutContainer` encapsulates logics of conflict detecting and resolving. `QtxShortcutTree` widget provides GUI to change shortcut preferences conveniently: it allows to remap plenty of shortcuts without applying, displays conflict-resolving dialog, highlights modifications until they are applied (saved into preference files).
+
+To (de)serialize shortcut preferences without dependence on language environment, shortcuts must be stored as pairs {action ID, key sequence}, where action IDs must be application-unique.
+
+Since desktop shortcuts may also be changed and interfere with shortcuts of modules, `QtxShortcutTree` should always display desktop shortcuts and shortcuts of all modules altogether, even if some modules are inactive. It means, that `QtxShortcutTree` must be fed not only with shortcut data {action ID, key sequence}[], but also with dictionaries {action ID, action name}[].
+
+Names of actions may be retrieved from instances of actions, but there is a pitfall: if a module has not been activated yet, its actions have not been initialized either.
+Qt Linguist is no help in this case too. To retrieve an action name using `QObject::tr(actionID)`, the `tr(const char*)` method must be called with instance of the class, which is designated as a context for the actionID in *.ts files. And contexts are usually descendants of SUIT_Application and CAM_Module. Again, until a module instance is created, there is no way for `SUIT_ShortcutMgr` to get even a name of a context-class, which an action with an ID belongs to, without any additional data. Straightforward mechanism for dynamic translation from action IDs to action names has been devised: for all actions, which are bound by default or may be bound by user to hotkeys, dictionaries must be placed into resource files. People who do/refine localizations should keep this in mind and also process entries like `<section name="shortcut_translations:action ID">` of resource files.
+
+To alleviate process of composing resources, a development tool `DevTools` has been made. It grabs all shortcuts and status tips of intercepted at runtime actions with valid IDs and dumps results into XML files with identical to project-conventional resource files structure. Run modules/features of interest, switch application language, and if IDs or names in the selected language of some actions of the module are not added yet to preference files, these dump files will be appended with new data – shortcuts and translations, if the last ones are provided in *.ts files.
+The tool also logs assets (text, tool tip, status tip, bound key sequence, etc.) of intercepted actions with invalid IDs. The intent is as follows: run modules/features of interest at several languages in exactly the same sequence of actions, paste content of resulting language-dedicated *.csv files to corresponding sheet of  [“ShortcutMgr. Resource generator.xlsx”](../../tools/DevTools/ShortcutMgr/ShortcutMgr. Resource generator.xlsx). Then come up with proper IDs for the actions, type the action IDs and their module IDs into corresponding columns and take away ready resource items.
+
+Shortcuts and translations for all actions of SHAPER and GEOM and those actions of desktop, which were bound (hardcoded) to non-empty key sequences, have been added to resource files. Now they are available for hot key remapping via GUI, no conflicts guaranteed. Any hardcoded shortcut is disabled, unless the same shortcut persists in resource files.
+
+## Possible conflicts between shortcuts of desktop and modules, except SHAPER and GEOM
+
+Most of remaining actions can not be made available for shortcut customization without further meticulous inspection of all other modules' code, devising and typing proper action IDs for all such occurrences.
+
+Since desktop shortcuts are allowed for remapping, user can end up with conflicting shortcuts of desktop actions and those actions of unprocessed modules (all, except SHAPER and GEOM), which are hardcoded to non-empty key sequences.
+
+Now actions with invalid IDs are disabled by `SUIT_ShortcutMgr` at runtime and not available for binding neither using UI, neither by editing of preference file. There are four approaches how to handle this:
+
+1. Keep as is: user can remap shortcuts of desktop, SHAPER and GEOM - no conflicts guaranteed, hardcoded (now means all) shortcuts of other modules are disabled.
+
+2. Go through unprocessed repositories and add valid ID in every occurrence of action creation. Or at least only for those invalid-ID actions, which are currently assigned non-empty key sequences. It should not be just dumb slapping of unique IDs: some actions comprise meta-action (see `SUIT_ShortcutMgr` class documentation) and must get the same ID, e.g. “Undo”, and some actions with similar names do absolutely unrelated things and must be given with different IDs.
+
+3. Comment the line in `SUIT_ShortcutMgr` code, which disables shortcuts of inavlid-ID actions. At that rate, users will get back all the shortcuts of unprocessed modules they have accustomed to, but since these actions can not be taken into account during conflict detection,
+users may face with shortcut interference, if a desktop action is bound to the same key sequence as a hardcoded shortcut from unprocessed module.
+
+4. Forbid user to edit shortcuts of desktop and shortcuts of unprocessed modules. When another module will be processed, allow to modify its shortcuts. When all modules will be processed, make desktop shortcuts available for customization.
+
+## Issue with ampersand-shortcuts
+
+`QPushButton::QPushButton(const QString&)`, being fed with an action name with an ampersand preceding a char, automatically creates a shortcut, bound to *Alt+\<char>* key sequence.
+
+E.g. `auto button = QPushButton(tr("&Help")` may create language-depdendent shortcuts. Suppose that \*_fr.ts file contains this:
+```
+<message>
+       <source>&amp;Help</source>
+       <translation>A&amp;ide</translation>
+<message>
+
+```
+
+Then help menu has different shortcuts if the application is run in EN or FR.
+
+**A part of the issue** is that some ampersand-shortcuts interfere between each other. You can witness this in master-native application. Switch language to FR, run the app, click on the area, where viewers appear, and stroke *Alt+A*. You will get a Qt-generated notification *"Ambiguous shortcut detected"*, because *Alt+A* is bound to *"New ParaView window"* and to *"Affichage"* simultaneously. If you stroke the sequence again, *"Affichage"* menu expands, since the button tray, where the menu-button resides, has gained focus.
+
+**Another part of the issue** is that ampersand-shortcuts are not always intercepted by `SUIT_ShortcutMgr::eventFilter(_)`. Normally, if the manager catches an unregistered `QAction`, it disables the action' shortcut. But, non-intercepted ampersand-shortcut remains enabled, and, if user binds some action to the same key sequence in the shortcut editor, the editor is not able to detect conflict and prevent interfering binding. Then user faces with the *"Ambiguous shortcut detected"* notification or button-menu is opened instead of executing the action, mapped to the key sequence in shortcut editor.
+
+**The question is how to handle ampersand-shortcuts?**
+1. Resolve conflicts between ampersand-shortcuts for all localizations. Prohibit binding actions to *Alt+\<char>* key sequences in shortcut editor.
+2. After every occurrence of `QPushButton` creation type something like this:
+```
+// Occurrence
+const auto helpButton = new QPushButton(tr("&Help");
+SUIT_ShortcutMgr::get()->registerButtonActions("/#AltHelp", *helpButton);
+
+----------------------------------------------------
+// SUIT_ShortcutMgr.cpp
+void SUIT_ShortcutMgr::registerButtonActions(const QString& theActionID, const QPushButton& theButton) const {
+       for (QAction* const action : theButton.actions()) {
+               registerAction(theActionID, action);
+       }
+}
+----------------------------------------------------
+// Resource file
+       <section name="shortcuts:">
+               <parameter name="#AltHelp" value="Alt+H"/>
+       </section>
+```
+Thus, ampersand-shortcuts will appear and be treated in shortcut editor as regular shortcuts.
+If the second option is preferable, should different ampersand-shortcuts for every target language be placed in resource files?
+
+## Minor issues
+1. `QtxShortcutTree` widget does not take the whole available height of preference window, it only takes as mush as its items require.
+2. Selection of `QtxShortcutTree`' item shadows "modified" highlighter. Can be fixed by replacing base `QTreeWidget` of `QtxShortcutTree` with `QTreeView`, or may be by applying some style sheet.
+3. `SUIT_ShortcutMgr` introduces concept of module, but the first module class is `CAM_Module` is introduced along with `CAM_Application`, which is descendant of `SUIT_Application`.
diff --git a/tools/DevTools/ShortcutMgr/ShortcutMgr. Resource generator.xlsx b/tools/DevTools/ShortcutMgr/ShortcutMgr. Resource generator.xlsx
new file mode 100644 (file)
index 0000000..bfc86f9
Binary files /dev/null and b/tools/DevTools/ShortcutMgr/ShortcutMgr. Resource generator.xlsx differ