Redesign recent documents role API

- For more flexibility in designing the recent documents menu, now there can be one menu item (known issue: you may specify more but AppKit doens't display more than one) in the submenu list, rather than separating the labels with a tab.
- Also added is the role `clearrecent` that can be given to a menu item that can clear the recent documents.
This commit is contained in:
Zhuo Lu 2017-11-20 16:15:43 -08:00 committed by Cheng Zhao
parent 828d233f2a
commit 5d44dbaf54
3 changed files with 53 additions and 33 deletions

View file

@ -26,8 +26,6 @@ class AtomMenuModel;
@protected
atom::AtomMenuModel* model_; // weak
base::scoped_nsobject<NSMenu> menu_;
NSMenuItem* openRecentMenuItem_;
NSMenuItem* openRecentClearMenuMenuItem_; // weak
BOOL isMenuOpen_;
BOOL useDefaultAccelerator_;
base::Callback<void()> closeCallback;

View file

@ -50,10 +50,17 @@ Role kRolesMap[] = {
{ @selector(selectPreviousTab:), "selectprevioustab" },
{ @selector(mergeAllWindows:), "mergeallwindows" },
{ @selector(moveTabToNewWindow:), "movetabtonewwindow" },
{ @selector(clearRecentDocuments:), "clearrecent" },
};
} // namespace
// Menu item is located for ease of removing it from the parent owner
NSMenuItem* recentDocumentsMenuItem_;
// TODO(sethlu): Doc & find a better naming
NSMenu* swapMenu_;
@implementation AtomMenuController
@synthesize model = model_;
@ -77,8 +84,6 @@ Role kRolesMap[] = {
model_ = nil;
[openRecentMenuItem_ release];
[super dealloc];
}
@ -90,14 +95,13 @@ Role kRolesMap[] = {
if (!menu_)
return;
// Retain submenu for recent documents
if (!openRecentMenuItem_) {
openRecentMenuItem_ = [[[[NSApp mainMenu]
itemWithTitle:@"Electron"] submenu] itemWithTitle:@"Open Recent"];
[openRecentMenuItem_ setHidden:NO];
[openRecentMenuItem_ retain];
openRecentClearMenuMenuItem_ =
[[openRecentMenuItem_ submenu] itemWithTitle:@"Clear Menu"];
if (!recentDocumentsMenuItem_) {
// Locate & retain the recent documents menu item
recentDocumentsMenuItem_ = [[[[[[NSApp mainMenu]
itemWithTitle:@"Electron"] submenu]
itemWithTitle:@"Open Recent"]
retain] autorelease];
[recentDocumentsMenuItem_ setHidden:NO];
}
model_ = model;
@ -145,6 +149,39 @@ Role kRolesMap[] = {
[menu insertItem:separator atIndex:index];
}
// TODO(sethlu): Doc
- (void)moveMenuItems:(NSMenu*)source
to:(NSMenu*)destination {
const long count = [source numberOfItems];
for (long index = 0; index < count; index++) {
NSMenuItem* removedItem = [[[source itemAtIndex:0] retain] autorelease];
[source removeItemAtIndex:0];
[destination addItem:removedItem];
}
}
// TODO(sethlu): Doc
- (void)replaceSubmenuShowingRecentDocuments:(NSMenuItem*)item {
NSMenu* recentDocumentsMenu = [[[recentDocumentsMenuItem_ submenu]
retain] autorelease];
// Remove menu items in recent documents back to swap menu
[self moveMenuItems:recentDocumentsMenu to:swapMenu_];
// Swap back the submenu
[recentDocumentsMenuItem_ setSubmenu:swapMenu_];
// Retain the item's submenu for a future recovery
swapMenu_ = [[[item submenu] retain] autorelease];
// Repopulate with items from the submenu to be replaced
[self moveMenuItems:swapMenu_ to:recentDocumentsMenu];
// Replace submenu
[item setSubmenu:recentDocumentsMenu];
// Remember the new menu item that carries the recent documents menu
recentDocumentsMenuItem_ = [[item retain] autorelease];
}
// Adds an item or a hierarchical menu to the item at the |index|,
// associated with the entry in the model identified by |modelIndex|.
- (void)addItemToMenu:(NSMenu*)menu
@ -154,26 +191,6 @@ Role kRolesMap[] = {
NSString* label = l10n_util::FixUpWindowsStyleLabel(label16);
base::string16 role = model->GetRoleAt(index);
if (role == base::ASCIIToUTF16("openrecent")) {
// Remove singleton menu item from parent menu
[[openRecentMenuItem_ menu] removeItem:openRecentMenuItem_];
// Label formatted as "Open Recent\tClear Menu"
NSArray *titles = [label componentsSeparatedByString:@"\t"];
// Open recent
[openRecentMenuItem_ setTitle:titles[0]];
[[openRecentMenuItem_ submenu] setTitle:titles[0]];
[menu insertItem:openRecentMenuItem_ atIndex:index];
// Clear menu item only displayed if specified in label
bool clearMenuVisible = [titles count] > 1;
[openRecentClearMenuMenuItem_ setHidden:!clearMenuVisible];
if (clearMenuVisible) [openRecentClearMenuMenuItem_ setTitle:titles[1]];
return;
}
base::scoped_nsobject<NSMenuItem> item(
[[NSMenuItem alloc] initWithTitle:label
action:@selector(itemSelected:)
@ -202,6 +219,8 @@ Role kRolesMap[] = {
[NSApp setHelpMenu:submenu];
else if (role == base::ASCIIToUTF16("services"))
[NSApp setServicesMenu:submenu];
else if (role == base::ASCIIToUTF16("openrecent"))
[self replaceSubmenuShowingRecentDocuments:item];
} else {
// The MenuModel works on indexes so we can't just set the command id as the
// tag like we do in other menus. Also set the represented object to be

View file

@ -103,7 +103,10 @@ const roles = {
label: 'Services'
},
openrecent: {
label: 'Open Recent\tClear Menu'
label: 'Open Recent'
},
clearrecent: {
label: 'Clear Menu'
},
startspeaking: {
label: 'Start Speaking'