| Index: chrome/browser/cocoa/bookmark_manager_controller.mm
|
| diff --git a/chrome/browser/cocoa/bookmark_manager_controller.mm b/chrome/browser/cocoa/bookmark_manager_controller.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8b39fb6908af1369fd8f97ad2f0e03e20479e421
|
| --- /dev/null
|
| +++ b/chrome/browser/cocoa/bookmark_manager_controller.mm
|
| @@ -0,0 +1,261 @@
|
| +// 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 "chrome/browser/cocoa/bookmark_manager_controller.h"
|
| +
|
| +#include "app/resource_bundle.h"
|
| +#include "base/mac_util.h"
|
| +#include "base/sys_string_conversions.h"
|
| +#include "chrome/browser/bookmarks/bookmark_model.h"
|
| +#include "chrome/browser/bookmarks/bookmark_model_observer.h"
|
| +#include "chrome/browser/browser.h"
|
| +#include "chrome/browser/browser_list.h"
|
| +#include "chrome/browser/browser_window.h"
|
| +#import "chrome/browser/cocoa/bookmark_groups_controller.h"
|
| +#import "chrome/browser/cocoa/bookmark_tree_controller.h"
|
| +#include "chrome/browser/profile.h"
|
| +#include "grit/app_resources.h"
|
| +#include "grit/theme_resources.h"
|
| +#include "skia/ext/skia_utils_mac.h"
|
| +
|
| +
|
| +// There's at most one BookmarkManagerController at a time. This points to it.
|
| +static BookmarkManagerController* sInstance;
|
| +
|
| +
|
| +@interface BookmarkManagerController ()
|
| +- (void)nodeChanged:(const BookmarkNode*)node
|
| + childrenChanged:(BOOL)childrenChanged;
|
| +@end
|
| +
|
| +
|
| +// Adapter to tell BookmarkManagerController when bookmarks change.
|
| +class BookmarkManagerBridge : public BookmarkModelObserver {
|
| + public:
|
| + BookmarkManagerBridge(BookmarkManagerController* manager)
|
| + :manager_(manager) { }
|
| +
|
| + virtual void Loaded(BookmarkModel* model) {
|
| + // Ignore this; model has already loaded by this point.
|
| + }
|
| +
|
| + virtual void BookmarkNodeMoved(BookmarkModel* model,
|
| + const BookmarkNode* old_parent,
|
| + int old_index,
|
| + const BookmarkNode* new_parent,
|
| + int new_index) {
|
| + [manager_ nodeChanged:old_parent childrenChanged:YES];
|
| + [manager_ nodeChanged:new_parent childrenChanged:YES];
|
| + }
|
| +
|
| + virtual void BookmarkNodeAdded(BookmarkModel* model,
|
| + const BookmarkNode* parent,
|
| + int index) {
|
| + [manager_ nodeChanged:parent childrenChanged:YES];
|
| + }
|
| +
|
| + virtual void BookmarkNodeRemoved(BookmarkModel* model,
|
| + const BookmarkNode* parent,
|
| + int old_index,
|
| + const BookmarkNode* node) {
|
| + [manager_ nodeChanged:parent childrenChanged:YES];
|
| + [manager_ forgetNode:node];
|
| + }
|
| +
|
| + virtual void BookmarkNodeChanged(BookmarkModel* model,
|
| + const BookmarkNode* node) {
|
| + [manager_ nodeChanged:node childrenChanged:NO];
|
| + }
|
| +
|
| + virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model,
|
| + const BookmarkNode* node) {
|
| + [manager_ nodeChanged:node childrenChanged:NO];
|
| + }
|
| +
|
| + virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
|
| + const BookmarkNode* node) {
|
| + [manager_ nodeChanged:node childrenChanged:YES];
|
| + }
|
| +
|
| + private:
|
| + BookmarkManagerController* manager_; // weak
|
| +};
|
| +
|
| +
|
| +@implementation BookmarkManagerController
|
| +
|
| +
|
| +// Private instance initialization method.
|
| +- (id)initWithProfile:(Profile*)profile {
|
| + // Use initWithWindowNibPath:: instead of initWithWindowNibName: so we
|
| + // can override it in a unit test.
|
| + NSString* nibPath = [mac_util::MainAppBundle()
|
| + pathForResource:@"BookmarkManager"
|
| + ofType:@"nib"];
|
| + self = [super initWithWindowNibPath:nibPath owner:self];
|
| + if (self != nil) {
|
| + profile_ = profile;
|
| + bridge_ = new BookmarkManagerBridge(self);
|
| + profile_->GetBookmarkModel()->AddObserver(bridge_);
|
| +
|
| + // Initialize some cached icons:
|
| + ResourceBundle& rb = ResourceBundle::GetSharedInstance();
|
| + folderIcon_.reset([rb.GetNSImageNamed(IDR_BOOKMARK_BAR_FOLDER) retain]);
|
| + defaultFavIcon_.reset([rb.GetNSImageNamed(IDR_DEFAULT_FAVICON) retain]);
|
| + }
|
| + return self;
|
| +}
|
| +
|
| +- (void)dealloc {
|
| + if (self == sInstance) {
|
| + sInstance = nil;
|
| + }
|
| + if (bridge_) {
|
| + profile_->GetBookmarkModel()->RemoveObserver(bridge_);
|
| + delete bridge_;
|
| + }
|
| + [super dealloc];
|
| +}
|
| +
|
| +- (void)awakeFromNib {
|
| + [groupsController_ reload];
|
| + [treeController_ bind:@"group"
|
| + toObject:groupsController_
|
| + withKeyPath:@"selectedGroup"
|
| + options:0];
|
| +}
|
| +
|
| +// can't synthesize category methods, unfortunately
|
| +- (BookmarkGroupsController*)groupsController {
|
| + return groupsController_;
|
| +}
|
| +
|
| +- (BookmarkTreeController*)treeController {
|
| + return treeController_;
|
| +}
|
| +
|
| +
|
| +#pragma mark -
|
| +#pragma mark DATA MODEL:
|
| +
|
| +
|
| +// Getter for the |bookmarkModel| property.
|
| +- (BookmarkModel*)bookmarkModel {
|
| + return profile_->GetBookmarkModel();
|
| +}
|
| +
|
| +// Maps a BookmarkNode to a table/outline row item placeholder.
|
| +- (const BookmarkNode*)nodeFromItem:(id)item {
|
| + return (const BookmarkNode*)[item pointerValue];
|
| +}
|
| +
|
| +// Maps a table/outline row item placeholder back to a BookmarkNode.
|
| +- (id)itemFromNode:(const BookmarkNode*)node {
|
| + if (!nodeMap_) {
|
| + nodeMap_.reset([[NSMapTable alloc]
|
| + initWithKeyOptions:NSPointerFunctionsOpaqueMemory |
|
| + NSPointerFunctionsOpaquePersonality
|
| + valueOptions:NSPointerFunctionsStrongMemory
|
| + capacity:500]);
|
| + }
|
| + NSValue* item = (NSValue*)NSMapGet(nodeMap_, node);
|
| + if (!item) {
|
| + item = [NSValue valueWithPointer:node];
|
| + NSMapInsertKnownAbsent(nodeMap_, node, item);
|
| + }
|
| + return item;
|
| +}
|
| +
|
| +// Removes a BookmarkNode from the node<->item mapping table.
|
| +- (void)forgetNode:(const BookmarkNode*)node {
|
| + NSMapRemove(nodeMap_, node);
|
| + for (int i = node->GetChildCount() - 1 ; i >= 0 ; i--) {
|
| + [self forgetNode:node->GetChild(i)];
|
| + }
|
| +}
|
| +
|
| +// Called when the bookmark model changes; forwards to the sub-controllers.
|
| +- (void)nodeChanged:(const BookmarkNode*)node
|
| + childrenChanged:(BOOL)childrenChanged {
|
| + [groupsController_ nodeChanged:node childrenChanged:childrenChanged];
|
| + // TreeController only cares about nodes we have items for, so don't bother
|
| + // creating a new item if the node's never been seen:
|
| + id item = (NSValue*)NSMapGet(nodeMap_, node);
|
| + if (item) {
|
| + [treeController_ itemChanged:item childrenChanged:childrenChanged];
|
| + }
|
| +}
|
| +
|
| +
|
| +// Returns the icon (fav- or folder) for a table/outline item.
|
| +- (NSImage*)iconForItem:(id)item {
|
| + const BookmarkNode* node = [self nodeFromItem:item];
|
| + if (node->is_folder()) {
|
| + return folderIcon_;
|
| + } else if (node->is_url()) {
|
| + const BookmarkNode* node = [self nodeFromItem:item];
|
| + const SkBitmap& skIcon = [self bookmarkModel]->GetFavIcon(node);
|
| + if (!skIcon.isNull()) {
|
| + return gfx::SkBitmapToNSImage(skIcon);
|
| + }
|
| + }
|
| + return defaultFavIcon_;
|
| +}
|
| +
|
| +
|
| +#pragma mark -
|
| +#pragma mark WINDOW MANAGEMENT:
|
| +
|
| +
|
| +// Public entry point to open the bookmark manager.
|
| ++ (BookmarkManagerController*)showBookmarkManager:(Profile*)profile
|
| +{
|
| + if (!sInstance) {
|
| + sInstance = [[self alloc] initWithProfile:profile];
|
| + }
|
| + [sInstance showWindow:self];
|
| + return sInstance;
|
| +}
|
| +
|
| +// When window closes, get rid of myself too. (NSWindow delegate)
|
| +- (void)windowWillClose:(NSNotification*)n {
|
| + [self autorelease];
|
| +}
|
| +
|
| +// Install the search field into the search toolbar item. (NSToolbar delegate)
|
| +- (void)toolbarWillAddItem:(NSNotification*)notification {
|
| + NSToolbarItem* item = [[notification userInfo] objectForKey:@"item"];
|
| + if ([[item itemIdentifier] isEqualToString:@"search"]) {
|
| + [item setView:toolbarSearchView_];
|
| + NSSize size = [toolbarSearchView_ frame].size;
|
| + [item setMinSize:size];
|
| + [item setMaxSize:size];
|
| + }
|
| +}
|
| +
|
| +// Called when the user types into the search field.
|
| +- (IBAction)searchFieldChanged:(id)sender {
|
| + //TODO(snej): Implement this
|
| +}
|
| +
|
| +
|
| +// Open a bookmark, by having Chrome open a tab on its URL.
|
| +- (void)openBookmarkItem:(id)item {
|
| + const BookmarkNode* node = [self nodeFromItem:item];
|
| + DCHECK(node);
|
| + if (!node->is_url())
|
| + return;
|
| + GURL url = node->GetURL();
|
| +
|
| + Browser* browser = BrowserList::GetLastActive();
|
| + // if no browser window exists then create one with no tabs to be filled in
|
| + if (!browser) {
|
| + browser = Browser::Create(profile_);
|
| + browser->window()->Show();
|
| + }
|
| + browser->OpenURL(url, GURL(), NEW_FOREGROUND_TAB,
|
| + PageTransition::AUTO_BOOKMARK);
|
| +}
|
| +
|
| +@end
|
|
|