Merge pull request #11166 from sethlu/openrecent

feat: Recent documents menu item
This commit is contained in:
Cheng Zhao 2017-11-28 10:55:14 +09:00 committed by GitHub
commit b161a4f515
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 106 additions and 6 deletions

View file

@ -50,10 +50,17 @@ Role kRolesMap[] = {
{ @selector(selectPreviousTab:), "selectprevioustab" }, { @selector(selectPreviousTab:), "selectprevioustab" },
{ @selector(mergeAllWindows:), "mergeallwindows" }, { @selector(mergeAllWindows:), "mergeallwindows" },
{ @selector(moveTabToNewWindow:), "movetabtonewwindow" }, { @selector(moveTabToNewWindow:), "movetabtonewwindow" },
{ @selector(clearRecentDocuments:), "clearrecentdocuments" },
}; };
} // namespace } // namespace
// Menu item is located for ease of removing it from the parent owner
static base::scoped_nsobject<NSMenuItem> recentDocumentsMenuItem_;
// Submenu retained to be swapped back to |recentDocumentsMenuItem_|
static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
@implementation AtomMenuController @implementation AtomMenuController
@synthesize model = model_; @synthesize model = model_;
@ -75,7 +82,8 @@ Role kRolesMap[] = {
// while its context menu is still open. // while its context menu is still open.
[self cancel]; [self cancel];
model_ = nullptr; model_ = nil;
[super dealloc]; [super dealloc];
} }
@ -87,6 +95,14 @@ Role kRolesMap[] = {
if (!menu_) if (!menu_)
return; return;
if (!recentDocumentsMenuItem_) {
// Locate & retain the recent documents menu item
recentDocumentsMenuItem_.reset([[[[[NSApp mainMenu]
itemWithTitle:@"Electron"] submenu]
itemWithTitle:@"Open Recent"]
retain]);
}
model_ = model; model_ = model;
[menu_ removeAllItems]; [menu_ removeAllItems];
@ -132,6 +148,42 @@ Role kRolesMap[] = {
[menu insertItem:separator atIndex:index]; [menu insertItem:separator atIndex:index];
} }
// Empties the source menu items to the destination.
- (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];
}
}
// Replaces the item's submenu instance with the singleton recent documents
// menu. Previously replaced menu items will be recovered.
- (void)replaceSubmenuShowingRecentDocuments:(NSMenuItem*)item {
NSMenu* recentDocumentsMenu = [[[recentDocumentsMenuItem_ submenu]
retain] autorelease];
// Remove menu items in recent documents back to swap menu
[self moveMenuItems:recentDocumentsMenu
to:recentDocumentsMenuSwap_];
// Swap back the submenu
[recentDocumentsMenuItem_ setSubmenu:recentDocumentsMenuSwap_];
// Retain the item's submenu for a future recovery
recentDocumentsMenuSwap_.reset([[item submenu] retain]);
// Repopulate with items from the submenu to be replaced
[self moveMenuItems:recentDocumentsMenuSwap_
to:recentDocumentsMenu];
// Replace submenu
[item setSubmenu:recentDocumentsMenu];
// Remember the new menu item that carries the recent documents menu
recentDocumentsMenuItem_.reset([item retain]);
}
// Adds an item or a hierarchical menu to the item at the |index|, // Adds an item or a hierarchical menu to the item at the |index|,
// associated with the entry in the model identified by |modelIndex|. // associated with the entry in the model identified by |modelIndex|.
- (void)addItemToMenu:(NSMenu*)menu - (void)addItemToMenu:(NSMenu*)menu
@ -139,6 +191,7 @@ Role kRolesMap[] = {
fromModel:(atom::AtomMenuModel*)model { fromModel:(atom::AtomMenuModel*)model {
base::string16 label16 = model->GetLabelAt(index); base::string16 label16 = model->GetLabelAt(index);
NSString* label = l10n_util::FixUpWindowsStyleLabel(label16); NSString* label = l10n_util::FixUpWindowsStyleLabel(label16);
base::scoped_nsobject<NSMenuItem> item( base::scoped_nsobject<NSMenuItem> item(
[[NSMenuItem alloc] initWithTitle:label [[NSMenuItem alloc] initWithTitle:label
action:@selector(itemSelected:) action:@selector(itemSelected:)
@ -149,6 +202,7 @@ Role kRolesMap[] = {
if (model->GetIconAt(index, &icon) && !icon.IsEmpty()) if (model->GetIconAt(index, &icon) && !icon.IsEmpty())
[item setImage:icon.ToNSImage()]; [item setImage:icon.ToNSImage()];
base::string16 role = model->GetRoleAt(index);
atom::AtomMenuModel::ItemType type = model->GetTypeAt(index); atom::AtomMenuModel::ItemType type = model->GetTypeAt(index);
if (type == atom::AtomMenuModel::TYPE_SUBMENU) { if (type == atom::AtomMenuModel::TYPE_SUBMENU) {
// Recursively build a submenu from the sub-model at this index. // Recursively build a submenu from the sub-model at this index.
@ -161,14 +215,14 @@ Role kRolesMap[] = {
[item setSubmenu:submenu]; [item setSubmenu:submenu];
// Set submenu's role. // Set submenu's role.
base::string16 role = model->GetRoleAt(index);
if (role == base::ASCIIToUTF16("window") && [submenu numberOfItems]) if (role == base::ASCIIToUTF16("window") && [submenu numberOfItems])
[NSApp setWindowsMenu:submenu]; [NSApp setWindowsMenu:submenu];
else if (role == base::ASCIIToUTF16("help")) else if (role == base::ASCIIToUTF16("help"))
[NSApp setHelpMenu:submenu]; [NSApp setHelpMenu:submenu];
else if (role == base::ASCIIToUTF16("services"))
if (role == base::ASCIIToUTF16("services"))
[NSApp setServicesMenu:submenu]; [NSApp setServicesMenu:submenu];
else if (role == base::ASCIIToUTF16("recentdocuments"))
[self replaceSubmenuShowingRecentDocuments:item];
} else { } else {
// The MenuModel works on indexes so we can't just set the command id as the // 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 // tag like we do in other menus. Also set the represented object to be
@ -192,7 +246,6 @@ Role kRolesMap[] = {
} }
// Set menu item's role. // Set menu item's role.
base::string16 role = model->GetRoleAt(index);
[item setTarget:self]; [item setTarget:self];
if (!role.empty()) { if (!role.empty()) {
for (const Role& pair : kRolesMap) { for (const Role& pair : kRolesMap) {

View file

@ -65,6 +65,22 @@
<reference key="NSOnImage" ref="229763992"/> <reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/> <reference key="NSMixedImage" ref="909111550"/>
</object> </object>
<object class="NSMenuItem" id="1025936716">
<reference key="NSMenu" ref="110575045"/>
<string key="NSTitle">Open Recent</string>
<string key="NSKeyEquiv"/>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<bool key="NSIsHidden">YES</bool>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
<string key="NSAction">submenuAction:</string>
<object class="NSMenu" key="NSSubmenu" id="1065607017">
<string key="NSTitle">Open Recent</string>
<array class="NSMutableArray" key="NSMenuItems"></array>
<string key="NSName">_NSRecentDocumentsMenu</string>
</object>
</object>
</array> </array>
<string key="NSName">_NSAppleMenu</string> <string key="NSName">_NSAppleMenu</string>
</object> </object>
@ -115,6 +131,7 @@
<reference key="object" ref="903638069"/> <reference key="object" ref="903638069"/>
<reference key="parent" ref="0"/> <reference key="parent" ref="0"/>
</object> </object>
<!-- NSMenu Main Menu -->
<object class="IBObjectRecord"> <object class="IBObjectRecord">
<int key="objectID">29</int> <int key="objectID">29</int>
<reference key="object" ref="649796088"/> <reference key="object" ref="649796088"/>
@ -123,6 +140,7 @@
</array> </array>
<reference key="parent" ref="0"/> <reference key="parent" ref="0"/>
</object> </object>
<!-- NSMenuItem Electron -->
<object class="IBObjectRecord"> <object class="IBObjectRecord">
<int key="objectID">56</int> <int key="objectID">56</int>
<reference key="object" ref="694149608"/> <reference key="object" ref="694149608"/>
@ -131,30 +149,51 @@
</array> </array>
<reference key="parent" ref="649796088"/> <reference key="parent" ref="649796088"/>
</object> </object>
<!-- NSMenu Electron -->
<object class="IBObjectRecord"> <object class="IBObjectRecord">
<int key="objectID">57</int> <int key="objectID">57</int>
<reference key="object" ref="110575045"/> <reference key="object" ref="110575045"/>
<array class="NSMutableArray" key="children"> <array class="NSMutableArray" key="children">
<reference ref="632727374"/> <reference ref="632727374"/>
<reference ref="1025936716"/>
</array> </array>
<reference key="parent" ref="694149608"/> <reference key="parent" ref="694149608"/>
</object> </object>
<!-- NSMenuItem Quit -->
<object class="IBObjectRecord"> <object class="IBObjectRecord">
<int key="objectID">136</int> <int key="objectID">136</int>
<reference key="object" ref="632727374"/> <reference key="object" ref="632727374"/>
<reference key="parent" ref="110575045"/> <reference key="parent" ref="110575045"/>
</object> </object>
<!-- NSMenuItem Open Recent -->
<object class="IBObjectRecord">
<int key="objectID">124</int>
<reference key="object" ref="1025936716"/>
<array class="NSMutableArray" key="children">
<reference ref="1065607017"/>
</array>
<reference key="parent" ref="110575045"/>
</object>
<!-- NSMenu Open Recent -->
<object class="IBObjectRecord">
<int key="objectID">125</int>
<reference key="object" ref="1065607017"/>
<array class="NSMutableArray" key="children"></array>
<reference key="parent" ref="1025936716"/>
</object>
</array> </array>
</object> </object>
<dictionary class="NSMutableDictionary" key="flattenedProperties"> <dictionary class="NSMutableDictionary" key="flattenedProperties">
<string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="-3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="-3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="136.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="29.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="29.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="371.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="371.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="56.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="56.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="57.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="57.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="136.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="124.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="125.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
</dictionary> </dictionary>
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/> <dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
<nil key="activeLocalization"/> <nil key="activeLocalization"/>

View file

@ -88,6 +88,8 @@ The following additional roles are available on macOS:
* `window` - The submenu is a "Window" menu * `window` - The submenu is a "Window" menu
* `help` - The submenu is a "Help" menu * `help` - The submenu is a "Help" menu
* `services` - The submenu is a "Services" menu * `services` - The submenu is a "Services" menu
* `recentdocuments` - The submenu is an "Open Recent" menu
* `clearrecentdocuments` - Map to the `clearRecentDocuments` action
When specifying a `role` on macOS, `label` and `accelerator` are the only When specifying a `role` on macOS, `label` and `accelerator` are the only
options that will affect the menu item. All other options will be ignored. options that will affect the menu item. All other options will be ignored.

View file

@ -102,6 +102,12 @@ const roles = {
services: { services: {
label: 'Services' label: 'Services'
}, },
recentdocuments: {
label: 'Open Recent'
},
clearrecentdocuments: {
label: 'Clear Menu'
},
startspeaking: { startspeaking: {
label: 'Start Speaking' label: 'Start Speaking'
}, },