Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Side by Side Diff: chrome/browser/ui/cocoa/search_engine_dialog_controller.mm

Issue 9285002: Remove the first-run search engine dialog/ballot. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Sync and merge. Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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/search_engine_dialog_controller.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "base/mac/bundle_locations.h"
11 #include "base/mac/mac_util.h"
12 #include "base/message_loop.h"
13 #include "base/sys_string_conversions.h"
14 #include "base/time.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/search_engines/template_url.h"
17 #include "chrome/browser/search_engines/template_url_service.h"
18 #include "chrome/browser/search_engines/template_url_service_factory.h"
19 #include "chrome/browser/search_engines/template_url_service_observer.h"
20 #include "grit/generated_resources.h"
21 #include "grit/theme_resources.h"
22 #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
23 #include "ui/base/l10n/l10n_util_mac.h"
24 #include "ui/base/resource/resource_bundle.h"
25 #include "ui/gfx/image/image.h"
26
27 // Horizontal spacing between search engine choices.
28 const int kSearchEngineSpacing = 20;
29
30 // Vertical spacing between the search engine logo and the button underneath.
31 const int kLogoButtonSpacing = 10;
32
33 // Width of a label used in place of a logo.
34 const int kLogoLabelWidth = 170;
35
36 // Height of a label used in place of a logo.
37 const int kLogoLabelHeight = 25;
38
39 @interface SearchEngineDialogController (Private)
40 - (void)onTemplateURLServiceChanged;
41 - (void)buildSearchEngineView;
42 - (NSView*)viewForSearchEngine:(const TemplateURL*)engine
43 atIndex:(size_t)index;
44 - (IBAction)searchEngineSelected:(id)sender;
45 @end
46
47 class SearchEngineDialogControllerBridge :
48 public base::RefCounted<SearchEngineDialogControllerBridge>,
49 public TemplateURLServiceObserver {
50 public:
51 SearchEngineDialogControllerBridge(SearchEngineDialogController* controller);
52
53 // TemplateURLServiceObserver
54 virtual void OnTemplateURLServiceChanged();
55
56 private:
57 SearchEngineDialogController* controller_;
58 };
59
60 SearchEngineDialogControllerBridge::SearchEngineDialogControllerBridge(
61 SearchEngineDialogController* controller) : controller_(controller) {
62 }
63
64 void SearchEngineDialogControllerBridge::OnTemplateURLServiceChanged() {
65 [controller_ onTemplateURLServiceChanged];
66 MessageLoop::current()->QuitNow();
67 }
68
69 @implementation SearchEngineDialogController
70
71 @synthesize profile = profile_;
72 @synthesize randomize = randomize_;
73
74 - (id)init {
75 NSString* nibpath =
76 [base::mac::FrameworkBundle() pathForResource:@"SearchEngineDialog"
77 ofType:@"nib"];
78 self = [super initWithWindowNibPath:nibpath owner:self];
79 if (self != nil) {
80 bridge_ = new SearchEngineDialogControllerBridge(self);
81 }
82 return self;
83 }
84
85 - (void)dealloc {
86 [super dealloc];
87 }
88
89 - (IBAction)showWindow:(id)sender {
90 searchEnginesModel_ = TemplateURLServiceFactory::GetForProfile(profile_);
91 searchEnginesModel_->AddObserver(bridge_.get());
92
93 if (searchEnginesModel_->loaded()) {
94 MessageLoop::current()->PostTask(FROM_HERE,
95 base::Bind(
96 &SearchEngineDialogControllerBridge::OnTemplateURLServiceChanged,
97 bridge_.get()));
98 } else {
99 searchEnginesModel_->Load();
100 }
101 MessageLoop::current()->Run();
102 }
103
104 - (void)onTemplateURLServiceChanged {
105 searchEnginesModel_->RemoveObserver(bridge_.get());
106
107 // Add the search engines in the search_engines_model_ to the buttons list.
108 // The first three will always be from prepopulated data.
109 std::vector<const TemplateURL*> templateUrls =
110 searchEnginesModel_->GetTemplateURLs();
111
112 // If we have fewer than two search engines, end the search engine dialog
113 // immediately, leaving the imported default search engine setting intact.
114 if (templateUrls.size() < 2) {
115 return;
116 }
117
118 NSWindow* win = [self window];
119
120 [win setBackgroundColor:[NSColor whiteColor]];
121
122 NSImage* headerImage = ResourceBundle::GetSharedInstance().
123 GetNativeImageNamed(IDR_SEARCH_ENGINE_DIALOG_TOP);
124 [headerImageView_ setImage:headerImage];
125
126 // Is the user's default search engine included in the first three
127 // prepopulated set? If not, we need to expand the dialog to include a fourth
128 // engine.
129 const TemplateURL* defaultSearchEngine =
130 searchEnginesModel_->GetDefaultSearchProvider();
131
132 std::vector<const TemplateURL*>::iterator engineIter =
133 templateUrls.begin();
134 for (int i = 0; engineIter != templateUrls.end(); ++i, ++engineIter) {
135 if (i < 3) {
136 choices_.push_back(*engineIter);
137 } else {
138 if (*engineIter == defaultSearchEngine)
139 choices_.push_back(*engineIter);
140 }
141 }
142
143 // Randomize the order of the logos if the option has been set.
144 if (randomize_) {
145 int seed = static_cast<int>(base::Time::Now().ToInternalValue());
146 srand(seed);
147 std::random_shuffle(choices_.begin(), choices_.end());
148 }
149
150 [self buildSearchEngineView];
151
152 // Display the dialog.
153 NSInteger choice = [NSApp runModalForWindow:win];
154 searchEnginesModel_->SetDefaultSearchProvider(choices_.at(choice));
155 }
156
157 - (void)buildSearchEngineView {
158 scoped_nsobject<NSMutableArray> searchEngineViews
159 ([[NSMutableArray alloc] init]);
160
161 for (size_t i = 0; i < choices_.size(); ++i)
162 [searchEngineViews addObject:[self viewForSearchEngine:choices_.at(i)
163 atIndex:i]];
164
165 NSSize newOverallSize = NSZeroSize;
166 for (NSView* view in searchEngineViews.get()) {
167 NSRect engineFrame = [view frame];
168 engineFrame.origin = NSMakePoint(newOverallSize.width, 0);
169 [searchEngineView_ addSubview:view];
170 [view setFrame:engineFrame];
171 newOverallSize = NSMakeSize(
172 newOverallSize.width + NSWidth(engineFrame) + kSearchEngineSpacing,
173 std::max(newOverallSize.height, NSHeight(engineFrame)));
174 }
175 newOverallSize.width -= kSearchEngineSpacing;
176
177 // Resize the window to fit (and because it's bound on all sides it will
178 // resize the search engine view).
179 NSSize currentOverallSize = [searchEngineView_ bounds].size;
180 NSSize deltaSize = NSMakeSize(
181 newOverallSize.width - currentOverallSize.width,
182 newOverallSize.height - currentOverallSize.height);
183 NSSize windowDeltaSize = [searchEngineView_ convertSize:deltaSize toView:nil];
184 NSRect windowFrame = [[self window] frame];
185 windowFrame.size.width += windowDeltaSize.width;
186 windowFrame.size.height += windowDeltaSize.height;
187 [[self window] setFrame:windowFrame display:NO];
188 }
189
190 - (NSView*)viewForSearchEngine:(const TemplateURL*)engine
191 atIndex:(size_t)index {
192 bool useImages = false;
193 #if defined(GOOGLE_CHROME_BUILD)
194 useImages = true;
195 #endif
196
197 // Make the engine identifier.
198 NSView* engineIdentifier = nil; // either the logo or the text label
199
200 int logoId = engine->logo_id();
201 NSString* shortName = SysUTF16ToNSString(engine->short_name());
202 if (useImages && logoId > 0) {
203 NSImage* logoImage =
204 ResourceBundle::GetSharedInstance().GetNativeImageNamed(logoId);
205 NSRect logoBounds = NSZeroRect;
206 logoBounds.size = [logoImage size];
207 NSImageView* logoView =
208 [[[NSImageView alloc] initWithFrame:logoBounds] autorelease];
209 [logoView setImage:logoImage];
210 [logoView setEditable:NO];
211
212 // Tooltip text provides accessibility.
213 [logoView setToolTip:shortName];
214 [logoView accessibilitySetOverrideValue:shortName
215 forAttribute:NSAccessibilityDescriptionAttribute];
216 engineIdentifier = logoView;
217 } else {
218 // No logo -- we must show a text label.
219 NSRect labelBounds = NSMakeRect(0, 0, kLogoLabelWidth, kLogoLabelHeight);
220 NSTextField* labelField =
221 [[[NSTextField alloc] initWithFrame:labelBounds] autorelease];
222 [labelField setBezeled:NO];
223 [labelField setEditable:NO];
224 [labelField setSelectable:NO];
225
226 scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
227 [[NSMutableParagraphStyle alloc] init]);
228 [paragraphStyle setAlignment:NSCenterTextAlignment];
229 NSDictionary* attrs = [NSDictionary dictionaryWithObjectsAndKeys:
230 [NSFont boldSystemFontOfSize:13], NSFontAttributeName,
231 paragraphStyle.get(), NSParagraphStyleAttributeName,
232 nil];
233
234 scoped_nsobject<NSAttributedString> attrValue(
235 [[NSAttributedString alloc] initWithString:shortName
236 attributes:attrs]);
237
238 [labelField setAttributedStringValue:attrValue.get()];
239
240 engineIdentifier = labelField;
241 }
242
243 // Make the "Choose" button.
244 scoped_nsobject<NSButton> chooseButton(
245 [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 34)]);
246 [chooseButton setBezelStyle:NSRoundedBezelStyle];
247 [[chooseButton cell] setFont:[NSFont systemFontOfSize:
248 [NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
249 [chooseButton setTitle:l10n_util::GetNSStringWithFixup(IDS_FR_SEARCH_CHOOSE)];
250 [GTMUILocalizerAndLayoutTweaker sizeToFitView:chooseButton.get()];
251 [chooseButton setTag:index];
252 [chooseButton setTarget:self];
253 [chooseButton setAction:@selector(searchEngineSelected:)];
254
255 // Provide a more descriptive accessibility description.
256 id accElement = NSAccessibilityUnignoredDescendant(engineIdentifier);
257 [[chooseButton cell] accessibilitySetOverrideValue:accElement
258 forAttribute:NSAccessibilityTitleUIElementAttribute];
259
260 // Put 'em together.
261 NSRect engineIdentifierFrame = [engineIdentifier frame];
262 NSRect chooseButtonFrame = [chooseButton frame];
263
264 NSRect containingViewFrame = NSZeroRect;
265 containingViewFrame.size.width += engineIdentifierFrame.size.width;
266 containingViewFrame.size.height += engineIdentifierFrame.size.height;
267 containingViewFrame.size.height += kLogoButtonSpacing;
268 containingViewFrame.size.height += chooseButtonFrame.size.height;
269
270 NSView* containingView =
271 [[[NSView alloc] initWithFrame:containingViewFrame] autorelease];
272
273 [containingView addSubview:engineIdentifier];
274 engineIdentifierFrame.origin.y =
275 chooseButtonFrame.size.height + kLogoButtonSpacing;
276 [engineIdentifier setFrame:engineIdentifierFrame];
277
278 [containingView addSubview:chooseButton];
279 chooseButtonFrame.origin.x =
280 int((containingViewFrame.size.width - chooseButtonFrame.size.width) / 2);
281 [chooseButton setFrame:chooseButtonFrame];
282
283 return containingView;
284 }
285
286 - (NSFont*)mainLabelFont {
287 return [NSFont boldSystemFontOfSize:13];
288 }
289
290 - (IBAction)searchEngineSelected:(id)sender {
291 [[self window] close];
292 [NSApp stopModalWithCode:[sender tag]];
293 }
294
295 @end
OLDNEW
« no previous file with comments | « chrome/browser/ui/cocoa/search_engine_dialog_controller.h ('k') | chrome/browser/ui/gtk/first_run_dialog.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698