1 // Copyright (c) 2012 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.
5 #import "chrome/browser/ui/cocoa/browser/edit_search_engine_cocoa_controller.h"
7 #include "base/logging.h"
8 #include "base/mac/bundle_locations.h"
9 #import "base/mac/mac_util.h"
10 #include "base/strings/string16.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "chrome/browser/search_engines/template_url.h"
13 #include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
14 #include "grit/generated_resources.h"
15 #include "grit/theme_resources.h"
16 #include "grit/ui_resources.h"
17 #include "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
18 #include "ui/base/l10n/l10n_util_mac.h"
19 #include "ui/base/resource/resource_bundle.h"
20 #include "ui/gfx/image/image.h"
24 void ShiftOriginY(NSView* view, CGFloat amount) {
25 NSPoint origin = [view frame].origin;
27 [view setFrameOrigin:origin];
32 @implementation EditSearchEngineCocoaController
34 - (id)initWithProfile:(Profile*)profile
35 delegate:(EditSearchEngineControllerDelegate*)delegate
36 templateURL:(TemplateURL*)url {
38 NSString* nibpath = [base::mac::FrameworkBundle()
39 pathForResource:@"EditSearchEngine"
41 if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
45 new EditSearchEngineController(templateURL_, delegate, profile_));
50 - (void)awakeFromNib {
51 DCHECK([self window]);
52 DCHECK_EQ(self, [[self window] delegate]);
54 // Make sure the url description field fits the text in it.
55 CGFloat descriptionShift = [GTMUILocalizerAndLayoutTweaker
56 sizeToFitFixedWidthTextField:urlDescriptionField_];
58 // Move the label container above the url description.
59 ShiftOriginY(labelContainer_, descriptionShift);
60 // There was no way via view containment to use a helper view to move all
61 // the textfields and images at once, most move them all on their own so
62 // they stay above the url description.
63 ShiftOriginY(nameField_, descriptionShift);
64 ShiftOriginY(keywordField_, descriptionShift);
65 ShiftOriginY(urlField_, descriptionShift);
66 ShiftOriginY(nameImage_, descriptionShift);
67 ShiftOriginY(keywordImage_, descriptionShift);
68 ShiftOriginY(urlImage_, descriptionShift);
70 // Resize the containing box for the name/keyword/url fields/images since it
71 // also contains the url description (which just grew).
72 [[fieldAndImageContainer_ contentView] setAutoresizesSubviews:NO];
73 NSRect rect = [fieldAndImageContainer_ frame];
74 rect.size.height += descriptionShift;
75 [fieldAndImageContainer_ setFrame:rect];
76 [[fieldAndImageContainer_ contentView] setAutoresizesSubviews:YES];
79 NSWindow* window = [self window];
80 NSSize windowDelta = NSMakeSize(0, descriptionShift);
81 [GTMUILocalizerAndLayoutTweaker
82 resizeWindowWithoutAutoResizingSubViews:window
86 // Defaults to |..._NEW_WINDOW_TITLE|.
87 [window setTitle:l10n_util::GetNSString(
88 IDS_SEARCH_ENGINES_EDITOR_EDIT_WINDOW_TITLE)];
89 [nameField_ setStringValue:
90 base::SysUTF16ToNSString(templateURL_->short_name())];
91 [keywordField_ setStringValue:
92 base::SysUTF16ToNSString(templateURL_->keyword())];
93 [urlField_ setStringValue:
94 base::SysUTF16ToNSString(templateURL_->url_ref().DisplayURL(
95 UIThreadSearchTermsData(profile_)))];
96 [urlField_ setEnabled:(templateURL_->prepopulate_id() == 0)];
98 // When creating a new keyword, this will mark the fields as "invalid" and
99 // will not let the user save. If this is an edit, then this will set all
100 // the images to the "valid" state.
101 [self validateFields];
104 // When the window closes, clean ourselves up.
105 - (void)windowWillClose:(NSNotification*)notif {
109 // Performs the logic of closing the window. If we are a sheet, then it ends the
110 // modal session; otherwise, it closes the window.
112 if ([[self window] isSheet]) {
113 [NSApp endSheet:[self window]];
115 [[self window] close];
119 - (IBAction)cancel:(id)sender {
123 - (IBAction)save:(id)sender {
124 DCHECK([self validateFields]);
125 base::string16 title = base::SysNSStringToUTF16([nameField_ stringValue]);
126 base::string16 keyword =
127 base::SysNSStringToUTF16([keywordField_ stringValue]);
128 std::string url = base::SysNSStringToUTF8([urlField_ stringValue]);
129 controller_->AcceptAddOrEdit(title, keyword, url);
133 // Delegate method for the text fields.
135 - (void)controlTextDidChange:(NSNotification*)notif {
136 [self validateFields];
139 - (void)controlTextDidEndEditing:(NSNotification*)notif {
140 [self validateFields];
143 // Private /////////////////////////////////////////////////////////////////////
145 // Sets the appropriate image and tooltip based on a boolean |valid|.
146 - (void)setIsValid:(BOOL)valid
147 toolTip:(int)messageID
148 forImageView:(NSImageView*)imageView
149 textField:(NSTextField*)textField {
150 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
151 NSImage* image = valid ? rb.GetNativeImageNamed(IDR_INPUT_GOOD).ToNSImage()
152 : rb.GetNativeImageNamed(IDR_INPUT_ALERT).ToNSImage();
153 [imageView setImage:image];
155 NSString* toolTip = nil;
157 toolTip = l10n_util::GetNSString(messageID);
158 [textField setToolTip:toolTip];
159 [imageView setToolTip:toolTip];
162 // This sets the image state for all the controls and enables or disables the
163 // done button. Returns YES if all the fields are valid.
164 - (BOOL)validateFields {
165 base::string16 title = base::SysNSStringToUTF16([nameField_ stringValue]);
166 BOOL titleValid = controller_->IsTitleValid(title);
167 [self setIsValid:titleValid
168 toolTip:IDS_SEARCH_ENGINES_INVALID_TITLE_TT
169 forImageView:nameImage_
170 textField:nameField_];
172 base::string16 keyword =
173 base::SysNSStringToUTF16([keywordField_ stringValue]);
174 BOOL keywordValid = controller_->IsKeywordValid(keyword);
175 [self setIsValid:keywordValid
176 toolTip:IDS_SEARCH_ENGINES_INVALID_KEYWORD_TT
177 forImageView:keywordImage_
178 textField:keywordField_];
180 std::string url = base::SysNSStringToUTF8([urlField_ stringValue]);
181 BOOL urlValid = controller_->IsURLValid(url);
182 [self setIsValid:urlValid
183 toolTip:IDS_SEARCH_ENGINES_INVALID_URL_TT
184 forImageView:urlImage_
185 textField:urlField_];
187 BOOL isValid = (titleValid && keywordValid && urlValid);
188 [doneButton_ setEnabled:isValid];