summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsnej@chromium.org <snej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-11 22:21:22 +0000
committersnej@chromium.org <snej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-11 22:21:22 +0000
commit2b4a20ecd8e1447df2a87b5e9e4cae0b0bd8fb2d (patch)
tree8eaee6b11eac92b3d254d12f5a2baa68af93aa03
parent21c68eeddcccebb281aaa0382b9653523c81f707 (diff)
downloadchromium_src-2b4a20ecd8e1447df2a87b5e9e4cae0b0bd8fb2d.zip
chromium_src-2b4a20ecd8e1447df2a87b5e9e4cae0b0bd8fb2d.tar.gz
chromium_src-2b4a20ecd8e1447df2a87b5e9e4cae0b0bd8fb2d.tar.bz2
Implemented bookmark manager context menus.
BUG=31857 TEST=none Mike Pinkerton recommended I use the cross-platform menu utilities for this; I decided not to do that yet, in this patch, for a few reasons: (1) I'm in the midst of doing heavy refactoring of the tree/list controller classes in a local branch, so anything I do now would have to get changed a lot in that branch anyway. (2) The Windows and GTK bookmark managers don't use them, so there's not existing common code to hook into. This means I'd have to write all that code, and presumably retrofit the other platform managers to use it. But we really want to get this patch into the upcoming (tonight?) dev-channel build to avoid user confusion. I have not added a menu to the nib. I've added code to BookmarkManagerController to create the NSMenu programmatically. I can switch to the cross-platform utilities after my refactoring. Another note: Yes, there is some duplication of code between the Groups and Tree controller classes. I'm not worrying about this because the Groups controller class is going away completely in my refactoring, so it only has a few more days to live. :-) Review URL: http://codereview.chromium.org/549010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@35949 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/cocoa/bookmark_groups_controller.mm102
-rw-r--r--chrome/browser/cocoa/bookmark_manager_controller.h4
-rw-r--r--chrome/browser/cocoa/bookmark_manager_controller.mm20
-rw-r--r--chrome/browser/cocoa/bookmark_tree_controller.mm114
-rw-r--r--chrome/browser/cocoa/bookmark_tree_controller_pasteboard.mm17
5 files changed, 210 insertions, 47 deletions
diff --git a/chrome/browser/cocoa/bookmark_groups_controller.mm b/chrome/browser/cocoa/bookmark_groups_controller.mm
index 759d5de..e82b847 100644
--- a/chrome/browser/cocoa/bookmark_groups_controller.mm
+++ b/chrome/browser/cocoa/bookmark_groups_controller.mm
@@ -88,15 +88,6 @@
}
}
-- (NSTableView*)groupsTable {
- return groupsTable_;
-}
-
-
-#pragma mark -
-#pragma mark COMMANDS:
-
-
// Updates the |selectedGroup| property based on the table view's selection.
- (void)syncSelection {
id selGroup = nil;
@@ -110,6 +101,29 @@
[self setSelectedGroup:selGroup];
}
+- (NSTableView*)groupsTable {
+ return groupsTable_;
+}
+
+// Returns the selected/right-clicked row #, or -1 if none.
+- (int)actionRow {
+ int row = [groupsTable_ clickedRow];
+ if (row < 0)
+ row = [groupsTable_ selectedRow];
+ return row;
+}
+
+// Returns the selected/right-clicked item, or nil if none.
+- (id)actionItem {
+ int row = [self actionRow];
+ return row >= 0 ? [groups_ objectAtIndex:row] : nil;
+}
+
+
+#pragma mark -
+#pragma mark COMMANDS:
+
+
// Called when a row is clicked; updates the |selectedGroup| property.
- (IBAction)tableClicked:(id)sender {
[self syncSelection];
@@ -117,21 +131,23 @@
// The Delete command; also invoked by the delete key.
- (IBAction)delete:(id)sender {
- const BookmarkNode* sel = [self selectedNode];
- if (!sel) {
+ id item = [self actionItem];
+ if (!item) {
NSBeep();
return;
}
- const BookmarkNode* parent = sel->GetParent();
- [manager_ bookmarkModel]->Remove(parent, parent->IndexOfChild(sel));
+ const BookmarkNode* node = [manager_ nodeFromItem:item];
+ const BookmarkNode* parent = node->GetParent();
+ [manager_ bookmarkModel]->Remove(parent, parent->IndexOfChild(node));
}
+// Makes the title of the selected row editable.
- (IBAction)editTitle:(id)sender {
- if ([groupsTable_ numberOfSelectedRows] != 1) {
+ int row = [self actionRow];
+ if (row < 0) {
NSBeep();
return;
}
- int row = [groupsTable_ selectedRow];
if (![self tableView:groupsTable_
shouldEditTableColumn:[[groupsTable_ tableColumns] objectAtIndex:0]
row:row]) {
@@ -144,6 +160,54 @@
select:YES];
}
+// Creates a new folder.
+- (IBAction)newFolder:(id)sender {
+ const BookmarkNode* targetNode;
+ NSInteger childIndex;
+ id item = [self actionItem];
+ if (item) {
+ // Insert at selected/clicked row.
+ const BookmarkNode* node = [manager_ nodeFromItem:item];
+ targetNode = node->GetParent();
+ childIndex = targetNode->IndexOfChild(node);
+ } else {
+ // ...or at very end if there's no selection:
+ targetNode = [manager_ bookmarkModel]->other_node();
+ childIndex = targetNode->GetChildCount();
+ }
+
+ const BookmarkNode* folder;
+ folder = [manager_ bookmarkModel]->AddGroup(targetNode, childIndex, L"");
+
+ // Edit the title:
+ id folderItem = [manager_ itemFromNode:folder];
+ [self setSelectedGroup:folderItem];
+ int row = [groups_ indexOfObject:folderItem];
+ DCHECK(row!=NSNotFound);
+ [groupsTable_ editColumn:0
+ row:row
+ withEvent:[NSApp currentEvent]
+ select:YES];
+}
+
+// Selectively enables/disables menu commands.
+- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
+ SEL action = [menuItem action];
+ if (action == @selector(delete:) || action == @selector(editTitle:)) {
+ // Note ">", not ">=". Row 0 is Bookmarks Bar, which is immutable.
+ return [self actionRow] > 0;
+ } else {
+ return YES;
+ }
+}
+
+- (NSMenu*)menu {
+ NSMenu* menu = [manager_ contextMenu];
+ for (NSMenuItem* item in [menu itemArray])
+ [item setTarget:self];
+ return menu;
+}
+
#pragma mark -
#pragma mark LIST VIEW:
@@ -199,6 +263,10 @@
[(BookmarkGroupsController*)[self delegate] delete:sender];
}
+- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
+ return [(BookmarkGroupsController*)[self delegate] validateMenuItem:menuItem];
+}
+
- (void)keyDown:(NSEvent*)event {
NSString* chars = [event charactersIgnoringModifiers];
if ([chars length] == 1) {
@@ -221,4 +289,8 @@
[super keyDown:event];
}
+- (NSMenu*)menu {
+ return [[self delegate] menu];
+}
+
@end
diff --git a/chrome/browser/cocoa/bookmark_manager_controller.h b/chrome/browser/cocoa/bookmark_manager_controller.h
index c5b8b73..4cb4b1e 100644
--- a/chrome/browser/cocoa/bookmark_manager_controller.h
+++ b/chrome/browser/cocoa/bookmark_manager_controller.h
@@ -44,6 +44,10 @@ class Profile;
// This will be the URL's favicon, a generic page icon, or a folder icon.
- (NSImage*)iconForItem:(id)item;
+// Returns a context menu for use with either table view pane.
+// A new instance is created every time, so the caller can customize it.
+- (NSMenu*)contextMenu;
+
// Opens a URL bookmark in a browser tab.
- (void)openBookmarkItem:(id)item;
diff --git a/chrome/browser/cocoa/bookmark_manager_controller.mm b/chrome/browser/cocoa/bookmark_manager_controller.mm
index 8b39fb6..7ae1c1d 100644
--- a/chrome/browser/cocoa/bookmark_manager_controller.mm
+++ b/chrome/browser/cocoa/bookmark_manager_controller.mm
@@ -4,6 +4,7 @@
#import "chrome/browser/cocoa/bookmark_manager_controller.h"
+#include "app/l10n_util_mac.h"
#include "app/resource_bundle.h"
#include "base/mac_util.h"
#include "base/sys_string_conversions.h"
@@ -16,6 +17,7 @@
#import "chrome/browser/cocoa/bookmark_tree_controller.h"
#include "chrome/browser/profile.h"
#include "grit/app_resources.h"
+#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "skia/ext/skia_utils_mac.h"
@@ -135,6 +137,24 @@ class BookmarkManagerBridge : public BookmarkModelObserver {
return treeController_;
}
+static void addItem(NSMenu* menu, int command, SEL action) {
+ [menu addItemWithTitle:l10n_util::GetNSStringWithFixup(command)
+ action:action
+ keyEquivalent:@""];
+}
+
+// Generates a context menu for use by the group/tree controllers.
+- (NSMenu*)contextMenu {
+ NSMenu* menu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
+ addItem(menu, IDS_BOOMARK_BAR_OPEN_IN_NEW_TAB, @selector(openItems:));
+ [menu addItem:[NSMenuItem separatorItem]];
+ addItem(menu, IDS_BOOKMARK_BAR_EDIT, @selector(editTitle:));
+ addItem(menu, IDS_BOOKMARK_BAR_REMOVE, @selector(delete:));
+ [menu addItem:[NSMenuItem separatorItem]];
+ addItem(menu, IDS_BOOMARK_BAR_NEW_FOLDER, @selector(newFolder:));
+ return menu;
+}
+
#pragma mark -
#pragma mark DATA MODEL:
diff --git a/chrome/browser/cocoa/bookmark_tree_controller.mm b/chrome/browser/cocoa/bookmark_tree_controller.mm
index d4b8d3c..accf698 100644
--- a/chrome/browser/cocoa/bookmark_tree_controller.mm
+++ b/chrome/browser/cocoa/bookmark_tree_controller.mm
@@ -22,7 +22,7 @@
// Initialization after the nib is loaded.
- (void)awakeFromNib {
[outline_ setTarget:self];
- [outline_ setDoubleAction:@selector(itemDoubleClicked:)];
+ [outline_ setDoubleAction:@selector(openItems:)];
[self registerDragTypes];
}
@@ -78,32 +78,47 @@
[outline_ selectRowIndexes:newSelection byExtendingSelection:NO];
}
+// Returns the selected/right-clicked item(s) for a command to act on.
+- (NSArray*)actionItems {
+ int row = [outline_ clickedRow];
+ if (row >= 0 && ![outline_ isRowSelected:row])
+ return [NSArray arrayWithObject:[outline_ itemAtRow:row]];
+
+ return [self selectedItems];
+}
+
#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];
+- (IBAction)openItems:(id)sender {
+ for (id item in [self actionItems]) {
+ if ([outline_ isExpandable:item]) {
+ if ([outline_ isItemExpanded:item])
+ [outline_ collapseItem:item];
+ else
+ [outline_ expandItem:item];
+ } else {
+ [manager_ openBookmarkItem:item];
+ }
}
}
// The Delete command (also bound to the delete key.)
- (IBAction)delete:(id)sender {
- NSIndexSet* selectedRows = [outline_ selectedRowIndexes];
- if (!selectedRows) {
+ NSArray* items = [self actionItems];
+ if ([items count] == 0) {
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]) {
+ for (NSInteger i = [items count] - 1; i >= 0; i--) {
const BookmarkNode* node = [manager_ nodeFromItem:
- [outline_ itemAtRow:row]];
+ [items objectAtIndex:i]];
const BookmarkNode* parent = node->GetParent();
[manager_ bookmarkModel]->Remove(parent, parent->IndexOfChild(node));
}
@@ -112,17 +127,82 @@
[outline_ deselectAll:self];
}
-- (IBAction)editTitle:(id)sender {
- if ([outline_ numberOfSelectedRows] != 1) {
- NSBeep();
- return;
- }
+- (void)editTitleOfItem:(id)item {
+ int row = [outline_ rowForItem:item];
+ DCHECK(row >= 0);
[outline_ editColumn:[outline_ columnWithIdentifier:@"title"]
- row:[outline_ selectedRow]
+ row:row
withEvent:[NSApp currentEvent]
select:YES];
}
+- (IBAction)editTitle:(id)sender {
+ NSArray* items = [self actionItems];
+ if ([items count] == 1)
+ [self editTitleOfItem:[items objectAtIndex:0]];
+ else
+ NSBeep();
+}
+
+- (IBAction)newFolder:(id)sender {
+ const BookmarkNode* targetNode;
+ NSInteger childIndex;
+ NSArray* items = [self actionItems];
+ if ([items count] > 0) {
+ // Insert at selected/clicked row.
+ const BookmarkNode* selNode = [self nodeFromItem:
+ [items objectAtIndex:0]];
+ targetNode = selNode->GetParent();
+ childIndex = targetNode->IndexOfChild(selNode);
+ } else {
+ // ...or at very end if there's no selection:
+ targetNode = [self nodeFromItem:group_];
+ childIndex = targetNode->GetChildCount();
+ }
+
+ const BookmarkNode* folder = [manager_ bookmarkModel]->
+ AddGroup(targetNode, childIndex, L"");
+ id folderItem = [manager_ itemFromNode:folder];
+ [outline_ expandItem:folderItem];
+ [self setSelectedItems:[NSArray arrayWithObject:folderItem]];
+ [self editTitleOfItem:folderItem];
+}
+
+- (NSMenu*)menu {
+ NSMenu* menu = [manager_ contextMenu];
+ for (NSMenuItem* item in [menu itemArray])
+ [item setTarget:self];
+ return menu;
+}
+
+// Selectively enables/disables menu commands.
+- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
+ SEL action = [menuItem action];
+ if (action == @selector(cut:) || action == @selector(copy:) ||
+ action == @selector(delete:)) {
+ return [[self actionItems] count] > 0;
+ } else if (action == @selector(openItems:)) {
+ NSArray* items = [self actionItems];
+ if ([items count] == 0)
+ return NO;
+ // Disable if folder selected (if only because title says "Open In Tab".)
+ for (id item in items) {
+ const BookmarkNode* node = [manager_ nodeFromItem:item];
+ if (!node->is_url())
+ return NO;
+ }
+ return YES;
+ } else if (action == @selector(editTitle:)) {
+ return [[self actionItems] count] == 1;
+ } else if (action == @selector(paste:)) {
+ return [[NSPasteboard generalPasteboard]
+ availableTypeFromArray:[outline_ registeredDraggedTypes]]
+ != nil;
+ } else {
+ return YES;
+ }
+}
+
#pragma mark -
#pragma mark DATA SOURCE:
@@ -276,4 +356,8 @@
[super keyDown:event];
}
+- (NSMenu*)menu {
+ return [[self delegate] menu];
+}
+
@end
diff --git a/chrome/browser/cocoa/bookmark_tree_controller_pasteboard.mm b/chrome/browser/cocoa/bookmark_tree_controller_pasteboard.mm
index 4ae5bab..0061dbe 100644
--- a/chrome/browser/cocoa/bookmark_tree_controller_pasteboard.mm
+++ b/chrome/browser/cocoa/bookmark_tree_controller_pasteboard.mm
@@ -428,21 +428,4 @@ static NSDictionary* makeBookmarkPlistEntry(NSString* name, NSString* urlStr) {
return YES;
}
-
-// Selectively enables/disables menu commands.
-- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
- SEL action = [menuItem action];
- if (action == @selector(cut:) || action == @selector(copy:) ||
- action == @selector(delete:)) {
- return [[outline_ selectedRowIndexes] count] > 0;
- } else if (action == @selector(paste:)) {
- return [[NSPasteboard generalPasteboard]
- availableTypeFromArray:[outline_ registeredDraggedTypes]]
- != nil;
- } else {
- return YES;
- }
-}
-
-
@end