Skip to content

Commit cd65597

Browse files
authored
Added support for multiple hotkeys per action (#490)
* Moved ActionsShortcutsManager into the nc::core namespace; DI'ing its Config depenency; Removed the 4 title placeholders in the main menu. * NSEventModifierFlagsHolder can be used from a clean C++ * Started laying out unit tests for ActionsShortcutsManager * Added a few more simple unit tests * clang-tidy * Allow constructing ActionShortcut out of EventData. Replaced IsKeyDown() with operator==(). * TagFromAction now returns std::optional, instead of relying on magic values to indicate errors * Removed the IF_MENU_TAG macro * ActionFromTag returns std::optional<std::string_view>, instead of encoding an error as an empty string * clang-tidy * ShortCutFromAction, ShortCutFromTag and DefaultShortCutFromTag return a std::optional instead of using the default state to convey errors * Added ActionTagsFromShortCut() and FirstOfActionTagsFromShortCut() that provide action(s) for a given shortcut * Removed ShortCutsUpdater, migrated client code to FirstOfActionTagsFromShortCut() * clang-tidy * Refactoring ActionShortcutsManager's API and internals to support multiple shortcuts per action * ShortCut -> Shortcut * ShortcutFromAction -> ShortcutsFromAction, ShortcutFromTag -> ShortcutsFromTag, DefaultShortcutFromTag -> DefaultShortcutsFromTag * Support for writing and reading multiple shortcuts per action * clang-tidy * Adding support for multiple shortcuts per action in the Settings dialog * Filtering out duplicate shortcuts per action * clang-tidy * Menu actions can be triggered via additional shortcuts as well * Extracted SetMenuShortcuts() into an NSMenu category. * Extracted part of ActionsShortcutsManager as a pure interface in nc::utility, DI'ed it into Viewer. * Updated the localization
1 parent 2d414fb commit cd65597

31 files changed

Lines changed: 1496 additions & 553 deletions

Source/NimbleCommander/NimbleCommander.xcodeproj/project.pbxproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@
197197
CF36DBE01F6BCDA0004A018E /* WebDAVConnectionSheetController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CF36DBE51F6BCDA0004A018E /* WebDAVConnectionSheetController.xib */; };
198198
CF36DBE11F6BCDA0004A018E /* WebDAVConnectionSheetController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CF36DBE51F6BCDA0004A018E /* WebDAVConnectionSheetController.xib */; };
199199
CF36DBE21F6BCDA0004A018E /* WebDAVConnectionSheetController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CF36DBE51F6BCDA0004A018E /* WebDAVConnectionSheetController.xib */; };
200+
CF371DAA2D18472E0034EB3F /* ActionsShortcutsManager_UT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CF371DA92D18472E0034EB3F /* ActionsShortcutsManager_UT.cpp */; };
200201
CF45CA281D3E3A6F0074F04C /* PreferencesWindowToolsTab.xib in Resources */ = {isa = PBXBuildFile; fileRef = CF45CA2C1D3E3A6F0074F04C /* PreferencesWindowToolsTab.xib */; };
201202
CF45CA291D3E3A6F0074F04C /* PreferencesWindowToolsTab.xib in Resources */ = {isa = PBXBuildFile; fileRef = CF45CA2C1D3E3A6F0074F04C /* PreferencesWindowToolsTab.xib */; };
202203
CF45CA2D1D3E3AA70074F04C /* ExternalToolParameterValueSheetController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CF45CA311D3E3AA70074F04C /* ExternalToolParameterValueSheetController.xib */; };
@@ -951,6 +952,7 @@
951952
CF31F66F1DFE644B005A1A40 /* Layout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = Layout.mm; path = NimbleCommander/States/FilePanels/Brief/Layout.mm; sourceTree = SOURCE_ROOT; };
952953
CF36DBE41F6BCDA0004A018E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/WebDAVConnectionSheetController.xib; sourceTree = "<group>"; };
953954
CF36DBE61F6BCF5B004A018E /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/WebDAVConnectionSheetController.strings; sourceTree = "<group>"; };
955+
CF371DA92D18472E0034EB3F /* ActionsShortcutsManager_UT.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ActionsShortcutsManager_UT.cpp; path = NimbleCommander/Tests/ActionsShortcutsManager_UT.cpp; sourceTree = "<group>"; };
954956
CF3989C12B44447D006103C1 /* Base.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Base.xcodeproj; path = ../Base/Base.xcodeproj; sourceTree = "<group>"; };
955957
CF3B7F6E201F20D300BF2090 /* PanelControllerActionsDispatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PanelControllerActionsDispatcher.h; path = NimbleCommander/States/FilePanels/PanelControllerActionsDispatcher.h; sourceTree = SOURCE_ROOT; };
956958
CF3B7F6F201F20D300BF2090 /* PanelControllerActionsDispatcher.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PanelControllerActionsDispatcher.mm; path = NimbleCommander/States/FilePanels/PanelControllerActionsDispatcher.mm; sourceTree = SOURCE_ROOT; };
@@ -1698,12 +1700,13 @@
16981700
CF5DE0BF2584153B00604DEE /* Tests */ = {
16991701
isa = PBXGroup;
17001702
children = (
1703+
CF371DA92D18472E0034EB3F /* ActionsShortcutsManager_UT.cpp */,
17011704
CF764CE62587661300D7ED17 /* DragSender_UT.mm */,
17021705
CF764D422587837200D7ED17 /* PanelBriefViewDynamicWidthLayoutEngine_UT.mm */,
17031706
CF764D4E258785CC00D7ED17 /* PanelBriefViewFixedNumberLayoutEngine_UT.mm */,
17041707
CF764D562587875E00D7ED17 /* PanelBriefViewFixedWidthLayoutEngine_UT.mm */,
1705-
CF5DE0C12584157B00604DEE /* Tests.cpp */,
17061708
CF5DE0C02584157B00604DEE /* Tests.h */,
1709+
CF5DE0C12584157B00604DEE /* Tests.cpp */,
17071710
CF67F1BE2954689000B92944 /* Theme_UT.mm */,
17081711
CFD2D26028A03DC0003C18F9 /* ThemesManager_UT.mm */,
17091712
);
@@ -3199,6 +3202,7 @@
31993202
files = (
32003203
CF67F1BF2954689000B92944 /* Theme_UT.mm in Sources */,
32013204
CF764D572587875E00D7ED17 /* PanelBriefViewFixedWidthLayoutEngine_UT.mm in Sources */,
3205+
CF371DAA2D18472E0034EB3F /* ActionsShortcutsManager_UT.cpp in Sources */,
32023206
CF764D4F258785CC00D7ED17 /* PanelBriefViewFixedNumberLayoutEngine_UT.mm in Sources */,
32033207
CF0A48902BDDA64700833160 /* PFMoveToApplicationsShim.mm in Sources */,
32043208
CF0A48912BDDA64A00833160 /* SparkleShim.m in Sources */,

Source/NimbleCommander/NimbleCommander/Bootstrap/AppDelegate+ViewerCreation.mm

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,9 @@ - (NCViewerView *)makeViewerWithFrame:(NSRect)frame
2020

2121
- (NCViewerViewController *)makeViewerController
2222
{
23-
auto shortcuts = [](std::string_view _name) {
24-
return ActionsShortcutsManager::Instance().ShortCutFromAction(_name);
25-
};
2623
return [[NCViewerViewController alloc] initWithHistory:self.internalViewerHistory
2724
config:self.globalConfig
28-
shortcutsProvider:shortcuts];
25+
shortcuts:nc::core::ActionsShortcutsManager::Instance()];
2926
}
3027

3128
@end

Source/NimbleCommander/NimbleCommander/Bootstrap/AppDelegate.mm

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -138,23 +138,6 @@ static void ResetDefaults()
138138
g_State->Commit();
139139
}
140140

