Index: chrome/browser/cocoa/search_engine_dialog_controller.mm |
=================================================================== |
--- chrome/browser/cocoa/search_engine_dialog_controller.mm (revision 0) |
+++ chrome/browser/cocoa/search_engine_dialog_controller.mm (revision 0) |
@@ -0,0 +1,279 @@ |
+// Copyright (c) 2010 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/search_engine_dialog_controller.h" |
+ |
+#include <algorithm> |
+ |
+#include "app/l10n_util_mac.h" |
+#include "app/resource_bundle.h" |
+#include "base/mac_util.h" |
+#include "base/nsimage_cache_mac.h" |
+#include "base/sys_string_conversions.h" |
+#include "base/time.h" |
+#include "chrome/browser/profile.h" |
+#include "chrome/browser/search_engines/template_url.h" |
+#include "chrome/browser/search_engines/template_url_model.h" |
+#include "chrome/browser/search_engines/template_url_model_observer.h" |
+#include "grit/generated_resources.h" |
+#include "grit/theme_resources.h" |
+#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" |
+ |
+// Horizontal spacing between search engine choices. |
+const int kSearchEngineSpacing = 20; |
+ |
+// Vertical spacing between the search engine logo and the button underneath. |
+const int kLogoButtonSpacing = 10; |
+ |
+// Width of a label used in place of a logo. |
+const int kLogoLabelWidth = 170; |
+ |
+// Height of a label used in place of a logo. |
+const int kLogoLabelHeight = 25; |
+ |
+@interface SearchEngineDialogController (Private) |
+- (void)onTemplateURLModelChanged; |
+- (void)buildSearchEngineView; |
+- (NSView*)viewForSearchEngine:(const TemplateURL*)engine |
+ atIndex:(size_t)index; |
+- (IBAction)searchEngineSelected:(id)sender; |
+@end |
+ |
+class SearchEngineDialogControllerBridge : public TemplateURLModelObserver { |
+ public: |
+ SearchEngineDialogControllerBridge(SearchEngineDialogController* controller); |
+ |
+ // TemplateURLModelObserver |
+ virtual void OnTemplateURLModelChanged(); |
+ |
+ private: |
+ SearchEngineDialogController* controller_; |
+}; |
+ |
+SearchEngineDialogControllerBridge::SearchEngineDialogControllerBridge( |
+ SearchEngineDialogController* controller) : controller_(controller) { |
+} |
+ |
+void SearchEngineDialogControllerBridge::OnTemplateURLModelChanged() { |
+ [controller_ onTemplateURLModelChanged]; |
+ MessageLoop::current()->QuitNow(); |
+} |
+ |
+@implementation SearchEngineDialogController |
+ |
+@synthesize profile = profile_; |
+@synthesize randomize = randomize_; |
+ |
+- (id)init { |
+ NSString* nibpath = |
+ [mac_util::MainAppBundle() pathForResource:@"SearchEngineDialog" |
+ ofType:@"nib"]; |
+ self = [super initWithWindowNibPath:nibpath owner:self]; |
+ if (self != nil) { |
+ bridge_.reset(new SearchEngineDialogControllerBridge(self)); |
+ } |
+ return self; |
+} |
+ |
+- (void)dealloc { |
+ [super dealloc]; |
+} |
+ |
+- (IBAction)showWindow:(id)sender { |
+ searchEnginesModel_ = profile_->GetTemplateURLModel(); |
+ searchEnginesModel_->AddObserver(bridge_.get()); |
+ |
+ if (searchEnginesModel_->loaded()) { |
+ [self onTemplateURLModelChanged]; |
+ } else { |
+ searchEnginesModel_->Load(); |
+ MessageLoop::current()->Run(); |
+ } |
+} |
+ |
+- (void)onTemplateURLModelChanged { |
+ searchEnginesModel_->RemoveObserver(bridge_.get()); |
+ |
+ // Add the search engines in the search_engines_model_ to the buttons list. |
+ // The first three will always be from prepopulated data. |
+ std::vector<const TemplateURL*> templateUrls = |
+ searchEnginesModel_->GetTemplateURLs(); |
+ |
+ // If we have fewer than two search engines, end the search engine dialog |
+ // immediately, leaving the imported default search engine setting intact. |
+ if (templateUrls.size() < 2) { |
+ return; |
+ } |
+ |
+ NSWindow* win = [self window]; |
+ |
+ [win setBackgroundColor:[NSColor whiteColor]]; |
+ |
+ NSImage* headerImage = ResourceBundle::GetSharedInstance(). |
+ GetNSImageNamed(IDR_SEARCH_ENGINE_DIALOG_TOP); |
+ [headerImageView_ setImage:headerImage]; |
+ |
+ // Is the user's default search engine included in the first three |
+ // prepopulated set? If not, we need to expand the dialog to include a fourth |
+ // engine. |
+ const TemplateURL* defaultSearchEngine = |
+ searchEnginesModel_->GetDefaultSearchProvider(); |
+ |
+ std::vector<const TemplateURL*>::iterator engineIter = |
+ templateUrls.begin(); |
+ for (int i = 0; engineIter != templateUrls.end(); ++i, ++engineIter) { |
+ if (i < 3) { |
+ choices_.push_back(*engineIter); |
+ } else { |
+ if (*engineIter == defaultSearchEngine) |
+ choices_.push_back(*engineIter); |
+ } |
+ } |
+ |
+ // Randomize the order of the logos if the option has been set. |
+ if (randomize_) { |
+ int seed = static_cast<int>(base::Time::Now().ToInternalValue()); |
+ srand(seed); |
+ std::random_shuffle(choices_.begin(), choices_.end()); |
+ } |
+ |
+ [self buildSearchEngineView]; |
+ |
+ // Display the dialog. |
+ NSInteger choice = [NSApp runModalForWindow:win]; |
+ searchEnginesModel_->SetDefaultSearchProvider(choices_.at(choice)); |
+} |
+ |
+- (void)buildSearchEngineView { |
+ scoped_nsobject<NSMutableArray> searchEngineViews |
+ ([[NSMutableArray alloc] init]); |
+ |
+ for (size_t i = 0; i < choices_.size(); ++i) |
+ [searchEngineViews addObject:[self viewForSearchEngine:choices_.at(i) |
+ atIndex:i]]; |
+ |
+ NSSize newOverallSize = NSZeroSize; |
+ for (NSView* view in searchEngineViews.get()) { |
+ NSRect engineFrame = [view frame]; |
+ engineFrame.origin = NSMakePoint(newOverallSize.width, 0); |
+ [searchEngineView_ addSubview:view]; |
+ [view setFrame:engineFrame]; |
+ newOverallSize = NSMakeSize( |
+ newOverallSize.width + NSWidth(engineFrame) + kSearchEngineSpacing, |
+ std::max(newOverallSize.height, NSHeight(engineFrame))); |
+ } |
+ newOverallSize.width -= kSearchEngineSpacing; |
+ |
+ // Resize the window to fit (and because it's bound on all sides it will |
+ // resize the search engine view). |
+ NSSize currentOverallSize = [searchEngineView_ bounds].size; |
+ NSSize deltaSize = NSMakeSize( |
+ newOverallSize.width - currentOverallSize.width, |
+ newOverallSize.height - currentOverallSize.height); |
+ NSSize windowDeltaSize = [searchEngineView_ convertSize:deltaSize toView:nil]; |
+ NSRect windowFrame = [[self window] frame]; |
+ windowFrame.size.width += windowDeltaSize.width; |
+ windowFrame.size.height += windowDeltaSize.height; |
+ [[self window] setFrame:windowFrame display:NO]; |
+} |
+ |
+- (NSView*)viewForSearchEngine:(const TemplateURL*)engine |
+ atIndex:(size_t)index { |
+ bool useImages = false; |
+#if defined(GOOGLE_CHROME_BUILD) |
+ useImages = true; |
+#endif |
+ |
+ // Make the engine identifier. |
+ NSView* engineIdentifier = nil; // either the logo or the text label |
+ |
+ int logoId = engine->logo_id(); |
+ if (useImages && logoId > 0) { |
+ NSImage* logoImage = |
+ ResourceBundle::GetSharedInstance().GetNSImageNamed(logoId); |
+ NSRect logoBounds = NSZeroRect; |
+ logoBounds.size = [logoImage size]; |
+ NSImageView* logoView = |
+ [[[NSImageView alloc] initWithFrame:logoBounds] autorelease]; |
+ [logoView setImage:logoImage]; |
+ [logoView setEditable:NO]; |
+ |
+ // Tooltip text provides accessibility. |
+ [logoView setToolTip:base::SysWideToNSString(engine->short_name())]; |
+ engineIdentifier = logoView; |
+ } else { |
+ // No logo -- we must show a text label. |
+ NSRect labelBounds = NSMakeRect(0, 0, kLogoLabelWidth, kLogoLabelHeight); |
+ NSTextField* labelField = |
+ [[[NSTextField alloc] initWithFrame:labelBounds] autorelease]; |
+ [labelField setBezeled:NO]; |
+ [labelField setEditable:NO]; |
+ [labelField setSelectable:NO]; |
+ |
+ scoped_nsobject<NSMutableParagraphStyle> paragraphStyle( |
+ [[NSMutableParagraphStyle alloc] init]); |
+ [paragraphStyle setAlignment:NSCenterTextAlignment]; |
+ NSDictionary* attrs = [NSDictionary dictionaryWithObjectsAndKeys: |
+ [NSFont boldSystemFontOfSize:13], NSFontAttributeName, |
+ paragraphStyle.get(), NSParagraphStyleAttributeName, |
+ nil]; |
+ |
+ NSString* value = base::SysWideToNSString(engine->short_name()); |
+ scoped_nsobject<NSAttributedString> attrValue( |
+ [[NSAttributedString alloc] initWithString:value |
+ attributes:attrs]); |
+ |
+ [labelField setAttributedStringValue:attrValue.get()]; |
+ |
+ engineIdentifier = labelField; |
+ } |
+ |
+ // Make the "Choose" button. |
+ scoped_nsobject<NSButton> chooseButton( |
+ [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 34)]); |
+ [chooseButton setBezelStyle:NSRoundedBezelStyle]; |
+ [[chooseButton cell] setFont:[NSFont systemFontOfSize: |
+ [NSFont systemFontSizeForControlSize:NSRegularControlSize]]]; |
+ [chooseButton setTitle:l10n_util::GetNSStringWithFixup(IDS_FR_SEARCH_CHOOSE)]; |
+ [GTMUILocalizerAndLayoutTweaker sizeToFitView:chooseButton.get()]; |
+ [chooseButton setTag:index]; |
+ [chooseButton setTarget:self]; |
+ [chooseButton setAction:@selector(searchEngineSelected:)]; |
+ |
+ // Put 'em together. |
+ NSRect engineIdentifierFrame = [engineIdentifier frame]; |
+ NSRect chooseButtonFrame = [chooseButton frame]; |
+ |
+ NSRect containingViewFrame = NSZeroRect; |
+ containingViewFrame.size.width += engineIdentifierFrame.size.width; |
+ containingViewFrame.size.height += engineIdentifierFrame.size.height; |
+ containingViewFrame.size.height += kLogoButtonSpacing; |
+ containingViewFrame.size.height += chooseButtonFrame.size.height; |
+ |
+ NSView* containingView = |
+ [[[NSView alloc] initWithFrame:containingViewFrame] autorelease]; |
+ |
+ [containingView addSubview:engineIdentifier]; |
+ engineIdentifierFrame.origin.y = |
+ chooseButtonFrame.size.height + kLogoButtonSpacing; |
+ [engineIdentifier setFrame:engineIdentifierFrame]; |
+ |
+ [containingView addSubview:chooseButton]; |
+ chooseButtonFrame.origin.x = |
+ int((containingViewFrame.size.width - chooseButtonFrame.size.width) / 2); |
+ [chooseButton setFrame:chooseButtonFrame]; |
+ |
+ return containingView; |
+} |
+ |
+- (NSFont*)mainLabelFont { |
+ return [NSFont boldSystemFontOfSize:13]; |
+} |
+ |
+- (IBAction)searchEngineSelected:(id)sender { |
+ [[self window] close]; |
+ [NSApp stopModalWithCode:[sender tag]]; |
+} |
+ |
+@end |
Property changes on: chrome/browser/cocoa/search_engine_dialog_controller.mm |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |