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

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

Issue 357005: Implement Bookmark All Tabs... using the BookmarkEditorController and determi... (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
Property Changes:
Name: svn:eol-style
+ LF
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #import "chrome/browser/cocoa/bookmark_editor_base_controller.h"
6 #include "app/l10n_util.h"
7 #include "base/logging.h"
8 #include "base/mac_util.h"
9 #include "base/sys_string_conversions.h"
10 #include "chrome/browser/bookmarks/bookmark_model.h"
11 #import "chrome/browser/cocoa/bookmark_all_tabs_controller.h"
12 #import "chrome/browser/cocoa/bookmark_editor_controller.h"
13 #import "chrome/browser/cocoa/bookmark_tree_browser_cell.h"
14 #include "chrome/browser/profile.h"
15 #include "grit/generated_resources.h"
16
17 @interface BookmarkEditorBaseController (Private)
18
19 // Given a cell in the folder browser, make that cell editable so that the
20 // bookmark folder name can be modified by the user.
21 - (void)editFolderNameInCell:(BookmarkTreeBrowserCell*)cell;
22
23 // The action called by the bookmark folder name cell being edited by
24 // the user when editing has been completed (such as by pressing <return>).
25 - (void)cellEditingCompleted:(id)sender;
26
27 // Update the folder name from the current edit in the given cell
28 // and return the focus to the folder tree browser.
29 - (void)saveFolderNameForCell:(BookmarkTreeBrowserCell*)cell;
30
31 // A custom action handler called by the bookmark folder browser when the
32 // user has double-clicked on a folder name.
33 - (void)browserDoubleClicked:(id)sender;
34
35 @end
36
37 // static; implemented for each platform.
38 void BookmarkEditor::Show(gfx::NativeWindow parent_hwnd,
39 Profile* profile,
40 const BookmarkNode* parent,
41 const EditDetails& details,
42 Configuration configuration,
43 Handler* handler) {
44 BookmarkEditorBaseController* controller = nil;
45 if (details.type == EditDetails::NEW_FOLDER) {
46 controller = [[BookmarkAllTabsController alloc]
47 initWithParentWindow:parent_hwnd
48 profile:profile
49 parent:parent
50 configuration:configuration
51 handler:handler];
52 } else {
53 controller = [[BookmarkEditorController alloc]
54 initWithParentWindow:parent_hwnd
55 profile:profile
56 parent:parent
57 node:details.existing_node
58 configuration:configuration
59 handler:handler];
60 }
61 [controller runAsModalSheet];
62 }
63
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
99
100 @synthesize initialName = initialName_;
101 @synthesize displayName = displayName_;
102 @synthesize okEnabled = okEnabled_;
103
104 - (id)initWithParentWindow:(NSWindow*)parentWindow
105 nibName:(NSString*)nibName
106 profile:(Profile*)profile
107 parent:(const BookmarkNode*)parent
108 configuration:(BookmarkEditor::Configuration)configuration
109 handler:(BookmarkEditor::Handler*)handler {
110 NSString* nibpath = [mac_util::MainAppBundle()
111 pathForResource:nibName
112 ofType:@"nib"];
113 if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
114 parentWindow_ = parentWindow;
115 profile_ = profile;
116 parentNode_ = parent;
117 configuration_ = configuration;
118 handler_.reset(handler);
119 initialName_ = [@"" retain];
120 }
121 return self;
122 }
123
124 - (void)dealloc {
125 [initialName_ release];
126 [displayName_ release];
127 [super dealloc];
128 }
129
130 - (void)awakeFromNib {
131 [self setDisplayName:[self initialName]];
132
133 if (configuration_ != BookmarkEditor::SHOW_TREE) {
134 // Remember the NSBrowser's height; we will shrink our frame by that
135 // much.
136 NSRect frame = [[self window] frame];
137 CGFloat browserHeight = [folderBrowser_ frame].size.height;
138 frame.size.height -= browserHeight;
139 frame.origin.y += browserHeight;
140 // Remove the NSBrowser and "new folder" button.
141 [folderBrowser_ removeFromSuperview];
142 [newFolderButton_ removeFromSuperview];
143 // Finally, commit the size change.
144 [[self window] setFrame:frame display:YES];
145 }
146
147 [folderBrowser_ setCellClass:[BookmarkTreeBrowserCell class]];
148 [folderBrowser_ setDoubleAction:@selector(browserDoubleClicked:)];
149 }
150
151 - (void)windowDidLoad {
152 if (configuration_ == BookmarkEditor::SHOW_TREE) {
153 [self selectNodeInBrowser:parentNode_];
154 }
155 }
156
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):
165 // Implementing this informal protocol allows us to open the sheet
166 // somewhere other than at the top of the window. NOTE: this means
167 // that I, the controller, am also the window's delegate.
168 - (NSRect)window:(NSWindow*)window willPositionSheet:(NSWindow*)sheet
169 usingRect:(NSRect)rect {
170 // adjust rect.origin.y to be the bottom of the toolbar
171 return rect;
172 }
173 */
174
175 // TODO(jrg): consider NSModalSession.
176 - (void)runAsModalSheet {
177 [NSApp beginSheet:[self window]
178 modalForWindow:parentWindow_
179 modalDelegate:self
180 didEndSelector:@selector(didEndSheet:returnCode:contextInfo:)
181 contextInfo:nil];
182 }
183
184 - (void)selectNodeInBrowser:(const BookmarkNode*)node {
185 DCHECK(configuration_ == BookmarkEditor::SHOW_TREE);
186 std::deque<NSInteger> rowsToSelect;
187 const BookmarkNode* nodeParent = nil;
188 if (node) {
189 nodeParent = node->GetParent();
190 // There should always be a parent node.
191 DCHECK(nodeParent);
192 while (nodeParent) {
193 int nodeRow = IndexOfFolderChild(node);
194 rowsToSelect.push_front(nodeRow);
195 node = nodeParent;
196 nodeParent = nodeParent->GetParent();
197 }
198 } else {
199 BookmarkModel* model = profile_->GetBookmarkModel();
200 nodeParent = model->GetBookmarkBarNode();
201 rowsToSelect.push_front(0);
202 }
203 for (std::deque<NSInteger>::size_type column = 0;
204 column < rowsToSelect.size();
205 ++column) {
206 [folderBrowser_ selectRow:rowsToSelect[column] inColumn:column];
207 }
208
209 // Force the OK button state to be re-evaluated.
210 [self willChangeValueForKey:@"okEnabled"];
211 [self didChangeValueForKey:@"okEnabled"];
212 }
213
214 - (const BookmarkNode*)selectedNode {
215 BookmarkModel* model = profile_->GetBookmarkModel();
216 const BookmarkNode* selectedNode = NULL;
217 // Determine a new parent node only if the browser is showing.
218 if (configuration_ == BookmarkEditor::SHOW_TREE) {
219 selectedNode = model->root_node();
220 NSInteger column = 0;
221 NSInteger selectedRow = [folderBrowser_ selectedRowInColumn:column];
222 while (selectedRow >= 0) {
223 selectedNode = GetFolderChildForParent(selectedNode,
224 selectedRow);
225 ++column;
226 selectedRow = [folderBrowser_ selectedRowInColumn:column];
227 }
228 } else {
229 // If the tree is not showing then we use the original parent.
230 selectedNode = parentNode_;
231 }
232 return selectedNode;
233 }
234
235 - (void)NotifyHandlerCreatedNode:(const BookmarkNode*)node {
236 if (handler_.get())
237 handler_->NodeCreated(node);
238 }
239
240 #pragma mark New Folder Handler & Folder Cell Editing
241
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 }
253
254 - (void)cellEditingCompleted:(id)sender {
255 DCHECK([sender isKindOfClass:[NSMatrix class]]);
256 BookmarkTreeBrowserCell* cell = [sender selectedCell];
257 DCHECK([cell isKindOfClass:[BookmarkTreeBrowserCell class]]);
258 [self saveFolderNameForCell:cell];
259 }
260
261 - (void)saveFolderNameForCell:(BookmarkTreeBrowserCell*)cell {
262 DCHECK([cell isKindOfClass:[BookmarkTreeBrowserCell class]]);
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 }
279
280 - (void)browserDoubleClicked:(id)sender {
281 BookmarkTreeBrowserCell* cell = [folderBrowser_ selectedCell];
282 DCHECK([cell isKindOfClass:[BookmarkTreeBrowserCell class]]);
283 [self editFolderNameInCell:cell];
284 }
285
286 - (IBAction)newFolder:(id)sender {
287 BookmarkModel* model = profile_->GetBookmarkModel();
288 const BookmarkNode* newParentNode = [self selectedNode];
289 int newIndex = newParentNode->GetChildCount();
290 std::wstring newFolderString =
291 l10n_util::GetString(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME);
292 const BookmarkNode* newFolder = model->AddGroup(newParentNode, newIndex,
293 newFolderString);
294 [self selectNodeInBrowser:newFolder];
295 BookmarkTreeBrowserCell* cell = [folderBrowser_ selectedCell];
296 [self editFolderNameInCell:cell];
297 }
298
299 - (BOOL)okEnabled {
300 return YES;
301 }
302
303 - (IBAction)ok:(id)sender {
304 [NSApp endSheet:[self window]];
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 }
324
325 #pragma mark For Unit Test Use Only
326
327 - (BOOL)okButtonEnabled {
328 return [okButton_ isEnabled];
329 }
330
331 - (void)selectTestNodeInBrowser:(const BookmarkNode*)node {
332 [self selectNodeInBrowser:node];
333 }
334
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
398
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698