diff options
author | andybons@chromium.org <andybons@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-19 21:14:13 +0000 |
---|---|---|
committer | andybons@chromium.org <andybons@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-19 21:14:13 +0000 |
commit | 01bfd02b5e75ad54e90c5379da3a84c714c79bf6 (patch) | |
tree | f5869f3579db11a629f4f8eab07ed9b6fa089167 /chrome | |
parent | cff386ccf5eb4de8bc409b85da0855e610824b24 (diff) | |
download | chromium_src-01bfd02b5e75ad54e90c5379da3a84c714c79bf6.zip chromium_src-01bfd02b5e75ad54e90c5379da3a84c714c79bf6.tar.gz chromium_src-01bfd02b5e75ad54e90c5379da3a84c714c79bf6.tar.bz2 |
[Mac] Refactors BrowserActionButton to be within its own file, also breaking a circular dependency on BrowserActionsController.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/543117
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36545 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/cocoa/extensions/browser_action_button.h | 64 | ||||
-rw-r--r-- | chrome/browser/cocoa/extensions/browser_action_button.mm | 184 | ||||
-rw-r--r-- | chrome/browser/cocoa/extensions/browser_actions_controller.h | 5 | ||||
-rw-r--r-- | chrome/browser/cocoa/extensions/browser_actions_controller.mm | 229 | ||||
-rw-r--r-- | chrome/browser/cocoa/toolbar_controller.mm | 1 | ||||
-rwxr-xr-x | chrome/chrome_browser.gypi | 2 |
6 files changed, 257 insertions, 228 deletions
diff --git a/chrome/browser/cocoa/extensions/browser_action_button.h b/chrome/browser/cocoa/extensions/browser_action_button.h new file mode 100644 index 0000000..d4ddba6 --- /dev/null +++ b/chrome/browser/cocoa/extensions/browser_action_button.h @@ -0,0 +1,64 @@ +// Copyright (c) 2010 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_COCOA_EXTENSIONS_BROWSER_ACTION_BUTTON_H_ +#define CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTION_BUTTON_H_ + +#import <Cocoa/Cocoa.h> + +#import "base/scoped_nsobject.h" +#include "base/scoped_ptr.h" +#include "chrome/browser/cocoa/toolbar_button_cell.h" + +class Extension; +class ExtensionAction; +class ExtensionImageTrackerBridge; + +extern const CGFloat kBrowserActionWidth; + +@interface BrowserActionButton : NSButton { + @private + scoped_ptr<ExtensionImageTrackerBridge> imageLoadingBridge_; + + scoped_nsobject<NSImage> defaultIcon_; + + scoped_nsobject<NSImage> tabSpecificIcon_; + + // The extension for this button. Weak. + Extension* extension_; + + // The ID of the active tab. + int tabId_; +} + +- (id)initWithExtension:(Extension*)extension + tabId:(int)tabId + xOffset:(int)xOffset; + +- (void)setDefaultIcon:(NSImage*)image; + +- (void)setTabSpecificIcon:(NSImage*)image; + +- (void)updateState; + +@property(readwrite, nonatomic) int tabId; +@property(readonly, nonatomic) Extension* extension; + +@end + +@interface BrowserActionCell : ToolbarButtonCell { + @private + // The current tab ID used when drawing the cell. + int tabId_; + + // The action we're drawing the cell for. Weak. + ExtensionAction* extensionAction_; +} + +@property(readwrite, nonatomic) int tabId; +@property(readwrite, nonatomic) ExtensionAction* extensionAction; + +@end + +#endif // CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTION_BUTTON_H_ diff --git a/chrome/browser/cocoa/extensions/browser_action_button.mm b/chrome/browser/cocoa/extensions/browser_action_button.mm new file mode 100644 index 0000000..00cdd86 --- /dev/null +++ b/chrome/browser/cocoa/extensions/browser_action_button.mm @@ -0,0 +1,184 @@ +// Copyright (c) 2010 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. + +#import "chrome/browser/cocoa/extensions/browser_action_button.h" + +#include "app/gfx/canvas_paint.h" +#include "base/gfx/rect.h" +#include "base/gfx/size.h" +#include "base/sys_string_conversions.h" +#include "chrome/browser/cocoa/extensions/extension_action_context_menu.h" +#include "chrome/browser/extensions/image_loading_tracker.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" +#include "chrome/common/notification_source.h" +#include "chrome/common/notification_type.h" +#include "skia/ext/skia_utils_mac.h" + +static const CGFloat kBrowserActionBadgeOriginYOffset = 5; + +// Since the container is the maximum height of the toolbar, we have to move the +// buttons up by this amount in order to have them look vertically centered +// within the toolbar. +static const CGFloat kBrowserActionOriginYOffset = 5; + +// The size of each button on the toolbar. +static const CGFloat kBrowserActionHeight = 27; +extern const CGFloat kBrowserActionWidth = 29; + +// A helper class to bridge the asynchronous Skia bitmap loading mechanism to +// the extension's button. +class ExtensionImageTrackerBridge : public NotificationObserver, + public ImageLoadingTracker::Observer { + public: + ExtensionImageTrackerBridge(BrowserActionButton* owner, Extension* extension) + : owner_(owner), + tracker_(NULL) { + // The Browser Action API does not allow the default icon path to be + // changed at runtime, so we can load this now and cache it. + std::string path = extension->browser_action()->default_icon_path(); + if (!path.empty()) { + tracker_ = new ImageLoadingTracker(this, 1); + tracker_->PostLoadImageTask(extension->GetResource(path), + gfx::Size(Extension::kBrowserActionIconMaxSize, + Extension::kBrowserActionIconMaxSize)); + } + registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED, + Source<ExtensionAction>(extension->browser_action())); + } + + ~ExtensionImageTrackerBridge() { + if (tracker_) + tracker_->StopTrackingImageLoad(); + } + + // ImageLoadingTracker::Observer implementation. + void OnImageLoaded(SkBitmap* image, size_t index) { + if (image) + [owner_ setDefaultIcon:gfx::SkBitmapToNSImage(*image)]; + tracker_ = NULL; + [owner_ updateState]; + } + + // Overridden from NotificationObserver. + void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (type == NotificationType::EXTENSION_BROWSER_ACTION_UPDATED) + [owner_ updateState]; + else + NOTREACHED(); + } + + private: + // Weak. Owns us. + BrowserActionButton* owner_; + + // Loads the button's icons for us on the file thread. Weak. + ImageLoadingTracker* tracker_; + + // Used for registering to receive notifications and automatic clean up. + NotificationRegistrar registrar_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionImageTrackerBridge); +}; + +@implementation BrowserActionButton + ++ (Class)cellClass { + return [BrowserActionCell class]; +} + +- (id)initWithExtension:(Extension*)extension + tabId:(int)tabId + xOffset:(int)xOffset { + NSRect frame = NSMakeRect(xOffset, + kBrowserActionOriginYOffset, + kBrowserActionWidth, + kBrowserActionHeight); + if ((self = [super initWithFrame:frame])) { + BrowserActionCell* cell = [[[BrowserActionCell alloc] init] autorelease]; + // [NSButton setCell:] warns to NOT use setCell: other than in the + // initializer of a control. However, we are using a basic + // NSButton whose initializer does not take an NSCell as an + // object. To honor the assumed semantics, we do nothing with + // NSButton between alloc/init and setCell:. + [self setCell:cell]; + [cell setTabId:tabId]; + [cell setExtensionAction:extension->browser_action()]; + + [self setTitle:@""]; + [self setButtonType:NSMomentaryChangeButton]; + [self setShowsBorderOnlyWhileMouseInside:YES]; + + [self setMenu:[[[ExtensionActionContextMenu alloc] + initWithExtension:extension] autorelease]]; + + tabId_ = tabId; + extension_ = extension; + imageLoadingBridge_.reset(new ExtensionImageTrackerBridge(self, extension)); + + [self updateState]; + } + + return self; +} + +- (void)setDefaultIcon:(NSImage*)image { + defaultIcon_.reset([image retain]); +} + +- (void)setTabSpecificIcon:(NSImage*)image { + tabSpecificIcon_.reset([image retain]); +} + +- (void)updateState { + if (tabId_ < 0) + return; + + std::string tooltip = extension_->browser_action()->GetTitle(tabId_); + if (tooltip.empty()) { + [self setToolTip:nil]; + } else { + [self setToolTip:base::SysUTF8ToNSString(tooltip)]; + } + + SkBitmap image = extension_->browser_action()->GetIcon(tabId_); + if (!image.isNull()) { + [self setTabSpecificIcon:gfx::SkBitmapToNSImage(image)]; + [self setImage:tabSpecificIcon_]; + } else if (defaultIcon_) { + [self setImage:defaultIcon_]; + } + + [[self cell] setTabId:tabId_]; + + [self setNeedsDisplay:YES]; +} + +@synthesize tabId = tabId_; +@synthesize extension = extension_; + +@end + +@implementation BrowserActionCell + +- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { + [super drawWithFrame:cellFrame inView:controlView]; + + // CanvasPaint draws its content to the current NSGraphicsContext in its + // destructor. If anything needs to be drawn afterwards, then enclose this + // in a nested block. + cellFrame.origin.y += kBrowserActionBadgeOriginYOffset; + gfx::CanvasPaint canvas(cellFrame, false); + canvas.set_composite_alpha(true); + gfx::Rect boundingRect(NSRectToCGRect(cellFrame)); + extensionAction_->PaintBadge(&canvas, boundingRect, tabId_); +} + +@synthesize tabId = tabId_; +@synthesize extensionAction = extensionAction_; + +@end diff --git a/chrome/browser/cocoa/extensions/browser_actions_controller.h b/chrome/browser/cocoa/extensions/browser_actions_controller.h index 6768a32..22d363a 100644 --- a/chrome/browser/cocoa/extensions/browser_actions_controller.h +++ b/chrome/browser/cocoa/extensions/browser_actions_controller.h @@ -18,7 +18,6 @@ class ExtensionsServiceObserverBridge; class Profile; extern const CGFloat kBrowserActionButtonPadding; -extern const CGFloat kBrowserActionWidth; extern NSString* const kBrowserActionsChangedNotification; @@ -75,10 +74,6 @@ extern NSString* const kBrowserActionsChangedNotification; // Executes the action designated by the extension. - (void)browserActionClicked:(BrowserActionButton*)sender; -// Returns the current ID of the active tab, -1 in the case where the user is in -// incognito mode. -- (int)currentTabId; - @end // @interface BrowserActionsController @interface BrowserActionsController(TestingAPI) diff --git a/chrome/browser/cocoa/extensions/browser_actions_controller.mm b/chrome/browser/cocoa/extensions/browser_actions_controller.mm index 53e645d..26a7ca6 100644 --- a/chrome/browser/cocoa/extensions/browser_actions_controller.mm +++ b/chrome/browser/cocoa/extensions/browser_actions_controller.mm @@ -6,247 +6,27 @@ #include <string> -#include "app/gfx/canvas_paint.h" #include "base/sys_string_conversions.h" #include "chrome/browser/browser.h" -#include "chrome/browser/cocoa/extensions/extension_action_context_menu.h" +#include "chrome/browser/cocoa/extensions/browser_action_button.h" #include "chrome/browser/cocoa/extensions/extension_popup_controller.h" -#include "chrome/browser/cocoa/toolbar_button_cell.h" #include "chrome/browser/extensions/extension_browser_event_router.h" #include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/extensions/extension_tabs_module.h" -#include "chrome/browser/extensions/image_loading_tracker.h" #include "chrome/browser/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/notification_observer.h" #include "chrome/common/notification_registrar.h" -#include "skia/ext/skia_utils_mac.h" - -static const CGFloat kBrowserActionBadgeOriginYOffset = 5; - -// Since the container is the maximum height of the toolbar, we have to move the -// buttons up by this amount in order to have them look vertically centered -// within the toolbar. -static const CGFloat kBrowserActionOriginYOffset = 5; - -// The size of each button on the toolbar. -static const CGFloat kBrowserActionHeight = 27; -extern const CGFloat kBrowserActionWidth = 29; // The padding between browser action buttons. extern const CGFloat kBrowserActionButtonPadding = 3; NSString* const kBrowserActionsChangedNotification = @"BrowserActionsChanged"; -@interface BrowserActionCell : ToolbarButtonCell { - @private - // The current tab ID used when drawing the cell. - int tabId_; - - // The action we're drawing the cell for. Weak. - ExtensionAction* extensionAction_; -} - -@property(readwrite, nonatomic) int tabId; -@property(readwrite, nonatomic) ExtensionAction* extensionAction; - -@end - -@implementation BrowserActionCell - -- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { - [super drawWithFrame:cellFrame inView:controlView]; - - // CanvasPaint draws its content to the current NSGraphicsContext in its - // destructor. If anything needs to be drawn afterwards, then enclose this - // in a nested block. - cellFrame.origin.y += kBrowserActionBadgeOriginYOffset; - gfx::CanvasPaint canvas(cellFrame, false); - canvas.set_composite_alpha(true); - gfx::Rect boundingRect(NSRectToCGRect(cellFrame)); - extensionAction_->PaintBadge(&canvas, boundingRect, tabId_); -} - -@synthesize tabId = tabId_; -@synthesize extensionAction = extensionAction_; - -@end - -class ExtensionImageTrackerBridge; - -@interface BrowserActionButton : NSButton { - @private - scoped_ptr<ExtensionImageTrackerBridge> imageLoadingBridge_; - - scoped_nsobject<NSImage> defaultIcon_; - - scoped_nsobject<NSImage> tabSpecificIcon_; - - // The extension for this button. Weak. - Extension* extension_; - - // Weak. Owns us. - BrowserActionsController* controller_; -} - -- (id)initWithExtension:(Extension*)extension - controller:(BrowserActionsController*)controller - xOffset:(int)xOffset; - -- (void)setDefaultIcon:(NSImage*)image; - -- (void)setTabSpecificIcon:(NSImage*)image; - -- (void)updateState; - -@property(readonly, nonatomic) Extension* extension; - -@end - -// A helper class to bridge the asynchronous Skia bitmap loading mechanism to -// the extension's button. -class ExtensionImageTrackerBridge : public NotificationObserver, - public ImageLoadingTracker::Observer { - public: - ExtensionImageTrackerBridge(BrowserActionButton* owner, Extension* extension) - : owner_(owner), - tracker_(NULL) { - // The Browser Action API does not allow the default icon path to be - // changed at runtime, so we can load this now and cache it. - std::string path = extension->browser_action()->default_icon_path(); - if (!path.empty()) { - tracker_ = new ImageLoadingTracker(this, 1); - tracker_->PostLoadImageTask(extension->GetResource(path), - gfx::Size(Extension::kBrowserActionIconMaxSize, - Extension::kBrowserActionIconMaxSize)); - } - registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED, - Source<ExtensionAction>(extension->browser_action())); - } - - ~ExtensionImageTrackerBridge() { - if (tracker_) - tracker_->StopTrackingImageLoad(); - } - - // ImageLoadingTracker::Observer implementation. - void OnImageLoaded(SkBitmap* image, size_t index) { - if (image) - [owner_ setDefaultIcon:gfx::SkBitmapToNSImage(*image)]; - tracker_ = NULL; - [owner_ updateState]; - } - - // Overridden from NotificationObserver. - void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { - if (type == NotificationType::EXTENSION_BROWSER_ACTION_UPDATED) - [owner_ updateState]; - else - NOTREACHED(); - } - - private: - // Weak. Owns us. - BrowserActionButton* owner_; - - // Loads the button's icons for us on the file thread. Weak. - ImageLoadingTracker* tracker_; - - // Used for registering to receive notifications and automatic clean up. - NotificationRegistrar registrar_; - - DISALLOW_COPY_AND_ASSIGN(ExtensionImageTrackerBridge); -}; - -@implementation BrowserActionButton - -+ (Class)cellClass { - return [BrowserActionCell class]; -} - -- (id)initWithExtension:(Extension*)extension - controller:(BrowserActionsController*)controller - xOffset:(int)xOffset { - NSRect frame = NSMakeRect(xOffset, - kBrowserActionOriginYOffset, - kBrowserActionWidth, - kBrowserActionHeight); - if ((self = [super initWithFrame:frame])) { - BrowserActionCell* cell = [[[BrowserActionCell alloc] init] autorelease]; - // [NSButton setCell:] warns to NOT use setCell: other than in the - // initializer of a control. However, we are using a basic - // NSButton whose initializer does not take an NSCell as an - // object. To honor the assumed semantics, we do nothing with - // NSButton between alloc/init and setCell:. - [self setCell:cell]; - [cell setTabId:[controller currentTabId]]; - [cell setExtensionAction:extension->browser_action()]; - - [self setTitle:@""]; - [self setButtonType:NSMomentaryChangeButton]; - [self setShowsBorderOnlyWhileMouseInside:YES]; - - [self setTarget:controller]; - [self setAction:@selector(browserActionClicked:)]; - - [self setMenu:[[[ExtensionActionContextMenu alloc] - initWithExtension:extension] autorelease]]; - - extension_ = extension; - controller_ = controller; - imageLoadingBridge_.reset(new ExtensionImageTrackerBridge(self, extension)); - - [self updateState]; - } - - return self; -} - -- (void)setDefaultIcon:(NSImage*)image { - defaultIcon_.reset([image retain]); -} - -- (void)setTabSpecificIcon:(NSImage*)image { - tabSpecificIcon_.reset([image retain]); -} - -- (void)updateState { - int tabId = [controller_ currentTabId]; - if (tabId < 0) - return; - - std::string tooltip = extension_->browser_action()->GetTitle(tabId); - if (tooltip.empty()) { - [self setToolTip:nil]; - } else { - [self setToolTip:base::SysUTF8ToNSString(tooltip)]; - } - - SkBitmap image = extension_->browser_action()->GetIcon(tabId); - if (!image.isNull()) { - [self setTabSpecificIcon:gfx::SkBitmapToNSImage(image)]; - [self setImage:tabSpecificIcon_]; - } else if (defaultIcon_) { - [self setImage:defaultIcon_]; - } - - [[self cell] setTabId:tabId]; - - [self setNeedsDisplay:YES]; -} - -@synthesize extension = extension_; - -@end - @interface BrowserActionsController(Private) - - (void)createActionButtonForExtension:(Extension*)extension; - (void)removeActionButtonForExtension:(Extension*)extension; - (void)repositionActionButtons; - +- (int)currentTabId; @end // A helper class to proxy extension notifications to the view controller's @@ -334,6 +114,7 @@ class ExtensionsServiceObserverBridge : public NotificationObserver { - (void)update { for (BrowserActionButton* button in [buttons_ allValues]) { + [button setTabId:[self currentTabId]]; [button updateState]; } } @@ -374,8 +155,10 @@ class ExtensionsServiceObserverBridge : public NotificationObserver { [buttons_ count] * (kBrowserActionWidth + kBrowserActionButtonPadding); BrowserActionButton* newButton = [[[BrowserActionButton alloc] initWithExtension:extension - controller:self + tabId:[self currentTabId] xOffset:xOffset] autorelease]; + [newButton setTarget:self]; + [newButton setAction:@selector(browserActionClicked:)]; NSString* buttonKey = base::SysUTF8ToNSString(extension->id()); [buttons_ setObject:newButton forKey:buttonKey]; [buttonOrder_ addObject:newButton]; diff --git a/chrome/browser/cocoa/toolbar_controller.mm b/chrome/browser/cocoa/toolbar_controller.mm index fba71ae..3fe1054 100644 --- a/chrome/browser/cocoa/toolbar_controller.mm +++ b/chrome/browser/cocoa/toolbar_controller.mm @@ -19,6 +19,7 @@ #import "chrome/browser/cocoa/back_forward_menu_controller.h" #import "chrome/browser/cocoa/background_gradient_view.h" #import "chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h" +#import "chrome/browser/cocoa/extensions/browser_action_button.h" #import "chrome/browser/cocoa/extensions/browser_actions_controller.h" #import "chrome/browser/cocoa/gradient_button_cell.h" #import "chrome/browser/cocoa/location_bar_view_mac.h" diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index a942217..666ecf8 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -437,6 +437,8 @@ 'browser/cocoa/extension_install_prompt.mm', 'browser/cocoa/extension_view_mac.h', 'browser/cocoa/extension_view_mac.mm', + 'browser/cocoa/extensions/browser_action_button.h', + 'browser/cocoa/extensions/browser_action_button.mm', 'browser/cocoa/extensions/browser_actions_controller.h', 'browser/cocoa/extensions/browser_actions_controller.mm', 'browser/cocoa/extensions/extension_action_context_menu.h', |