Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(63)

Side by Side Diff: chrome/browser/cocoa/bookmark_editor_base_controller.mm

Issue 393006: Change the folder presentation in the Bookmark Editor and the Bookmark All Ta... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <stack>
6
5 #import "chrome/browser/cocoa/bookmark_editor_base_controller.h" 7 #import "chrome/browser/cocoa/bookmark_editor_base_controller.h"
6 #include "app/l10n_util.h" 8 #include "app/l10n_util.h"
9 #include "app/l10n_util_mac.h"
7 #include "base/logging.h" 10 #include "base/logging.h"
8 #include "base/mac_util.h" 11 #include "base/mac_util.h"
9 #include "base/sys_string_conversions.h" 12 #include "base/sys_string_conversions.h"
10 #include "chrome/browser/bookmarks/bookmark_model.h" 13 #include "chrome/browser/bookmarks/bookmark_model.h"
11 #import "chrome/browser/cocoa/bookmark_all_tabs_controller.h" 14 #import "chrome/browser/cocoa/bookmark_all_tabs_controller.h"
12 #import "chrome/browser/cocoa/bookmark_editor_controller.h" 15 #import "chrome/browser/cocoa/bookmark_editor_controller.h"
13 #import "chrome/browser/cocoa/bookmark_tree_browser_cell.h" 16 #import "chrome/browser/cocoa/bookmark_tree_browser_cell.h"
14 #include "chrome/browser/profile.h" 17 #include "chrome/browser/profile.h"
15 #include "grit/generated_resources.h" 18 #include "grit/generated_resources.h"
16 19
17 @interface BookmarkEditorBaseController (Private) 20 @interface BookmarkEditorBaseController (Private)
18 21
19 // Given a cell in the folder browser, make that cell editable so that the 22 @property (retain, readwrite) NSArray* folderTreeArray;
20 // bookmark folder name can be modified by the user.
21 - (void)editFolderNameInCell:(BookmarkTreeBrowserCell*)cell;
22 23
23 // The action called by the bookmark folder name cell being edited by 24 // Return the folder tree object for the given path.
24 // the user when editing has been completed (such as by pressing <return>). 25 - (BookmarkFolderInfo*)folderForIndexPath:(NSIndexPath*)path;
25 - (void)cellEditingCompleted:(id)sender;
26 26
27 // Update the folder name from the current edit in the given cell 27 // Given a folder node, collect an array containing BookmarkFolderInfos
28 // and return the focus to the folder tree browser. 28 // describing its subchildren which are also folders.
29 - (void)saveFolderNameForCell:(BookmarkTreeBrowserCell*)cell; 29 - (NSMutableArray*)addChildFoldersFromNode:(const BookmarkNode*)node;
30 30
31 // A custom action handler called by the bookmark folder browser when the 31 // Scan the folder tree stemming from the given tree folder and create
32 // user has double-clicked on a folder name. 32 // any newly added folders.
33 - (void)browserDoubleClicked:(id)sender; 33 - (void)createNewFoldersForFolder:(BookmarkFolderInfo*)treeFolder;
34
35 // Scan the folder tree looking for the given bookmark node and return
36 // the selection path thereto.
37 - (NSIndexPath*)selectionPathForNode:(const BookmarkNode*)node;
34 38
35 @end 39 @end
36 40
37 // static; implemented for each platform. 41 // static; implemented for each platform. Update this function for new
42 // classes derived from BookmarkEditorBaseController.
38 void BookmarkEditor::Show(gfx::NativeWindow parent_hwnd, 43 void BookmarkEditor::Show(gfx::NativeWindow parent_hwnd,
39 Profile* profile, 44 Profile* profile,
40 const BookmarkNode* parent, 45 const BookmarkNode* parent,
41 const EditDetails& details, 46 const EditDetails& details,
42 Configuration configuration, 47 Configuration configuration,
43 Handler* handler) { 48 Handler* handler) {
44 BookmarkEditorBaseController* controller = nil; 49 BookmarkEditorBaseController* controller = nil;
45 if (details.type == EditDetails::NEW_FOLDER) { 50 if (details.type == EditDetails::NEW_FOLDER) {
46 controller = [[BookmarkAllTabsController alloc] 51 controller = [[BookmarkAllTabsController alloc]
47 initWithParentWindow:parent_hwnd 52 initWithParentWindow:parent_hwnd
48 profile:profile 53 profile:profile
49 parent:parent 54 parent:parent
50 configuration:configuration 55 configuration:configuration
51 handler:handler]; 56 handler:handler];
52 } else { 57 } else {
53 controller = [[BookmarkEditorController alloc] 58 controller = [[BookmarkEditorController alloc]
54 initWithParentWindow:parent_hwnd 59 initWithParentWindow:parent_hwnd
55 profile:profile 60 profile:profile
56 parent:parent 61 parent:parent
57 node:details.existing_node 62 node:details.existing_node
58 configuration:configuration 63 configuration:configuration
59 handler:handler]; 64 handler:handler];
60 } 65 }
61 [controller runAsModalSheet]; 66 [controller runAsModalSheet];
62 } 67 }
63 68
64 #pragma mark Bookmark TreeNode Helpers
65
66 namespace {
67
68 // Find the index'th folder child of a parent, ignoring bookmarks (leafs).
69 const BookmarkNode* GetFolderChildForParent(const BookmarkNode* parent_node,
70 NSInteger folder_index) {
71 const BookmarkNode* child_node = nil;
72 int i = 0;
73 int child_count = parent_node->GetChildCount();
74 do {
75 child_node = parent_node->GetChild(i);
76 if (child_node->type() != BookmarkNode::URL)
77 --folder_index;
78 ++i;
79 } while (folder_index >= 0 && i < child_count);
80 return child_node;
81 }
82
83 // Determine the index of a child within its parent ignoring
84 // bookmarks (leafs).
85 int IndexOfFolderChild(const BookmarkNode* child_node) {
86 const BookmarkNode* node_parent = child_node->GetParent();
87 int child_index = node_parent->IndexOfChild(child_node);
88 for (int i = child_index - 1; i >= 0; --i) {
89 const BookmarkNode* sibling = node_parent->GetChild(i);
90 if (sibling->type() == BookmarkNode::URL)
91 --child_index;
92 }
93 return child_index;
94 }
95
96 } // namespace
97
98 @implementation BookmarkEditorBaseController 69 @implementation BookmarkEditorBaseController
99 70
100 @synthesize initialName = initialName_; 71 @synthesize initialName = initialName_;
101 @synthesize displayName = displayName_; 72 @synthesize displayName = displayName_;
102 @synthesize okEnabled = okEnabled_; 73 @synthesize okEnabled = okEnabled_;
103 74
104 - (id)initWithParentWindow:(NSWindow*)parentWindow 75 - (id)initWithParentWindow:(NSWindow*)parentWindow
105 nibName:(NSString*)nibName 76 nibName:(NSString*)nibName
106 profile:(Profile*)profile 77 profile:(Profile*)profile
107 parent:(const BookmarkNode*)parent 78 parent:(const BookmarkNode*)parent
(...skipping 16 matching lines...) Expand all
124 - (void)dealloc { 95 - (void)dealloc {
125 [initialName_ release]; 96 [initialName_ release];
126 [displayName_ release]; 97 [displayName_ release];
127 [super dealloc]; 98 [super dealloc];
128 } 99 }
129 100
130 - (void)awakeFromNib { 101 - (void)awakeFromNib {
131 [self setDisplayName:[self initialName]]; 102 [self setDisplayName:[self initialName]];
132 103
133 if (configuration_ != BookmarkEditor::SHOW_TREE) { 104 if (configuration_ != BookmarkEditor::SHOW_TREE) {
134 // Remember the NSBrowser's height; we will shrink our frame by that 105 // Remember the tree view's height; we will shrink our frame by that much.
135 // much.
136 NSRect frame = [[self window] frame]; 106 NSRect frame = [[self window] frame];
137 CGFloat browserHeight = [folderBrowser_ frame].size.height; 107 CGFloat browserHeight = [folderTreeView_ frame].size.height;
138 frame.size.height -= browserHeight; 108 frame.size.height -= browserHeight;
139 frame.origin.y += browserHeight; 109 frame.origin.y += browserHeight;
140 // Remove the NSBrowser and "new folder" button. 110 // Remove the folder tree and "new folder" button.
141 [folderBrowser_ removeFromSuperview]; 111 [folderTreeView_ removeFromSuperview];
142 [newFolderButton_ removeFromSuperview]; 112 [newFolderButton_ removeFromSuperview];
143 // Finally, commit the size change. 113 // Finally, commit the size change.
144 [[self window] setFrame:frame display:YES]; 114 [[self window] setFrame:frame display:YES];
145 } 115 }
146 116
147 [folderBrowser_ setCellClass:[BookmarkTreeBrowserCell class]]; 117 // Build up a tree of the current folder configuration.
148 [folderBrowser_ setDoubleAction:@selector(browserDoubleClicked:)]; 118 BookmarkModel* model = profile_->GetBookmarkModel();
119 const BookmarkNode* rootNode = model->root_node();
120 NSMutableArray* baseArray = [self addChildFoldersFromNode:rootNode];
121 DCHECK(baseArray);
122 [self setFolderTreeArray:baseArray];
149 } 123 }
150 124
151 - (void)windowDidLoad { 125 - (void)windowDidLoad {
152 if (configuration_ == BookmarkEditor::SHOW_TREE) { 126 if (configuration_ == BookmarkEditor::SHOW_TREE) {
153 [self selectNodeInBrowser:parentNode_]; 127 [self selectNodeInBrowser:parentNode_];
154 } 128 }
155 } 129 }
156 130
157 - (void)windowWillClose:(NSNotification *)notification {
158 // If a folder name cell is being edited then force it to end editing
159 // so that any changes are recorded.
160 [[self window] makeFirstResponder:nil];
161 [self autorelease];
162 }
163
164 /* TODO(jrg): 131 /* TODO(jrg):
165 // Implementing this informal protocol allows us to open the sheet 132 // Implementing this informal protocol allows us to open the sheet
166 // somewhere other than at the top of the window. NOTE: this means 133 // somewhere other than at the top of the window. NOTE: this means
167 // that I, the controller, am also the window's delegate. 134 // that I, the controller, am also the window's delegate.
168 - (NSRect)window:(NSWindow*)window willPositionSheet:(NSWindow*)sheet 135 - (NSRect)window:(NSWindow*)window willPositionSheet:(NSWindow*)sheet
169 usingRect:(NSRect)rect { 136 usingRect:(NSRect)rect {
170 // adjust rect.origin.y to be the bottom of the toolbar 137 // adjust rect.origin.y to be the bottom of the toolbar
171 return rect; 138 return rect;
172 } 139 }
173 */ 140 */
174 141
175 // TODO(jrg): consider NSModalSession. 142 // TODO(jrg): consider NSModalSession.
176 - (void)runAsModalSheet { 143 - (void)runAsModalSheet {
177 [NSApp beginSheet:[self window] 144 [NSApp beginSheet:[self window]
178 modalForWindow:parentWindow_ 145 modalForWindow:parentWindow_
179 modalDelegate:self 146 modalDelegate:self
180 didEndSelector:@selector(didEndSheet:returnCode:contextInfo:) 147 didEndSelector:@selector(didEndSheet:returnCode:contextInfo:)
181 contextInfo:nil]; 148 contextInfo:nil];
182 } 149 }
183 150
184 - (void)selectNodeInBrowser:(const BookmarkNode*)node { 151 - (BOOL)okEnabled {
185 DCHECK(configuration_ == BookmarkEditor::SHOW_TREE); 152 return YES;
186 std::deque<NSInteger> rowsToSelect; 153 }
187 const BookmarkNode* nodeParent = nil; 154
188 if (node) { 155 - (IBAction)ok:(id)sender {
189 nodeParent = node->GetParent(); 156 // At least one of these two functions should be provided by derived classes.
190 // There should always be a parent node. 157 BOOL hasWillCommit = [self respondsToSelector:@selector(willCommit)];
191 DCHECK(nodeParent); 158 BOOL hasDidCommit = [self respondsToSelector:@selector(didCommit)];
192 while (nodeParent) { 159 DCHECK(hasWillCommit || hasDidCommit);
193 int nodeRow = IndexOfFolderChild(node); 160 BOOL shouldContinue = YES;
194 rowsToSelect.push_front(nodeRow); 161 if (hasWillCommit) {
195 node = nodeParent; 162 NSNumber* hasWillContinue = [self performSelector:@selector(willCommit)];
196 nodeParent = nodeParent->GetParent(); 163 if (hasWillContinue && [hasWillContinue isKindOfClass:[NSNumber class]])
197 } 164 shouldContinue = [hasWillContinue boolValue];
198 } else {
199 BookmarkModel* model = profile_->GetBookmarkModel();
200 nodeParent = model->GetBookmarkBarNode();
201 rowsToSelect.push_front(0);
202 } 165 }
203 for (std::deque<NSInteger>::size_type column = 0; 166 if (shouldContinue)
204 column < rowsToSelect.size(); 167 [self createNewFolders];
205 ++column) { 168 if (hasDidCommit) {
206 [folderBrowser_ selectRow:rowsToSelect[column] inColumn:column]; 169 NSNumber* hasDidContinue = [self performSelector:@selector(didCommit)];
170 if (hasDidContinue && [hasDidContinue isKindOfClass:[NSNumber class]])
171 shouldContinue = [hasDidContinue boolValue];
207 } 172 }
173 if (shouldContinue)
174 [NSApp endSheet:[self window]];
175 }
208 176
209 // Force the OK button state to be re-evaluated. 177 - (IBAction)cancel:(id)sender {
210 [self willChangeValueForKey:@"okEnabled"]; 178 [NSApp endSheet:[self window]];
211 [self didChangeValueForKey:@"okEnabled"]; 179 }
180
181 - (void)didEndSheet:(NSWindow*)sheet
182 returnCode:(int)returnCode
183 contextInfo:(void*)contextInfo {
184 [sheet close];
185 }
186
187 - (void)windowWillClose:(NSNotification*)notification {
188 [self autorelease];
189 }
190
191 #pragma mark Folder Tree Management
192
193 - (BookmarkModel*)bookmarkModel {
194 return profile_->GetBookmarkModel();
195 }
196
197 - (const BookmarkNode*)parentNode {
198 return parentNode_;
199 }
200
201 - (BookmarkFolderInfo*)folderForIndexPath:(NSIndexPath*)indexPath {
202 NSUInteger pathCount = [indexPath length];
203 BookmarkFolderInfo* item = nil;
204 NSArray* treeNode = [self folderTreeArray];
205 for (NSUInteger i = 0; i < pathCount; ++i) {
206 item = [treeNode objectAtIndex:[indexPath indexAtPosition:i]];
207 treeNode = [item children];
208 }
209 return item;
210 }
211
212 - (NSIndexPath*)selectedIndexPath {
213 NSIndexPath* selectedIndexPath = nil;
214 NSArray* selections = [self tableSelectionPaths];
215 if ([selections count]) {
216 DCHECK([selections count] == 1); // Should be exactly one selection.
217 selectedIndexPath = [selections objectAtIndex:0];
218 }
219 return selectedIndexPath;
220 }
221
222 - (BookmarkFolderInfo*)selectedFolder {
223 BookmarkFolderInfo* item = nil;
224 NSIndexPath* selectedIndexPath = [self selectedIndexPath];
225 if (selectedIndexPath) {
226 item = [self folderForIndexPath:selectedIndexPath];
227 }
228 return item;
212 } 229 }
213 230
214 - (const BookmarkNode*)selectedNode { 231 - (const BookmarkNode*)selectedNode {
215 BookmarkModel* model = profile_->GetBookmarkModel();
216 const BookmarkNode* selectedNode = NULL; 232 const BookmarkNode* selectedNode = NULL;
217 // Determine a new parent node only if the browser is showing. 233 // Determine a new parent node only if the browser is showing.
218 if (configuration_ == BookmarkEditor::SHOW_TREE) { 234 if (configuration_ == BookmarkEditor::SHOW_TREE) {
219 selectedNode = model->root_node(); 235 BookmarkFolderInfo* folderInfo = [self selectedFolder];
220 NSInteger column = 0; 236 if (folderInfo)
221 NSInteger selectedRow = [folderBrowser_ selectedRowInColumn:column]; 237 selectedNode = [folderInfo folderNode];
222 while (selectedRow >= 0) {
223 selectedNode = GetFolderChildForParent(selectedNode,
224 selectedRow);
225 ++column;
226 selectedRow = [folderBrowser_ selectedRowInColumn:column];
227 }
228 } else { 238 } else {
229 // If the tree is not showing then we use the original parent. 239 // If the tree is not showing then we use the original parent.
230 selectedNode = parentNode_; 240 selectedNode = parentNode_;
231 } 241 }
232 return selectedNode; 242 return selectedNode;
233 } 243 }
234 244
235 - (void)NotifyHandlerCreatedNode:(const BookmarkNode*)node { 245 - (void)notifyHandlerCreatedNode:(const BookmarkNode*)node {
236 if (handler_.get()) 246 if (handler_.get())
237 handler_->NodeCreated(node); 247 handler_->NodeCreated(node);
238 } 248 }
239 249
240 #pragma mark New Folder Handler & Folder Cell Editing 250 - (NSArray*)folderTreeArray {
241 251 return folderTreeArray_.get();
242 - (void)editFolderNameInCell:(BookmarkTreeBrowserCell*)cell {
243 DCHECK([cell isKindOfClass:[BookmarkTreeBrowserCell class]]);
244 [cell setEditable:YES];
245 [cell setTarget:self];
246 [cell setAction:@selector(cellEditingCompleted:)];
247 [cell setSendsActionOnEndEditing:YES];
248 NSMatrix* matrix = [cell matrix];
249 // Set the delegate so that we get called when editing completes.
250 [matrix setDelegate:self];
251 [matrix selectText:self];
252 } 252 }
253 253
254 - (void)cellEditingCompleted:(id)sender { 254 - (void)setFolderTreeArray:(NSArray*)folderTreeArray {
255 DCHECK([sender isKindOfClass:[NSMatrix class]]); 255 folderTreeArray_.reset([folderTreeArray retain]);
256 BookmarkTreeBrowserCell* cell = [sender selectedCell];
257 DCHECK([cell isKindOfClass:[BookmarkTreeBrowserCell class]]);
258 [self saveFolderNameForCell:cell];
259 } 256 }
260 257
261 - (void)saveFolderNameForCell:(BookmarkTreeBrowserCell*)cell { 258 - (NSArray*)tableSelectionPaths {
262 DCHECK([cell isKindOfClass:[BookmarkTreeBrowserCell class]]); 259 return tableSelectionPaths_.get();
263 // It's possible that the cell can get reused so clean things up
264 // to prevent inadvertant notifications.
265 [cell setTarget:nil];
266 [cell setAction:nil];
267 [cell setEditable:NO];
268 [cell setSendsActionOnEndEditing:NO];
269 // Force a responder change here to force the editing of the cell's text
270 // to complete otherwise the call to -[cell title] could return stale text.
271 // The focus does not automatically get reset to the browser when the
272 // cell gives up focus.
273 [[folderBrowser_ window] makeFirstResponder:folderBrowser_];
274 const BookmarkNode* bookmarkNode = [cell bookmarkNode];
275 BookmarkModel* model = profile_->GetBookmarkModel();
276 NSString* newTitle = [cell title];
277 model->SetTitle(bookmarkNode, base::SysNSStringToWide(newTitle));
278 } 260 }
279 261
280 - (void)browserDoubleClicked:(id)sender { 262 - (void)setTableSelectionPath:(NSIndexPath*)tableSelectionPath {
281 BookmarkTreeBrowserCell* cell = [folderBrowser_ selectedCell]; 263 [self setTableSelectionPaths:[NSArray arrayWithObject:tableSelectionPath]];
282 DCHECK([cell isKindOfClass:[BookmarkTreeBrowserCell class]]); 264 }
283 [self editFolderNameInCell:cell]; 265
266 - (void)setTableSelectionPaths:(NSArray*)tableSelectionPaths {
267 tableSelectionPaths_.reset([tableSelectionPaths retain]);
268 }
269
270 - (void)selectNodeInBrowser:(const BookmarkNode*)node {
271 DCHECK(configuration_ == BookmarkEditor::SHOW_TREE);
272 NSIndexPath* selectionPath = [self selectionPathForNode:node];
273 [self willChangeValueForKey:@"okEnabled"];
274 [self setTableSelectionPath:selectionPath];
275 [self didChangeValueForKey:@"okEnabled"];
276 }
277
278 - (NSIndexPath*)selectionPathForNode:(const BookmarkNode*)desiredNode {
279 // Back up the parent chaing for desiredNode, building up a stack
280 // of ancestor nodes. Then crawl down the folderTreeArray looking
281 // for each ancestor in order while building up the selectionPath.
282 std::stack<const BookmarkNode*> nodeStack;
283 BookmarkModel* model = profile_->GetBookmarkModel();
284 const BookmarkNode* rootNode = model->root_node();
285 const BookmarkNode* node = desiredNode;
286 while (node != rootNode) {
287 nodeStack.push(node);
288 node = node->GetParent();
289 }
290 NSUInteger stackSize = nodeStack.size();
291
292 NSIndexPath* path = nil;
293 NSArray* folders = [self folderTreeArray];
294 while (!nodeStack.empty()) {
295 node = nodeStack.top();
296 nodeStack.pop();
297 // Find node in the current folders array.
298 NSUInteger i = 0;
299 for (BookmarkFolderInfo *folderInfo in folders) {
300 const BookmarkNode* testNode = [folderInfo folderNode];
301 if (testNode == node) {
302 path = path ? [path indexPathByAddingIndex:i] :
303 [NSIndexPath indexPathWithIndex:i];
304 folders = [folderInfo children];
305 break;
306 }
307 ++i;
308 }
309 }
310 DCHECK([path length] == stackSize);
311 return path;
312 }
313
314 - (NSMutableArray*)addChildFoldersFromNode:(const BookmarkNode*)node {
315 NSMutableArray* childFolders = nil;
316 int childCount = node->GetChildCount();
317 for (int i = 0; i < childCount; ++i) {
318 const BookmarkNode* childNode = node->GetChild(i);
319 if (childNode->type() != BookmarkNode::URL) {
320 NSString* childName = base::SysWideToNSString(childNode->GetTitle());
321 NSMutableArray* children = [self addChildFoldersFromNode:childNode];
322 BookmarkFolderInfo* folderInfo =
323 [BookmarkFolderInfo bookmarkFolderInfoWithFolderName:childName
324 folderNode:childNode
325 children:children];
326 if (!childFolders)
327 childFolders = [NSMutableArray arrayWithObject:folderInfo];
328 else
329 [childFolders addObject:folderInfo];
330 }
331 }
332 return childFolders;
333 }
334
335 #pragma mark New Folder Handler
336
337 - (void)createNewFoldersForFolder:(BookmarkFolderInfo*)folderInfo {
338 NSArray* subfolders = [folderInfo children];
339 const BookmarkNode* parentNode = [folderInfo folderNode];
340 DCHECK(parentNode);
341 NSUInteger i = 0;
342 for (BookmarkFolderInfo *subFolderInfo in subfolders) {
343 if ([subFolderInfo newFolder]) {
344 BookmarkModel* model = [self bookmarkModel];
345 const BookmarkNode* newFolder =
346 model->AddGroup(parentNode, i,
347 base::SysNSStringToWide([subFolderInfo folderName]));
348 [self notifyHandlerCreatedNode:newFolder];
349 // Update our dictionary with the actual folder node just created.
350 [subFolderInfo setFolderNode:newFolder];
351 [subFolderInfo setNewFolder:NO];
352 }
353 [self createNewFoldersForFolder:subFolderInfo];
354 ++i;
355 }
284 } 356 }
285 357
286 - (IBAction)newFolder:(id)sender { 358 - (IBAction)newFolder:(id)sender {
287 BookmarkModel* model = profile_->GetBookmarkModel(); 359 // Create a new folder off of the selected folder node.
288 const BookmarkNode* newParentNode = [self selectedNode]; 360 BookmarkFolderInfo* parentInfo = [self selectedFolder];
289 int newIndex = newParentNode->GetChildCount(); 361 if (parentInfo) {
290 std::wstring newFolderString = 362 NSIndexPath* selection = [self selectedIndexPath];
291 l10n_util::GetString(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME); 363 NSString* newFolderName =
292 const BookmarkNode* newFolder = model->AddGroup(newParentNode, newIndex, 364 l10n_util::GetNSStringWithFixup(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME);
293 newFolderString); 365 BookmarkFolderInfo* folderInfo =
294 [self selectNodeInBrowser:newFolder]; 366 [BookmarkFolderInfo bookmarkFolderInfoWithFolderName:newFolderName];
295 BookmarkTreeBrowserCell* cell = [folderBrowser_ selectedCell]; 367 [self willChangeValueForKey:@"folderTreeArray"];
296 [self editFolderNameInCell:cell]; 368 NSMutableArray* children = [parentInfo children];
369 if (children) {
370 [children addObject:folderInfo];
371 } else {
372 children = [NSMutableArray arrayWithObject:folderInfo];
373 [parentInfo setChildren:children];
374 }
375 [self didChangeValueForKey:@"folderTreeArray"];
376
377 // Expose the parent folder children.
378 [folderTreeView_ expandItem:parentInfo];
379
380 // Select the new folder node and put the folder name into edit mode.
381 selection = [selection indexPathByAddingIndex:[children count] - 1];
382 [self setTableSelectionPath:selection];
383 NSInteger row = [folderTreeView_ selectedRow];
384 DCHECK(row >= 0);
385 [folderTreeView_ editColumn:0 row:row withEvent:nil select:YES];
386 }
297 } 387 }
298 388
299 - (BOOL)okEnabled { 389 - (void)createNewFolders {
300 return YES; 390 // Scan the tree looking for nodes marked 'newFolder' and create those nodes.
301 } 391 NSArray* folderTreeArray = [self folderTreeArray];
302 392 for (BookmarkFolderInfo *folderInfo in folderTreeArray) {
303 - (IBAction)ok:(id)sender { 393 [self createNewFoldersForFolder:folderInfo];
304 [NSApp endSheet:[self window]]; 394 }
305 }
306
307 - (IBAction)cancel:(id)sender {
308 [NSApp endSheet:[self window]];
309 }
310
311 - (void)didEndSheet:(NSWindow*)sheet
312 returnCode:(int)returnCode
313 contextInfo:(void*)contextInfo {
314 [sheet close];
315 }
316
317 - (BookmarkModel*)bookmarkModel {
318 return profile_->GetBookmarkModel();
319 }
320
321 - (const BookmarkNode*)parentNode {
322 return parentNode_;
323 } 395 }
324 396
325 #pragma mark For Unit Test Use Only 397 #pragma mark For Unit Test Use Only
326 398
327 - (BOOL)okButtonEnabled { 399 - (BOOL)okButtonEnabled {
328 return [okButton_ isEnabled]; 400 return [okButton_ isEnabled];
329 } 401 }
330 402
331 - (void)selectTestNodeInBrowser:(const BookmarkNode*)node { 403 - (void)selectTestNodeInBrowser:(const BookmarkNode*)node {
332 [self selectNodeInBrowser:node]; 404 [self selectNodeInBrowser:node];
333 } 405 }
334 406
335 + (const BookmarkNode*)folderChildForParent:(const BookmarkNode*)parent
336 withFolderIndex:(NSInteger)index {
337 return GetFolderChildForParent(parent, index);
338 }
339
340 + (int)indexOfFolderChild:(const BookmarkNode*)child {
341 return IndexOfFolderChild(child);
342 }
343
344
345 #pragma mark NSBrowser delegate methods
346
347 // Given a column number, determine the parent bookmark folder node for the
348 // bookmarks being shown in that column. This is done by scanning forward
349 // from column zero and following the selected row for each column up
350 // to the parent of the desired column.
351 - (const BookmarkNode*)parentNodeForColumn:(NSInteger)column {
352 DCHECK(column >= 0);
353 BookmarkModel* model = profile_->GetBookmarkModel();
354 const BookmarkNode* node = model->root_node();
355 for (NSInteger i = 0; i < column; ++i) {
356 NSInteger selectedRowInColumn = [folderBrowser_ selectedRowInColumn:i];
357 node = GetFolderChildForParent(node, selectedRowInColumn);
358 }
359 return node;
360 }
361
362 // This implementation returns the number of folders contained in the parent
363 // folder node for this column.
364 // TOTO(mrossetti): Decide if bookmark (i.e. non-folder) nodes should be
365 // shown, perhaps in gray.
366 - (NSInteger)browser:(NSBrowser*)sender numberOfRowsInColumn:(NSInteger)col {
367 NSInteger rowCount = 0;
368 const BookmarkNode* parentNode = [self parentNodeForColumn:col];
369 if (parentNode) {
370 int childCount = parentNode->GetChildCount();
371 for (int i = 0; i < childCount; ++i) {
372 const BookmarkNode* childNode = parentNode->GetChild(i);
373 if (childNode->type() != BookmarkNode::URL)
374 ++rowCount;
375 }
376 }
377 return rowCount;
378 }
379
380 - (void)browser:(NSBrowser*)sender
381 willDisplayCell:(NSBrowserCell*)cell
382 atRow:(NSInteger)row
383 column:(NSInteger)column {
384 DCHECK(row >= 0); // Trust AppKit, but verify.
385 DCHECK(column >= 0);
386 DCHECK([cell isKindOfClass:[BookmarkTreeBrowserCell class]]);
387 const BookmarkNode* parentNode = [self parentNodeForColumn:column];
388 const BookmarkNode* childNode = GetFolderChildForParent(parentNode, row);
389 DCHECK(childNode);
390 BookmarkTreeBrowserCell* browserCell =
391 static_cast<BookmarkTreeBrowserCell*>(cell);
392 [browserCell setTitle:base::SysWideToNSString(childNode->GetTitle())];
393 [browserCell setBookmarkNode:childNode];
394 [browserCell setMatrix:[folderBrowser_ matrixInColumn:column]];
395 }
396
397 @end // BookmarkEditorBaseController 407 @end // BookmarkEditorBaseController
398 408
409 @implementation BookmarkFolderInfo
410
411 @synthesize folderName = folderName_;
412 @synthesize folderNode = folderNode_;
413 @synthesize children = children_;
414 @synthesize newFolder = newFolder_;
415
416 + (id)bookmarkFolderInfoWithFolderName:(NSString*)folderName
417 folderNode:(const BookmarkNode*)folderNode
418 children:(NSMutableArray*)children {
419 return [[[BookmarkFolderInfo alloc] initWithFolderName:folderName
420 folderNode:folderNode
421 children:children
422 newFolder:NO]
423 autorelease];
424 }
425
426 + (id)bookmarkFolderInfoWithFolderName:(NSString*)folderName {
427 return [[[BookmarkFolderInfo alloc] initWithFolderName:folderName
428 folderNode:NULL
429 children:nil
430 newFolder:YES]
431 autorelease];
432 }
433
434 - (id)initWithFolderName:(NSString*)folderName
435 folderNode:(const BookmarkNode*)folderNode
436 children:(NSMutableArray*)children
437 newFolder:(BOOL)newFolder {
438 if ((self = [super init])) {
439 // A folderName is always required, and if newFolder is NO then there
440 // should be a folderNode. Children is optional.
441 DCHECK(folderName && (newFolder || folderNode));
442 if (folderName && (newFolder || folderNode)) {
443 folderName_ = [folderName copy];
444 folderNode_ = folderNode;
445 children_ = [children retain];
446 newFolder_ = newFolder;
447 } else {
448 NOTREACHED(); // Invalid init.
449 [self release];
450 self = nil;
451 }
452 }
453 return self;
454 }
455
456 - (id)init {
457 NOTREACHED(); // Should never be called.
458 return [self initWithFolderName:nil folderNode:nil children:nil newFolder:NO];
459 }
460
461 - (void)dealloc {
462 [folderName_ release];
463 [children_ release];
464 [super dealloc];
465 }
466
467 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698