Index: chrome/browser/cocoa/bookmark_tree_controller.mm |
diff --git a/chrome/browser/cocoa/bookmark_tree_controller.mm b/chrome/browser/cocoa/bookmark_tree_controller.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3de9d5122f481880aba33c1bc9a7317c30539b59 |
--- /dev/null |
+++ b/chrome/browser/cocoa/bookmark_tree_controller.mm |
@@ -0,0 +1,253 @@ |
+// 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_tree_controller.h" |
+ |
+#include "base/nsimage_cache_mac.h" |
+#include "base/sys_string_conversions.h" |
+#import "chrome/browser/cocoa/bookmark_manager_controller.h" |
+#include "chrome/browser/bookmarks/bookmark_model.h" |
+#include "googleurl/src/gurl.h" |
+#import "third_party/apple/ImageAndTextCell.h" |
+ |
+ |
+@implementation BookmarkTreeController |
+ |
+// Allow the |group| property to be bound (by BookmarkManagerController.) |
++ (void)initialize { |
+ [self exposeBinding:@"group"]; |
+} |
+ |
+// Initialization after the nib is loaded. |
+- (void)awakeFromNib { |
+ [outline_ setTarget:self]; |
+ [outline_ setDoubleAction:@selector(itemDoubleClicked:)]; |
+ [self registerDragTypes]; |
+} |
+ |
+- (id)group { |
+ return group_; |
+} |
+ |
+- (void)setGroup:(id)group { |
+ if (group != group_) { |
+ group_ = group; |
+ |
+ [outline_ deselectAll:self]; |
+ [outline_ reloadData]; |
+ [outline_ noteNumberOfRowsChanged]; |
+ } |
+} |
+ |
+- (NSOutlineView*)outline { |
+ return outline_; |
+} |
+ |
+// Updates the tree after the data model has changed. |
+- (void)itemChanged:(id)nodeItem childrenChanged:(BOOL)childrenChanged { |
+ if (nodeItem == group_) |
+ nodeItem = nil; |
+ [outline_ reloadItem:nodeItem reloadChildren:childrenChanged]; |
+} |
+ |
+// Getter for the |selectedItems| property. |
+- (NSArray*)selectedItems { |
+ NSMutableArray* items = [NSMutableArray array]; |
+ NSIndexSet* selectedRows = [outline_ selectedRowIndexes]; |
+ if (selectedRows != nil) { |
+ for (NSInteger row = [selectedRows firstIndex]; row != NSNotFound; |
+ row = [selectedRows indexGreaterThanIndex:row]) { |
+ [items addObject:[outline_ itemAtRow:row]]; |
+ } |
+ } |
+ return items; |
+} |
+ |
+// Setter for the |selectedItems| property. |
+- (void)setSelectedItems:(NSArray*)items { |
+ NSMutableIndexSet* newSelection = [NSMutableIndexSet indexSet]; |
+ |
+ for (NSUInteger i = 0; i < [items count]; i++) { |
+ NSInteger row = [outline_ rowForItem:[items objectAtIndex:i]]; |
+ if (row >= 0) { |
+ [newSelection addIndex:row]; |
+ } |
+ } |
+ |
+ [outline_ selectRowIndexes:newSelection byExtendingSelection:NO]; |
+} |
+ |
+ |
+#pragma mark - |
+#pragma mark COMMANDS: |
+ |
+ |
+// Responds to a double-click by opening the selected URL(s). |
+- (IBAction)itemDoubleClicked:(id)sender { |
+ for (id item in [self selectedItems]) { |
+ [manager_ openBookmarkItem:item]; |
+ } |
+} |
+ |
+// The Delete command (also bound to the delete key.) |
+- (IBAction)delete:(id)sender { |
+ NSIndexSet* selectedRows = [outline_ selectedRowIndexes]; |
+ if (!selectedRows) { |
+ NSBeep(); |
+ return; |
+ } |
+ // Iterate backwards so that any selected children are deleted before |
+ // selected parents (opposite order would cause double-free!) and so each |
+ // deletion doesn't invalidate the remaining row numbers. |
+ for (NSInteger row = [selectedRows lastIndex]; row != NSNotFound; |
+ row = [selectedRows indexLessThanIndex:row]) { |
+ const BookmarkNode* node = [manager_ nodeFromItem: |
+ [outline_ itemAtRow:row]]; |
+ const BookmarkNode* parent = node->GetParent(); |
+ [manager_ bookmarkModel]->Remove(parent, parent->IndexOfChild(node)); |
+ } |
+ |
+ [outline_ reloadData]; |
+ [outline_ deselectAll:self]; |
+} |
+ |
+ |
+#pragma mark - |
+#pragma mark DATA SOURCE: |
+ |
+ |
+// The NSOutlineView data source methods are called with a nil item to |
+// represent the root of the tree; this compensates for that. |
+- (const BookmarkNode*)nodeFromItem:(id)item { |
+ return [manager_ nodeFromItem:(item ? item : group_)]; |
+} |
+ |
+- (id)itemFromNode:(const BookmarkNode*)node { |
+ id item = [manager_ itemFromNode:node]; |
+ return item == group_ ? nil : item; |
+} |
+ |
+// Returns the children of an item (NSOutlineView data source) |
+- (NSArray*)childrenOfItem:(id)item { |
+ const BookmarkNode* node = [self nodeFromItem:item]; |
+ if (!node) { |
+ return nil; |
+ } |
+ int nChildren = node->GetChildCount(); |
+ NSMutableArray* children = [NSMutableArray arrayWithCapacity:nChildren]; |
+ for (int i = 0; i < nChildren; i++) { |
+ [children addObject:[self itemFromNode:node->GetChild(i)]]; |
+ } |
+ return children; |
+} |
+ |
+// Returns the number of children of an item (NSOutlineView data source) |
+- (NSInteger) outlineView:(NSOutlineView*)outlineView |
+ numberOfChildrenOfItem:(id)item { |
+ const BookmarkNode* node = [self nodeFromItem:item]; |
+ return node ? node->GetChildCount() : 0; |
+} |
+ |
+// Returns a child of an item (NSOutlineView data source) |
+- (id)outlineView:(NSOutlineView*)outlineView |
+ child:(NSInteger)index |
+ ofItem:(id)item { |
+ const BookmarkNode* node = [self nodeFromItem:item]; |
+ return [self itemFromNode:node->GetChild(index)]; |
+} |
+ |
+// Returns whether an item is a folder (NSOutlineView data source) |
+- (BOOL)outlineView:(NSOutlineView*)outlineView isItemExpandable:(id)item { |
+ return [self nodeFromItem:item]->is_folder(); |
+} |
+ |
+// Returns the value to display in a cell (NSOutlineView data source) |
+- (id) outlineView:(NSOutlineView*)outlineView |
+ objectValueForTableColumn:(NSTableColumn*)tableColumn |
+ byItem:(id)item { |
+ const BookmarkNode* node = [self nodeFromItem:item]; |
+ NSString* ident = [tableColumn identifier]; |
+ if ([ident isEqualToString:@"title"]) { |
+ return base::SysWideToNSString(node->GetTitle()); |
+ } else if ([ident isEqualToString:@"url"]) { |
+ return base::SysUTF8ToNSString(node->GetURL().possibly_invalid_spec()); |
+ } else { |
+ NOTREACHED(); |
+ return nil; |
+ } |
+} |
+ |
+// Stores the edited value of a cell (NSOutlineView data source) |
+- (void)outlineView:(NSOutlineView*)outlineView |
+ setObjectValue:(id)value |
+ forTableColumn:(NSTableColumn*)tableColumn |
+ byItem:(id)item |
+{ |
+ const BookmarkNode* node = [self nodeFromItem:item]; |
+ NSString* ident = [tableColumn identifier]; |
+ if ([ident isEqualToString:@"title"]) { |
+ [manager_ bookmarkModel]->SetTitle(node, base::SysNSStringToWide(value)); |
+ } else if ([ident isEqualToString:@"url"]) { |
+ GURL url(base::SysNSStringToUTF8(value)); |
+ if (url != node->GetURL()) { |
+ //TODO(snej): Uncomment this once SetURL exists (bug 10603). |
+ // ...or work around it by removing node and adding new one. |
+ //[manager_ bookmarkModel]->SetURL(node, url); |
+ } |
+ } |
+} |
+ |
+// Returns whether a cell is editable (NSOutlineView data source) |
+- (BOOL) outlineView:(NSOutlineView*)outlineView |
+ shouldEditTableColumn:(NSTableColumn*)tableColumn |
+ item:(id)item { |
+ //TODO(snej): Make URL column editable once setter method exists (bug 10603). |
+ NSString* ident = [tableColumn identifier]; |
+ return [ident isEqualToString:@"title"]; |
+} |
+ |
+// Sets a cell's icon before it's drawn (NSOutlineView data source) |
+- (void)outlineView:(NSOutlineView*)outlineView |
+ willDisplayCell:(id)cell |
+ forTableColumn:(NSTableColumn*)tableColumn |
+ item:(id)item |
+{ |
+ if ([[tableColumn identifier] isEqualToString:@"title"]) { |
+ [(ImageAndTextCell*)cell setImage:[manager_ iconForItem:item]]; |
+ } |
+} |
+ |
+@end |
+ |
+ |
+@implementation BookmarksOutlineView |
+ |
+- (IBAction)cut:(id)sender { |
+ [(BookmarkTreeController*)[self delegate] cut:sender]; |
+} |
+ |
+- (IBAction)copy:(id)sender { |
+ [(BookmarkTreeController*)[self delegate] copy:sender]; |
+} |
+ |
+- (IBAction)paste:(id)sender { |
+ [(BookmarkTreeController*)[self delegate] paste:sender]; |
+} |
+ |
+- (IBAction)delete:(id)sender { |
+ [(BookmarkTreeController*)[self delegate] delete:sender]; |
+} |
+ |
+- (BOOL)validateMenuItem:(NSMenuItem*)menuItem { |
+ return [[self delegate] validateMenuItem:menuItem]; |
+} |
+ |
+- (void)keyDown:(NSEvent*)event { |
+ if ([event keyCode] == 51) // Delete key |
+ [self delete:self]; |
+ else |
+ [super keyDown:event]; |
+} |
+ |
+@end |