141-
static void UpdateMenuItemsPlaceholders(int _tag)
142-
{
143-
static const auto app_name =
144-
static_cast<NSString *>([NSBundle.mainBundle.infoDictionary objectForKey:@"CFBundleName"]);
145-
146-
if( auto menu_item = [NSApp.mainMenu itemWithTagHierarchical:_tag] ) {
147-
auto title = menu_item.title;
148-
title = [title stringByReplacingOccurrencesOfString:@"{AppName}" withString:app_name];
149-
menu_item.title = title;
150-
}
151-
}
152-
153-
static void UpdateMenuItemsPlaceholders(const char *_action)
154-
{
155-
UpdateMenuItemsPlaceholders(ActionsShortcutsManager::TagFromAction(_action));
156-
}
157-
158141
static void CheckDefaultsReset()
159142
{
160143
const auto erase_mask =
@@ -299,8 +282,7 @@ - (void)applicationWillFinishLaunching:(NSNotification *) [[maybe_unused]] _noti
299282
[self updateMainMenuFeaturesByVersionAndState];
300283

301284
// update menu with current shortcuts layout
302-
ActionsShortcutsManager::Instance().SetMenuShortCuts([NSApp mainMenu]);
303-
285+
[NSApp.mainMenu nc_setMenuItemShortcutsWithActionsShortcutsManager:nc::core::ActionsShortcutsManager::Instance()];
304286
[self wireMenuDelegates];
305287

306288
if( nc::base::AmISandboxed() ) {
@@ -318,9 +300,11 @@ - (void)applicationWillFinishLaunching:(NSNotification *) [[maybe_unused]] _noti
318300
- (void)wireMenuDelegates
319301
{
320302
// set up menu delegates. do this via DI to reduce links to AppDelegate in whole codebase
321-
auto item_for_action = [](const char *_action) {
322-
auto tag = ActionsShortcutsManager::TagFromAction(_action);
323-
return [NSApp.mainMenu itemWithTagHierarchical:tag];
303+
auto item_for_action = [](const char *_action) -> NSMenuItem * {
304+
const std::optional<int> tag = nc::core::ActionsShortcutsManager::Instance().TagFromAction(_action);
305+
if( tag == std::nullopt )
306+
return nil;
307+
return [NSApp.mainMenu itemWithTagHierarchical:*tag];
324308
};
325309

326310
static auto layouts_delegate = [[PanelViewLayoutsMenuDelegate alloc] initWithStorage:*self.panelLayouts];
@@ -371,7 +355,9 @@ - (void)wireMenuDelegates
371355
- (void)updateMainMenuFeaturesByVersionAndState
372356
{
373357
// disable some features available in menu by configuration limitation
374-
auto tag_from_lit = [](const char *s) { return ActionsShortcutsManager::TagFromAction(s); };
358+
auto tag_from_lit = [](const char *s) {
359+
return nc::core::ActionsShortcutsManager::Instance().TagFromAction(s).value();
360+
};
375361
auto current_menuitem = [&](const char *s) { return [NSApp.mainMenu itemWithTagHierarchical:tag_from_lit(s)]; };
376362
auto hide = [&](const char *s) {
377363
auto item = current_menuitem(s);
@@ -408,13 +394,6 @@ - (void)applicationDidFinishLaunching:(NSNotification *) [[maybe_unused]] _notif
408394
#pragma clang diagnostic pop
409395
NSUpdateDynamicServices();
410396

411-
// Since we have different app names (Nimble Commander and Nimble Commander Pro) and one
412-
// fixed menu, we have to emplace the right title upon startup in some menu elements.
413-
UpdateMenuItemsPlaceholders("menu.nimble_commander.about");
414-
UpdateMenuItemsPlaceholders("menu.nimble_commander.hide");
415-
UpdateMenuItemsPlaceholders("menu.nimble_commander.quit");
416-
UpdateMenuItemsPlaceholders(17000); // Menu->Help
417-
418397
[self temporaryFileStorage]; // implicitly runs the background temp storage purging
419398

420399
// Non-MAS version extended logic below:
@@ -649,10 +628,11 @@ - (IBAction)OnMenuToggleAdminMode:(id) [[maybe_unused]] _sender
649628

650629
- (BOOL)validateMenuItem:(NSMenuItem *)item
651630
{
652-
auto tag = item.tag;
631+
static const int admin_mode_tag =
632+
nc::core::ActionsShortcutsManager::Instance().TagFromAction("menu.nimble_commander.toggle_admin_mode").value();
633+
const long tag = item.tag;
653634

654-
IF_MENU_TAG("menu.nimble_commander.toggle_admin_mode")
655-
{
635+
if( tag == admin_mode_tag ) {
656636
bool enabled = nc::routedio::RoutedIO::Instance().Enabled();
657637
item.title = enabled ? NSLocalizedString(@"Disable Admin Mode", "Menu item title for disabling an admin mode")
658638
: NSLocalizedString(@"Enable Admin Mode", "Menu item title for enabling an admin mode");

Source/NimbleCommander/NimbleCommander/Bootstrap/Base.lproj/MainMenu.xib

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="23091" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
2+
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="23504" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
33
<dependencies>
44
<deployment identifier="macosx"/>
5-
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23091"/>
5+
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23504"/>
66
</dependencies>
77
<objects>
88
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
@@ -17,7 +17,7 @@
1717
<menuItem title="Nimble Commander" id="56">
1818
<menu key="submenu" title="Nimble Commander" systemMenu="apple" id="57">
1919
<items>
20-
<menuItem title="About {AppName}" tag="10000" id="58">
20+
<menuItem title="About Nimble Commander" tag="10000" id="58">
2121
<modifierMask key="keyEquivalentModifierMask"/>
2222
<connections>
2323
<action selector="orderFrontStandardAboutPanel:" target="-2" id="142"/>
@@ -46,7 +46,7 @@
4646
<menuItem isSeparatorItem="YES" id="144">
4747
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
4848
</menuItem>
49-
<menuItem title="Hide {AppName}" tag="10020" keyEquivalent="h" id="134">
49+
<menuItem title="Hide Nimble Commander" tag="10020" keyEquivalent="h" id="134">
5050
<connections>
5151
<action selector="hide:" target="-1" id="367"/>
5252
</connections>
@@ -65,7 +65,7 @@
6565
<menuItem isSeparatorItem="YES" id="149">
6666
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
6767
</menuItem>
68-
<menuItem title="Quit {AppName}" tag="10050" keyEquivalent="q" id="136">
68+
<menuItem title="Quit Nimble Commander" tag="10050" keyEquivalent="q" id="136">
6969
<connections>
7070
<action selector="terminate:" target="-3" id="449"/>
7171
</connections>
@@ -1029,7 +1029,7 @@ CQ
10291029
<modifierMask key="keyEquivalentModifierMask"/>
10301030
<menu key="submenu" title="Help" systemMenu="help" id="491">
10311031
<items>
1032-
<menuItem title="{AppName} Help" tag="17000" keyEquivalent="?" id="iBP-LD-aNS">
1032+
<menuItem title="Nimble Commander Help" tag="17000" keyEquivalent="?" id="iBP-LD-aNS">
10331033
<connections>
10341034
<action selector="OnShowHelp:" target="-1" id="mbF-jF-ZMK"/>
10351035
</connections>

Source/NimbleCommander/NimbleCommander/Bootstrap/ru.lproj/MainMenu.strings

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@
7676
/* Class = "NSMenu"; title = "Nimble Commander"; ObjectID = "57"; */
7777
"57.title" = "Nimble Commander";
7878

79-
/* Class = "NSMenuItem"; title = "About {AppName}"; ObjectID = "58"; */
80-
"58.title" = "О {AppName}";
79+
/* Class = "NSMenuItem"; title = "About Nimble Commander"; ObjectID = "58"; */
80+
"58.title" = "О Nimble Commander";
8181

8282
/* Class = "NSMenuItem"; title = "Enter"; ObjectID = "72"; */
8383
"72.title" = "Войти";
@@ -103,11 +103,11 @@
103103
/* Class = "NSMenuItem"; title = "Services"; ObjectID = "131"; */
104104
"131.title" = "Службы";
105105

106-
/* Class = "NSMenuItem"; title = "Hide {AppName}"; ObjectID = "134"; */
107-
"134.title" = "Скрыть {AppName}";
106+
/* Class = "NSMenuItem"; title = "Hide Nimble Commander"; ObjectID = "134"; */
107+
"134.title" = "Скрыть Nimble Commander";
108108

109-
/* Class = "NSMenuItem"; title = "Quit {AppName}"; ObjectID = "136"; */
110-
"136.title" = "Завершить {AppName}";
109+
/* Class = "NSMenuItem"; title = "Quit Nimble Commander"; ObjectID = "136"; */
110+
"136.title" = "Завершить Nimble Commander";
111111

112112
/* Class = "NSMenuItem"; title = "Hide Others"; ObjectID = "145"; */
113113
"145.title" = "Скрыть остальные";
@@ -355,8 +355,8 @@
355355
/* Class = "NSMenuItem"; title = "External Editor"; ObjectID = "IBo-yJ-DeD"; */
356356
"IBo-yJ-DeD.title" = "Внешний редактор";
357357

358-
/* Class = "NSMenuItem"; title = "{AppName} Help"; ObjectID = "iBP-LD-aNS"; */
359-
"iBP-LD-aNS.title" = "Справка {AppName}";
358+
/* Class = "NSMenuItem"; title = "Nimble Commander Help"; ObjectID = "iBP-LD-aNS"; */
359+
"iBP-LD-aNS.title" = "Справка Nimble Commander";
360360

361361
/* Class = "NSMenuItem"; title = "Home"; ObjectID = "iGm-8g-qdX"; */
362362
"iGm-8g-qdX.title" = "Личное";

0 commit comments

Comments
 (0)