// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #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_editor_controller.h" // static; implemented for each platform. void BookmarkEditor::Show(gfx::NativeWindow parent_hwnd, Profile* profile, const BookmarkNode* parent, const BookmarkNode* node, Configuration configuration, Handler* handler) { BookmarkEditorController* controller = [[BookmarkEditorController alloc] initWithParentWindow:parent_hwnd profile:profile parent:parent node:node configuration:configuration handler:handler]; [controller runAsModalSheet]; } @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; // "Add Page..." has no "node" so this may be NULL. node_ = node; configuration_ = configuration; handler_.reset(handler); } return self; } - (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]); 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) { // build the tree et al NOTIMPLEMENTED(); } else { // Remember the NSBrowser's height; we will shrink our frame by that // much. NSRect frame = [[self window] frame]; CGFloat browserHeight = [browser_ frame].size.height; frame.size.height -= browserHeight; frame.origin.y += browserHeight; // Remove the NSBrowser and "new folder" button. [browser_ removeFromSuperview]; [newFolderButton_ removeFromSuperview]; // Finally, commit the size change. [[self window] setFrame:frame display:YES]; } } /* 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]; } // TODO(jrg) - (IBAction)newFolder:(id)sender { NOTIMPLEMENTED(); } - (IBAction)cancel:(id)sender { [NSApp endSheet:[self window]]; } // If possible, return a valid GURL from the URL text field. - (GURL)GURLFromUrlField { NSString *url = [urlField_ stringValue]; GURL newURL = GURL([url UTF8String]); if (!newURL.is_valid()) { // Mimic observed friendliness from Windows newURL = GURL([[NSString stringWithFormat:@"http://%@", url] UTF8String]); } return newURL; } // When the URL changes we may enable or disable the OK button. // 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]; NSString* name = [nameField_ stringValue]; // if empty or only whitespace, name is not valid. bool name_valid = true; if (([name length] == 0) || ([[name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0)) { name_valid = false; } if (newURL.is_valid() && name_valid) { [okButton_ setEnabled:YES]; } else { [okButton_ setEnabled:NO]; } } // TODO(jrg): Once the tree is available edits may be more extensive // than just name/url. - (IBAction)ok:(id)sender { NSString *name = [nameField_ stringValue]; NSString *url = [urlField_ stringValue]; if ((![name isEqual:initialName_]) || (![url isEqual:initialUrl_])) { std::wstring newTitle = base::SysNSStringToWide(name); GURL newURL = [self GURLFromUrlField]; if (!newURL.is_valid()) { // Shouldn't be reached -- OK button disabled if not valid! NOTREACHED(); return; } int index = 0; BookmarkModel* model = profile_->GetBookmarkModel(); if (node_) { index = parentNode_->IndexOfChild(node_); model->Remove(parentNode_, index); } else { index = parentNode_->GetChildCount(); } const BookmarkNode* node = model->AddURL(parentNode_, index, newTitle, newURL); // Honor handler semantics: callback on node creation if (handler_.get()) handler_->NodeCreated(node); } [NSApp endSheet:[self window]]; } - (void)didEndSheet:(NSWindow*)sheet returnCode:(int)returnCode contextInfo:(void*)contextInfo { // 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 window] orderOut:self]; // BookmarkEditor::Show() will create us then run away. Unusually // for a controller, we are responsible for deallocating ourself. [self autorelease]; } - (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]; } @end // BookmarkEditorController