| Index: chrome/browser/cocoa/bookmark_editor_controller.mm
|
| ===================================================================
|
| --- chrome/browser/cocoa/bookmark_editor_controller.mm (revision 31168)
|
| +++ chrome/browser/cocoa/bookmark_editor_controller.mm (working copy)
|
| @@ -2,319 +2,69 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| +#import "chrome/browser/cocoa/bookmark_editor_controller.h"
|
| #include "app/l10n_util.h"
|
| -#include "base/logging.h"
|
| -#include "base/mac_util.h"
|
| #include "base/sys_string_conversions.h"
|
| -#include "chrome/browser/bookmarks/bookmark_editor.h"
|
| #include "chrome/browser/bookmarks/bookmark_model.h"
|
| -#include "chrome/browser/profile.h"
|
| -#import "chrome/browser/cocoa/bookmark_tree_browser_cell.h"
|
| -#import "chrome/browser/cocoa/bookmark_editor_controller.h"
|
| -#include "grit/generated_resources.h"
|
|
|
| @interface BookmarkEditorController (Private)
|
|
|
| // Grab the url from the text field and convert.
|
| - (GURL)GURLFromUrlField;
|
|
|
| -// 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;
|
| -
|
| -// 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;
|
| -
|
| -// 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;
|
| -
|
| -// A custom action handler called by the bookmark folder browser when the
|
| -// user has double-clicked on a folder name.
|
| -- (void)browserDoubleClicked:(id)sender;
|
| -
|
| -// 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.
|
| -- (const BookmarkNode*)selectedNode;
|
| -
|
| -// Select/highlight the given node within the browser tree view. If the
|
| -// node is nil then select the bookmark bar.
|
| -- (void)selectNodeInBrowser:(const BookmarkNode*)node;
|
| -
|
| @end
|
|
|
| -// static; implemented for each platform.
|
| -void BookmarkEditor::Show(gfx::NativeWindow parent_hwnd,
|
| - Profile* profile,
|
| - const BookmarkNode* parent,
|
| - const EditDetails& details,
|
| - Configuration configuration,
|
| - Handler* handler) {
|
| - if (details.type == EditDetails::NEW_FOLDER) {
|
| - // TODO(sky): implement this.
|
| - NOTIMPLEMENTED();
|
| - return;
|
| - }
|
| - BookmarkEditorController* controller = [[BookmarkEditorController alloc]
|
| - initWithParentWindow:parent_hwnd
|
| - profile:profile
|
| - parent:parent
|
| - node:details.existing_node
|
| - configuration:configuration
|
| - handler:handler];
|
| - [controller runAsModalSheet];
|
| -}
|
| +@implementation BookmarkEditorController
|
|
|
| -#pragma mark Bookmark TreeNode Helpers
|
| +@synthesize displayURL = displayURL_;
|
|
|
| -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;
|
| ++ (NSSet*)keyPathsForValuesAffectingOkEnabled {
|
| + return [NSSet setWithObject:@"displayURL"];
|
| }
|
|
|
| -// 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 BookmarkEditorController
|
| -
|
| - (id)initWithParentWindow:(NSWindow*)parentWindow
|
| profile:(Profile*)profile
|
| parent:(const BookmarkNode*)parent
|
| node:(const BookmarkNode*)node
|
| configuration:(BookmarkEditor::Configuration)configuration
|
| handler:(BookmarkEditor::Handler*)handler {
|
| - NSString* nibpath = [mac_util::MainAppBundle()
|
| - pathForResource:@"BookmarkEditor"
|
| - ofType:@"nib"];
|
| - if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
|
| - parentWindow_ = parentWindow;
|
| - profile_ = profile;
|
| - parentNode_ = parent;
|
| + if ((self = [super initWithParentWindow:parentWindow
|
| + nibName:@"BookmarkEditor"
|
| + profile:profile
|
| + parent:parent
|
| + configuration:configuration
|
| + handler:handler])) {
|
| // "Add Page..." has no "node" so this may be NULL.
|
| node_ = node;
|
| - configuration_ = configuration;
|
| - handler_.reset(handler);
|
| }
|
| return self;
|
| }
|
|
|
| +- (void)dealloc {
|
| + [displayURL_ release];
|
| + [super dealloc];
|
| +}
|
| +
|
| - (void)awakeFromNib {
|
| // Set text fields to match our bookmark. If the node is NULL we
|
| // arrived here from an "Add Page..." item in a context menu.
|
| if (node_) {
|
| - initialName_.reset([base::SysWideToNSString(node_->GetTitle()) retain]);
|
| + [self setInitialName:base::SysWideToNSString(node_->GetTitle())];
|
| std::string url_string = node_->GetURL().possibly_invalid_spec();
|
| initialUrl_.reset([[NSString stringWithUTF8String:url_string.c_str()]
|
| retain]);
|
| } else {
|
| - initialName_.reset([@"" retain]);
|
| initialUrl_.reset([@"" retain]);
|
| }
|
| - [nameField_ setStringValue:initialName_];
|
| - [urlField_ setStringValue:initialUrl_];
|
| -
|
| - // Get a ping when the URL or name text fields change;
|
| - // trigger an initial ping to set things up.
|
| - [nameField_ setDelegate:self];
|
| - [urlField_ setDelegate:self];
|
| - [self controlTextDidChange:nil];
|
| -
|
| - if (configuration_ != BookmarkEditor::SHOW_TREE) {
|
| - // Remember the NSBrowser's height; we will shrink our frame by that
|
| - // much.
|
| - NSRect frame = [[self window] frame];
|
| - CGFloat browserHeight = [folderBrowser_ frame].size.height;
|
| - frame.size.height -= browserHeight;
|
| - frame.origin.y += browserHeight;
|
| - // Remove the NSBrowser and "new folder" button.
|
| - [folderBrowser_ removeFromSuperview];
|
| - [newFolderButton_ removeFromSuperview];
|
| - // Finally, commit the size change.
|
| - [[self window] setFrame:frame display:YES];
|
| - }
|
| -
|
| - [folderBrowser_ setCellClass:[BookmarkTreeBrowserCell class]];
|
| - [folderBrowser_ setDoubleAction:@selector(browserDoubleClicked:)];
|
| + [self setDisplayURL:initialUrl_];
|
| + [super awakeFromNib];
|
| }
|
|
|
| -- (void)windowDidLoad {
|
| - if (configuration_ == BookmarkEditor::SHOW_TREE) {
|
| - // Find and select the |parent| bookmark node in the folder tree browser.
|
| - [self selectNodeInBrowser:parentNode_];
|
| - }
|
| -}
|
| -
|
| -- (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];
|
| -
|
| - // This is probably unnecessary but it feels cleaner since the
|
| - // delegate of a text field can be automatically registered for
|
| - // notifications.
|
| - [nameField_ setDelegate:nil];
|
| - [urlField_ setDelegate: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
|
| -// that I, the controller, am also the window's delegate.
|
| -- (NSRect)window:(NSWindow*)window willPositionSheet:(NSWindow*)sheet
|
| - usingRect:(NSRect)rect {
|
| - // adjust rect.origin.y to be the bottom of the toolbar
|
| - return rect;
|
| -}
|
| -*/
|
| -
|
| -// TODO(jrg): consider NSModalSession.
|
| -- (void)runAsModalSheet {
|
| - [NSApp beginSheet:[self window]
|
| - modalForWindow:parentWindow_
|
| - modalDelegate:self
|
| - didEndSelector:@selector(didEndSheet:returnCode:contextInfo:)
|
| - 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);
|
| - }
|
| - for (std::deque<NSInteger>::size_type column = 0;
|
| - column < rowsToSelect.size();
|
| - ++column) {
|
| - [folderBrowser_ selectRow:rowsToSelect[column] inColumn:column];
|
| - }
|
| - [self controlTextDidChange:nil];
|
| -}
|
| -
|
| -- (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];
|
| - }
|
| - } else {
|
| - // If the tree is not showing then we use the original parent.
|
| - selectedNode = parentNode_;
|
| - }
|
| - return selectedNode;
|
| -}
|
| -
|
| -#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 wants to complete.
|
| - [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.
|
| - [[folderBrowser_ window] makeFirstResponder:folderBrowser_];
|
| - const BookmarkNode* bookmarkNode = [cell bookmarkNode];
|
| - BookmarkModel* model = profile_->GetBookmarkModel();
|
| - NSString* newTitle = [cell title];
|
| - model->SetTitle(bookmarkNode, base::SysNSStringToWide(newTitle));
|
| -}
|
| -
|
| -- (void)browserDoubleClicked:(id)sender {
|
| - BookmarkTreeBrowserCell* cell = [folderBrowser_ selectedCell];
|
| - DCHECK([cell isKindOfClass:[BookmarkTreeBrowserCell class]]);
|
| - [self editFolderNameInCell:cell];
|
| -}
|
| -
|
| -- (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];
|
| -}
|
| -
|
| #pragma mark Bookmark Editing
|
|
|
| // If possible, return a valid GURL from the URL text field.
|
| - (GURL)GURLFromUrlField {
|
| - NSString* url = [urlField_ stringValue];
|
| + NSString* url = [self displayURL];
|
| GURL newURL = GURL([url UTF8String]);
|
| if (!newURL.is_valid()) {
|
| // Mimic observed friendliness from Windows
|
| @@ -323,25 +73,28 @@
|
| return newURL;
|
| }
|
|
|
| -// Enable the OK button if there is a bookmark name and there is a valid URL.
|
| -// We set ourselves as the delegate of urlField_ so this gets called.
|
| -// (Yes, setting ourself as a delegate automatically registers us for
|
| -// the notification.)
|
| -- (void)controlTextDidChange:(NSNotification*)aNotification {
|
| - GURL newURL = [self GURLFromUrlField];
|
| - [okButton_ setEnabled:(newURL.is_valid()) ? YES : NO];
|
| +// Enable the OK button if there is a valid URL.
|
| +- (BOOL)okEnabled {
|
| + BOOL okEnabled = NO;
|
| + if ([[self displayURL] length]) {
|
| + GURL newURL = [self GURLFromUrlField];
|
| + okEnabled = (newURL.is_valid()) ? YES : NO;
|
| + }
|
| + return okEnabled;
|
| }
|
|
|
| -// The ok: action is connected to the OK button in the Edit Bookmark window
|
| -// of the BookmarkEditor.xib. The the bookmark's name and URL are assumed
|
| -// to be valid (otherwise the OK button 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.
|
| +// The the bookmark's URL is assumed to be valid (otherwise the OK button
|
| +// 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 {
|
| - NSString* name = [nameField_ stringValue];
|
| + NSString* name = [[self displayName] stringByTrimmingCharactersInSet:
|
| + [NSCharacterSet newlineCharacterSet]];
|
| std::wstring newTitle = base::SysNSStringToWide(name);
|
| + const BookmarkNode* newParentNode = [self selectedNode];
|
| + BookmarkModel* model = [self bookmarkModel];
|
| + int newIndex = newParentNode->GetChildCount();
|
| GURL newURL = [self GURLFromUrlField];
|
| if (!newURL.is_valid()) {
|
| // Shouldn't be reached -- OK button disabled if not valid!
|
| @@ -350,115 +103,22 @@
|
| }
|
|
|
| // Determine where the new/replacement bookmark is to go.
|
| - const BookmarkNode* newParentNode = [self selectedNode];
|
| - BookmarkModel* model = profile_->GetBookmarkModel();
|
| - int newIndex = newParentNode->GetChildCount();
|
| - if (node_ && parentNode_) {
|
| + const BookmarkNode* parentNode = [self parentNode];
|
| + if (node_ && parentNode) {
|
| // Replace the old bookmark with the updated bookmark.
|
| - int oldIndex = parentNode_->IndexOfChild(node_);
|
| + int oldIndex = parentNode->IndexOfChild(node_);
|
| if (oldIndex >= 0)
|
| - model->Remove(parentNode_, oldIndex);
|
| - if (parentNode_ == newParentNode)
|
| + model->Remove(parentNode, oldIndex);
|
| + if (parentNode == newParentNode)
|
| newIndex = oldIndex;
|
| }
|
| // Add bookmark as new node at the end of the newly selected folder.
|
| const BookmarkNode* node = model->AddURL(newParentNode, newIndex,
|
| newTitle, newURL);
|
| // Honor handler semantics: callback on node creation.
|
| - if (handler_.get())
|
| - handler_->NodeCreated(node);
|
| - [NSApp endSheet:[self window]];
|
| + [self NotifyHandlerCreatedNode:node];
|
| + [super ok:sender];
|
| }
|
|
|
| -- (IBAction)cancel:(id)sender {
|
| - [NSApp endSheet:[self window]];
|
| -}
|
| -
|
| -- (void)didEndSheet:(NSWindow*)sheet
|
| - returnCode:(int)returnCode
|
| - contextInfo:(void*)contextInfo {
|
| - [sheet close];
|
| -}
|
| -
|
| -#pragma mark For Unit Test Use Only
|
| -
|
| -- (NSString*)displayName {
|
| - return [nameField_ stringValue];
|
| -}
|
| -
|
| -- (NSString*)displayURL {
|
| - return [urlField_ stringValue];
|
| -}
|
| -
|
| -- (void)setDisplayName:(NSString*)name {
|
| - [nameField_ setStringValue:name];
|
| - [self controlTextDidChange:nil];
|
| -}
|
| -
|
| -- (void)setDisplayURL:(NSString*)name {
|
| - [urlField_ setStringValue:name];
|
| - [self controlTextDidChange:nil];
|
| -}
|
| -
|
| -- (BOOL)okButtonEnabled {
|
| - return [okButton_ isEnabled];
|
| -}
|
| -
|
| -- (void)selectTestNodeInBrowser:(const BookmarkNode*)node {
|
| - [self selectNodeInBrowser:node];
|
| -}
|
| -
|
| -#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;
|
| - }
|
| - }
|
| - 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]];
|
| -}
|
| -
|
| @end // BookmarkEditorController
|
|
|
|
|