Commit 0313803a authored by rdevlin.cronin's avatar rdevlin.cronin Committed by Commit bot

Move more extension action cocoa logic into the platform delegate.

Move the logic for extension action context menus and
close-popup activate-action observations into the cocoa
platform delegate.

BUG=429810

Review URL: https://codereview.chromium.org/703443002

Cr-Commit-Position: refs/heads/master@{#302723}
parent 84b57b28
......@@ -7,15 +7,12 @@
#import <Cocoa/Cocoa.h>
#include <string>
#import "base/mac/scoped_nsobject.h"
#include "base/memory/scoped_ptr.h"
#import "chrome/browser/ui/cocoa/image_button_cell.h"
class Browser;
@class BrowserActionsController;
@class ExtensionActionContextMenuController;
class ToolbarActionViewController;
class ToolbarActionViewDelegateBridge;
......@@ -49,17 +46,13 @@ extern NSString* const kBrowserActionButtonDragEndNotification;
// The point where the mouse down event occurred. Used to prevent a drag from
// starting until it moves at least kMinimumDragDistance.
NSPoint dragStartPoint_;
base::scoped_nsobject<
ExtensionActionContextMenuController> contextMenuController_;
}
// Init the button with the frame. Takes ownership of |viewController| and
// |menuController|, does not own |controller|.
// Init the button with the frame. Takes ownership of |viewController|, but
// does not own |controller|.
- (id)initWithFrame:(NSRect)frame
viewController:(scoped_ptr<ToolbarActionViewController>)viewController
controller:(BrowserActionsController*)controller
menuController:(ExtensionActionContextMenuController*)menuController;
controller:(BrowserActionsController*)controller;
- (void)setFrame:(NSRect)frameRect animate:(BOOL)animate;
......
......@@ -40,12 +40,18 @@ class ToolbarActionViewDelegateBridge : public ToolbarActionViewDelegateCocoa {
BrowserActionsController* controller);
~ToolbarActionViewDelegateBridge();
ExtensionActionContextMenuController* menuController() {
return menuController_;
}
private:
// ToolbarActionViewDelegateCocoa:
ToolbarActionViewController* GetPreferredPopupViewController() override;
content::WebContents* GetCurrentWebContents() const override;
void UpdateState() override;
NSPoint GetPopupPoint() override;
void SetContextMenuController(
ExtensionActionContextMenuController* menuController) override;
// The owning button. Weak.
BrowserActionButton* owner_;
......@@ -53,6 +59,9 @@ class ToolbarActionViewDelegateBridge : public ToolbarActionViewDelegateCocoa {
// The BrowserActionsController that owns the button. Weak.
BrowserActionsController* controller_;
// The context menu controller. Weak.
ExtensionActionContextMenuController* menuController_;
DISALLOW_COPY_AND_ASSIGN(ToolbarActionViewDelegateBridge);
};
......@@ -60,7 +69,8 @@ ToolbarActionViewDelegateBridge::ToolbarActionViewDelegateBridge(
BrowserActionButton* owner,
BrowserActionsController* controller)
: owner_(owner),
controller_(controller) {
controller_(controller),
menuController_(nil) {
}
ToolbarActionViewDelegateBridge::~ToolbarActionViewDelegateBridge() {
......@@ -84,6 +94,11 @@ NSPoint ToolbarActionViewDelegateBridge::GetPopupPoint() {
return [controller_ popupPointForId:[owner_ viewController]->GetId()];
}
void ToolbarActionViewDelegateBridge::SetContextMenuController(
ExtensionActionContextMenuController* menuController) {
menuController_ = menuController;
}
@interface BrowserActionCell (Internals)
- (void)drawBadgeWithinFrame:(NSRect)frame;
@end
......@@ -102,8 +117,7 @@ NSPoint ToolbarActionViewDelegateBridge::GetPopupPoint() {
- (id)initWithFrame:(NSRect)frame
viewController:(scoped_ptr<ToolbarActionViewController>)viewController
controller:(BrowserActionsController*)controller
menuController:(ExtensionActionContextMenuController*)menuController {
controller:(BrowserActionsController*)controller {
if ((self = [super initWithFrame:frame])) {
BrowserActionCell* cell = [[[BrowserActionCell alloc] init] autorelease];
// [NSButton setCell:] warns to NOT use setCell: other than in the
......@@ -138,8 +152,6 @@ NSPoint ToolbarActionViewDelegateBridge::GetPopupPoint() {
[self setButtonType:NSMomentaryChangeButton];
[self setShowsBorderOnlyWhileMouseInside:YES];
contextMenuController_.reset(menuController);
base::scoped_nsobject<NSMenu> contextMenu(
[[NSMenu alloc] initWithTitle:@""]);
[contextMenu setDelegate:self];
......@@ -300,7 +312,10 @@ NSPoint ToolbarActionViewDelegateBridge::GetPopupPoint() {
- (void)menuNeedsUpdate:(NSMenu*)menu {
[menu removeAllItems];
[contextMenuController_ populateMenu:menu];
// |menuController()| can be nil if we don't show context menus for the given
// action.
if (viewControllerDelegate_->menuController())
[viewControllerDelegate_->menuController() populateMenu:menu];
}
@end
......
......@@ -8,7 +8,6 @@
#include <string>
#include "base/strings/sys_string_conversions.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_action.h"
#include "chrome/browser/extensions/extension_action_manager.h"
#include "chrome/browser/extensions/extension_toolbar_model.h"
......@@ -17,16 +16,11 @@
#include "chrome/browser/ui/browser_window.h"
#import "chrome/browser/ui/cocoa/extensions/browser_action_button.h"
#import "chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h"
#import "chrome/browser/ui/cocoa/extensions/extension_action_context_menu_controller.h"
#import "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h"
#import "chrome/browser/ui/cocoa/image_button_cell.h"
#import "chrome/browser/ui/cocoa/menu_button.h"
#include "chrome/browser/ui/extensions/extension_action_view_controller.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_source.h"
#include "grit/theme_resources.h"
#import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSAnimation+Duration.h"
......@@ -170,47 +164,11 @@ const CGFloat kBrowserActionBubbleYOffset = 3.0;
// A helper class to proxy extension notifications to the view controller's
// appropriate methods.
class ExtensionServiceObserverBridge
: public content::NotificationObserver,
public extensions::ExtensionToolbarModel::Observer {
: public extensions::ExtensionToolbarModel::Observer {
public:
ExtensionServiceObserverBridge(BrowserActionsController* owner,
Browser* browser)
: owner_(owner), browser_(browser) {
registrar_.Add(this,
extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
content::Source<Profile>(browser->profile()));
registrar_.Add(
this,
extensions::NOTIFICATION_EXTENSION_COMMAND_BROWSER_ACTION_MAC,
content::Source<Profile>(browser->profile()));
}
// Overridden from content::NotificationObserver.
void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) override {
switch (type) {
case extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE: {
ExtensionPopupController* popup = [ExtensionPopupController popup];
if (popup && ![popup isClosing])
[popup close];
break;
}
case extensions::NOTIFICATION_EXTENSION_COMMAND_BROWSER_ACTION_MAC: {
std::pair<const std::string, gfx::NativeWindow>* payload =
content::Details<std::pair<const std::string, gfx::NativeWindow> >(
details).ptr();
std::string extension_id = payload->first;
gfx::NativeWindow window = payload->second;
if (window != browser_->window()->GetNativeWindow())
break;
[owner_ activateBrowserAction:extension_id];
break;
}
default:
NOTREACHED() << L"Unexpected notification";
}
}
// extensions::ExtensionToolbarModel::Observer implementation.
......@@ -256,9 +214,6 @@ class ExtensionServiceObserverBridge
// The browser we listen for events from. Weak.
Browser* browser_;
// Used for registering to receive notifications and automatic clean up.
content::NotificationRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(ExtensionServiceObserverBridge);
};
......@@ -491,19 +446,11 @@ class ExtensionServiceObserverBridge
<< "Don't create a BrowserActionButton if there is no browser action.";
scoped_ptr<ToolbarActionViewController> viewController(
new ExtensionActionViewController(extension, browser_, extensionAction));
// TODO(devlin): Move ContextMenuController stuff to
// ExtensionActionViewController.
ExtensionActionContextMenuController* menuController =
[[ExtensionActionContextMenuController alloc]
initWithExtension:extension
browser:browser_
extensionAction:extensionAction];
BrowserActionButton* newButton =
[[[BrowserActionButton alloc]
initWithFrame:buttonFrame
viewController:viewController.Pass()
controller:self
menuController:menuController] autorelease];
controller:self] autorelease];
[newButton setTarget:self];
[newButton setAction:@selector(browserActionClicked:)];
NSString* buttonKey = base::SysUTF8ToNSString(extension->id());
......
......@@ -5,14 +5,19 @@
#ifndef CHROME_BROWSER_UI_COCOA_EXTENSIONS_EXTENSION_ACTION_PLATFORM_DELEGATE_COCOA_H_
#define CHROME_BROWSER_UI_COCOA_EXTENSIONS_EXTENSION_ACTION_PLATFORM_DELEGATE_COCOA_H_
#include "base/mac/scoped_nsobject.h"
#include "chrome/browser/ui/extensions/extension_action_platform_delegate.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
@class ExtensionActionContextMenuController;
@class ExtensionPopupController;
class ToolbarActionViewDelegateCocoa;
// The cocoa-specific implementation for ExtensionActionPlatformDelegate.
class ExtensionActionPlatformDelegateCocoa
: public ExtensionActionPlatformDelegate {
: public ExtensionActionPlatformDelegate,
public content::NotificationObserver {
public:
ExtensionActionPlatformDelegateCocoa(
ExtensionActionViewController* controller);
......@@ -32,14 +37,25 @@ class ExtensionActionPlatformDelegateCocoa
const GURL& popup_url,
bool grant_tab_permissions) override;
// content::NotificationObserver:
void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) override;
// Returns the popup shown by this extension action, if one exists.
ExtensionPopupController* GetPopup() const;
// Returns the delegate in its cocoa implementation.
ToolbarActionViewDelegateCocoa* GetDelegateCocoa();
// The main controller for this extension action.
ExtensionActionViewController* controller_;
// The context menu controller for the extension action, if any.
base::scoped_nsobject<ExtensionActionContextMenuController> menuController_;
content::NotificationRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(ExtensionActionPlatformDelegateCocoa);
};
......
......@@ -4,10 +4,37 @@
#import "chrome/browser/ui/cocoa/extensions/extension_action_platform_delegate_cocoa.h"
#include <string>
#include <utility>
#include "base/logging.h"
#include "chrome/browser/extensions/extension_action.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#import "chrome/browser/ui/cocoa/extensions/extension_action_context_menu_controller.h"
#import "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h"
#import "chrome/browser/ui/cocoa/toolbar/toolbar_action_view_delegate_cocoa.h"
#include "chrome/common/extensions/api/extension_action/action_info.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "extensions/browser/notification_types.h"
#include "extensions/common/extension.h"
namespace {
// Returns the notification to listen to for activation for a particular
// |extension_action|.
int GetNotificationTypeForAction(const ExtensionAction& extension_action) {
if (extension_action.action_type() == extensions::ActionInfo::TYPE_BROWSER)
return extensions::NOTIFICATION_EXTENSION_COMMAND_BROWSER_ACTION_MAC;
// We should only have page and browser action types.
DCHECK_EQ(extensions::ActionInfo::TYPE_PAGE, extension_action.action_type());
return extensions::NOTIFICATION_EXTENSION_COMMAND_PAGE_ACTION_MAC;
}
} // namespace
// static
scoped_ptr<ExtensionActionPlatformDelegate>
ExtensionActionPlatformDelegate::Create(
......@@ -38,6 +65,22 @@ void ExtensionActionPlatformDelegateCocoa::RegisterCommand() {
}
void ExtensionActionPlatformDelegateCocoa::OnDelegateSet() {
if (controller_->extension()->ShowConfigureContextMenus()) {
menuController_.reset([[ExtensionActionContextMenuController alloc]
initWithExtension:controller_->extension()
browser:controller_->browser()
extensionAction:controller_->extension_action()]);
GetDelegateCocoa()->SetContextMenuController(menuController_.get());
}
registrar_.Add(
this,
extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
content::Source<Profile>(controller_->browser()->profile()));
registrar_.Add(
this,
GetNotificationTypeForAction(*controller_->extension_action()),
content::Source<Profile>(controller_->browser()->profile()));
}
bool ExtensionActionPlatformDelegateCocoa::IsShowingPopup() const {
......@@ -46,13 +89,14 @@ bool ExtensionActionPlatformDelegateCocoa::IsShowingPopup() const {
void ExtensionActionPlatformDelegateCocoa::CloseActivePopup() {
ExtensionPopupController* popup = [ExtensionPopupController popup];
if (popup)
if (popup && ![popup isClosing])
[popup close];
}
void ExtensionActionPlatformDelegateCocoa::CloseOwnPopup() {
ExtensionPopupController* popup = GetPopup();
DCHECK(popup);
if (popup && ![popup isClosing])
[popup close];
}
......@@ -81,3 +125,33 @@ ExtensionPopupController* ExtensionActionPlatformDelegateCocoa::GetPopup()
return popup && [popup extensionId] == controller_->extension()->id() ?
popup : nil;
}
void ExtensionActionPlatformDelegateCocoa::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE:
CloseActivePopup();
break;
case extensions::NOTIFICATION_EXTENSION_COMMAND_BROWSER_ACTION_MAC:
case extensions::NOTIFICATION_EXTENSION_COMMAND_PAGE_ACTION_MAC: {
DCHECK_EQ(type,
GetNotificationTypeForAction(*controller_->extension_action()));
std::pair<const std::string, gfx::NativeWindow>* payload =
content::Details<std::pair<const std::string, gfx::NativeWindow> >(
details).ptr();
const std::string& extension_id = payload->first;
gfx::NativeWindow window = payload->second;
if (window == controller_->browser()->window()->GetNativeWindow() &&
extension_id == controller_->extension()->id() &&
controller_->IsEnabled(
controller_->view_delegate()->GetCurrentWebContents())) {
controller_->ExecuteAction(true);
}
break;
}
default:
NOTREACHED() << L"Unexpected notification";
}
}
......@@ -9,8 +9,6 @@
#include "base/strings/string16.h"
#import "chrome/browser/ui/cocoa/location_bar/image_decoration.h"
#import "chrome/browser/ui/cocoa/toolbar/toolbar_action_view_delegate_cocoa.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
class ExtensionAction;
@class ExtensionActionContextMenuController;
......@@ -30,8 +28,7 @@ class Extension;
// Action and notify the extension when the icon is clicked.
class PageActionDecoration : public ImageDecoration,
public ToolbarActionViewDelegateCocoa,
public content::NotificationObserver {
public ToolbarActionViewDelegateCocoa {
public:
PageActionDecoration(LocationBarViewMac* owner,
Browser* browser,
......@@ -74,11 +71,8 @@ class PageActionDecoration : public ImageDecoration,
content::WebContents* GetCurrentWebContents() const override;
void UpdateState() override;
NSPoint GetPopupPoint() override;
// Overridden from NotificationObserver:
void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) override;
void SetContextMenuController(
ExtensionActionContextMenuController* menuController) override;
// The location bar view that owns us.
LocationBarViewMac* owner_;
......@@ -89,19 +83,14 @@ class PageActionDecoration : public ImageDecoration,
// The string to show for a tooltip.
base::scoped_nsobject<NSString> tooltip_;
// The context menu controller for the Page Action.
base::scoped_nsobject<
ExtensionActionContextMenuController> contextMenuController_;
// The context menu controller for the Page Action. Weak.
ExtensionActionContextMenuController* contextMenuController_;
// This is used for post-install visual feedback. The page_action
// icon is briefly shown even if it hasn't been enabled by its
// extension.
bool preview_enabled_;
// Used to register for notifications received by
// NotificationObserver.
content::NotificationRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(PageActionDecoration);
};
......
......@@ -5,17 +5,12 @@
#import "chrome/browser/ui/cocoa/location_bar/page_action_decoration.h"
#include "base/strings/sys_string_conversions.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_action.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#import "chrome/browser/ui/cocoa/extensions/extension_action_context_menu_controller.h"
#import "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h"
#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
#include "chrome/browser/ui/extensions/extension_action_view_controller.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/extension_registry.h"
#include "ui/gfx/image/image.h"
......@@ -38,6 +33,7 @@ PageActionDecoration::PageActionDecoration(
Browser* browser,
ExtensionAction* page_action)
: owner_(NULL),
contextMenuController_(nil),
preview_enabled_(false) {
const Extension* extension = extensions::ExtensionRegistry::Get(
browser->profile())->enabled_extensions().GetByID(
......@@ -46,15 +42,7 @@ PageActionDecoration::PageActionDecoration(
viewController_.reset(
new ExtensionActionViewController(extension, browser, page_action));
// TODO(devlin): Move these notifications to
// ExtensionActionPlatformDelegateCocoa.
registrar_.Add(this,
extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
content::Source<Profile>(browser->profile()));
registrar_.Add(this,
extensions::NOTIFICATION_EXTENSION_COMMAND_PAGE_ACTION_MAC,
content::Source<Profile>(browser->profile()));
viewController_->SetDelegate(this);
// We set the owner last of all so that we can determine whether we are in
// the process of initializing this class or not.
......@@ -142,18 +130,15 @@ NSPoint PageActionDecoration::GetBubblePointInFrame(NSRect frame) {
}
NSMenu* PageActionDecoration::GetMenu() {
const Extension* extension = viewController_->extension();
if (!extension->ShowConfigureContextMenus())
return nil;
contextMenuController_.reset([[ExtensionActionContextMenuController alloc]
initWithExtension:extension
browser:viewController_->browser()
extensionAction:GetPageAction()]);
base::scoped_nsobject<NSMenu> contextMenu([[NSMenu alloc] initWithTitle:@""]);
// |contextMenuController| can be nil if we don't show menus for this
// extension.
if (contextMenuController_) {
base::scoped_nsobject<NSMenu> contextMenu(
[[NSMenu alloc] initWithTitle:@""]);
[contextMenuController_ populateMenu:contextMenu];
return contextMenu.autorelease();
}
return nil;
}
void PageActionDecoration::SetToolTip(const base::string16& tooltip) {
......@@ -189,35 +174,7 @@ NSPoint PageActionDecoration::GetPopupPoint() {
return anchor;
}
void PageActionDecoration::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE: {
ExtensionPopupController* popup = [ExtensionPopupController popup];
if (popup && ![popup isClosing])
[popup close];
break;
}
case extensions::NOTIFICATION_EXTENSION_COMMAND_PAGE_ACTION_MAC: {
std::pair<const std::string, gfx::NativeWindow>* payload =
content::Details<std::pair<const std::string, gfx::NativeWindow> >(
details).ptr();
const std::string& extension_id = payload->first;
gfx::NativeWindow window = payload->second;
if (window != viewController_->browser()->window()->GetNativeWindow())
break;
if (extension_id != GetExtension()->id())
break;
if (IsVisible())
ActivatePageAction(true);
break;
}
default:
NOTREACHED() << "Unexpected notification";
break;
}
void PageActionDecoration::SetContextMenuController(
ExtensionActionContextMenuController* menuController) {
contextMenuController_ = menuController;
}
......@@ -7,11 +7,18 @@
#include "chrome/browser/ui/toolbar/toolbar_action_view_delegate.h"
@class ExtensionActionContextMenuController;
class ToolbarActionViewDelegateCocoa : public ToolbarActionViewDelegate {
public:
// A cocoa-specific implementation to return the point used when showing a
// popup.
virtual NSPoint GetPopupPoint() = 0;
// TODO(devlin): Ideally, this would take a
// ToolbarActionContextMenuController, but that doesn't exist (yet).
virtual void SetContextMenuController(
ExtensionActionContextMenuController* menuController) = 0;
};
#endif // CHROME_BROWSER_UI_COCOA_TOOLBAR_TOOLBAR_ACTION_VIEW_DELEGATE_COCOA_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment