From c422c9199cfaff70b58abdb12d8d0e5b6bcd8101 Mon Sep 17 00:00:00 2001 From: "jrg@chromium.org" Date: Wed, 24 Mar 2010 22:06:06 +0000 Subject: Cmd-click in bookmark subfolders will open all. Refactor code for better sharing. BUG=http://crbug.com/26380 (cmd-click in subfolders now opens all) BUG=http://crbug.com/35966 (code dup reduced) TEST=\ Cmd-click a folder in the bar --> open all Cmd-click a folder in a SUBfolder of the bar --> open all Review URL: http://codereview.chromium.org/1134008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42546 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/browser/cocoa/bookmark_bar_controller.h | 5 ++ chrome/browser/cocoa/bookmark_bar_controller.mm | 69 ++++++---------- .../cocoa/bookmark_bar_controller_unittest.mm | 12 +++ .../browser/cocoa/bookmark_bar_folder_controller.h | 5 ++ .../cocoa/bookmark_bar_folder_controller.mm | 56 +++++++++---- .../bookmark_bar_folder_controller_unittest.mm | 33 +++++++- .../cocoa/bookmark_bar_folder_view_unittest.mm | 11 +++ chrome/browser/cocoa/bookmark_button.h | 13 +++ chrome/browser/cocoa/bookmark_folder_target.h | 31 ++++++++ chrome/browser/cocoa/bookmark_folder_target.mm | 68 ++++++++++++++++ .../cocoa/bookmark_folder_target_unittest.mm | 92 ++++++++++++++++++++++ 11 files changed, 331 insertions(+), 64 deletions(-) create mode 100644 chrome/browser/cocoa/bookmark_folder_target.h create mode 100644 chrome/browser/cocoa/bookmark_folder_target.mm create mode 100644 chrome/browser/cocoa/bookmark_folder_target_unittest.mm (limited to 'chrome/browser') diff --git a/chrome/browser/cocoa/bookmark_bar_controller.h b/chrome/browser/cocoa/bookmark_bar_controller.h index 5dff09a..dfc51d4 100644 --- a/chrome/browser/cocoa/bookmark_bar_controller.h +++ b/chrome/browser/cocoa/bookmark_bar_controller.h @@ -22,6 +22,7 @@ @class BookmarkBarFolderController; @class BookmarkBarView; @class BookmarkButton; +@class BookmarkFolderTarget; class BookmarkModel; @class BookmarkMenu; class BookmarkNode; @@ -166,6 +167,9 @@ willAnimateFromState:(bookmarks::VisualState)oldState // Delegate that can resize us. id resizeDelegate_; // weak + // Logic for dealing with a click on a bookmark folder button. + scoped_nsobject folderTarget_; + // A controller for a pop-up bookmark folder window (custom menu). // This is not a scoped_nsobject because it owns itself (when its // window closes the controller gets autoreleased). @@ -320,6 +324,7 @@ willAnimateFromState:(bookmarks::VisualState)oldState - (BookmarkBarFolderController*)folderController; - (BookmarkButton*)buttonForDroppingOnAtPoint:(NSPoint)point; - (BOOL)isEventAClickOutside:(NSEvent*)event; +- (id)folderTarget; @end // The (internal) |NSPasteboard| type string for bookmark button drags, used for diff --git a/chrome/browser/cocoa/bookmark_bar_controller.mm b/chrome/browser/cocoa/bookmark_bar_controller.mm index 60b1b26..163dfd4 100644 --- a/chrome/browser/cocoa/bookmark_bar_controller.mm +++ b/chrome/browser/cocoa/bookmark_bar_controller.mm @@ -22,6 +22,7 @@ #import "chrome/browser/cocoa/bookmark_button.h" #import "chrome/browser/cocoa/bookmark_button_cell.h" #import "chrome/browser/cocoa/bookmark_editor_controller.h" +#import "chrome/browser/cocoa/bookmark_folder_target.h" #import "chrome/browser/cocoa/bookmark_menu.h" #import "chrome/browser/cocoa/bookmark_menu_cocoa_controller.h" #import "chrome/browser/cocoa/bookmark_name_folder_controller.h" @@ -208,6 +209,7 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; buttons_.reset([[NSMutableArray alloc] init]); delegate_ = delegate; resizeDelegate_ = resizeDelegate; + folderTarget_.reset([[BookmarkFolderTarget alloc] initWithController:self]); ResourceBundle& rb = ResourceBundle::GetSharedInstance(); folderImage_.reset([rb.GetNSImageNamed(IDR_BOOKMARK_BAR_FOLDER) retain]); @@ -455,7 +457,7 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; return; // Else open a new one if it makes sense to do so. if ([sender bookmarkNode]->is_folder()) - [self openBookmarkFolderFromButton:sender]; + [folderTarget_ openBookmarkFolderFromButton:sender]; } // BookmarkButtonDelegate protocol implementation. @@ -526,6 +528,12 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; return NO; } +// Exposed for testing. +- (id)folderTarget { + return folderTarget_.get(); +} + + // Keep the "no items" label centered in response to a frame size change. - (void)centerNoItemsLabel { // Note that this computation is done in the parent's coordinate system, @@ -851,6 +859,8 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) { hoverButton_.reset(); } hoverButton_.reset([button retain]); + DCHECK([[hoverButton_ target] + respondsToSelector:@selector(openBookmarkFolderFromButton:)]); [[hoverButton_ target] performSelector:@selector(openBookmarkFolderFromButton:) withObject:hoverButton_ @@ -1069,6 +1079,11 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) { } } +// Redirect to our logic shared with BookmarkBarFolderController. +- (IBAction)openBookmarkFolderFromButton:(id)sender { + [folderTarget_ openBookmarkFolderFromButton:sender]; +} + // Recursively add the given bookmark node and all its children to // menu, one menu item per node. - (void)addNode:(const BookmarkNode*)child toMenu:(NSMenu*)menu { @@ -1132,54 +1147,20 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) { return menu; } -// This IBAction is called when the user clicks (mouseUp, really) on a -// "folder" bookmark button. (In this context, "Click" does not -// include right-click to open a context menu which follows a -// different path). Scenarios when folder X is clicked: -// *Predicate* *Action* -// (nothing) Open Folder X -// Folder X open Close folder X -// Folder Y open Close Y, open X -// Cmd-click Open All with proper disposition -// -// Note complication in which a click-drag engages drag and drop, not -// a click-to-open. Thus the path to get here is a little twisted. -- (IBAction)openBookmarkFolderFromButton:(id)sender { - DCHECK(sender); - BOOL same = false; - - if (folderController_) { - // closeAllBookmarkFolders sets folderController_ to nil - // so we need the SAME check to happen first. - same = ([folderController_ parentButton] == sender); +// Add a new folder controller as triggered by the given folder button. +- (void)addNewFolderControllerWithParentButton:(BookmarkButton*)parentButton { + DCHECK(!folderController_); + if (folderController_) [self closeAllBookmarkFolders]; - } - - // Watch out for a modifier click. For example, command-click - // should open all. - // - // NOTE: we cannot use [[sender cell] mouseDownFlags] because we - // thwart the normal mouse click mechanism to make buttons - // draggable. Thus we must use [NSApp currentEvent]. - DCHECK([sender bookmarkNode]->is_folder()); - WindowOpenDisposition disposition = - event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); - if (disposition == NEW_BACKGROUND_TAB) { - [self openBookmarkNodesRecursive:[sender bookmarkNode] - disposition:disposition]; - return; - } - - // If click on same folder, close it and be done. - // Else we clicked on a different folder so more work to do. - if (same) - return; // Folder controller, like many window controllers, owns itself. folderController_ = [[BookmarkBarFolderController alloc] - initWithParentButton:sender - parentController:self]; + initWithParentButton:parentButton + parentController:self]; [folderController_ showWindow:self]; + + // Only BookmarkBarController has this; the + // BookmarkBarFolderController does not. [self watchForClickOutside:YES]; } diff --git a/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm b/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm index 96f4365..ae1c35e 100644 --- a/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm +++ b/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm @@ -24,6 +24,18 @@ #include "testing/platform_test.h" #import "third_party/ocmock/OCMock/OCMock.h" +// Add a redirect to make testing easier. +@interface BookmarkBarController(MakeTestingEasier) +- (IBAction)openBookmarkFolderFromButton:(id)sender; +@end + +@implementation BookmarkBarController(MakeTestingEasier) +- (IBAction)openBookmarkFolderFromButton:(id)sender { + [[self folderTarget] openBookmarkFolderFromButton:sender]; +} +@end + + // Just like a BookmarkBarController but openURL: is stubbed out. @interface BookmarkBarControllerNoOpen : BookmarkBarController { @public diff --git a/chrome/browser/cocoa/bookmark_bar_folder_controller.h b/chrome/browser/cocoa/bookmark_bar_folder_controller.h index 86d53f7..201a5ea 100644 --- a/chrome/browser/cocoa/bookmark_bar_folder_controller.h +++ b/chrome/browser/cocoa/bookmark_bar_folder_controller.h @@ -8,6 +8,7 @@ #import "chrome/browser/cocoa/bookmark_button.h" @class BookmarkBarFolderView; +@class BookmarkFolderTarget; // A controller for the pop-up windows from bookmark folder buttons // which look sort of like menus. @@ -62,6 +63,9 @@ // not necessarily fired yet). scoped_nsobject hoverButton_; + // Logic for dealing with a click on a bookmark folder button. + scoped_nsobject folderTarget_; + // A controller for a pop-up bookmark folder window (custom menu). // We (self) are the parentController_ for our folderController_. // This is not a scoped_nsobject because it owns itself (when its @@ -98,5 +102,6 @@ - (NSPoint)windowTopLeft; - (NSArray*)buttons; - (BookmarkBarFolderController*)folderController; +- (id)folderTarget; @end diff --git a/chrome/browser/cocoa/bookmark_bar_folder_controller.mm b/chrome/browser/cocoa/bookmark_bar_folder_controller.mm index ffa190b4..0257613 100644 --- a/chrome/browser/cocoa/bookmark_bar_folder_controller.mm +++ b/chrome/browser/cocoa/bookmark_bar_folder_controller.mm @@ -11,7 +11,10 @@ #import "chrome/browser/cocoa/bookmark_bar_controller.h" // namespace bookmarks #import "chrome/browser/cocoa/bookmark_bar_folder_view.h" #import "chrome/browser/cocoa/bookmark_button_cell.h" +#import "chrome/browser/cocoa/bookmark_folder_target.h" #import "chrome/browser/cocoa/browser_window_controller.h" +#import "chrome/browser/cocoa/event_utils.h" + namespace { @@ -31,7 +34,6 @@ const CGFloat kBookmarkBarFolderScrollAmount = - (void)removeScrollTracking; - (void)endScroll; - (void)addScrollTimerWithDelta:(CGFloat)delta; -- (IBAction)openBookmarkFolderFromButton:(id)sender; @end @@ -46,6 +48,7 @@ const CGFloat kBookmarkBarFolderScrollAmount = parentButton_.reset([button retain]); parentController_.reset([controller retain]); buttons_.reset([[NSMutableArray alloc] init]); + folderTarget_.reset([[BookmarkFolderTarget alloc] initWithController:self]); // Register for theme changes. NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter]; @@ -104,6 +107,11 @@ const CGFloat kBookmarkBarFolderScrollAmount = return [parentController_ cellForBookmarkNode:child]; } +// Redirect to our logic shared with BookmarkBarController. +- (IBAction)openBookmarkFolderFromButton:(id)sender { + [folderTarget_ openBookmarkFolderFromButton:sender]; +} + // Create a bookmark button for the given node using frame. // // If |node| is NULL this is an "(empty)" button. @@ -159,11 +167,14 @@ const CGFloat kBookmarkBarFolderScrollAmount = return mainView_; } -// Exposed for testing. - (BookmarkBarFolderController*)folderController { return folderController_; } +- (id)folderTarget { + return folderTarget_.get(); +} + // Compute and return the top left point of our window (screen // coordinates). The top left is positioned in a manner similar to // cascading menus. @@ -532,7 +543,6 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) { - (NSDragOperation)draggingEntered:(id)info { draggingExited_ = NO; NSPoint currentLocation = [info draggingLocation]; - BookmarkButton* button = [self buttonForDroppingOnAtPoint:currentLocation]; if ([button isFolder]) { if (hoverButton_ == button) { @@ -540,6 +550,9 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) { } if (hoverButton_) { // Oops, another one triggered or open. + DCHECK( + [[hoverButton_ target] + respondsToSelector:@selector(closeBookmarkFolderOnHoverButton:)]); [NSObject cancelPreviousPerformRequestsWithTarget:[hoverButton_ target]]; [self performSelector:@selector(closeBookmarkFolderOnHoverButton:) @@ -547,6 +560,8 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) { afterDelay:bookmarks::kDragHoverCloseDelay]; } hoverButton_.reset([button retain]); + DCHECK([[hoverButton_ target] + respondsToSelector:@selector(openBookmarkFolderFromButton:)]); [[hoverButton_ target] performSelector:@selector(openBookmarkFolderFromButton:) withObject:hoverButton_ @@ -556,7 +571,11 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) { // If we get here we may no longer have a hover button. if (!button) { if (hoverButton_) { - [NSObject cancelPreviousPerformRequestsWithTarget:[hoverButton_ target]]; + [NSObject cancelPreviousPerformRequestsWithTarget:[hoverButton_ + target]]; + DCHECK( + [[hoverButton_ target] + respondsToSelector:@selector(closeBookmarkFolderOnHoverButton:)]); [self performSelector:@selector(closeBookmarkFolderOnHoverButton:) withObject:hoverButton_ afterDelay:bookmarks::kDragHoverCloseDelay]; @@ -738,7 +757,7 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) { // Open a new one if meaningful. if ([sender isFolder]) - [self openBookmarkFolderFromButton:sender]; + [folderTarget_ openBookmarkFolderFromButton:sender]; } // Called from BookmarkButton. @@ -772,22 +791,27 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) { } - (IBAction)openBookmark:(id)sender { - // Carent controller closes it all... + // Parent controller closes it all... [parentController_ openBookmark:sender]; } -// Unlike the bookmark_bar_controller, we do not watch for click outside. -- (IBAction)openBookmarkFolderFromButton:(id)sender { - if (folderController_) { - // If the same we have nothing to do. - if ([folderController_ parentButton] == sender) - return; +// Flow up the chain until someone (the top level controller) knows +// what to do. +- (void)openBookmarkNodesRecursive:(const BookmarkNode*)node + disposition:(WindowOpenDisposition)disposition { + [parentController_ openBookmarkNodesRecursive:node + disposition:disposition]; +} - [self closeBookmarkFolder:sender]; - } +// Add a new folder controller as triggered by the given folder button. +- (void)addNewFolderControllerWithParentButton:(BookmarkButton*)parentButton { + if (folderController_) + [self closeAllBookmarkFolders]; + + // Folder controller, like many window controllers, owns itself. folderController_ = [[BookmarkBarFolderController alloc] - initWithParentButton:sender - parentController:self]; + initWithParentButton:parentButton + parentController:self]; [folderController_ showWindow:self]; } diff --git a/chrome/browser/cocoa/bookmark_bar_folder_controller_unittest.mm b/chrome/browser/cocoa/bookmark_bar_folder_controller_unittest.mm index 7d00a23..844e090 100644 --- a/chrome/browser/cocoa/bookmark_bar_folder_controller_unittest.mm +++ b/chrome/browser/cocoa/bookmark_bar_folder_controller_unittest.mm @@ -13,6 +13,18 @@ #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" +// Add a redirect to make testing easier. +@interface BookmarkBarFolderController(MakeTestingEasier) +- (IBAction)openBookmarkFolderFromButton:(id)sender; +@end + +@implementation BookmarkBarFolderController(MakeTestingEasier) +- (IBAction)openBookmarkFolderFromButton:(id)sender { + [[self folderTarget] openBookmarkFolderFromButton:sender]; +} +@end + + @interface BookmarkBarFolderControllerPong : BookmarkBarFolderController { BOOL childFolderWillShow_; BOOL childFolderWillClose_; @@ -32,6 +44,13 @@ - (void)childFolderWillClose:(id)child { childFolderWillClose_ = YES; } + +// We don't have a real BookmarkBarController as our parent root so +// we fake this one out. +- (void)closeAllBookmarkFolders { + [self closeBookmarkFolder:self]; +} + @end class BookmarkBarFolderControllerTest : public CocoaTest { @@ -50,7 +69,10 @@ class BookmarkBarFolderControllerTest : public CocoaTest { L"sibbling group"); const BookmarkNode* folderB = model->AddGroup(folderA, folderA->GetChildCount(), - L"subgroup"); + L"subgroup 1"); + model->AddGroup(folderA, + folderA->GetChildCount(), + L"subgroup 2"); model->AddURL(folderA, folderA->GetChildCount(), L"title a", GURL("http://www.google.com/a")); longTitleNode_ = model->AddURL( @@ -209,17 +231,20 @@ TEST_F(BookmarkBarFolderControllerTest, OpenFolder) { EXPECT_TRUE(bbfc.get()); EXPECT_FALSE([bbfc folderController]); - [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:0]]; + BookmarkButton* button = [[bbfc buttons] objectAtIndex:0]; + [bbfc openBookmarkFolderFromButton:button]; id controller = [bbfc folderController]; EXPECT_TRUE(controller); + EXPECT_EQ([controller parentButton], button); - // Open the same one --> no change. + // Click the same one --> it gets closed. [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:0]]; - EXPECT_EQ(controller, [bbfc folderController]); + EXPECT_FALSE([bbfc folderController]); // Open a new one --> change. [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:1]]; EXPECT_NE(controller, [bbfc folderController]); + EXPECT_NE([[bbfc folderController] parentButton], button); // Close it --> all gone! [bbfc closeBookmarkFolder:nil]; diff --git a/chrome/browser/cocoa/bookmark_bar_folder_view_unittest.mm b/chrome/browser/cocoa/bookmark_bar_folder_view_unittest.mm index 088c0c8..2cf339e 100644 --- a/chrome/browser/cocoa/bookmark_bar_folder_view_unittest.mm +++ b/chrome/browser/cocoa/bookmark_bar_folder_view_unittest.mm @@ -103,6 +103,17 @@ - (void)childFolderWillClose:(id)child { } +- (void)openBookmarkNodesRecursive:(const BookmarkNode*)node + disposition:(WindowOpenDisposition)disposition { +} + +- (void)addNewFolderControllerWithParentButton:(BookmarkButton*)parentButton { +} + +- (BookmarkBarFolderController*)folderController { + return nil; +} + @end namespace { diff --git a/chrome/browser/cocoa/bookmark_button.h b/chrome/browser/cocoa/bookmark_button.h index 3fea094..5050315 100644 --- a/chrome/browser/cocoa/bookmark_button.h +++ b/chrome/browser/cocoa/bookmark_button.h @@ -4,7 +4,9 @@ #import #import "chrome/browser/cocoa/draggable_button.h" +#include "webkit/glue/window_open_disposition.h" +@class BookmarkBarFolderController; @class BookmarkButton; class BookmarkModel; class BookmarkNode; @@ -103,6 +105,17 @@ class ThemeProvider; // Called just before a child folder closes. - (void)childFolderWillClose:(id)child; +// Return a controller's folder controller for a subfolder, or nil. +- (BookmarkBarFolderController*)folderController; + +// Recursively open all bookmarks from this folder using the given disposition. +- (void)openBookmarkNodesRecursive:(const BookmarkNode*)node + disposition:(WindowOpenDisposition)disposition; + +// Add a new folder controller as triggered by the given folder button. +// If there is a current folder controller, close it. +- (void)addNewFolderControllerWithParentButton:(BookmarkButton*)parentButton; + @end // @protocol BookmarkButtonControllerProtocol diff --git a/chrome/browser/cocoa/bookmark_folder_target.h b/chrome/browser/cocoa/bookmark_folder_target.h new file mode 100644 index 0000000..c5482d9 --- /dev/null +++ b/chrome/browser/cocoa/bookmark_folder_target.h @@ -0,0 +1,31 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_BROWSER_COCOA_BOOKMARK_FOLDER_TARGET_CONTROLLER_H_ +#define CHROME_BROWSER_COCOA_BOOKMARK_FOLDER_TARGET_CONTROLLER_H_ + +#import + +@protocol BookmarkButtonControllerProtocol; + +// Target (in the target/action sense) of a bookmark folder button. +// Since ObjC doesn't have multiple inheritance we use has-a instead +// of is-a to share behavior between the BookmarkBarFolderController +// (NSWindowController) and the BookmarkBarController +// (NSViewController). +// +// This class is unit tested in the context of a BookmarkBarController. +@interface BookmarkFolderTarget : NSObject { + // The owner of the bookmark folder button + id controller_; // weak +} + +- (id)initWithController:(id)controller; + +// Main IBAction for a button click. +- (IBAction)openBookmarkFolderFromButton:(id)sender; + +@end + +#endif // CHROME_BROWSER_COCOA_BOOKMARK_FOLDER_TARGET_CONTROLLER_H_ diff --git a/chrome/browser/cocoa/bookmark_folder_target.mm b/chrome/browser/cocoa/bookmark_folder_target.mm new file mode 100644 index 0000000..54a868e --- /dev/null +++ b/chrome/browser/cocoa/bookmark_folder_target.mm @@ -0,0 +1,68 @@ +// Copyright (c) 2010 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_folder_target.h" + +#include "base/logging.h" +#include "chrome/browser/bookmarks/bookmark_model.h" +#import "chrome/browser/cocoa/bookmark_bar_folder_controller.h" +#import "chrome/browser/cocoa/bookmark_button.h" +#import "chrome/browser/cocoa/event_utils.h" + +@implementation BookmarkFolderTarget + +- (id)initWithController:(id)controller { + if ((self = [super init])) { + controller_ = controller; + } + return self; +} + +// This IBAction is called when the user clicks (mouseUp, really) on a +// "folder" bookmark button. (In this context, "Click" does not +// include right-click to open a context menu which follows a +// different path). Scenarios when folder X is clicked: +// *Predicate* *Action* +// (nothing) Open Folder X +// Folder X open Close folder X +// Folder Y open Close Y, open X +// Cmd-click Open All with proper disposition +// +// Note complication in which a click-drag engages drag and drop, not +// a click-to-open. Thus the path to get here is a little twisted. +- (IBAction)openBookmarkFolderFromButton:(id)sender { + DCHECK(sender); + BOOL same = false; + + if ([controller_ folderController]) { + // closeAllBookmarkFolders sets folderController_ to nil + // so we need the SAME check to happen first. + same = ([[controller_ folderController] parentButton] == sender); + [controller_ closeAllBookmarkFolders]; + } + + // Watch out for a modifier click. For example, command-click + // should open all. + // + // NOTE: we cannot use [[sender cell] mouseDownFlags] because we + // thwart the normal mouse click mechanism to make buttons + // draggable. Thus we must use [NSApp currentEvent]. + DCHECK([sender bookmarkNode]->is_folder()); + WindowOpenDisposition disposition = + event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); + if (disposition == NEW_BACKGROUND_TAB) { + [controller_ openBookmarkNodesRecursive:[sender bookmarkNode] + disposition:disposition]; + return; + } + + // If click on same folder, close it and be done. + // Else we clicked on a different folder so more work to do. + if (same) + return; + + [controller_ addNewFolderControllerWithParentButton:sender]; +} + +@end diff --git a/chrome/browser/cocoa/bookmark_folder_target_unittest.mm b/chrome/browser/cocoa/bookmark_folder_target_unittest.mm new file mode 100644 index 0000000..179892e --- /dev/null +++ b/chrome/browser/cocoa/bookmark_folder_target_unittest.mm @@ -0,0 +1,92 @@ +// Copyright (c) 2010 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_bar_controller.h" +#import "chrome/browser/cocoa/bookmark_bar_folder_controller.h" +#import "chrome/browser/cocoa/bookmark_folder_target.h" +#include "chrome/browser/cocoa/bookmark_button.h" +#include "chrome/browser/cocoa/browser_test_helper.h" +#include "chrome/browser/cocoa/cocoa_test_helper.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" +#import "third_party/ocmock/OCMock/OCMock.h" + + +class BookmarkFolderTargetTest : public CocoaTest { + public: + virtual void SetUp() { + CocoaTest::SetUp(); + BookmarkModel* model = helper_.profile()->GetBookmarkModel(); + bmbNode_ = model->GetBookmarkBarNode(); + } + + BrowserTestHelper helper_; + const BookmarkNode* bmbNode_; +}; + +TEST_F(BookmarkFolderTargetTest, StartWithNothing) { + // Need a fake "button" which has a bookmark node. + id sender = [OCMockObject mockForClass:[BookmarkButton class]]; + [[[sender stub] andReturnValue:OCMOCK_VALUE(bmbNode_)] bookmarkNode]; + + // Fake controller + id controller = [OCMockObject mockForClass:[BookmarkBarFolderController + class]]; + // No current folder + [[[controller stub] andReturn:nil] folderController]; + + // Make sure we get an addNew + [[controller expect] addNewFolderControllerWithParentButton:sender]; + + scoped_nsobject target( + [[BookmarkFolderTarget alloc] initWithController:controller]); + + [target openBookmarkFolderFromButton:sender]; + [controller verify]; +} + +TEST_F(BookmarkFolderTargetTest, ReopenSame) { + // Need a fake "button" which has a bookmark node. + id sender = [OCMockObject mockForClass:[BookmarkButton class]]; + [[[sender stub] andReturnValue:OCMOCK_VALUE(bmbNode_)] bookmarkNode]; + + // Fake controller + id controller = [OCMockObject mockForClass:[BookmarkBarFolderController + class]]; + // YES a current folder. Self-mock that as well, so "same" will be true. + [[[controller stub] andReturn:controller] folderController]; + [[[controller stub] andReturn:sender] parentButton]; + + // Make sure we close all and do NOT create a new one. + [[controller expect] closeAllBookmarkFolders]; + + scoped_nsobject target( + [[BookmarkFolderTarget alloc] initWithController:controller]); + + [target openBookmarkFolderFromButton:sender]; + [controller verify]; +} + +TEST_F(BookmarkFolderTargetTest, ReopenNotSame) { + // Need a fake "button" which has a bookmark node. + id sender = [OCMockObject mockForClass:[BookmarkButton class]]; + [[[sender stub] andReturnValue:OCMOCK_VALUE(bmbNode_)] bookmarkNode]; + + // Fake controller + id controller = [OCMockObject mockForClass:[BookmarkBarFolderController + class]]; + // YES a current folder but NOT same. + [[[controller stub] andReturn:controller] folderController]; + [[[controller stub] andReturn:nil] parentButton]; + + // Make sure we close all AND create a new one. + [[controller expect] closeAllBookmarkFolders]; + [[controller expect] addNewFolderControllerWithParentButton:sender]; + + scoped_nsobject target( + [[BookmarkFolderTarget alloc] initWithController:controller]); + + [target openBookmarkFolderFromButton:sender]; + [controller verify]; +} -- cgit v1.1