Skip to content

Commit

Permalink
Added support for multiple hotkeys per action (#490)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
mikekazakov authored Dec 28, 2024
1 parent 2d414fb commit cd65597
Show file tree
Hide file tree
Showing 31 changed files with 1,496 additions and 553 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@
CF36DBE01F6BCDA0004A018E /* WebDAVConnectionSheetController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CF36DBE51F6BCDA0004A018E /* WebDAVConnectionSheetController.xib */; };
CF36DBE11F6BCDA0004A018E /* WebDAVConnectionSheetController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CF36DBE51F6BCDA0004A018E /* WebDAVConnectionSheetController.xib */; };
CF36DBE21F6BCDA0004A018E /* WebDAVConnectionSheetController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CF36DBE51F6BCDA0004A018E /* WebDAVConnectionSheetController.xib */; };
CF371DAA2D18472E0034EB3F /* ActionsShortcutsManager_UT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CF371DA92D18472E0034EB3F /* ActionsShortcutsManager_UT.cpp */; };
CF45CA281D3E3A6F0074F04C /* PreferencesWindowToolsTab.xib in Resources */ = {isa = PBXBuildFile; fileRef = CF45CA2C1D3E3A6F0074F04C /* PreferencesWindowToolsTab.xib */; };
CF45CA291D3E3A6F0074F04C /* PreferencesWindowToolsTab.xib in Resources */ = {isa = PBXBuildFile; fileRef = CF45CA2C1D3E3A6F0074F04C /* PreferencesWindowToolsTab.xib */; };
CF45CA2D1D3E3AA70074F04C /* ExternalToolParameterValueSheetController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CF45CA311D3E3AA70074F04C /* ExternalToolParameterValueSheetController.xib */; };
Expand Down Expand Up @@ -951,6 +952,7 @@
CF31F66F1DFE644B005A1A40 /* Layout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = Layout.mm; path = NimbleCommander/States/FilePanels/Brief/Layout.mm; sourceTree = SOURCE_ROOT; };
CF36DBE41F6BCDA0004A018E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/WebDAVConnectionSheetController.xib; sourceTree = "<group>"; };
CF36DBE61F6BCF5B004A018E /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/WebDAVConnectionSheetController.strings; sourceTree = "<group>"; };
CF371DA92D18472E0034EB3F /* ActionsShortcutsManager_UT.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ActionsShortcutsManager_UT.cpp; path = NimbleCommander/Tests/ActionsShortcutsManager_UT.cpp; sourceTree = "<group>"; };
CF3989C12B44447D006103C1 /* Base.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Base.xcodeproj; path = ../Base/Base.xcodeproj; sourceTree = "<group>"; };
CF3B7F6E201F20D300BF2090 /* PanelControllerActionsDispatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PanelControllerActionsDispatcher.h; path = NimbleCommander/States/FilePanels/PanelControllerActionsDispatcher.h; sourceTree = SOURCE_ROOT; };
CF3B7F6F201F20D300BF2090 /* PanelControllerActionsDispatcher.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PanelControllerActionsDispatcher.mm; path = NimbleCommander/States/FilePanels/PanelControllerActionsDispatcher.mm; sourceTree = SOURCE_ROOT; };
Expand Down Expand Up @@ -1698,12 +1700,13 @@
CF5DE0BF2584153B00604DEE /* Tests */ = {
isa = PBXGroup;
children = (
CF371DA92D18472E0034EB3F /* ActionsShortcutsManager_UT.cpp */,
CF764CE62587661300D7ED17 /* DragSender_UT.mm */,
CF764D422587837200D7ED17 /* PanelBriefViewDynamicWidthLayoutEngine_UT.mm */,
CF764D4E258785CC00D7ED17 /* PanelBriefViewFixedNumberLayoutEngine_UT.mm */,
CF764D562587875E00D7ED17 /* PanelBriefViewFixedWidthLayoutEngine_UT.mm */,
CF5DE0C12584157B00604DEE /* Tests.cpp */,
CF5DE0C02584157B00604DEE /* Tests.h */,
CF5DE0C12584157B00604DEE /* Tests.cpp */,
CF67F1BE2954689000B92944 /* Theme_UT.mm */,
CFD2D26028A03DC0003C18F9 /* ThemesManager_UT.mm */,
);
Expand Down Expand Up @@ -3199,6 +3202,7 @@
files = (
CF67F1BF2954689000B92944 /* Theme_UT.mm in Sources */,
CF764D572587875E00D7ED17 /* PanelBriefViewFixedWidthLayoutEngine_UT.mm in Sources */,
CF371DAA2D18472E0034EB3F /* ActionsShortcutsManager_UT.cpp in Sources */,
CF764D4F258785CC00D7ED17 /* PanelBriefViewFixedNumberLayoutEngine_UT.mm in Sources */,
CF0A48902BDDA64700833160 /* PFMoveToApplicationsShim.mm in Sources */,
CF0A48912BDDA64A00833160 /* SparkleShim.m in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,9 @@ - (NCViewerView *)makeViewerWithFrame:(NSRect)frame

- (NCViewerViewController *)makeViewerController
{
auto shortcuts = [](std::string_view _name) {
return ActionsShortcutsManager::Instance().ShortCutFromAction(_name);
};
return [[NCViewerViewController alloc] initWithHistory:self.internalViewerHistory
config:self.globalConfig
shortcutsProvider:shortcuts];
shortcuts:nc::core::ActionsShortcutsManager::Instance()];
}

@end
46 changes: 13 additions & 33 deletions Source/NimbleCommander/NimbleCommander/Bootstrap/AppDelegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -138,23 +138,6 @@ static void ResetDefaults()
g_State->Commit();
}

static void UpdateMenuItemsPlaceholders(int _tag)
{
static const auto app_name =
static_cast<NSString *>([NSBundle.mainBundle.infoDictionary objectForKey:@"CFBundleName"]);

if( auto menu_item = [NSApp.mainMenu itemWithTagHierarchical:_tag] ) {
auto title = menu_item.title;
title = [title stringByReplacingOccurrencesOfString:@"{AppName}" withString:app_name];
menu_item.title = title;
}
}

static void UpdateMenuItemsPlaceholders(const char *_action)
{
UpdateMenuItemsPlaceholders(ActionsShortcutsManager::TagFromAction(_action));
}

static void CheckDefaultsReset()
{
const auto erase_mask =
Expand Down Expand Up @@ -299,8 +282,7 @@ - (void)applicationWillFinishLaunching:(NSNotification *) [[maybe_unused]] _noti
[self updateMainMenuFeaturesByVersionAndState];

// update menu with current shortcuts layout
ActionsShortcutsManager::Instance().SetMenuShortCuts([NSApp mainMenu]);

[NSApp.mainMenu nc_setMenuItemShortcutsWithActionsShortcutsManager:nc::core::ActionsShortcutsManager::Instance()];
[self wireMenuDelegates];

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

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

// Since we have different app names (Nimble Commander and Nimble Commander Pro) and one
// fixed menu, we have to emplace the right title upon startup in some menu elements.
UpdateMenuItemsPlaceholders("menu.nimble_commander.about");
UpdateMenuItemsPlaceholders("menu.nimble_commander.hide");
UpdateMenuItemsPlaceholders("menu.nimble_commander.quit");
UpdateMenuItemsPlaceholders(17000); // Menu->Help

[self temporaryFileStorage]; // implicitly runs the background temp storage purging

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

- (BOOL)validateMenuItem:(NSMenuItem *)item
{
auto tag = item.tag;
static const int admin_mode_tag =
nc::core::ActionsShortcutsManager::Instance().TagFromAction("menu.nimble_commander.toggle_admin_mode").value();
const long tag = item.tag;

IF_MENU_TAG("menu.nimble_commander.toggle_admin_mode")
{
if( tag == admin_mode_tag ) {
bool enabled = nc::routedio::RoutedIO::Instance().Enabled();
item.title = enabled ? NSLocalizedString(@"Disable Admin Mode", "Menu item title for disabling an admin mode")
: NSLocalizedString(@"Enable Admin Mode", "Menu item title for enabling an admin mode");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="23091" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="23504" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23091"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23504"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
Expand All @@ -17,7 +17,7 @@
<menuItem title="Nimble Commander" id="56">
<menu key="submenu" title="Nimble Commander" systemMenu="apple" id="57">
<items>
<menuItem title="About {AppName}" tag="10000" id="58">
<menuItem title="About Nimble Commander" tag="10000" id="58">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-2" id="142"/>
Expand Down Expand Up @@ -46,7 +46,7 @@
<menuItem isSeparatorItem="YES" id="144">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Hide {AppName}" tag="10020" keyEquivalent="h" id="134">
<menuItem title="Hide Nimble Commander" tag="10020" keyEquivalent="h" id="134">
<connections>
<action selector="hide:" target="-1" id="367"/>
</connections>
Expand All @@ -65,7 +65,7 @@
<menuItem isSeparatorItem="YES" id="149">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Quit {AppName}" tag="10050" keyEquivalent="q" id="136">
<menuItem title="Quit Nimble Commander" tag="10050" keyEquivalent="q" id="136">
<connections>
<action selector="terminate:" target="-3" id="449"/>
</connections>
Expand Down Expand Up @@ -1029,7 +1029,7 @@ CQ
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="491">
<items>
<menuItem title="{AppName} Help" tag="17000" keyEquivalent="?" id="iBP-LD-aNS">
<menuItem title="Nimble Commander Help" tag="17000" keyEquivalent="?" id="iBP-LD-aNS">
<connections>
<action selector="OnShowHelp:" target="-1" id="mbF-jF-ZMK"/>
</connections>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@
/* Class = "NSMenu"; title = "Nimble Commander"; ObjectID = "57"; */
"57.title" = "Nimble Commander";

/* Class = "NSMenuItem"; title = "About {AppName}"; ObjectID = "58"; */
"58.title" = "О {AppName}";
/* Class = "NSMenuItem"; title = "About Nimble Commander"; ObjectID = "58"; */
"58.title" = "О Nimble Commander";

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

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

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

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

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

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

0 comments on commit cd65597

Please sign in to comment.