diff options
author | pinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-20 17:59:26 +0000 |
---|---|---|
committer | pinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-20 17:59:26 +0000 |
commit | 1870c693331f6f12a2075482884a2cb09f1ceab4 (patch) | |
tree | abbb684b501ca6fefd743e894d55cd10a9c26620 /chrome/browser | |
parent | 5ee78e021cf0d67d72db177f330d123bafce53c0 (diff) | |
download | chromium_src-1870c693331f6f12a2075482884a2cb09f1ceab4.zip chromium_src-1870c693331f6f12a2075482884a2cb09f1ceab4.tar.gz chromium_src-1870c693331f6f12a2075482884a2cb09f1ceab4.tar.bz2 |
Implement context menus on Mac.
Review URL: http://codereview.chromium.org/42448
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12198 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
3 files changed, 190 insertions, 1 deletions
diff --git a/chrome/browser/tab_contents/render_view_context_menu_mac.h b/chrome/browser/tab_contents/render_view_context_menu_mac.h new file mode 100644 index 0000000..9a4f60e --- /dev/null +++ b/chrome/browser/tab_contents/render_view_context_menu_mac.h @@ -0,0 +1,48 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_TAB_CONTENTS_RENDER_VIEW_CONTEXT_MENU_MAC_H_ +#define CHROME_BROWSER_TAB_CONTENTS_RENDER_VIEW_CONTEXT_MENU_MAC_H_ + +#import <Cocoa/Cocoa.h> + +#include "chrome/browser/tab_contents/render_view_context_menu.h" + +@class ContextMenuTarget; + +// Mac implementation of the context menu display code. Uses a Cocoa NSMenu +// to display the context menu. Internally uses an obj-c object as the +// target of the NSMenu, bridging back to this C++ class. + +class RenderViewContextMenuMac : public RenderViewContextMenu { + public: + RenderViewContextMenuMac(WebContents* web_contents, + const ContextMenuParams& params, + NSView* parent_view); + virtual ~RenderViewContextMenuMac(); + + // Elevate to public so that the obj-c target can call it. + void ExecuteCommand(int command_id) { ExecuteItemCommand(command_id); } + + protected: + // RenderViewContextMenu implementation- + virtual void AppendMenuItem(int id); + virtual void AppendMenuItem(int id, const std::wstring& label); + virtual void AppendRadioMenuItem(int id, const std::wstring& label); + virtual void AppendCheckboxMenuItem(int id, const std::wstring& label); + virtual void AppendSeparator(); + virtual void StartSubMenu(int id, const std::wstring& label); + virtual void FinishSubMenu(); + + // Do things like remove the windows accelerators. + static NSString* PrepareLabelForDisplay(const std::wstring& label); + + private: + NSMenu* menu_; + NSMenu* insert_menu_; // weak, where new items are inserted (usually + // |menu_| unless there's a submenu in progress). + ContextMenuTarget* target_; // obj-c target for menu actions +}; + +#endif // CHROME_BROWSER_TAB_CONTENTS_RENDER_VIEW_CONTEXT_MENU_MAC_H_ diff --git a/chrome/browser/tab_contents/render_view_context_menu_mac.mm b/chrome/browser/tab_contents/render_view_context_menu_mac.mm new file mode 100644 index 0000000..70d1900 --- /dev/null +++ b/chrome/browser/tab_contents/render_view_context_menu_mac.mm @@ -0,0 +1,138 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/tab_contents/render_view_context_menu_mac.h" + +#include "base/compiler_specific.h" +#include "base/sys_string_conversions.h" +#include "chrome/browser/profile.h" +#include "chrome/common/l10n_util.h" +#include "grit/generated_resources.h" + +// Obj-C bridge class that is the target of all items in the context menu. +// Relies on the tag being set to the command id. Uses |context_| to +// execute the command once it is selected and determine if commands should +// be enabled or disabled. + +@interface ContextMenuTarget : NSObject { + @private + RenderViewContextMenuMac* context_; // weak, owns us. +} +- (id)initWithContext:(RenderViewContextMenuMac*)context; +- (void)itemSelected:(id)sender; +@end + +@implementation ContextMenuTarget + +- (id)initWithContext:(RenderViewContextMenuMac*)context { + if ((self = [super init])) { + DCHECK(context); + context_ = context; + } + return self; +} + +- (void)itemSelected:(id)sender { + context_->ExecuteCommand([sender tag]); +} + +@end + +RenderViewContextMenuMac::RenderViewContextMenuMac( + WebContents* web_contents, + const ContextMenuParams& params, + NSView* parent_view) + : RenderViewContextMenu(web_contents, params), + menu_([[NSMenu alloc] init]), + insert_menu_(menu_), + target_(nil) { + [menu_ setAutoenablesItems:NO]; + target_ = [[ContextMenuTarget alloc] initWithContext:this]; + InitMenu(params.node); + + // show the menu + [NSMenu popUpContextMenu:menu_ + withEvent:[NSApp currentEvent] + forView:parent_view]; +} + +RenderViewContextMenuMac::~RenderViewContextMenuMac() { + [target_ release]; + [menu_ release]; +} + +// Do things like remove the windows accelerators. +// TODO(pinkerton): Do we want to do anything like make a maximum string width +// and middle-truncate? +NSString* RenderViewContextMenuMac::PrepareLabelForDisplay( + const std::wstring& label) { + // Strip out any "&"'s that are windows accelerators and we don't use. + NSMutableString* title = + [NSMutableString stringWithString:base::SysWideToNSString(label)]; + NSRange range = NSMakeRange(0, [title length]); + [title replaceOccurrencesOfString:@"&" withString:@"" options:0 range:range]; + return title; +} + +void RenderViewContextMenuMac::AppendMenuItem(int command_id) { + AppendMenuItem(command_id, l10n_util::GetString(command_id)); +} + +void RenderViewContextMenuMac::AppendMenuItem(int command_id, + const std::wstring& label) { + // Create the item and set its target/action to |target_| with the command + // as |command_id|. Then add it to the menu at the end. + NSMenuItem* item = + [[[NSMenuItem alloc] initWithTitle:PrepareLabelForDisplay(label) + action:@selector(itemSelected:) + keyEquivalent:@""] autorelease]; + [item setTag:command_id]; + [item setTarget:target_]; + [item setEnabled:IsItemCommandEnabled(command_id) ? YES : NO]; + [insert_menu_ addItem:item]; +} + +void RenderViewContextMenuMac::AppendRadioMenuItem(int id, + const std::wstring& label) { + NOTIMPLEMENTED(); +} + +void RenderViewContextMenuMac::AppendCheckboxMenuItem(int id, + const std::wstring& label) { + NOTIMPLEMENTED(); +} + +void RenderViewContextMenuMac::AppendSeparator() { + NSMenuItem* separator = [NSMenuItem separatorItem]; + [insert_menu_ addItem:separator]; +} + +void RenderViewContextMenuMac::StartSubMenu(int command_id, + const std::wstring& label) { + // I'm not a fan of this kind of API, but the other platforms have similar + // guards so at least we know everyone will break together if someone + // tries to mis-use the API. + if (insert_menu_ != menu_) { + NOTREACHED(); + return; + } + + // We don't need to retain the submenu as the context menu already does, but + // we switch the "insert menu" so subsequent items are added to the submenu + // and not the main menu. This happens until someone calls FinishSubMenu(). + NSMenuItem* submenu_item = + [[[NSMenuItem alloc] initWithTitle:PrepareLabelForDisplay(label) + action:nil + keyEquivalent:nil] autorelease]; + insert_menu_ = [[[NSMenu alloc] init] autorelease]; + [submenu_item setSubmenu:insert_menu_]; + [menu_ addItem:submenu_item]; +} + +void RenderViewContextMenuMac::FinishSubMenu() { + // Set the "insert menu" back to the main menu so that subsequently added + // items get added to the main context menu. + DCHECK(insert_menu_ != menu_); + insert_menu_ = menu_; +} diff --git a/chrome/browser/tab_contents/web_contents_view_mac.mm b/chrome/browser/tab_contents/web_contents_view_mac.mm index a63cf86..4c93ed7 100644 --- a/chrome/browser/tab_contents/web_contents_view_mac.mm +++ b/chrome/browser/tab_contents/web_contents_view_mac.mm @@ -8,6 +8,7 @@ #include "chrome/browser/cocoa/sad_tab_view.h" #include "chrome/browser/renderer_host/render_widget_host.h" #include "chrome/browser/renderer_host/render_widget_host_view_mac.h" +#include "chrome/browser/tab_contents/render_view_context_menu_mac.h" #include "chrome/browser/tab_contents/web_contents.h" #include "chrome/common/temp_scaffolding_stubs.h" @@ -180,7 +181,9 @@ void WebContentsViewMac::OnFindReply(int request_id, } void WebContentsViewMac::ShowContextMenu(const ContextMenuParams& params) { - NOTIMPLEMENTED(); + RenderViewContextMenuMac menu(web_contents_, + params, + GetNativeView()); } WebContents* WebContentsViewMac::CreateNewWindowInternal( |