• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4
5#import "chrome/browser/ui/cocoa/browser/edit_search_engine_cocoa_controller.h"
6
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"
21
22namespace {
23
24void ShiftOriginY(NSView* view, CGFloat amount) {
25  NSPoint origin = [view frame].origin;
26  origin.y += amount;
27  [view setFrameOrigin:origin];
28}
29
30}  // namespace
31
32@implementation EditSearchEngineCocoaController
33
34- (id)initWithProfile:(Profile*)profile
35             delegate:(EditSearchEngineControllerDelegate*)delegate
36          templateURL:(TemplateURL*)url {
37  DCHECK(profile);
38  NSString* nibpath = [base::mac::FrameworkBundle()
39                        pathForResource:@"EditSearchEngine"
40                                 ofType:@"nib"];
41  if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
42    profile_ = profile;
43    templateURL_ = url;
44    controller_.reset(
45        new EditSearchEngineController(templateURL_, delegate, profile_));
46  }
47  return self;
48}
49
50- (void)awakeFromNib {
51  DCHECK([self window]);
52  DCHECK_EQ(self, [[self window] delegate]);
53
54  // Make sure the url description field fits the text in it.
55  CGFloat descriptionShift = [GTMUILocalizerAndLayoutTweaker
56      sizeToFitFixedWidthTextField:urlDescriptionField_];
57
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);
69
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];
77
78  // Resize the window.
79  NSWindow* window = [self window];
80  NSSize windowDelta = NSMakeSize(0, descriptionShift);
81  [GTMUILocalizerAndLayoutTweaker
82      resizeWindowWithoutAutoResizingSubViews:window
83                                        delta:windowDelta];
84
85  if (templateURL_) {
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)];
97  }
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];
102}
103
104// When the window closes, clean ourselves up.
105- (void)windowWillClose:(NSNotification*)notif {
106  [self autorelease];
107}
108
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.
111- (void)doClose {
112  if ([[self window] isSheet]) {
113    [NSApp endSheet:[self window]];
114  } else {
115    [[self window] close];
116  }
117}
118
119- (IBAction)cancel:(id)sender {
120  [self doClose];
121}
122
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);
130  [self doClose];
131}
132
133// Delegate method for the text fields.
134
135- (void)controlTextDidChange:(NSNotification*)notif {
136  [self validateFields];
137}
138
139- (void)controlTextDidEndEditing:(NSNotification*)notif {
140  [self validateFields];
141}
142
143// Private /////////////////////////////////////////////////////////////////////
144
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];
154
155  NSString* toolTip = nil;
156  if (!valid)
157    toolTip = l10n_util::GetNSString(messageID);
158  [textField setToolTip:toolTip];
159  [imageView setToolTip:toolTip];
160}
161
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_];
171
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_];
179
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_];
186
187  BOOL isValid = (titleValid && keywordValid && urlValid);
188  [doneButton_ setEnabled:isValid];
189  return isValid;
190}
191
192@end
193