Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(92)

Unified Diff: chrome/browser/cocoa/extension_shelf_controller.mm

Issue 175025: Add a bare-bones extension shelf that displays extension items on OS X. (Closed)
Patch Set: Merge ToT, address more comments Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/cocoa/extension_shelf_controller.mm
diff --git a/chrome/browser/cocoa/extension_shelf_controller.mm b/chrome/browser/cocoa/extension_shelf_controller.mm
new file mode 100644
index 0000000000000000000000000000000000000000..ec7a40bfd1e0f9b85a5f12ebbb539eddb723ae72
--- /dev/null
+++ b/chrome/browser/cocoa/extension_shelf_controller.mm
@@ -0,0 +1,356 @@
+// 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.
+
+#import "extension_shelf_controller.h"
+
+#include "base/mac_util.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/extensions/extension_shelf_model.h"
+#include "skia/ext/skia_utils_mac.h"
+
+namespace {
+
+const int kExtensionShelfPaddingTop = 1;
+const int kToolstripPadding = 2;
+
+}
+
+// This class manages the extensions ("toolstrips") on the shelf. It listens to
+// events sent by the extension system, and acts as a bridge between that and
+// the cocoa world.
+class ExtensionShelfMac : public ExtensionShelfModelObserver {
+ public:
+ ExtensionShelfMac(Browser* browser, ExtensionShelfController* controller);
+ virtual ~ExtensionShelfMac();
+
+ // ExtensionShelfModelObserver
+ virtual void ToolstripInsertedAt(ExtensionHost* toolstrip, int index);
+ virtual void ToolstripRemovingAt(ExtensionHost* toolstrip, int index);
+ virtual void ToolstripMoved(ExtensionHost* toolstrip,
+ int from_index,
+ int to_index);
+ virtual void ToolstripChangedAt(ExtensionHost* toolstrip, int index);
+ virtual void ExtensionShelfEmpty();
+ virtual void ShelfModelReloaded();
+ virtual void ShelfModelDeleting();
+
+ // Determines what is our target height and sets it.
+ void AdjustHeight();
+
+ private:
+ class Toolstrip;
+
+ void Show();
+ void Hide();
+
+ // Create the contents of the extension shelf.
+ void Init(Profile* profile);
+
+ // Loads the background image into memory, or does nothing if already loaded.
+ void InitBackground();
+
+ // Re-inserts all toolstrips from the model. Must be called when the shelf
+ // contains no toolstrips.
+ void LoadFromModel();
+
+ void DeleteToolstrips();
+
+ Toolstrip* ToolstripAtIndex(int index);
+
+ ExtensionShelfController* controller_; // weak, owns us
+
+ Browser* browser_; // weak
+
+ // Lazily-initialized background for toolstrips.
+ scoped_ptr<SkBitmap> background_;
+
+ // The model representing the toolstrips on the shelf.
+ ExtensionShelfModel* model_; // weak
+
+ // Set of toolstrip views which are really on the shelf.
+ std::set<Toolstrip*> toolstrips_;
+
+ // Stores if we are currently layouting items.
+ bool is_adjusting_height_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionShelfMac);
+};
+
+// This class represents a single extension ("toolstrip") on the extension
+// shelf.
+class ExtensionShelfMac::Toolstrip {
+ public:
+ explicit Toolstrip(ExtensionHost* host)
+ : host_(host) {
+ DCHECK(host_->view());
+ Init();
+ }
+
+ // Inserts the native NSView belonging to this extension into the view that
+ // belongs to |controller|. Makes sure the controller is notified when the
+ // extension's |frame| changes.
+ void AddToolstripToController(ExtensionShelfController* controller);
+
+ // Removes the native NSView belonging to this extension from the view that
+ // belongs to |controller|. Removes |controller| as a frame size observer.
+ void RemoveToolstripFromController(ExtensionShelfController* controller);
+
+ // Sets the image that is used by the extension.
+ void SetBackground(const SkBitmap& background) {
+ host_->view()->SetBackground(background);
+ }
+
+ // Returns the native NSView belonging to this extension.
+ gfx::NativeView native_view() {
+ return host_->view()->native_view();
+ }
+
+ private:
+ void Init();
+
+ ExtensionHost* host_; // weak
+
+ const std::string extension_name_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Toolstrip);
+};
+
+void ExtensionShelfMac::Toolstrip::AddToolstripToController(
+ ExtensionShelfController* controller) {
+ NSView* toolstrip_view = host_->view()->native_view();
+ [[controller view] addSubview:toolstrip_view];
+
+ [[NSNotificationCenter defaultCenter]
+ addObserver:controller
+ selector:@selector(updateVisibility:)
+ name:NSViewFrameDidChangeNotification
+ object:toolstrip_view];
+}
+
+void ExtensionShelfMac::Toolstrip::RemoveToolstripFromController(
+ ExtensionShelfController* controller) {
+ [host_->view()->native_view() removeFromSuperview];
+
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:controller
+ name:NSViewFrameDidChangeNotification
+ object:host_->view()->native_view()];
+}
+
+void ExtensionShelfMac::Toolstrip::Init() {
+ host_->view()->set_is_toolstrip(true);
+}
+
+ExtensionShelfMac::ExtensionShelfMac(Browser* browser,
+ ExtensionShelfController* controller)
+ : controller_(controller),
+ browser_(browser),
+ model_(browser->extension_shelf_model()),
+ is_adjusting_height_(false) {
+ if (model_) // Can be NULL in tests.
+ Init(browser_->profile());
+}
+
+ExtensionShelfMac::~ExtensionShelfMac() {
+ DeleteToolstrips();
+ if (model_)
+ model_->RemoveObserver(this);
+}
+
+void ExtensionShelfMac::Show() {
+ [controller_ show:nil];
+}
+
+void ExtensionShelfMac::Hide() {
+ [controller_ hide:nil];
+}
+
+void ExtensionShelfMac::ToolstripInsertedAt(ExtensionHost* host,
+ int index) {
+ InitBackground();
+ Toolstrip* toolstrip = new Toolstrip(host);
+ toolstrip->SetBackground(*background_.get());
+ toolstrip->AddToolstripToController(controller_);
+ toolstrips_.insert(toolstrip);
+ model_->SetToolstripDataAt(index, toolstrip);
+
+ AdjustHeight();
+}
+
+void ExtensionShelfMac::ToolstripRemovingAt(ExtensionHost* host,
+ int index) {
+ Toolstrip* toolstrip = ToolstripAtIndex(index);
+ toolstrip->RemoveToolstripFromController(controller_);
+ toolstrips_.erase(toolstrip);
+ model_->SetToolstripDataAt(index, NULL);
+ delete toolstrip;
+
+ AdjustHeight();
+}
+
+void ExtensionShelfMac::ToolstripMoved(ExtensionHost* host,
+ int from_index,
+ int to_index) {
+ // TODO(thakis): Implement reordering toolstrips.
+ AdjustHeight();
+}
+
+void ExtensionShelfMac::ToolstripChangedAt(
+ ExtensionHost* toolstrip, int index) {
+ // TODO(thakis): Implement changing toolstrips.
+ AdjustHeight();
+}
+
+void ExtensionShelfMac::ExtensionShelfEmpty() {
+ AdjustHeight();
+}
+
+void ExtensionShelfMac::ShelfModelReloaded() {
+ DeleteToolstrips();
+ LoadFromModel();
+}
+
+void ExtensionShelfMac::ShelfModelDeleting() {
+ DeleteToolstrips();
+ model_->RemoveObserver(this);
+ model_ = NULL;
+}
+
+void ExtensionShelfMac::Init(Profile* profile) {
+ LoadFromModel();
+ model_->AddObserver(this);
+}
+
+void ExtensionShelfMac::InitBackground() {
+ if (background_.get())
+ return;
+
+ // If this is called while the shelf is invisible, shortly resize the shelf so
+ // that it can paint itself.
+ NSRect current_frame = [[controller_ view] frame];
+ if (current_frame.size.height < [controller_ height]) {
+ NSRect new_frame = current_frame;
+ new_frame.size.height = [controller_ height];
+ [[controller_ view] setFrame:new_frame];
+ }
+
+ // The background is tiled horizontally in the toolstrip. Hence, its width
+ // should not be too small so that tiling is fast, and not too large, so that
+ // not too much memory is needed -- but the exact width doesn't really matter.
+ const CGFloat kBackgroundTileWidth = 100;
+
+ // Paint shelf background into an SkBitmap. If we decide to keep the shelf, we
+ // need to do this for both the "main window" and "not main window" shadings.
+ NSRect background_rect = NSMakeRect(
+ 0, 0,
+ kBackgroundTileWidth, [controller_ height] - kExtensionShelfPaddingTop);
+ NSBitmapImageRep* bitmap_rep = [[controller_ view]
+ bitmapImageRepForCachingDisplayInRect:background_rect];
+
+ [[controller_ view] cacheDisplayInRect:background_rect
+ toBitmapImageRep:bitmap_rep];
+ background_.reset(new SkBitmap(gfx::CGImageToSkBitmap([bitmap_rep CGImage])));
+
+ // Restore old frame.
+ [[controller_ view] setFrame:current_frame];
+}
+
+void ExtensionShelfMac::AdjustHeight() {
+ if (model_->empty() || toolstrips_.empty()) {
+ // It's possible that |model_| is not empty, but |toolstrips_| are empty
+ // when removing the last toolstrip.
+ DCHECK(toolstrips_.empty());
+ Hide();
+ return;
+ }
+
+ if (is_adjusting_height_)
+ return;
+ is_adjusting_height_ = true;
+
+ Show();
+
+ // Lay out items horizontally from left to right. This method's name is
+ // misleading, but matches linux and windows for now.
+ CGFloat x = 0;
+ for (std::set<Toolstrip*>::iterator iter = toolstrips_.begin();
+ iter != toolstrips_.end(); ++iter) {
+ NSView* view = (*iter)->native_view();
+ NSRect frame = [view frame];
+ frame.origin.x = x;
+ frame.origin.y = 0;
+ frame.size.height = [controller_ height] - kExtensionShelfPaddingTop;
+ [view setFrame:frame];
+ x += frame.size.width + kToolstripPadding;
+ }
+
+ is_adjusting_height_ = false;
+}
+
+void ExtensionShelfMac::LoadFromModel() {
+ DCHECK(toolstrips_.empty());
+ int count = model_->count();
+ for (int i = 0; i < count; ++i)
+ ToolstripInsertedAt(model_->ToolstripAt(i).host, i);
+ AdjustHeight();
+}
+
+void ExtensionShelfMac::DeleteToolstrips() {
+ for (std::set<Toolstrip*>::iterator iter = toolstrips_.begin();
+ iter != toolstrips_.end(); ++iter) {
+ (*iter)->RemoveToolstripFromController(controller_);
+ delete *iter;
+ }
+ toolstrips_.clear();
+}
+
+ExtensionShelfMac::Toolstrip* ExtensionShelfMac::ToolstripAtIndex(int index) {
+ return static_cast<Toolstrip*>(model_->ToolstripAt(index).data);
+}
+
+
+@implementation ExtensionShelfController
+
+- (id)initWithBrowser:(Browser*)browser
+ resizeDelegate:(id<ViewResizer>)resizeDelegate {
+ if ((self = [super initWithNibName:@"ExtensionShelf"
+ bundle:mac_util::MainAppBundle()])) {
+ resizeDelegate_ = resizeDelegate;
+ browser_ = browser;
+ shelfHeight_ = [[self view] bounds].size.height;
+
+ NSRect frame = [[self view] frame];
+ frame.size.height = 0;
+ [[self view] setFrame:frame];
+ }
+ return self;
+}
+
+- (void)wasInsertedIntoWindow {
+ // The bridge_ calls cacheDisplayInRect:toBitmapImageRep:, which requires that
+ // the view is in a superview to work. Hence, create the bridge object no
+ // sooner.
+ DCHECK(bridge_.get() == NULL);
+ bridge_.reset(new ExtensionShelfMac(browser_, self));
+}
+
+- (IBAction)show:(id)sender {
+ [resizeDelegate_ resizeView:[self view] newHeight:shelfHeight_];
+}
+
+- (IBAction)hide:(id)sender {
+ [resizeDelegate_ resizeView:[self view] newHeight:0];
+}
+
+- (CGFloat)height {
+ return shelfHeight_;
+}
+
+- (void)updateVisibility:(id)sender {
+ if(bridge_.get())
+ bridge_->AdjustHeight();
+}
+
+@end
« no previous file with comments | « chrome/browser/cocoa/extension_shelf_controller.h ('k') | chrome/browser/cocoa/extension_shelf_controller_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698