// 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. #import "chrome/browser/cocoa/edit_search_engine_cocoa_controller.h" #include "app/l10n_util_mac.h" #include "app/resource_bundle.h" #import "base/mac_util.h" #include "base/sys_string_conversions.h" #include "chrome/browser/search_engines/template_url_model.h" #include "grit/app_resources.h" #include "grit/generated_resources.h" #include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" namespace { void ShiftOriginY(NSView* view, CGFloat amount) { NSPoint origin = [view frame].origin; origin.y += amount; [view setFrameOrigin:origin]; } } // namespace @implementation EditSearchEngineCocoaController - (id)initWithProfile:(Profile*)profile delegate:(EditSearchEngineControllerDelegate*)delegate templateURL:(const TemplateURL*)url { DCHECK(profile); NSString* nibpath = [mac_util::MainAppBundle() pathForResource:@"EditSearchEngine" ofType:@"nib"]; if ((self = [super initWithWindowNibPath:nibpath owner:self])) { profile_ = profile; templateURL_ = url; controller_.reset( new EditSearchEngineController(templateURL_, delegate, profile_)); } return self; } - (void)awakeFromNib { DCHECK([self window]); DCHECK_EQ(self, [[self window] delegate]); // Make sure the url description field fits the text in it. CGFloat descriptionShift = [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:urlDescriptionField_]; // Move the label container above the url description. ShiftOriginY(labelContainer_, descriptionShift); // There was no way via view containment to use a helper view to move all // the textfields and images at once, most move them all on their own so // they stay above the url description. ShiftOriginY(nameField_, descriptionShift); ShiftOriginY(keywordField_, descriptionShift); ShiftOriginY(urlField_, descriptionShift); ShiftOriginY(nameImage_, descriptionShift); ShiftOriginY(keywordImage_, descriptionShift); ShiftOriginY(urlImage_, descriptionShift); // Resize the containing box for the name/keyword/url fields/images since it // also contains the url description (which just grew). [[fieldAndImageContainer_ contentView] setAutoresizesSubviews:NO]; NSRect rect = [fieldAndImageContainer_ frame]; rect.size.height += descriptionShift; [fieldAndImageContainer_ setFrame:rect]; [[fieldAndImageContainer_ contentView] setAutoresizesSubviews:YES]; // Resize the window. NSWindow* window = [self window]; NSSize windowDelta = NSMakeSize(0, descriptionShift); [GTMUILocalizerAndLayoutTweaker resizeWindowWithoutAutoResizingSubViews:window delta:windowDelta]; ResourceBundle& bundle = ResourceBundle::GetSharedInstance(); goodImage_.reset([bundle.GetNSImageNamed(IDR_INPUT_GOOD) retain]); badImage_.reset([bundle.GetNSImageNamed(IDR_INPUT_ALERT) retain]); if (templateURL_) { // Defaults to |..._NEW_WINDOW_TITLE|. [window setTitle:l10n_util::GetNSString( IDS_SEARCH_ENGINES_EDITOR_EDIT_WINDOW_TITLE)]; [nameField_ setStringValue: base::SysWideToNSString(templateURL_->short_name())]; [keywordField_ setStringValue: base::SysWideToNSString(templateURL_->keyword())]; [urlField_ setStringValue: base::SysWideToNSString(templateURL_->url()->DisplayURL())]; [urlField_ setEnabled:(templateURL_->prepopulate_id() == 0)]; } // When creating a new keyword, this will mark the fields as "invalid" and // will not let the user save. If this is an edit, then this will set all // the images to the "valid" state. [self validateFields]; } // When the window closes, clean ourselves up. - (void)windowWillClose:(NSNotification*)notif { [self autorelease]; } // Performs the logic of closing the window. If we are a sheet, then it ends the // modal session; otherwise, it closes the window. - (void)doClose { if ([[self window] isSheet]) { [NSApp endSheet:[self window]]; } else { [[self window] close]; } } - (IBAction)cancel:(id)sender { [self doClose]; } - (IBAction)save:(id)sender { DCHECK([self validateFields]); std::wstring title = base::SysNSStringToWide([nameField_ stringValue]); std::wstring keyword = base::SysNSStringToWide([keywordField_ stringValue]); std::wstring url = base::SysNSStringToWide([urlField_ stringValue]); controller_->AcceptAddOrEdit(title, keyword, url); [self doClose]; } // Delegate method for the text fields. - (void)controlTextDidChange:(NSNotification*)notif { [self validateFields]; } - (void)controlTextDidEndEditing:(NSNotification*)notif { [self validateFields]; } // Private -------------------------------------------------------------------- // Sets the appropriate image and tooltip based on a boolean |valid|. - (void)setIsValid:(BOOL)valid toolTip:(int)messageID forImageView:(NSImageView*)imageView textField:(NSTextField*)textField { NSImage* image = (valid) ? goodImage_ : badImage_; [imageView setImage:image]; NSString* toolTip = nil; if (!valid) toolTip = l10n_util::GetNSString(messageID); [textField setToolTip:toolTip]; [imageView setToolTip:toolTip]; } // This sets the image state for all the controls and enables or disables the // done button. Returns YES if all the fields are valid. - (BOOL)validateFields { std::wstring title = base::SysNSStringToWide([nameField_ stringValue]); BOOL titleValid = controller_->IsTitleValid(title); [self setIsValid:titleValid toolTip:IDS_SEARCH_ENGINES_INVALID_TITLE_TT forImageView:nameImage_ textField:nameField_]; std::wstring keyword = base::SysNSStringToWide([keywordField_ stringValue]); BOOL keywordValid = controller_->IsKeywordValid(keyword); [self setIsValid:keywordValid toolTip:IDS_SEARCH_ENGINES_INVALID_KEYWORD_TT forImageView:keywordImage_ textField:keywordField_]; std::wstring url = base::SysNSStringToWide([urlField_ stringValue]); BOOL urlValid = controller_->IsURLValid(url); [self setIsValid:urlValid toolTip:IDS_SEARCH_ENGINES_INVALID_URL_TT forImageView:urlImage_ textField:urlField_]; BOOL isValid = (titleValid && keywordValid && urlValid); [doneButton_ setEnabled:isValid]; return isValid; } @end