summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa/bookmark_menu_bridge.mm
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/cocoa/bookmark_menu_bridge.mm')
-rw-r--r--chrome/browser/cocoa/bookmark_menu_bridge.mm252
1 files changed, 252 insertions, 0 deletions
diff --git a/chrome/browser/cocoa/bookmark_menu_bridge.mm b/chrome/browser/cocoa/bookmark_menu_bridge.mm
new file mode 100644
index 0000000..e635548
--- /dev/null
+++ b/chrome/browser/cocoa/bookmark_menu_bridge.mm
@@ -0,0 +1,252 @@
+// 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 <AppKit/AppKit.h>
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/nsimage_cache_mac.h"
+#include "base/sys_string_conversions.h"
+#import "chrome/browser/app_controller_mac.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/cocoa/bookmark_menu_bridge.h"
+#import "chrome/browser/cocoa/bookmark_menu_cocoa_controller.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/profile_manager.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "skia/ext/skia_utils_mac.h"
+
+BookmarkMenuBridge::BookmarkMenuBridge(Profile* profile)
+ : menuIsValid_(false),
+ profile_(profile),
+ controller_([[BookmarkMenuCocoaController alloc] initWithBridge:this]) {
+ if (GetBookmarkModel())
+ ObserveBookmarkModel();
+}
+
+BookmarkMenuBridge::~BookmarkMenuBridge() {
+ BookmarkModel *model = GetBookmarkModel();
+ if (model)
+ model->RemoveObserver(this);
+ [controller_ release];
+}
+
+NSMenu* BookmarkMenuBridge::BookmarkMenu() {
+ return [controller_ menu];
+}
+
+void BookmarkMenuBridge::Loaded(BookmarkModel* model) {
+ InvalidateMenu();
+}
+
+void BookmarkMenuBridge::UpdateMenu(NSMenu* bookmark_menu) {
+ DCHECK(bookmark_menu);
+ if (menuIsValid_)
+ return;
+ BookmarkModel* model = GetBookmarkModel();
+ if (!model || !model->IsLoaded())
+ return;
+
+ if (!folder_image_) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ folder_image_.reset([rb.GetNSImageNamed(IDR_BOOKMARK_BAR_FOLDER) retain]);
+ }
+
+ ClearBookmarkMenu(bookmark_menu);
+
+ // Add bookmark bar items, if any.
+ const BookmarkNode* barNode = model->GetBookmarkBarNode();
+ CHECK(barNode);
+ if (barNode->GetChildCount()) {
+ [bookmark_menu addItem:[NSMenuItem separatorItem]];
+ AddNodeToMenu(barNode, bookmark_menu);
+ }
+
+ // Create a submenu for "other bookmarks", and fill it in.
+ NSString* other_items_title =
+ l10n_util::GetNSString(IDS_BOOMARK_BAR_OTHER_FOLDER_NAME);
+ [bookmark_menu addItem:[NSMenuItem separatorItem]];
+ AddNodeAsSubmenu(bookmark_menu,
+ model->other_node(),
+ other_items_title);
+
+ menuIsValid_ = true;
+}
+
+void BookmarkMenuBridge::BookmarkModelBeingDeleted(BookmarkModel* model) {
+ NSMenu* bookmark_menu = BookmarkMenu();
+ if (bookmark_menu == nil)
+ return;
+
+ ClearBookmarkMenu(bookmark_menu);
+}
+
+void BookmarkMenuBridge::BookmarkNodeMoved(BookmarkModel* model,
+ const BookmarkNode* old_parent,
+ int old_index,
+ const BookmarkNode* new_parent,
+ int new_index) {
+ InvalidateMenu();
+}
+
+void BookmarkMenuBridge::BookmarkNodeAdded(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int index) {
+ InvalidateMenu();
+}
+
+void BookmarkMenuBridge::BookmarkNodeRemoved(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int old_index,
+ const BookmarkNode* node) {
+ InvalidateMenu();
+}
+
+void BookmarkMenuBridge::BookmarkNodeChanged(BookmarkModel* model,
+ const BookmarkNode* node) {
+ NSMenuItem* item = MenuItemForNode(node);
+ if (item)
+ ConfigureMenuItem(node, item, true);
+}
+
+void BookmarkMenuBridge::BookmarkNodeFavIconLoaded(BookmarkModel* model,
+ const BookmarkNode* node) {
+ NSMenuItem* item = MenuItemForNode(node);
+ if (item)
+ ConfigureMenuItem(node, item, false);
+}
+
+void BookmarkMenuBridge::BookmarkNodeChildrenReordered(
+ BookmarkModel* model, const BookmarkNode* node) {
+ InvalidateMenu();
+}
+
+// Watch for changes.
+void BookmarkMenuBridge::ObserveBookmarkModel() {
+ BookmarkModel* model = GetBookmarkModel();
+ model->AddObserver(this);
+ if (model->IsLoaded())
+ Loaded(model);
+}
+
+BookmarkModel* BookmarkMenuBridge::GetBookmarkModel() {
+ if (!profile_)
+ return NULL;
+ return profile_->GetBookmarkModel();
+}
+
+Profile* BookmarkMenuBridge::GetProfile() {
+ return profile_;
+}
+
+void BookmarkMenuBridge::ClearBookmarkMenu(NSMenu* menu) {
+ bookmark_nodes_.clear();
+ // Recursively delete all menus that look like a bookmark. Assume
+ // all items with submenus contain only bookmarks. Also delete all
+ // separator items since we explicirly add them back in. This should
+ // deletes everything except the first item ("Add Bookmark...").
+ NSArray* items = [menu itemArray];
+ for (NSMenuItem* item in items) {
+ // Convention: items in the bookmark list which are bookmarks have
+ // an action of openBookmarkMenuItem:. Also, assume all items
+ // with submenus are submenus of bookmarks.
+ if (([item action] == @selector(openBookmarkMenuItem:)) ||
+ [item hasSubmenu] ||
+ [item isSeparatorItem]) {
+ // This will eventually [obj release] all its kids, if it has
+ // any.
+ [menu removeItem:item];
+ } else {
+ // Leave it alone.
+ }
+ }
+}
+
+void BookmarkMenuBridge::AddNodeAsSubmenu(NSMenu* menu,
+ const BookmarkNode* node,
+ NSString* title) {
+ NSMenuItem* items = [[[NSMenuItem alloc]
+ initWithTitle:title
+ action:nil
+ keyEquivalent:@""] autorelease];
+ [items setImage:folder_image_];
+ [menu addItem:items];
+ NSMenu* other_submenu = [[[NSMenu alloc] initWithTitle:title]
+ autorelease];
+ [menu setSubmenu:other_submenu forItem:items];
+ AddNodeToMenu(node, other_submenu);
+}
+
+// TODO(jrg): limit the number of bookmarks in the menubar?
+void BookmarkMenuBridge::AddNodeToMenu(const BookmarkNode* node, NSMenu* menu) {
+ int child_count = node->GetChildCount();
+ if (!child_count) {
+ NSString* empty_string = l10n_util::GetNSString(IDS_MENU_EMPTY_SUBMENU);
+ NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:empty_string
+ action:nil
+ keyEquivalent:@""] autorelease];
+ [menu addItem:item];
+ } else for (int i = 0; i < child_count; i++) {
+ const BookmarkNode* child = node->GetChild(i);
+ NSString* title = [BookmarkMenuCocoaController menuTitleForNode:child];
+ NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:title
+ action:nil
+ keyEquivalent:@""] autorelease];
+ [menu addItem:item];
+ bookmark_nodes_[child] = item;
+ if (child->is_folder()) {
+ [item setImage:folder_image_];
+ NSMenu* submenu = [[[NSMenu alloc] initWithTitle:title] autorelease];
+ [menu setSubmenu:submenu forItem:item];
+ AddNodeToMenu(child, submenu); // recursive call
+ } else {
+ ConfigureMenuItem(child, item, false);
+ }
+ }
+}
+
+void BookmarkMenuBridge::ConfigureMenuItem(const BookmarkNode* node,
+ NSMenuItem* item,
+ bool set_title) {
+ if (set_title) {
+ NSString* title = [BookmarkMenuCocoaController menuTitleForNode:node];
+ [item setTitle:title];
+ }
+ [item setTarget:controller_];
+ [item setAction:@selector(openBookmarkMenuItem:)];
+ [item setTag:node->id()];
+ // Add a tooltip
+ std::string url_string = node->GetURL().possibly_invalid_spec();
+ NSString* tooltip = [NSString stringWithFormat:@"%@\n%s",
+ base::SysWideToNSString(node->GetTitle()),
+ url_string.c_str()];
+ [item setToolTip:tooltip];
+
+ // Check to see if we have a favicon.
+ NSImage* favicon = nil;
+ BookmarkModel* model = GetBookmarkModel();
+ if (model) {
+ const SkBitmap& bitmap = model->GetFavIcon(node);
+ if (!bitmap.isNull())
+ favicon = gfx::SkBitmapToNSImage(bitmap);
+ }
+ // Either we do not have a loaded favicon or the conversion from SkBitmap
+ // failed. Use the default site image instead.
+ if (!favicon)
+ favicon = nsimage_cache::ImageNamed(@"nav.pdf");
+ [item setImage:favicon];
+}
+
+NSMenuItem* BookmarkMenuBridge::MenuItemForNode(const BookmarkNode* node) {
+ if (!node)
+ return nil;
+ std::map<const BookmarkNode*, NSMenuItem*>::iterator it =
+ bookmark_nodes_.find(node);
+ if (it == bookmark_nodes_.end())
+ return nil;
+ return it->second;
+}