diff options
Diffstat (limited to 'chrome/browser/cocoa')
9 files changed, 585 insertions, 407 deletions
diff --git a/chrome/browser/cocoa/bookmark_all_tabs_controller.h b/chrome/browser/cocoa/bookmark_all_tabs_controller.h index e861c50..8d2d2b9 100644 --- a/chrome/browser/cocoa/bookmark_all_tabs_controller.h +++ b/chrome/browser/cocoa/bookmark_all_tabs_controller.h @@ -15,8 +15,9 @@ typedef std::pair<std::wstring, GURL> ActiveTabNameURLPair; typedef std::vector<ActiveTabNameURLPair> ActiveTabsNameURLPairVector; -// A controller for the bookmark editor, opened with Edit... from the -// context menu of a bookmark button. +// A controller for the Bookmark All Tabs sheet which is presented upon +// selecting the Bookmark All Tabs... menu item shown by the contextual +// menu in the bookmarks bar. @interface BookmarkAllTabsController : BookmarkEditorBaseController { @private ActiveTabsNameURLPairVector activeTabPairsVector_; diff --git a/chrome/browser/cocoa/bookmark_all_tabs_controller.mm b/chrome/browser/cocoa/bookmark_all_tabs_controller.mm index 93b4026..8c2e236 100644 --- a/chrome/browser/cocoa/bookmark_all_tabs_controller.mm +++ b/chrome/browser/cocoa/bookmark_all_tabs_controller.mm @@ -30,9 +30,8 @@ } - (void)awakeFromNib { - [self - setInitialName: - l10n_util::GetNSStringWithFixup(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME)]; + [self setInitialName: + l10n_util::GetNSStringWithFixup(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME)]; [super awakeFromNib]; } @@ -52,10 +51,10 @@ } } -// The the name for the folder into which the tabs will be recorded as -// bookmarks is assumed to be non-empty. The folder is then created -// and a bookmark for each open tab added therein. -- (IBAction)ok:(id)sender { +// Called by -[BookmarkEditorBaseController ok:]. Creates the container +// folder for the tabs and then the bookmarks in that new folder. +// Returns a BOOL as an NSNumber indicating that the commit may proceed. +- (NSNumber*)didCommit { NSString* name = [[self displayName] stringByTrimmingCharactersInSet: [NSCharacterSet newlineCharacterSet]]; std::wstring newTitle = base::SysNSStringToWide(name); @@ -67,7 +66,7 @@ BookmarkModel* model = [self bookmarkModel]; const BookmarkNode* newFolder = model->AddGroup(newParentNode, newIndex, newFolderString); - [self NotifyHandlerCreatedNode:newFolder]; + [self notifyHandlerCreatedNode:newFolder]; // Get a list of all open tabs, create nodes for them, and add // to the new folder node. [self UpdateActiveTabPairs]; @@ -77,9 +76,9 @@ it != activeTabPairsVector_.end(); ++it, ++i) { const BookmarkNode* node = model->AddURL(newFolder, i, it->first, it->second); - [self NotifyHandlerCreatedNode:node]; + [self notifyHandlerCreatedNode:node]; } - [super ok:sender]; + return [NSNumber numberWithBool:YES]; } - (ActiveTabsNameURLPairVector*)activeTabPairsVector { diff --git a/chrome/browser/cocoa/bookmark_all_tabs_controller_unittest.mm b/chrome/browser/cocoa/bookmark_all_tabs_controller_unittest.mm index 1d0a724..118a554 100644 --- a/chrome/browser/cocoa/bookmark_all_tabs_controller_unittest.mm +++ b/chrome/browser/cocoa/bookmark_all_tabs_controller_unittest.mm @@ -59,11 +59,11 @@ class BookmarkAllTabsControllerTest : public CocoaTest { virtual void SetUp() { CocoaTest::SetUp(); controller_ = CreateController(); - EXPECT_TRUE([controller_ window]); + [controller_ runAsModalSheet]; } virtual void TearDown() { - [controller_ close]; + controller_ = NULL; CocoaTest::TearDown(); } }; @@ -71,6 +71,7 @@ class BookmarkAllTabsControllerTest : public CocoaTest { TEST_F(BookmarkAllTabsControllerTest, BookmarkAllTabs) { // OK button should always be enabled. EXPECT_TRUE([controller_ okButtonEnabled]); + [controller_ selectTestNodeInBrowser:group_a_]; [controller_ setDisplayName:@"ALL MY TABS"]; [controller_ ok:nil]; EXPECT_EQ(4, group_a_->GetChildCount()); diff --git a/chrome/browser/cocoa/bookmark_editor_base_controller.h b/chrome/browser/cocoa/bookmark_editor_base_controller.h index cb0725d..265289f 100644 --- a/chrome/browser/cocoa/bookmark_editor_base_controller.h +++ b/chrome/browser/cocoa/bookmark_editor_base_controller.h @@ -12,23 +12,23 @@ #include "base/scoped_nsobject.h" #include "chrome/browser/bookmarks/bookmark_editor.h" -@class BookmarkTreeBrowserCell; class BookmarkModel; +@class BookmarkTreeBrowserCell; // A base controller class for bookmark creation and editing dialogs which // present the current bookmark folder structure in a tree view. Do not // instantiate this controller directly -- use one of its derived classes. -// NOTE: If your derived classes is intended to be dispatched via the +// NOTE: If a derived class is intended to be dispatched via the // BookmarkEditor::Show static function found in the accompanying -// implementation will need to update that function. -@interface BookmarkEditorBaseController : - NSWindowController<NSMatrixDelegate, NSTextFieldDelegate> { +// implementation, that function will need to be update. +@interface BookmarkEditorBaseController : NSWindowController { @private - IBOutlet NSBrowser* folderBrowser_; IBOutlet NSButton* newFolderButton_; IBOutlet NSButton* okButton_; // Used for unit testing only. + IBOutlet NSTreeController* folderTreeController_; + IBOutlet NSOutlineView* folderTreeView_; - NSWindow* parentWindow_; + NSWindow* parentWindow_; // weak Profile* profile_; // weak const BookmarkNode* parentNode_; // weak; owned by the model BookmarkEditor::Configuration configuration_; @@ -36,11 +36,19 @@ class BookmarkModel; NSString* initialName_; NSString* displayName_; // Bound to a text field in the dialog. BOOL okEnabled_; // Bound to the OK button. + // An array of BookmarkFolderInfo where each item describes a folder in the + // BookmarkNode structure. + scoped_nsobject<NSArray> folderTreeArray_; + // Bound to the table view giving a path to the current selections, of which + // there should only ever be one. + scoped_nsobject<NSArray> tableSelectionPaths_; } @property (copy) NSString* initialName; @property (copy) NSString* displayName; @property (assign) BOOL okEnabled; +@property (retain, readonly) NSArray* folderTreeArray; +@property (copy) NSArray* tableSelectionPaths; // Designated initializer. Derived classes should call through to this init. - (id)initWithParentWindow:(NSWindow*)parentWindow @@ -57,11 +65,22 @@ class BookmarkModel; // an untitled name, and put it into editing mode. - (IBAction)newFolder:(id)sender; -// Actions for the buttons at the bottom of the window. +// The cancel action will dismiss the dialog. Derived classes which +// override cancel:, must call this after accessing any dialog-related +// data. - (IBAction)cancel:(id)sender; -// The OK action will record the edited bookmark. The default dismisses -// the dialog and should be called by the derived class if overridden. +// The OK action will dismiss the dialog. This action is bound +// to the OK button of a dialog which presents a tree view of a profile's +// folder hierarchy and allows the creation of new folders within that tree. +// When the OK button is pressed, this function will: 1) call the derived +// class's -[willCommit] function, 2) create any new folders created by +// the user while the dialog is presented, 3) call the derived class's +// -[didCommit] function, and then 4) dismiss the dialog. At least one +// of -[willCommit] and -[didCommit] must be provided by the derived class +// and should return a NSNumber containing a BOOL or nil ('nil' means YES) +// indicating if the operation should be allowed to continue. +// Note: A derived class should not override the ok: action. - (IBAction)ok:(id)sender; // Methods for use by derived classes only. @@ -69,8 +88,7 @@ class BookmarkModel; // Determine and returns the rightmost selected/highlighted element (node) // in the bookmark tree view if the tree view is showing, otherwise returns // the original |parentNode_|. If the tree view is showing but nothing is -// selected then return the root node. This assumes that leaf nodes (pure -// bookmarks) are not being presented. +// selected then the root node is returned. - (const BookmarkNode*)selectedNode; // Select/highlight the given node within the browser tree view. If the @@ -78,7 +96,7 @@ class BookmarkModel; - (void)selectNodeInBrowser:(const BookmarkNode*)node; // Notify the handler, if any, of a node creation. -- (void)NotifyHandlerCreatedNode:(const BookmarkNode*)node; +- (void)notifyHandlerCreatedNode:(const BookmarkNode*)node; // Accessors - (BookmarkModel*)bookmarkModel; @@ -86,12 +104,64 @@ class BookmarkModel; @end +// Describes the profile's bookmark folder structure: the folder name, the +// original BookmarkNode pointer (if the folder already exists), a BOOL +// indicating if the folder is new (meaning: created during this session +// but not yet committed to the bookmark structure), and an NSArray of +// child folder BookmarkFolderInfo's following this same structure. +@interface BookmarkFolderInfo : NSObject { + @private + NSString* folderName_; + const BookmarkNode* folderNode_; // weak + NSMutableArray* children_; + BOOL newFolder_; +} + +@property (copy, readwrite) NSString* folderName; +@property (assign, readwrite) const BookmarkNode* folderNode; +@property (retain, readwrite) NSMutableArray* children; +@property (assign, readwrite) BOOL newFolder; + +// Convenience creator for adding a new folder to the editor's bookmark +// structure. This folder will be added to the bookmark model when the +// user accepts the dialog. |folderName| must be provided. ++ (id)bookmarkFolderInfoWithFolderName:(NSString*)folderName; + +// Designated initializer. |folderName| must be provided. For folders which +// already exist in the bookmark model, |folderNode| and |children| (if any +// children are already attached to this folder) must be provided and +// |newFolder| should be NO. For folders which the user has added during +// this session and which have not been committed yet, |newFolder| should be +// YES and |folderNode| and |children| should be NULL/nil. +- (id)initWithFolderName:(NSString*)folderName + folderNode:(const BookmarkNode*)folderNode + children:(NSMutableArray*)children + newFolder:(BOOL)newFolder; + +// Convenience creator used during construction of the editor's bookmark +// structure. |folderName| and |folderNode| must be provided. |children| +// is optional. Private: exposed here for unit testing purposes. ++ (id)bookmarkFolderInfoWithFolderName:(NSString*)folderName + folderNode:(const BookmarkNode*)folderNode + children:(NSMutableArray*)children; + +@end + @interface BookmarkEditorBaseController(TestingAPI) + @property (readonly) BOOL okButtonEnabled; + +// Create any newly added folders. New folders are nodes in folderTreeArray +// which are marked as being new (i.e. their kFolderTreeNewFolderKey +// dictionary item is YES). This is called by -[ok:]. +- (void)createNewFolders; + +// Select the given bookmark node within the tree view. - (void)selectTestNodeInBrowser:(const BookmarkNode*)node; -+ (const BookmarkNode*)folderChildForParent:(const BookmarkNode*)parent - withFolderIndex:(NSInteger)index; -+ (int)indexOfFolderChild:(const BookmarkNode*)child; + +// Return the dictionary for the folder selected in the tree. +- (BookmarkFolderInfo*)selectedFolder; + @end #endif /* CHROME_BROWSER_COCOA_BOOKMARK_EDITOR_BASE_CONTROLLER_H_ */ diff --git a/chrome/browser/cocoa/bookmark_editor_base_controller.mm b/chrome/browser/cocoa/bookmark_editor_base_controller.mm index d97874a..59b8913 100644 --- a/chrome/browser/cocoa/bookmark_editor_base_controller.mm +++ b/chrome/browser/cocoa/bookmark_editor_base_controller.mm @@ -2,8 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <stack> + #import "chrome/browser/cocoa/bookmark_editor_base_controller.h" #include "app/l10n_util.h" +#include "app/l10n_util_mac.h" #include "base/logging.h" #include "base/mac_util.h" #include "base/sys_string_conversions.h" @@ -16,25 +19,27 @@ @interface BookmarkEditorBaseController (Private) -// Given a cell in the folder browser, make that cell editable so that the -// bookmark folder name can be modified by the user. -- (void)editFolderNameInCell:(BookmarkTreeBrowserCell*)cell; +@property (retain, readwrite) NSArray* folderTreeArray; + +// Return the folder tree object for the given path. +- (BookmarkFolderInfo*)folderForIndexPath:(NSIndexPath*)path; -// The action called by the bookmark folder name cell being edited by -// the user when editing has been completed (such as by pressing <return>). -- (void)cellEditingCompleted:(id)sender; +// Given a folder node, collect an array containing BookmarkFolderInfos +// describing its subchildren which are also folders. +- (NSMutableArray*)addChildFoldersFromNode:(const BookmarkNode*)node; -// Update the folder name from the current edit in the given cell -// and return the focus to the folder tree browser. -- (void)saveFolderNameForCell:(BookmarkTreeBrowserCell*)cell; +// Scan the folder tree stemming from the given tree folder and create +// any newly added folders. +- (void)createNewFoldersForFolder:(BookmarkFolderInfo*)treeFolder; -// A custom action handler called by the bookmark folder browser when the -// user has double-clicked on a folder name. -- (void)browserDoubleClicked:(id)sender; +// Scan the folder tree looking for the given bookmark node and return +// the selection path thereto. +- (NSIndexPath*)selectionPathForNode:(const BookmarkNode*)node; @end -// static; implemented for each platform. +// static; implemented for each platform. Update this function for new +// classes derived from BookmarkEditorBaseController. void BookmarkEditor::Show(gfx::NativeWindow parent_hwnd, Profile* profile, const BookmarkNode* parent, @@ -61,40 +66,6 @@ void BookmarkEditor::Show(gfx::NativeWindow parent_hwnd, [controller runAsModalSheet]; } -#pragma mark Bookmark TreeNode Helpers - -namespace { - -// Find the index'th folder child of a parent, ignoring bookmarks (leafs). -const BookmarkNode* GetFolderChildForParent(const BookmarkNode* parent_node, - NSInteger folder_index) { - const BookmarkNode* child_node = nil; - int i = 0; - int child_count = parent_node->GetChildCount(); - do { - child_node = parent_node->GetChild(i); - if (child_node->type() != BookmarkNode::URL) - --folder_index; - ++i; - } while (folder_index >= 0 && i < child_count); - return child_node; -} - -// Determine the index of a child within its parent ignoring -// bookmarks (leafs). -int IndexOfFolderChild(const BookmarkNode* child_node) { - const BookmarkNode* node_parent = child_node->GetParent(); - int child_index = node_parent->IndexOfChild(child_node); - for (int i = child_index - 1; i >= 0; --i) { - const BookmarkNode* sibling = node_parent->GetChild(i); - if (sibling->type() == BookmarkNode::URL) - --child_index; - } - return child_index; -} - -} // namespace - @implementation BookmarkEditorBaseController @synthesize initialName = initialName_; @@ -131,21 +102,24 @@ int IndexOfFolderChild(const BookmarkNode* child_node) { [self setDisplayName:[self initialName]]; if (configuration_ != BookmarkEditor::SHOW_TREE) { - // Remember the NSBrowser's height; we will shrink our frame by that - // much. + // Remember the tree view's height; we will shrink our frame by that much. NSRect frame = [[self window] frame]; - CGFloat browserHeight = [folderBrowser_ frame].size.height; + CGFloat browserHeight = [folderTreeView_ frame].size.height; frame.size.height -= browserHeight; frame.origin.y += browserHeight; - // Remove the NSBrowser and "new folder" button. - [folderBrowser_ removeFromSuperview]; + // Remove the folder tree and "new folder" button. + [folderTreeView_ removeFromSuperview]; [newFolderButton_ removeFromSuperview]; // Finally, commit the size change. [[self window] setFrame:frame display:YES]; } - [folderBrowser_ setCellClass:[BookmarkTreeBrowserCell class]]; - [folderBrowser_ setDoubleAction:@selector(browserDoubleClicked:)]; + // Build up a tree of the current folder configuration. + BookmarkModel* model = profile_->GetBookmarkModel(); + const BookmarkNode* rootNode = model->root_node(); + NSMutableArray* baseArray = [self addChildFoldersFromNode:rootNode]; + DCHECK(baseArray); + [self setFolderTreeArray:baseArray]; } - (void)windowDidLoad { @@ -154,13 +128,6 @@ int IndexOfFolderChild(const BookmarkNode* child_node) { } } -- (void)windowWillClose:(NSNotification *)notification { - // If a folder name cell is being edited then force it to end editing - // so that any changes are recorded. - [[self window] makeFirstResponder:nil]; - [self autorelease]; -} - /* TODO(jrg): // Implementing this informal protocol allows us to open the sheet // somewhere other than at the top of the window. NOTE: this means @@ -181,50 +148,93 @@ int IndexOfFolderChild(const BookmarkNode* child_node) { contextInfo:nil]; } -- (void)selectNodeInBrowser:(const BookmarkNode*)node { - DCHECK(configuration_ == BookmarkEditor::SHOW_TREE); - std::deque<NSInteger> rowsToSelect; - const BookmarkNode* nodeParent = nil; - if (node) { - nodeParent = node->GetParent(); - // There should always be a parent node. - DCHECK(nodeParent); - while (nodeParent) { - int nodeRow = IndexOfFolderChild(node); - rowsToSelect.push_front(nodeRow); - node = nodeParent; - nodeParent = nodeParent->GetParent(); - } - } else { - BookmarkModel* model = profile_->GetBookmarkModel(); - nodeParent = model->GetBookmarkBarNode(); - rowsToSelect.push_front(0); +- (BOOL)okEnabled { + return YES; +} + +- (IBAction)ok:(id)sender { + // At least one of these two functions should be provided by derived classes. + BOOL hasWillCommit = [self respondsToSelector:@selector(willCommit)]; + BOOL hasDidCommit = [self respondsToSelector:@selector(didCommit)]; + DCHECK(hasWillCommit || hasDidCommit); + BOOL shouldContinue = YES; + if (hasWillCommit) { + NSNumber* hasWillContinue = [self performSelector:@selector(willCommit)]; + if (hasWillContinue && [hasWillContinue isKindOfClass:[NSNumber class]]) + shouldContinue = [hasWillContinue boolValue]; } - for (std::deque<NSInteger>::size_type column = 0; - column < rowsToSelect.size(); - ++column) { - [folderBrowser_ selectRow:rowsToSelect[column] inColumn:column]; + if (shouldContinue) + [self createNewFolders]; + if (hasDidCommit) { + NSNumber* hasDidContinue = [self performSelector:@selector(didCommit)]; + if (hasDidContinue && [hasDidContinue isKindOfClass:[NSNumber class]]) + shouldContinue = [hasDidContinue boolValue]; } + if (shouldContinue) + [NSApp endSheet:[self window]]; +} - // Force the OK button state to be re-evaluated. - [self willChangeValueForKey:@"okEnabled"]; - [self didChangeValueForKey:@"okEnabled"]; +- (IBAction)cancel:(id)sender { + [NSApp endSheet:[self window]]; +} + +- (void)didEndSheet:(NSWindow*)sheet + returnCode:(int)returnCode + contextInfo:(void*)contextInfo { + [sheet close]; +} + +- (void)windowWillClose:(NSNotification*)notification { + [self autorelease]; +} + +#pragma mark Folder Tree Management + +- (BookmarkModel*)bookmarkModel { + return profile_->GetBookmarkModel(); +} + +- (const BookmarkNode*)parentNode { + return parentNode_; +} + +- (BookmarkFolderInfo*)folderForIndexPath:(NSIndexPath*)indexPath { + NSUInteger pathCount = [indexPath length]; + BookmarkFolderInfo* item = nil; + NSArray* treeNode = [self folderTreeArray]; + for (NSUInteger i = 0; i < pathCount; ++i) { + item = [treeNode objectAtIndex:[indexPath indexAtPosition:i]]; + treeNode = [item children]; + } + return item; +} + +- (NSIndexPath*)selectedIndexPath { + NSIndexPath* selectedIndexPath = nil; + NSArray* selections = [self tableSelectionPaths]; + if ([selections count]) { + DCHECK([selections count] == 1); // Should be exactly one selection. + selectedIndexPath = [selections objectAtIndex:0]; + } + return selectedIndexPath; +} + +- (BookmarkFolderInfo*)selectedFolder { + BookmarkFolderInfo* item = nil; + NSIndexPath* selectedIndexPath = [self selectedIndexPath]; + if (selectedIndexPath) { + item = [self folderForIndexPath:selectedIndexPath]; + } + return item; } - (const BookmarkNode*)selectedNode { - BookmarkModel* model = profile_->GetBookmarkModel(); const BookmarkNode* selectedNode = NULL; // Determine a new parent node only if the browser is showing. if (configuration_ == BookmarkEditor::SHOW_TREE) { - selectedNode = model->root_node(); - NSInteger column = 0; - NSInteger selectedRow = [folderBrowser_ selectedRowInColumn:column]; - while (selectedRow >= 0) { - selectedNode = GetFolderChildForParent(selectedNode, - selectedRow); - ++column; - selectedRow = [folderBrowser_ selectedRowInColumn:column]; - } + BookmarkFolderInfo* folderInfo = [self selectedFolder]; + if (folderInfo) + selectedNode = [folderInfo folderNode]; } else { // If the tree is not showing then we use the original parent. selectedNode = parentNode_; @@ -232,94 +242,156 @@ int IndexOfFolderChild(const BookmarkNode* child_node) { return selectedNode; } -- (void)NotifyHandlerCreatedNode:(const BookmarkNode*)node { +- (void)notifyHandlerCreatedNode:(const BookmarkNode*)node { if (handler_.get()) handler_->NodeCreated(node); } -#pragma mark New Folder Handler & Folder Cell Editing - -- (void)editFolderNameInCell:(BookmarkTreeBrowserCell*)cell { - DCHECK([cell isKindOfClass:[BookmarkTreeBrowserCell class]]); - [cell setEditable:YES]; - [cell setTarget:self]; - [cell setAction:@selector(cellEditingCompleted:)]; - [cell setSendsActionOnEndEditing:YES]; - NSMatrix* matrix = [cell matrix]; - // Set the delegate so that we get called when editing completes. - [matrix setDelegate:self]; - [matrix selectText:self]; -} - -- (void)cellEditingCompleted:(id)sender { - DCHECK([sender isKindOfClass:[NSMatrix class]]); - BookmarkTreeBrowserCell* cell = [sender selectedCell]; - DCHECK([cell isKindOfClass:[BookmarkTreeBrowserCell class]]); - [self saveFolderNameForCell:cell]; -} - -- (void)saveFolderNameForCell:(BookmarkTreeBrowserCell*)cell { - DCHECK([cell isKindOfClass:[BookmarkTreeBrowserCell class]]); - // It's possible that the cell can get reused so clean things up - // to prevent inadvertant notifications. - [cell setTarget:nil]; - [cell setAction:nil]; - [cell setEditable:NO]; - [cell setSendsActionOnEndEditing:NO]; - // Force a responder change here to force the editing of the cell's text - // to complete otherwise the call to -[cell title] could return stale text. - // The focus does not automatically get reset to the browser when the - // cell gives up focus. - [[folderBrowser_ window] makeFirstResponder:folderBrowser_]; - const BookmarkNode* bookmarkNode = [cell bookmarkNode]; - BookmarkModel* model = profile_->GetBookmarkModel(); - NSString* newTitle = [cell title]; - model->SetTitle(bookmarkNode, base::SysNSStringToWide(newTitle)); +- (NSArray*)folderTreeArray { + return folderTreeArray_.get(); } -- (void)browserDoubleClicked:(id)sender { - BookmarkTreeBrowserCell* cell = [folderBrowser_ selectedCell]; - DCHECK([cell isKindOfClass:[BookmarkTreeBrowserCell class]]); - [self editFolderNameInCell:cell]; +- (void)setFolderTreeArray:(NSArray*)folderTreeArray { + folderTreeArray_.reset([folderTreeArray retain]); } -- (IBAction)newFolder:(id)sender { - BookmarkModel* model = profile_->GetBookmarkModel(); - const BookmarkNode* newParentNode = [self selectedNode]; - int newIndex = newParentNode->GetChildCount(); - std::wstring newFolderString = - l10n_util::GetString(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME); - const BookmarkNode* newFolder = model->AddGroup(newParentNode, newIndex, - newFolderString); - [self selectNodeInBrowser:newFolder]; - BookmarkTreeBrowserCell* cell = [folderBrowser_ selectedCell]; - [self editFolderNameInCell:cell]; +- (NSArray*)tableSelectionPaths { + return tableSelectionPaths_.get(); } -- (BOOL)okEnabled { - return YES; +- (void)setTableSelectionPath:(NSIndexPath*)tableSelectionPath { + [self setTableSelectionPaths:[NSArray arrayWithObject:tableSelectionPath]]; } -- (IBAction)ok:(id)sender { - [NSApp endSheet:[self window]]; +- (void)setTableSelectionPaths:(NSArray*)tableSelectionPaths { + tableSelectionPaths_.reset([tableSelectionPaths retain]); } -- (IBAction)cancel:(id)sender { - [NSApp endSheet:[self window]]; +- (void)selectNodeInBrowser:(const BookmarkNode*)node { + DCHECK(configuration_ == BookmarkEditor::SHOW_TREE); + NSIndexPath* selectionPath = [self selectionPathForNode:node]; + [self willChangeValueForKey:@"okEnabled"]; + [self setTableSelectionPath:selectionPath]; + [self didChangeValueForKey:@"okEnabled"]; } -- (void)didEndSheet:(NSWindow*)sheet - returnCode:(int)returnCode - contextInfo:(void*)contextInfo { - [sheet close]; +- (NSIndexPath*)selectionPathForNode:(const BookmarkNode*)desiredNode { + // Back up the parent chaing for desiredNode, building up a stack + // of ancestor nodes. Then crawl down the folderTreeArray looking + // for each ancestor in order while building up the selectionPath. + std::stack<const BookmarkNode*> nodeStack; + BookmarkModel* model = profile_->GetBookmarkModel(); + const BookmarkNode* rootNode = model->root_node(); + const BookmarkNode* node = desiredNode; + while (node != rootNode) { + nodeStack.push(node); + node = node->GetParent(); + } + NSUInteger stackSize = nodeStack.size(); + + NSIndexPath* path = nil; + NSArray* folders = [self folderTreeArray]; + while (!nodeStack.empty()) { + node = nodeStack.top(); + nodeStack.pop(); + // Find node in the current folders array. + NSUInteger i = 0; + for (BookmarkFolderInfo *folderInfo in folders) { + const BookmarkNode* testNode = [folderInfo folderNode]; + if (testNode == node) { + path = path ? [path indexPathByAddingIndex:i] : + [NSIndexPath indexPathWithIndex:i]; + folders = [folderInfo children]; + break; + } + ++i; + } + } + DCHECK([path length] == stackSize); + return path; } -- (BookmarkModel*)bookmarkModel { - return profile_->GetBookmarkModel(); +- (NSMutableArray*)addChildFoldersFromNode:(const BookmarkNode*)node { + NSMutableArray* childFolders = nil; + int childCount = node->GetChildCount(); + for (int i = 0; i < childCount; ++i) { + const BookmarkNode* childNode = node->GetChild(i); + if (childNode->type() != BookmarkNode::URL) { + NSString* childName = base::SysWideToNSString(childNode->GetTitle()); + NSMutableArray* children = [self addChildFoldersFromNode:childNode]; + BookmarkFolderInfo* folderInfo = + [BookmarkFolderInfo bookmarkFolderInfoWithFolderName:childName + folderNode:childNode + children:children]; + if (!childFolders) + childFolders = [NSMutableArray arrayWithObject:folderInfo]; + else + [childFolders addObject:folderInfo]; + } + } + return childFolders; } -- (const BookmarkNode*)parentNode { - return parentNode_; +#pragma mark New Folder Handler + +- (void)createNewFoldersForFolder:(BookmarkFolderInfo*)folderInfo { + NSArray* subfolders = [folderInfo children]; + const BookmarkNode* parentNode = [folderInfo folderNode]; + DCHECK(parentNode); + NSUInteger i = 0; + for (BookmarkFolderInfo *subFolderInfo in subfolders) { + if ([subFolderInfo newFolder]) { + BookmarkModel* model = [self bookmarkModel]; + const BookmarkNode* newFolder = + model->AddGroup(parentNode, i, + base::SysNSStringToWide([subFolderInfo folderName])); + [self notifyHandlerCreatedNode:newFolder]; + // Update our dictionary with the actual folder node just created. + [subFolderInfo setFolderNode:newFolder]; + [subFolderInfo setNewFolder:NO]; + } + [self createNewFoldersForFolder:subFolderInfo]; + ++i; + } +} + +- (IBAction)newFolder:(id)sender { + // Create a new folder off of the selected folder node. + BookmarkFolderInfo* parentInfo = [self selectedFolder]; + if (parentInfo) { + NSIndexPath* selection = [self selectedIndexPath]; + NSString* newFolderName = + l10n_util::GetNSStringWithFixup(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME); + BookmarkFolderInfo* folderInfo = + [BookmarkFolderInfo bookmarkFolderInfoWithFolderName:newFolderName]; + [self willChangeValueForKey:@"folderTreeArray"]; + NSMutableArray* children = [parentInfo children]; + if (children) { + [children addObject:folderInfo]; + } else { + children = [NSMutableArray arrayWithObject:folderInfo]; + [parentInfo setChildren:children]; + } + [self didChangeValueForKey:@"folderTreeArray"]; + + // Expose the parent folder children. + [folderTreeView_ expandItem:parentInfo]; + + // Select the new folder node and put the folder name into edit mode. + selection = [selection indexPathByAddingIndex:[children count] - 1]; + [self setTableSelectionPath:selection]; + NSInteger row = [folderTreeView_ selectedRow]; + DCHECK(row >= 0); + [folderTreeView_ editColumn:0 row:row withEvent:nil select:YES]; + } +} + +- (void)createNewFolders { + // Scan the tree looking for nodes marked 'newFolder' and create those nodes. + NSArray* folderTreeArray = [self folderTreeArray]; + for (BookmarkFolderInfo *folderInfo in folderTreeArray) { + [self createNewFoldersForFolder:folderInfo]; + } } #pragma mark For Unit Test Use Only @@ -332,67 +404,64 @@ int IndexOfFolderChild(const BookmarkNode* child_node) { [self selectNodeInBrowser:node]; } -+ (const BookmarkNode*)folderChildForParent:(const BookmarkNode*)parent - withFolderIndex:(NSInteger)index { - return GetFolderChildForParent(parent, index); -} +@end // BookmarkEditorBaseController -+ (int)indexOfFolderChild:(const BookmarkNode*)child { - return IndexOfFolderChild(child); +@implementation BookmarkFolderInfo + +@synthesize folderName = folderName_; +@synthesize folderNode = folderNode_; +@synthesize children = children_; +@synthesize newFolder = newFolder_; + ++ (id)bookmarkFolderInfoWithFolderName:(NSString*)folderName + folderNode:(const BookmarkNode*)folderNode + children:(NSMutableArray*)children { + return [[[BookmarkFolderInfo alloc] initWithFolderName:folderName + folderNode:folderNode + children:children + newFolder:NO] + autorelease]; } ++ (id)bookmarkFolderInfoWithFolderName:(NSString*)folderName { + return [[[BookmarkFolderInfo alloc] initWithFolderName:folderName + folderNode:NULL + children:nil + newFolder:YES] + autorelease]; +} -#pragma mark NSBrowser delegate methods - -// Given a column number, determine the parent bookmark folder node for the -// bookmarks being shown in that column. This is done by scanning forward -// from column zero and following the selected row for each column up -// to the parent of the desired column. -- (const BookmarkNode*)parentNodeForColumn:(NSInteger)column { - DCHECK(column >= 0); - BookmarkModel* model = profile_->GetBookmarkModel(); - const BookmarkNode* node = model->root_node(); - for (NSInteger i = 0; i < column; ++i) { - NSInteger selectedRowInColumn = [folderBrowser_ selectedRowInColumn:i]; - node = GetFolderChildForParent(node, selectedRowInColumn); - } - return node; -} - -// This implementation returns the number of folders contained in the parent -// folder node for this column. -// TOTO(mrossetti): Decide if bookmark (i.e. non-folder) nodes should be -// shown, perhaps in gray. -- (NSInteger)browser:(NSBrowser*)sender numberOfRowsInColumn:(NSInteger)col { - NSInteger rowCount = 0; - const BookmarkNode* parentNode = [self parentNodeForColumn:col]; - if (parentNode) { - int childCount = parentNode->GetChildCount(); - for (int i = 0; i < childCount; ++i) { - const BookmarkNode* childNode = parentNode->GetChild(i); - if (childNode->type() != BookmarkNode::URL) - ++rowCount; +- (id)initWithFolderName:(NSString*)folderName + folderNode:(const BookmarkNode*)folderNode + children:(NSMutableArray*)children + newFolder:(BOOL)newFolder { + if ((self = [super init])) { + // A folderName is always required, and if newFolder is NO then there + // should be a folderNode. Children is optional. + DCHECK(folderName && (newFolder || folderNode)); + if (folderName && (newFolder || folderNode)) { + folderName_ = [folderName copy]; + folderNode_ = folderNode; + children_ = [children retain]; + newFolder_ = newFolder; + } else { + NOTREACHED(); // Invalid init. + [self release]; + self = nil; } } - return rowCount; -} - -- (void)browser:(NSBrowser*)sender - willDisplayCell:(NSBrowserCell*)cell - atRow:(NSInteger)row - column:(NSInteger)column { - DCHECK(row >= 0); // Trust AppKit, but verify. - DCHECK(column >= 0); - DCHECK([cell isKindOfClass:[BookmarkTreeBrowserCell class]]); - const BookmarkNode* parentNode = [self parentNodeForColumn:column]; - const BookmarkNode* childNode = GetFolderChildForParent(parentNode, row); - DCHECK(childNode); - BookmarkTreeBrowserCell* browserCell = - static_cast<BookmarkTreeBrowserCell*>(cell); - [browserCell setTitle:base::SysWideToNSString(childNode->GetTitle())]; - [browserCell setBookmarkNode:childNode]; - [browserCell setMatrix:[folderBrowser_ matrixInColumn:column]]; + return self; } -@end // BookmarkEditorBaseController +- (id)init { + NOTREACHED(); // Should never be called. + return [self initWithFolderName:nil folderNode:nil children:nil newFolder:NO]; +} + +- (void)dealloc { + [folderName_ release]; + [children_ release]; + [super dealloc]; +} +@end diff --git a/chrome/browser/cocoa/bookmark_editor_base_controller_unittest.mm b/chrome/browser/cocoa/bookmark_editor_base_controller_unittest.mm index 2bb1fa1..698276e 100644 --- a/chrome/browser/cocoa/bookmark_editor_base_controller_unittest.mm +++ b/chrome/browser/cocoa/bookmark_editor_base_controller_unittest.mm @@ -4,18 +4,20 @@ #import <Cocoa/Cocoa.h> +#include "app/l10n_util_mac.h" #include "base/scoped_nsobject.h" #include "base/sys_string_conversions.h" #import "chrome/browser/cocoa/bookmark_editor_controller.h" #include "chrome/browser/cocoa/browser_test_helper.h" #import "chrome/browser/cocoa/cocoa_test_helper.h" +#include "grit/generated_resources.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" class BookmarkEditorBaseControllerTest : public CocoaTest { public: - BrowserTestHelper helper_; - BookmarkEditorBaseController* controller_; + BrowserTestHelper browser_helper_; + BookmarkEditorBaseController* controller_; // weak const BookmarkNode* group_a_; const BookmarkNode* group_b_; const BookmarkNode* group_b_0_; @@ -33,7 +35,7 @@ class BookmarkEditorBaseControllerTest : public CocoaTest { // b-30 // b-31 // b-4 - BookmarkModel& model(*(helper_.profile()->GetBookmarkModel())); + BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel())); const BookmarkNode* root = model.GetBookmarkBarNode(); group_a_ = model.AddGroup(root, 0, L"a"); model.AddURL(group_a_, 0, L"a-0", GURL("http://a-0.com")); @@ -63,7 +65,7 @@ class BookmarkEditorBaseControllerTest : public CocoaTest { return [[BookmarkEditorBaseController alloc] initWithParentWindow:test_window() nibName:@"BookmarkAllTabs" - profile:helper_.profile() + profile:browser_helper_.profile() parent:group_b_0_ configuration:BookmarkEditor::SHOW_TREE handler:nil]; @@ -73,16 +75,17 @@ class BookmarkEditorBaseControllerTest : public CocoaTest { CocoaTest::SetUp(); controller_ = CreateController(); EXPECT_TRUE([controller_ window]); + [controller_ runAsModalSheet]; } virtual void TearDown() { - [controller_ close]; + controller_ = NULL; CocoaTest::TearDown(); } }; TEST_F(BookmarkEditorBaseControllerTest, VerifyBookmarkTestModel) { - BookmarkModel& model(*(helper_.profile()->GetBookmarkModel())); + BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel())); const BookmarkNode& root(*model.GetBookmarkBarNode()); EXPECT_EQ(4, root.GetChildCount()); // a @@ -127,22 +130,52 @@ TEST_F(BookmarkEditorBaseControllerTest, VerifyBookmarkTestModel) { // d child = root.GetChild(3); EXPECT_EQ(0, child->GetChildCount()); + [controller_ cancel:nil]; } -TEST_F(BookmarkEditorBaseControllerTest, FolderChildForParent) { - const BookmarkNode* child = - [BookmarkEditorBaseController folderChildForParent:group_b_ - withFolderIndex:1]; - EXPECT_EQ(child, group_b_3_); +TEST_F(BookmarkEditorBaseControllerTest, NodeSelection) { + EXPECT_TRUE([controller_ folderTreeArray]); + [controller_ selectTestNodeInBrowser:group_b_3_]; + const BookmarkNode* node = [controller_ selectedNode]; + EXPECT_EQ(node, group_b_3_); + [controller_ cancel:nil]; } -TEST_F(BookmarkEditorBaseControllerTest, IndexOfFolderChild) { - int index = [BookmarkEditorBaseController indexOfFolderChild:group_b_3_]; - EXPECT_EQ(index, 1); +TEST_F(BookmarkEditorBaseControllerTest, CreateFolder) { + EXPECT_EQ(2, group_b_3_->GetChildCount()); + [controller_ selectTestNodeInBrowser:group_b_3_]; + NSString* expectedName = + l10n_util::GetNSStringWithFixup(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME); + [controller_ setDisplayName:expectedName]; + [controller_ newFolder:nil]; + NSArray* selectionPaths = [controller_ tableSelectionPaths]; + EXPECT_EQ(1U, [selectionPaths count]); + NSIndexPath* selectionPath = [selectionPaths objectAtIndex:0]; + EXPECT_EQ(4U, [selectionPath length]); + BookmarkFolderInfo* newFolderInfo = [controller_ selectedFolder]; + EXPECT_TRUE(newFolderInfo); + NSString* newFolderName = [newFolderInfo folderName]; + EXPECT_TRUE([newFolderName isEqualToString:expectedName]); + [controller_ createNewFolders]; + // Verify that the tab folder was added to the new folder. + EXPECT_EQ(3, group_b_3_->GetChildCount()); + [controller_ cancel:nil]; } -TEST_F(BookmarkEditorBaseControllerTest, NodeSelection) { - [controller_ selectNodeInBrowser:group_b_3_]; - const BookmarkNode* node = [controller_ selectedNode]; - EXPECT_EQ(node, group_b_3_); + +class BookmarkFolderInfoTest : public CocoaTest { }; + +TEST_F(BookmarkFolderInfoTest, Construction) { + NSMutableArray* children = [NSMutableArray arrayWithObject:@"child"]; + // We just need a pointer, and any pointer will do. + const BookmarkNode* fakeNode = + reinterpret_cast<const BookmarkNode*>(&children); + BookmarkFolderInfo* info = + [BookmarkFolderInfo bookmarkFolderInfoWithFolderName:@"name" + folderNode:fakeNode + children:children]; + EXPECT_TRUE(info); + EXPECT_EQ([info folderName], @"name"); + EXPECT_EQ([info children], children); + EXPECT_EQ([info folderNode], fakeNode); } diff --git a/chrome/browser/cocoa/bookmark_editor_controller.h b/chrome/browser/cocoa/bookmark_editor_controller.h index ff779b8..1fcf5f7 100644 --- a/chrome/browser/cocoa/bookmark_editor_controller.h +++ b/chrome/browser/cocoa/bookmark_editor_controller.h @@ -7,8 +7,9 @@ #import "chrome/browser/cocoa/bookmark_editor_base_controller.h" -// A controller for the bookmark editor, opened with Edit... from the -// context menu of a bookmark button. +// A controller for the bookmark editor, opened by 1) Edit... from the +// context menu of a bookmark button, and 2) Bookmark this Page...'s Edit +// button. @interface BookmarkEditorController : BookmarkEditorBaseController { @private const BookmarkNode* node_; // weak; owned by the model diff --git a/chrome/browser/cocoa/bookmark_editor_controller.mm b/chrome/browser/cocoa/bookmark_editor_controller.mm index 8164d4b..f471f1f 100644 --- a/chrome/browser/cocoa/bookmark_editor_controller.mm +++ b/chrome/browser/cocoa/bookmark_editor_controller.mm @@ -87,8 +87,9 @@ // should not be enabled). If the bookmark previously existed then it is // removed from its old folder. The bookmark is then added to its new // folder. If the folder has not changed then the bookmark stays in its -// original position (index) otherwise it is added to the end of the new folder. -- (IBAction)ok:(id)sender { +// original position (index) otherwise it is added to the end of the new +// folder. Called by -[BookmarkEditorBaseController ok:]. +- (NSNumber*)didCommit { NSString* name = [[self displayName] stringByTrimmingCharactersInSet: [NSCharacterSet newlineCharacterSet]]; std::wstring newTitle = base::SysNSStringToWide(name); @@ -97,9 +98,9 @@ int newIndex = newParentNode->GetChildCount(); GURL newURL = [self GURLFromUrlField]; if (!newURL.is_valid()) { - // Shouldn't be reached -- OK button disabled if not valid! + // Shouldn't be reached -- OK button should be disabled if not valid! NOTREACHED(); - return; + return [NSNumber numberWithBool:NO]; } // Determine where the new/replacement bookmark is to go. @@ -116,8 +117,8 @@ const BookmarkNode* node = model->AddURL(newParentNode, newIndex, newTitle, newURL); // Honor handler semantics: callback on node creation. - [self NotifyHandlerCreatedNode:node]; - [super ok:sender]; + [self notifyHandlerCreatedNode:node]; + return [NSNumber numberWithBool:YES]; } @end // BookmarkEditorController diff --git a/chrome/browser/cocoa/bookmark_editor_controller_unittest.mm b/chrome/browser/cocoa/bookmark_editor_controller_unittest.mm index db340b1..f505585 100644 --- a/chrome/browser/cocoa/bookmark_editor_controller_unittest.mm +++ b/chrome/browser/cocoa/bookmark_editor_controller_unittest.mm @@ -4,7 +4,6 @@ #import <Cocoa/Cocoa.h> -#include "base/scoped_nsobject.h" #include "base/sys_string_conversions.h" #import "chrome/browser/cocoa/bookmark_editor_controller.h" #include "chrome/browser/cocoa/browser_test_helper.h" @@ -14,86 +13,40 @@ class BookmarkEditorControllerTest : public CocoaTest { public: - BrowserTestHelper helper_; + BrowserTestHelper browser_helper_; const BookmarkNode* default_node_; const BookmarkNode* default_parent_; const char* default_name_; std::wstring default_title_; - BookmarkEditorController* default_controller_; + BookmarkEditorController* controller_; virtual void SetUp() { CocoaTest::SetUp(); - BookmarkModel* model = helper_.profile()->GetBookmarkModel(); + BookmarkModel* model = browser_helper_.profile()->GetBookmarkModel(); default_parent_ = model->GetBookmarkBarNode(); default_name_ = "http://www.zim-bop-a-dee.com/"; default_title_ = L"ooh title"; const BookmarkNode* default_node = model->AddURL(default_parent_, 0, default_title_, GURL(default_name_)); - default_controller_ = [[BookmarkEditorController alloc] - initWithParentWindow:test_window() - profile:helper_.profile() - parent:default_parent_ - node:default_node - configuration:BookmarkEditor::NO_TREE - handler:nil]; - [default_controller_ window]; // Forces a nib load + controller_ = [[BookmarkEditorController alloc] + initWithParentWindow:test_window() + profile:browser_helper_.profile() + parent:default_parent_ + node:default_node + configuration:BookmarkEditor::NO_TREE + handler:nil]; + [controller_ runAsModalSheet]; } virtual void TearDown() { - [default_controller_ close]; + controller_ = NULL; CocoaTest::TearDown(); } }; -TEST_F(BookmarkEditorControllerTest, NoNodeNoTree) { - BookmarkModel* model = helper_.profile()->GetBookmarkModel(); - const BookmarkNode* parent = model->GetBookmarkBarNode(); - const BookmarkNode* node = NULL; - - BookmarkEditorController* controller = - [[BookmarkEditorController alloc] - initWithParentWindow:test_window() - profile:helper_.profile() - parent:parent - node:node - configuration:BookmarkEditor::NO_TREE - handler:nil]; - - EXPECT_NE((NSWindow*)nil, [controller window]); // Forces a nib load - EXPECT_EQ(@"", [controller displayName]); - EXPECT_EQ(@"", [controller displayURL]); - EXPECT_FALSE([controller okButtonEnabled]); - [controller close]; -} - -TEST_F(BookmarkEditorControllerTest, YesNodeShowTree) { - BookmarkModel* model = helper_.profile()->GetBookmarkModel(); - const BookmarkNode* parent = model->GetBookmarkBarNode(); - const char* url_name = "http://www.zim-bop-a-dee.com/"; - const BookmarkNode* node = model->AddURL(parent, 0, default_title_, - GURL(url_name)); - - BookmarkEditorController* controller = - [[BookmarkEditorController alloc] - initWithParentWindow:test_window() - profile:helper_.profile() - parent:parent - node:node - configuration:BookmarkEditor::SHOW_TREE - handler:nil]; - - EXPECT_NE((NSWindow*)nil, [controller window]); // Forces a nib load - EXPECT_TRUE([base::SysWideToNSString(default_title_) - isEqual:[controller displayName]]); - EXPECT_TRUE([[NSString stringWithCString:url_name - encoding:NSUTF8StringEncoding] - isEqual:[controller displayURL]]); - [controller close]; -} - TEST_F(BookmarkEditorControllerTest, NoEdit) { - [default_controller_ ok:nil]; + [controller_ cancel:nil]; ASSERT_EQ(default_parent_->GetChildCount(), 1); const BookmarkNode* child = default_parent_->GetChild(0); EXPECT_EQ(child->GetTitle(), default_title_); @@ -101,8 +54,8 @@ TEST_F(BookmarkEditorControllerTest, NoEdit) { } TEST_F(BookmarkEditorControllerTest, EditTitle) { - [default_controller_ setDisplayName:@"whamma jamma bamma"]; - [default_controller_ ok:nil]; + [controller_ setDisplayName:@"whamma jamma bamma"]; + [controller_ ok:nil]; ASSERT_EQ(default_parent_->GetChildCount(), 1); const BookmarkNode* child = default_parent_->GetChild(0); EXPECT_EQ(child->GetTitle(), L"whamma jamma bamma"); @@ -110,10 +63,10 @@ TEST_F(BookmarkEditorControllerTest, EditTitle) { } TEST_F(BookmarkEditorControllerTest, EditURL) { - EXPECT_TRUE([default_controller_ okButtonEnabled]); - [default_controller_ setDisplayURL:@"http://yellow-sneakers.com/"]; - EXPECT_TRUE([default_controller_ okButtonEnabled]); - [default_controller_ ok:nil]; + EXPECT_TRUE([controller_ okButtonEnabled]); + [controller_ setDisplayURL:@"http://yellow-sneakers.com/"]; + EXPECT_TRUE([controller_ okButtonEnabled]); + [controller_ ok:nil]; ASSERT_EQ(default_parent_->GetChildCount(), 1); const BookmarkNode* child = default_parent_->GetChild(0); EXPECT_EQ(child->GetTitle(), default_title_); @@ -121,8 +74,8 @@ TEST_F(BookmarkEditorControllerTest, EditURL) { } TEST_F(BookmarkEditorControllerTest, EditAndFixPrefix) { - [default_controller_ setDisplayURL:@"x"]; - [default_controller_ ok:nil]; + [controller_ setDisplayURL:@"x"]; + [controller_ ok:nil]; ASSERT_EQ(default_parent_->GetChildCount(), 1); const BookmarkNode* child = default_parent_->GetChild(0); EXPECT_TRUE(child->GetURL().is_valid()); @@ -131,27 +84,102 @@ TEST_F(BookmarkEditorControllerTest, EditAndFixPrefix) { TEST_F(BookmarkEditorControllerTest, EditAndConfirmOKButton) { // Confirm OK button enabled/disabled as appropriate: // First test the URL. - EXPECT_TRUE([default_controller_ okButtonEnabled]); - [default_controller_ setDisplayURL:@""]; - EXPECT_FALSE([default_controller_ okButtonEnabled]); - [default_controller_ setDisplayURL:@"http://www.cnn.com"]; - EXPECT_TRUE([default_controller_ okButtonEnabled]); + EXPECT_TRUE([controller_ okButtonEnabled]); + [controller_ setDisplayURL:@""]; + EXPECT_FALSE([controller_ okButtonEnabled]); + [controller_ setDisplayURL:@"http://www.cnn.com"]; + EXPECT_TRUE([controller_ okButtonEnabled]); // Then test the name. - [default_controller_ setDisplayName:@""]; - EXPECT_TRUE([default_controller_ okButtonEnabled]); - [default_controller_ setDisplayName:@" "]; - EXPECT_TRUE([default_controller_ okButtonEnabled]); + [controller_ setDisplayName:@""]; + EXPECT_TRUE([controller_ okButtonEnabled]); + [controller_ setDisplayName:@" "]; + EXPECT_TRUE([controller_ okButtonEnabled]); // Then little mix of both. - [default_controller_ setDisplayName:@"name"]; - EXPECT_TRUE([default_controller_ okButtonEnabled]); - [default_controller_ setDisplayURL:@""]; - EXPECT_FALSE([default_controller_ okButtonEnabled]); + [controller_ setDisplayName:@"name"]; + EXPECT_TRUE([controller_ okButtonEnabled]); + [controller_ setDisplayURL:@""]; + EXPECT_FALSE([controller_ okButtonEnabled]); + [controller_ cancel:nil]; +} + +class BookmarkEditorControllerNoNodeTest : public CocoaTest { + public: + BrowserTestHelper browser_helper_; + BookmarkEditorController* controller_; + + virtual void SetUp() { + CocoaTest::SetUp(); + BookmarkModel* model = browser_helper_.profile()->GetBookmarkModel(); + const BookmarkNode* parent = model->GetBookmarkBarNode(); + controller_ = [[BookmarkEditorController alloc] + initWithParentWindow:test_window() + profile:browser_helper_.profile() + parent:parent + node:NULL + configuration:BookmarkEditor::NO_TREE + handler:nil]; + + [controller_ runAsModalSheet]; + } + + virtual void TearDown() { + controller_ = NULL; + CocoaTest::TearDown(); + } +}; + +TEST_F(BookmarkEditorControllerNoNodeTest, NoNodeNoTree) { + EXPECT_EQ(@"", [controller_ displayName]); + EXPECT_EQ(@"", [controller_ displayURL]); + EXPECT_FALSE([controller_ okButtonEnabled]); + [controller_ cancel:nil]; +} + +class BookmarkEditorControllerYesNodeTest : public CocoaTest { + public: + BrowserTestHelper browser_helper_; + std::wstring default_title_; + const char* url_name_; + BookmarkEditorController* controller_; + + virtual void SetUp() { + CocoaTest::SetUp(); + BookmarkModel* model = browser_helper_.profile()->GetBookmarkModel(); + const BookmarkNode* parent = model->GetBookmarkBarNode(); + default_title_ = L"wooh title"; + url_name_ = "http://www.zoom-baby-doo-da.com/"; + const BookmarkNode* node = model->AddURL(parent, 0, default_title_, + GURL(url_name_)); + controller_ = [[BookmarkEditorController alloc] + initWithParentWindow:test_window() + profile:browser_helper_.profile() + parent:parent + node:node + configuration:BookmarkEditor::NO_TREE + handler:nil]; + + [controller_ runAsModalSheet]; + } + + virtual void TearDown() { + controller_ = NULL; + CocoaTest::TearDown(); + } +}; + +TEST_F(BookmarkEditorControllerYesNodeTest, YesNodeShowTree) { + EXPECT_TRUE([base::SysWideToNSString(default_title_) + isEqual:[controller_ displayName]]); + EXPECT_TRUE([[NSString stringWithCString:url_name_ + encoding:NSUTF8StringEncoding] + isEqual:[controller_ displayURL]]); + [controller_ cancel:nil]; } class BookmarkEditorControllerTreeTest : public CocoaTest { public: - BrowserTestHelper helper_; - BookmarkEditorController* default_controller_; + BrowserTestHelper browser_helper_; + BookmarkEditorController* controller_; const BookmarkNode* group_a_; const BookmarkNode* group_b_; const BookmarkNode* group_bb_; @@ -169,7 +197,7 @@ class BookmarkEditorControllerTreeTest : public CocoaTest { // bb-4 // b-1 // b-2 - BookmarkModel& model(*(helper_.profile()->GetBookmarkModel())); + BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel())); const BookmarkNode* root = model.GetBookmarkBarNode(); group_a_ = model.AddGroup(root, 0, L"a"); model.AddURL(group_a_, 0, L"a-0", GURL("http://a-0.com")); @@ -200,7 +228,7 @@ class BookmarkEditorControllerTreeTest : public CocoaTest { virtual BookmarkEditorController* CreateController() { return [[BookmarkEditorController alloc] initWithParentWindow:test_window() - profile:helper_.profile() + profile:browser_helper_.profile() parent:group_bb_ node:bookmark_bb_3_ configuration:BookmarkEditor::SHOW_TREE @@ -208,19 +236,18 @@ class BookmarkEditorControllerTreeTest : public CocoaTest { } virtual void SetUp() { - CocoaTest::SetUp(); - default_controller_ = CreateController(); - EXPECT_TRUE([default_controller_ window]); + controller_ = CreateController(); + [controller_ runAsModalSheet]; } virtual void TearDown() { - [default_controller_ close]; + controller_ = NULL; CocoaTest::TearDown(); } }; TEST_F(BookmarkEditorControllerTreeTest, VerifyBookmarkTestModel) { - BookmarkModel& model(*(helper_.profile()->GetBookmarkModel())); + BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel())); model.root_node(); const BookmarkNode& root(*model.GetBookmarkBarNode()); EXPECT_EQ(4, root.GetChildCount()); @@ -267,12 +294,13 @@ TEST_F(BookmarkEditorControllerTreeTest, VerifyBookmarkTestModel) { child = root.GetChild(3); EXPECT_EQ(0, child->GetChildCount()); + [controller_ cancel:nil]; } TEST_F(BookmarkEditorControllerTreeTest, RenameBookmarkInPlace) { const BookmarkNode* oldParent = bookmark_bb_3_->GetParent(); - [default_controller_ setDisplayName:@"NEW NAME"]; - [default_controller_ ok:nil]; + [controller_ setDisplayName:@"NEW NAME"]; + [controller_ ok:nil]; const BookmarkNode* newParent = bookmark_bb_3_->GetParent(); ASSERT_EQ(newParent, oldParent); int childIndex = newParent->IndexOfChild(bookmark_bb_3_); @@ -281,8 +309,8 @@ TEST_F(BookmarkEditorControllerTreeTest, RenameBookmarkInPlace) { TEST_F(BookmarkEditorControllerTreeTest, ChangeBookmarkURLInPlace) { const BookmarkNode* oldParent = bookmark_bb_3_->GetParent(); - [default_controller_ setDisplayURL:@"http://NEWURL.com"]; - [default_controller_ ok:nil]; + [controller_ setDisplayURL:@"http://NEWURL.com"]; + [controller_ ok:nil]; const BookmarkNode* newParent = bookmark_bb_3_->GetParent(); ASSERT_EQ(newParent, oldParent); int childIndex = newParent->IndexOfChild(bookmark_bb_3_); @@ -290,8 +318,8 @@ TEST_F(BookmarkEditorControllerTreeTest, ChangeBookmarkURLInPlace) { } TEST_F(BookmarkEditorControllerTreeTest, ChangeBookmarkGroup) { - [default_controller_ selectTestNodeInBrowser:group_c_]; - [default_controller_ ok:nil]; + [controller_ selectTestNodeInBrowser:group_c_]; + [controller_ ok:nil]; const BookmarkNode* parent = bookmark_bb_3_->GetParent(); ASSERT_EQ(parent, group_c_); int childIndex = parent->IndexOfChild(bookmark_bb_3_); @@ -299,9 +327,9 @@ TEST_F(BookmarkEditorControllerTreeTest, ChangeBookmarkGroup) { } TEST_F(BookmarkEditorControllerTreeTest, ChangeNameAndBookmarkGroup) { - [default_controller_ setDisplayName:@"NEW NAME"]; - [default_controller_ selectTestNodeInBrowser:group_c_]; - [default_controller_ ok:nil]; + [controller_ setDisplayName:@"NEW NAME"]; + [controller_ selectTestNodeInBrowser:group_c_]; + [controller_ ok:nil]; const BookmarkNode* parent = bookmark_bb_3_->GetParent(); ASSERT_EQ(parent, group_c_); int childIndex = parent->IndexOfChild(bookmark_bb_3_); @@ -310,11 +338,10 @@ TEST_F(BookmarkEditorControllerTreeTest, ChangeNameAndBookmarkGroup) { } TEST_F(BookmarkEditorControllerTreeTest, AddFolderWithGroupSelected) { - [default_controller_ newFolder:nil]; - [default_controller_ cancel:nil]; - EXPECT_EQ(6, group_bb_->GetChildCount()); - const BookmarkNode* folderChild = group_bb_->GetChild(5); - EXPECT_EQ(folderChild->GetTitle(), L"New folder"); + // Folders are NOT added unless the OK button is pressed. + [controller_ newFolder:nil]; + [controller_ cancel:nil]; + EXPECT_EQ(5, group_bb_->GetChildCount()); } class BookmarkEditorControllerTreeNoNodeTest : @@ -323,7 +350,7 @@ class BookmarkEditorControllerTreeNoNodeTest : virtual BookmarkEditorController* CreateController() { return [[BookmarkEditorController alloc] initWithParentWindow:test_window() - profile:helper_.profile() + profile:browser_helper_.profile() parent:group_bb_ node:nil configuration:BookmarkEditor::SHOW_TREE @@ -333,35 +360,11 @@ class BookmarkEditorControllerTreeNoNodeTest : }; TEST_F(BookmarkEditorControllerTreeNoNodeTest, NewBookmarkNoNode) { - [default_controller_ setDisplayName:@"NEW BOOKMARK"]; - [default_controller_ setDisplayURL:@"http://NEWURL.com"]; - [default_controller_ ok:nil]; + [controller_ setDisplayName:@"NEW BOOKMARK"]; + [controller_ setDisplayURL:@"http://NEWURL.com"]; + [controller_ ok:nil]; const BookmarkNode* new_node = group_bb_->GetChild(5); ASSERT_EQ(0, new_node->GetChildCount()); EXPECT_EQ(new_node->GetTitle(), L"NEW BOOKMARK"); EXPECT_EQ(new_node->GetURL(), GURL("http://NEWURL.com")); } - -class BookmarkEditorControllerTreeNoParentTest : - public BookmarkEditorControllerTreeTest { - public: - virtual BookmarkEditorController* CreateController() { - return [[BookmarkEditorController alloc] - initWithParentWindow:test_window() - profile:helper_.profile() - parent:nil - node:nil - configuration:BookmarkEditor::SHOW_TREE - handler:nil]; - } -}; - -TEST_F(BookmarkEditorControllerTreeNoParentTest, AddFolderWithNoGroupSelected) { - [default_controller_ newFolder:nil]; - [default_controller_ cancel:nil]; - BookmarkModel* model = helper_.profile()->GetBookmarkModel(); - const BookmarkNode* bookmarkBar = model->GetBookmarkBarNode(); - EXPECT_EQ(5, bookmarkBar->GetChildCount()); - const BookmarkNode* folderChild = bookmarkBar->GetChild(4); - EXPECT_EQ(folderChild->GetTitle(), L"New folder"); -} |