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

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

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

Powered by Google App Engine
This is Rietveld 408576698