summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorjrg@chromium.org <jrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-15 19:26:33 +0000
committerjrg@chromium.org <jrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-15 19:26:33 +0000
commit9a7e86a71073e1026e053d2a8a00f880cb4c3bd8 (patch)
tree49976fb5356aa419f9f38108e4b7253a1eb0bc70 /chrome/browser
parent809d43de928a6a80723d360d68feafabe3c5071e (diff)
downloadchromium_src-9a7e86a71073e1026e053d2a8a00f880cb4c3bd8.zip
chromium_src-9a7e86a71073e1026e053d2a8a00f880cb4c3bd8.tar.gz
chromium_src-9a7e86a71073e1026e053d2a8a00f880cb4c3bd8.tar.bz2
Fix "open all" on a folder node to open only 'marks in that folder,
not ALL all. Make Delete and Rename enabled for folder context menu (but disabled for "Other Bookmarks"). nib changes (related to the context menus): - Telegate is the bookmark bar controller. - Switched type from NSMenu to BookmarkMenu. TEST=New window. Create folder "empty" with nothing in it. Create folder "two" with 2 bookmarks in it. Create a final bookmark in the top level of the bar. Context menu (right click) over all folders. Make sure Delete and Rename enabled for folders but not "Other Bookmarks". Make sure "Open All" (and friends) disabled over "empty", enabled over "two". "Open All" on "two" --> see 2 opened. "Open All" on the bar itself --> see 3 opened. Ditto for "Open all in new window" and "open all in incognito window". Create a new window. In new window, make sure folders have context menus. BUG=http://crbug.com/27522, http://crbug.com/27529 Review URL: http://codereview.chromium.org/391046 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@32029 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/cocoa/bookmark_bar_controller.h6
-rw-r--r--chrome/browser/cocoa/bookmark_bar_controller.mm99
-rw-r--r--chrome/browser/cocoa/bookmark_bar_controller_unittest.mm77
-rw-r--r--chrome/browser/cocoa/bookmark_button_cell.mm9
-rw-r--r--chrome/browser/cocoa/bookmark_button_cell_unittest.mm16
-rw-r--r--chrome/browser/cocoa/bookmark_menu.h18
-rw-r--r--chrome/browser/cocoa/bookmark_menu.mm22
-rw-r--r--chrome/browser/cocoa/bookmark_menu_unittest.mm28
8 files changed, 220 insertions, 55 deletions
diff --git a/chrome/browser/cocoa/bookmark_bar_controller.h b/chrome/browser/cocoa/bookmark_bar_controller.h
index c390893..648a9ad 100644
--- a/chrome/browser/cocoa/bookmark_bar_controller.h
+++ b/chrome/browser/cocoa/bookmark_bar_controller.h
@@ -19,6 +19,7 @@
class BookmarkModel;
class BookmarkNode;
@class BookmarkBarView;
+@class BookmarkMenu;
class Browser;
class GURL;
@class MenuButton;
@@ -127,6 +128,10 @@ willAnimateFromState:(bookmarks::VisualState)oldState
// "Other bookmarks" button on the right side.
scoped_nsobject<NSButton> otherBookmarksButton_;
+
+ // We have a special menu for folder buttons. This starts as a copy
+ // of the bar menu.
+ scoped_nsobject<BookmarkMenu> buttonFolderContextMenu_;
}
@property(readonly, nonatomic) bookmarks::VisualState visualState;
@@ -238,6 +243,7 @@ willAnimateFromState:(bookmarks::VisualState)oldState
- (NSMenu*)offTheSideMenu;
- (NSButton*)offTheSideButton;
- (NSButton*)otherBookmarksButton;
+- (BookmarkNode*)nodeFromMenuItem:(id)sender;
@end
#endif // CHROME_BROWSER_COCOA_BOOKMARK_BAR_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/bookmark_bar_controller.mm b/chrome/browser/cocoa/bookmark_bar_controller.mm
index 3db0e8b..3694999 100644
--- a/chrome/browser/cocoa/bookmark_bar_controller.mm
+++ b/chrome/browser/cocoa/bookmark_bar_controller.mm
@@ -19,6 +19,7 @@
#import "chrome/browser/cocoa/bookmark_button_cell.h"
#import "chrome/browser/cocoa/bookmark_editor_controller.h"
#import "chrome/browser/cocoa/bookmark_name_folder_controller.h"
+#import "chrome/browser/cocoa/bookmark_menu.h"
#import "chrome/browser/cocoa/bookmark_menu_cocoa_controller.h"
#import "chrome/browser/cocoa/event_utils.h"
#import "chrome/browser/cocoa/menu_button.h"
@@ -118,6 +119,7 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
}
@end
+
@interface BookmarkBarController(Private)
// Determines the appropriate state for the given situation.
+ (bookmarks::VisualState)visualStateToShowNormalBar:(BOOL)showNormalBar
@@ -157,6 +159,7 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
- (void)resizeButtons;
- (void)centerNoItemsLabel;
- (NSImage*)getFavIconForNode:(const BookmarkNode*)node;
+- (void)setNodeForBarMenu;
@end
@implementation BookmarkBarController
@@ -215,10 +218,6 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
// We are enabled by default.
barIsEnabled_ = YES;
- // Don't pass ourself along (as 'self') until our init is completely
- // done. Thus, this call is (almost) last.
- bridge_.reset(new BookmarkBarBridge(self, bookmarkModel_));
-
DCHECK([offTheSideButton_ attachedMenu]);
// To make life happier when the bookmark bar is floating, the chevron is a
@@ -226,6 +225,10 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
[offTheSideButton_ removeFromSuperview];
[buttonView_ addSubview:offTheSideButton_];
+ // Copy the bar menu so we know if it's from the bar or a folder.
+ // Then we set its represented item to be the bookmark bar.
+ buttonFolderContextMenu_.reset([[[self view] menu] copy]);
+
// When resized we may need to add new buttons, or remove them (if
// no longer visible), or add/remove the "off the side" menu.
[[self view] setPostsFrameChangedNotifications:YES];
@@ -234,6 +237,10 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
selector:@selector(frameDidChange)
name:NSViewFrameDidChangeNotification
object:[self view]];
+
+ // Don't pass ourself along (as 'self') until our init is completely
+ // done. Thus, this call is (almost) last.
+ bridge_.reset(new BookmarkBarBridge(self, bookmarkModel_));
}
// (Private) Method is the same as [self view], but is provided to be explicit.
@@ -469,16 +476,6 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
return browser_->profile()->GetThemeProvider();
}
-// Return nil if menuItem has no delegate.
-- (BookmarkNode*)nodeFromMenuItem:(id)menuItem {
- NSCell* cell = reinterpret_cast<NSCell*>([[menuItem menu] delegate]);
- if (!cell)
- return nil;
- BookmarkNode* node = static_cast<BookmarkNode*>(
- [[cell representedObject] pointerValue]);
- return node;
-}
-
- (BookmarkNode*)nodeFromButton:(id)button {
NSCell* cell = [button cell];
BookmarkNode* node = static_cast<BookmarkNode*>(
@@ -487,16 +484,47 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
return node;
}
-// At this time, the only items which ever get disabled are the "Open All
-// Bookmarks" options.
-- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
+// Enable or disable items. We are the menu delegate for both the bar
+// and for bookmark folder buttons.
+- (BOOL)validateUserInterfaceItem:(id)item {
+ if (![item isKindOfClass:[NSMenuItem class]])
+ return YES;
+
+ BookmarkNode* node = [self nodeFromMenuItem:item];
+
+ // If this is the bar menu, we only have things to do if there are
+ // buttons. If this is a folder button menu, we only have things to
+ // do if the folder has items.
+ NSMenu* menu = [item menu];
+ BOOL thingsToDo = NO;
+ if (menu == [[self view] menu]) {
+ thingsToDo = [buttons_ count] ? YES : NO;
+ } else {
+ if (node && node->is_folder() && node->GetChildCount()) {
+ thingsToDo = YES;
+ }
+ }
+
+ // Disable openAll* if we have nothing to do.
SEL action = [item action];
- if (((action == @selector(openAllBookmarks:)) ||
+ if ((!thingsToDo) &&
+ ((action == @selector(openAllBookmarks:)) ||
(action == @selector(openAllBookmarksNewWindow:)) ||
- (action == @selector(openAllBookmarksIncognitoWindow:))) &&
- (![buttons_ count])) {
+ (action == @selector(openAllBookmarksIncognitoWindow:)))) {
return NO;
}
+
+ if ((action == @selector(editBookmark:)) ||
+ (action == @selector(deleteBookmark:))) {
+ // Don't allow edit/delete of the bar node, or of "Other Bookmarks"
+ if ((node == nil) ||
+ (node == bookmarkModel_->other_node()) ||
+ (node == bookmarkModel_->GetBookmarkBarNode())) {
+ return NO;
+ }
+ }
+
+ // Enabled by default.
return YES;
}
@@ -723,26 +751,28 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
}
}
+// Return the BookmarkNode associated with the given NSMenuItem.
+- (BookmarkNode*)nodeFromMenuItem:(id)sender {
+ BookmarkMenu* menu = (BookmarkMenu*)[sender menu];
+ if ([menu isKindOfClass:[BookmarkMenu class]])
+ return const_cast<BookmarkNode*>([menu node]);
+ return NULL;
+}
+
- (IBAction)openAllBookmarks:(id)sender {
- // TODO(jrg):
- // Is there an easier way to get a non-const root node for the bookmark bar?
- // I can't iterate over them unless it's non-const.
- BookmarkNode* node = const_cast<BookmarkNode*>(
- bookmarkModel_->GetBookmarkBarNode());
+ BookmarkNode* node = [self nodeFromMenuItem:sender];
[self openBookmarkNodesRecursive:node disposition:NEW_FOREGROUND_TAB];
UserMetrics::RecordAction(L"OpenAllBookmarks", browser_->profile());
}
- (IBAction)openAllBookmarksNewWindow:(id)sender {
- BookmarkNode* node = const_cast<BookmarkNode*>(
- bookmarkModel_->GetBookmarkBarNode());
+ BookmarkNode* node = [self nodeFromMenuItem:sender];
[self openBookmarkNodesRecursive:node disposition:NEW_WINDOW];
UserMetrics::RecordAction(L"OpenAllBookmarksNewWindow", browser_->profile());
}
- (IBAction)openAllBookmarksIncognitoWindow:(id)sender {
- BookmarkNode* node = const_cast<BookmarkNode*>(
- bookmarkModel_->GetBookmarkBarNode());
+ BookmarkNode* node = [self nodeFromMenuItem:sender];
[self openBookmarkNodesRecursive:node disposition:OFF_THE_RECORD];
UserMetrics::RecordAction(L"OpenAllBookmarksIncognitoWindow", browser_->profile());
}
@@ -795,7 +825,7 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
NSImage* image = [self getFavIconForNode:node];
[cell setBookmarkCellText:title image:image];
if (node->is_folder())
- [cell setMenu:[[self view] menu]];
+ [cell setMenu:buttonFolderContextMenu_];
else
[cell setMenu:buttonContextMenu_];
return cell;
@@ -1015,6 +1045,15 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
[self addNonBookmarkButtonsToView];
[self addButtonsToView];
[self showOrHideOffTheSideButton];
+ [self setNodeForBarMenu];
+}
+
+// Now that the model is loaded, set the bookmark bar root as the node
+// represented by the bookmark bar (default, background) menu.
+- (void)setNodeForBarMenu {
+ const BookmarkNode* node = bookmarkModel_->GetBookmarkBarNode();
+ BookmarkMenu* menu = static_cast<BookmarkMenu*>([[self view] menu]);
+ [menu setRepresentedObject:[NSValue valueWithPointer:node]];
}
- (void)beingDeleted:(BookmarkModel*)model {
diff --git a/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm b/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm
index 228bd68..7433bf2 100644
--- a/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm
@@ -10,6 +10,7 @@
#import "chrome/browser/cocoa/bookmark_bar_constants.h"
#import "chrome/browser/cocoa/bookmark_bar_controller.h"
#import "chrome/browser/cocoa/bookmark_bar_view.h"
+#import "chrome/browser/cocoa/bookmark_menu.h"
#include "chrome/browser/cocoa/browser_test_helper.h"
#import "chrome/browser/cocoa/cocoa_test_helper.h"
#include "chrome/browser/cocoa/test_event_utils.h"
@@ -100,7 +101,7 @@ class BookmarkBarControllerTest : public PlatformTest {
InstallAndToggleBar(bar_.get());
// Create a menu/item to act like a sender
- menu_.reset([[NSMenu alloc] initWithTitle:@"I_dont_care"]);
+ menu_.reset([[BookmarkMenu alloc] initWithTitle:@"I_dont_care"]);
menu_item_.reset([[NSMenuItem alloc]
initWithTitle:@"still_dont_care"
action:NULL
@@ -135,13 +136,13 @@ class BookmarkBarControllerTest : public PlatformTest {
// Return a menu item that points to the right URL.
NSMenuItem* ItemForBookmarkBarMenu(GURL& gurl) {
node_.reset(new BookmarkNode(gurl));
- [cell_ setRepresentedObject:[NSValue valueWithPointer:node_.get()]];
+ [menu_ setRepresentedObject:[NSValue valueWithPointer:node_.get()]];
return menu_item_;
}
// Does NOT take ownership of node.
NSMenuItem* ItemForBookmarkBarMenu(const BookmarkNode* node) {
- [cell_ setRepresentedObject:[NSValue valueWithPointer:node]];
+ [menu_ setRepresentedObject:[NSValue valueWithPointer:node]];
return menu_item_;
}
@@ -150,7 +151,7 @@ class BookmarkBarControllerTest : public PlatformTest {
BrowserTestHelper helper_;
scoped_nsobject<ViewResizerPong> resizeDelegate_;
scoped_nsobject<BookmarkBarControllerNoOpen> bar_;
- scoped_nsobject<NSMenu> menu_;
+ scoped_nsobject<BookmarkMenu> menu_;
scoped_nsobject<NSMenuItem> menu_item_;
scoped_nsobject<NSButtonCell> cell_;
scoped_ptr<BookmarkNode> node_;
@@ -520,8 +521,9 @@ TEST_F(BookmarkBarControllerTest, OpenAllBookmarks) {
L"title", GURL("http://two-two.com"));
model->AddURL(parent, parent->GetChildCount(),
L"title", GURL("https://three.com"));
- [bar_ openAllBookmarks:nil];
+ // Our first OpenAll... is from the bar itself.
+ [bar_ openAllBookmarks:ItemForBookmarkBarMenu(parent)];
EXPECT_EQ(bar_.get()->urls_.size(), 4U);
EXPECT_EQ(bar_.get()->dispositions_.size(), 4U);
@@ -538,6 +540,14 @@ TEST_F(BookmarkBarControllerTest, OpenAllBookmarks) {
EXPECT_TRUE(i == end);
EXPECT_EQ(bar_.get()->dispositions_[3], NEW_BACKGROUND_TAB);
+
+ // Now try an OpenAll... from a folder node.
+ bar_.get()->urls_.clear();
+ bar_.get()->dispositions_.clear();
+ [bar_ openAllBookmarks:ItemForBookmarkBarMenu(folder)];
+
+ EXPECT_EQ(bar_.get()->urls_.size(), 2U);
+ EXPECT_EQ(bar_.get()->dispositions_.size(), 2U);
}
// TODO(jrg): write a test to confirm that nodeFavIconLoaded calls
@@ -691,4 +701,61 @@ TEST_F(BookmarkBarControllerTest, DropBookmarks) {
}
}
+TEST_F(BookmarkBarControllerTest, TestButtonOrBar) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ GURL gurl1("http://www.google.com");
+ std::wstring title1(L"x");
+ model->SetURLStarred(gurl1, title1, true);
+
+ GURL gurl2("http://www.google.com/gurl_power");
+ std::wstring title2(L"gurl power");
+ model->SetURLStarred(gurl2, title2, true);
+
+ NSButton* first = [[bar_ buttons] objectAtIndex:0];
+ NSButton* second = [[bar_ buttons] objectAtIndex:1];
+ EXPECT_TRUE(first && second);
+
+ NSMenuItem* menuItem = [[[first cell] menu] itemAtIndex:0];
+ BookmarkNode* node = [bar_ nodeFromMenuItem:menuItem];
+ EXPECT_TRUE(node);
+ EXPECT_EQ(node, model->GetBookmarkBarNode()->GetChild(0));
+
+ menuItem = [[[second cell] menu] itemAtIndex:0];
+ node = [bar_ nodeFromMenuItem:menuItem];
+ EXPECT_TRUE(node);
+ EXPECT_EQ(node, model->GetBookmarkBarNode()->GetChild(1));
+
+ menuItem = [[[bar_ view] menu] itemAtIndex:0];
+ node = [bar_ nodeFromMenuItem:menuItem];
+ EXPECT_TRUE(node);
+ EXPECT_EQ(node, model->GetBookmarkBarNode());
+}
+
+TEST_F(BookmarkBarControllerTest, TestMenuNodeAndDisable) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ const BookmarkNode* folder = model->AddGroup(parent,
+ parent->GetChildCount(),
+ L"group");
+ NSButton* button = [[bar_ buttons] objectAtIndex:0];
+ EXPECT_TRUE(button);
+
+ // Confirm the menu knows which node it is talking about
+ BookmarkMenu* menu = static_cast<BookmarkMenu*>([[button cell] menu]);
+ EXPECT_TRUE(menu);
+ EXPECT_TRUE([menu isKindOfClass:[BookmarkMenu class]]);
+ EXPECT_EQ(folder, [menu node]);
+
+ // Make sure "Open All" is disabled (nothing to open -- no children!)
+ // (Assumes "Open All" is the 1st item)
+ NSMenuItem* item = [menu itemAtIndex:0];
+ EXPECT_FALSE([bar_ validateUserInterfaceItem:item]);
+
+ // Now add a child and make sure the item would be enabled.
+ model->AddURL(folder, folder->GetChildCount(),
+ L"super duper wide title",
+ GURL("http://superfriends.hall-of-justice.edu"));
+ EXPECT_TRUE([bar_ validateUserInterfaceItem:item]);
+}
+
} // namespace
diff --git a/chrome/browser/cocoa/bookmark_button_cell.mm b/chrome/browser/cocoa/bookmark_button_cell.mm
index 1e2190b..147ae04 100644
--- a/chrome/browser/cocoa/bookmark_button_cell.mm
+++ b/chrome/browser/cocoa/bookmark_button_cell.mm
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#import "chrome/browser/cocoa/bookmark_button_cell.h"
+#import "chrome/browser/cocoa/bookmark_menu.h"
#import "third_party/GTM/AppKit/GTMTheme.h"
@implementation BookmarkButtonCell
@@ -53,12 +54,10 @@
// We share the context menu among all bookmark buttons. To allow us
// to disambiguate when needed (e.g. "open bookmark"), we set the
-// menu's delegate to be us. We (the cell) have the bookmark encoded
-// in our represented object.
-// Convention needed in -[BookmarkBarController openBookmarkIn***] calls.
+// menu's associated node to be our represented object.
- (NSMenu*)menu {
- NSMenu* menu = [super menu];
- [menu setDelegate:self];
+ BookmarkMenu* menu = (BookmarkMenu*)[super menu];
+ [menu setRepresentedObject:[self representedObject]];
return menu;
}
diff --git a/chrome/browser/cocoa/bookmark_button_cell_unittest.mm b/chrome/browser/cocoa/bookmark_button_cell_unittest.mm
index 9cb6ca6..aabe1af 100644
--- a/chrome/browser/cocoa/bookmark_button_cell_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_button_cell_unittest.mm
@@ -4,6 +4,7 @@
#include "base/scoped_nsobject.h"
#import "chrome/browser/cocoa/bookmark_button_cell.h"
+#import "chrome/browser/cocoa/bookmark_menu.h"
#import "chrome/browser/cocoa/cocoa_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -31,21 +32,6 @@ TEST_F(BookmarkButtonCellTest, SizeForBounds) {
EXPECT_TRUE(size.width < 200 && size.height < 200);
}
-// Make sure a cell's menu has the cell itself as the delegate. This
-// is our convention for reusing the context menu across all bookmarks
-// while being unambiguous when used.
-TEST_F(BookmarkButtonCellTest, MenuDelegate) {
- scoped_nsobject<BookmarkButtonCell> cell([[BookmarkButtonCell alloc]
- initTextCell:@"Testing"]);
- EXPECT_FALSE([cell.get() menu]);
-
- scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"foo"]);
- [cell setMenu:menu.get()];
- EXPECT_TRUE([cell.get() menu]);
- EXPECT_EQ([[cell.get() menu] delegate], cell.get());
- [cell setMenu:nil];
-}
-
// Make sure the default from the base class is overridden
TEST_F(BookmarkButtonCellTest, MouseEnterStuff) {
scoped_nsobject<BookmarkButtonCell> cell([[BookmarkButtonCell alloc]
diff --git a/chrome/browser/cocoa/bookmark_menu.h b/chrome/browser/cocoa/bookmark_menu.h
new file mode 100644
index 0000000..7a5ff25
--- /dev/null
+++ b/chrome/browser/cocoa/bookmark_menu.h
@@ -0,0 +1,18 @@
+// 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 <Cocoa/Cocoa.h>
+struct BookmarkNode;
+
+// The context menu for bookmark buttons needs to know which
+// BookmarkNode it is talking about. For example, "Open All" is
+// disabled if the bookmark node is a folder and has no children.
+@interface BookmarkMenu : NSMenu {
+ @private
+ const BookmarkNode* node_;
+}
+- (void)setRepresentedObject:(id)object;
+@property const BookmarkNode* node;
+@end
+
diff --git a/chrome/browser/cocoa/bookmark_menu.mm b/chrome/browser/cocoa/bookmark_menu.mm
new file mode 100644
index 0000000..cbfdc38
--- /dev/null
+++ b/chrome/browser/cocoa/bookmark_menu.mm
@@ -0,0 +1,22 @@
+// 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_menu.h"
+
+
+@implementation BookmarkMenu
+
+@synthesize node = node_;
+
+// Convention in the bookmark bar controller: the bookmark button
+// cells have a BookmarkNode as their represented object. This object
+// is placed in a BookmarkMenu at the time a cell is asked for its
+// menu.
+- (void)setRepresentedObject:(id)object {
+ if ([object isKindOfClass:[NSValue class]]) {
+ node_ = static_cast<const BookmarkNode*>([object pointerValue]);
+ }
+}
+
+@end
diff --git a/chrome/browser/cocoa/bookmark_menu_unittest.mm b/chrome/browser/cocoa/bookmark_menu_unittest.mm
new file mode 100644
index 0000000..2afb16c
--- /dev/null
+++ b/chrome/browser/cocoa/bookmark_menu_unittest.mm
@@ -0,0 +1,28 @@
+// 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.
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/cocoa/bookmark_menu.h"
+#import "chrome/browser/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class BookmarkMenuTest : public CocoaTest {
+ public:
+};
+
+TEST_F(BookmarkMenuTest, Basics) {
+ scoped_nsobject<BookmarkMenu> menu;
+ menu.reset([[BookmarkMenu alloc] initWithTitle:@"title"]);
+ [menu addItem:[[NSMenuItem alloc] initWithTitle:@"item"
+ action:NULL
+ keyEquivalent:@""]];
+ NSValue* value = [NSValue valueWithPointer:menu.get()];
+ [menu setRepresentedObject:value];
+ EXPECT_EQ((void*)menu.get(), (void*)[menu node]);
+}
+
+} // namespace