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 #include "chrome/browser/ui/views/default_search_view.h" 6 7 #include <string> 8 9 #include "base/utf_string_conversions.h" 10 #include "chrome/browser/profiles/profile.h" 11 #include "chrome/browser/search_engines/template_url.h" 12 #include "chrome/browser/search_engines/template_url_model.h" 13 #include "chrome/browser/search_engines/template_url_prepopulate_data.h" 14 #include "content/browser/tab_contents/tab_contents.h" 15 #include "grit/generated_resources.h" 16 #include "grit/locale_settings.h" 17 #include "grit/theme_resources.h" 18 #include "ui/base/message_box_flags.h" 19 #include "ui/base/l10n/l10n_util.h" 20 #include "ui/base/resource/resource_bundle.h" 21 #include "ui/gfx/canvas.h" 22 #include "views/controls/button/native_button.h" 23 #include "views/controls/image_view.h" 24 #include "views/controls/label.h" 25 #include "views/layout/grid_layout.h" 26 #include "views/layout/layout_constants.h" 27 #include "views/window/dialog_client_view.h" 28 #include "views/window/window.h" 29 30 namespace { 31 32 // Returns a short name and logo resource id for the given host. 33 void GetShortNameAndLogoId(PrefService* prefs, 34 const TemplateURL* turl, 35 std::wstring* short_name, 36 int* logo_id) { 37 DCHECK(prefs); 38 DCHECK(turl); 39 DCHECK(short_name); 40 DCHECK(logo_id); 41 42 GURL url = TemplateURLModel::GenerateSearchURL(turl); 43 scoped_ptr<TemplateURL> built_in_data( 44 TemplateURLPrepopulateData::GetEngineForOrigin(prefs, url)); 45 46 // Use the built-in information to generate the short name (to ensure 47 // that we don't use a name given by the search engine to itself which 48 // in the worst case could be misleading). 49 if (built_in_data.get()) { 50 *short_name = built_in_data->short_name(); 51 *logo_id = built_in_data->logo_id(); 52 } else { 53 *short_name = UTF8ToWide(url.host()).c_str(); 54 *logo_id = kNoSearchEngineLogo; 55 } 56 } 57 58 views::Label* CreateProviderLabel(int message_id) { 59 views::Label* choice_label = 60 new views::Label(UTF16ToWide(l10n_util::GetStringUTF16(message_id))); 61 choice_label->SetColor(SK_ColorBLACK); 62 choice_label->SetFont( 63 choice_label->font().DeriveFont(1, gfx::Font::NORMAL)); 64 return choice_label; 65 } 66 67 views::View* CreateProviderLogo( 68 int logo_id, 69 const std::wstring& short_name) { 70 views::View* logo_view = NULL; 71 72 // The width for the "logo" element when text is displayed. 73 const int kTextLogoWidth = 132; 74 75 bool use_images = false; 76 #if defined(GOOGLE_CHROME_BUILD) 77 use_images = true; 78 #endif 79 80 if (use_images && logo_id != kNoSearchEngineLogo) { 81 views::ImageView* logo_image = new views::ImageView(); 82 SkBitmap* logo_bmp = 83 ResourceBundle::GetSharedInstance().GetBitmapNamed(logo_id); 84 logo_image->SetImage(logo_bmp); 85 logo_image->SetTooltipText(short_name); 86 logo_view = logo_image; 87 } else { 88 // No logo -- show a text label. 89 views::Label* logo_label = new views::Label(short_name); 90 logo_label->SetColor(SK_ColorDKGRAY); 91 logo_label->SetFont(logo_label->font().DeriveFont(3, gfx::Font::BOLD)); 92 logo_label->SetHorizontalAlignment(views::Label::ALIGN_CENTER); 93 // Tooltip text provides accessibility for low-vision users. 94 logo_label->SetTooltipText(short_name); 95 logo_view = logo_label; 96 } 97 98 return logo_view; 99 } 100 views::NativeButton* CreateProviderChoiceButton( 101 views::ButtonListener* listener, 102 int message_id, 103 const std::wstring& short_name) { 104 return new views::NativeButton(listener, UTF16ToWide( 105 l10n_util::GetStringFUTF16(message_id, WideToUTF16(short_name)))); 106 } 107 108 } // namespace 109 110 // static 111 void DefaultSearchView::Show(TabContents* tab_contents, 112 TemplateURL* default_url, 113 TemplateURLModel* template_url_model) { 114 scoped_ptr<TemplateURL> template_url(default_url); 115 if (!template_url_model->CanMakeDefault(default_url) || 116 default_url->url()->GetHost().empty()) 117 return; 118 119 // When the window closes, it will delete itself. 120 new DefaultSearchView(tab_contents, template_url.release(), 121 template_url_model); 122 } 123 124 DefaultSearchView::~DefaultSearchView() { 125 } 126 127 void DefaultSearchView::OnPaint(gfx::Canvas* canvas) { 128 // Fill in behind the background image with the standard gray toolbar color. 129 canvas->FillRectInt(SkColorSetRGB(237, 238, 237), 0, 0, width(), 130 background_image_->height()); 131 // The rest of the dialog background should be white. 132 DCHECK(height() > background_image_->height()); 133 canvas->FillRectInt(SK_ColorWHITE, 0, background_image_->height(), width(), 134 height() - background_image_->height()); 135 } 136 137 void DefaultSearchView::ButtonPressed(views::Button* sender, 138 const views::Event& event) { 139 views::DialogClientView* client = GetDialogClientView(); 140 if (sender == proposed_provider_button_) 141 client->AcceptWindow(); 142 else 143 client->CancelWindow(); 144 } 145 146 std::wstring DefaultSearchView::GetWindowTitle() const { 147 return UTF16ToWide(l10n_util::GetStringUTF16(IDS_DEFAULT_SEARCH_TITLE)); 148 } 149 150 views::View* DefaultSearchView::GetInitiallyFocusedView() { 151 return default_provider_button_; 152 } 153 154 views::View* DefaultSearchView::GetContentsView() { 155 return this; 156 } 157 158 int DefaultSearchView::GetDialogButtons() const { 159 return ui::MessageBoxFlags::DIALOGBUTTON_NONE; 160 } 161 162 bool DefaultSearchView::Accept() { 163 // Check this again in case the default became managed while this dialog was 164 // displayed. 165 TemplateURL* set_as_default = proposed_turl_.get(); 166 if (!template_url_model_->CanMakeDefault(set_as_default)) 167 return true; 168 169 template_url_model_->Add(proposed_turl_.release()); 170 template_url_model_->SetDefaultSearchProvider(set_as_default); 171 return true; 172 } 173 174 DefaultSearchView::DefaultSearchView(TabContents* tab_contents, 175 TemplateURL* proposed_default_turl, 176 TemplateURLModel* template_url_model) 177 : background_image_(NULL), 178 default_provider_button_(NULL), 179 proposed_provider_button_(NULL), 180 proposed_turl_(proposed_default_turl), 181 template_url_model_(template_url_model) { 182 PrefService* prefs = tab_contents->profile()->GetPrefs(); 183 SetupControls(prefs); 184 185 // Show the dialog. 186 tab_contents->CreateConstrainedDialog(this); 187 } 188 189 void DefaultSearchView::SetupControls(PrefService* prefs) { 190 using views::ColumnSet; 191 using views::GridLayout; 192 using views::ImageView; 193 using views::Label; 194 195 // Column set id's. 196 const int kWholeDialogViewSetId = 0; 197 const int kPaddedWholeDialogViewSetId = 1; 198 const int kChoicesViewSetId = 2; 199 200 // Set up the information for the proposed default. 201 std::wstring proposed_short_name; 202 int proposed_logo_id = kNoSearchEngineLogo; 203 GetShortNameAndLogoId(prefs, 204 proposed_turl_.get(), 205 &proposed_short_name, 206 &proposed_logo_id); 207 if (proposed_logo_id != kNoSearchEngineLogo) 208 proposed_turl_->set_logo_id(proposed_logo_id); 209 210 211 // Set up the information for the current default. 212 std::wstring default_short_name; 213 int default_logo_id = kNoSearchEngineLogo; 214 GetShortNameAndLogoId(prefs, 215 template_url_model_->GetDefaultSearchProvider(), 216 &default_short_name, 217 &default_logo_id); 218 219 // Now set-up the dialog contents. 220 GridLayout* layout = new views::GridLayout(this); 221 layout->SetInsets(0, 0, views::kPanelVertMargin, 0); 222 SetLayoutManager(layout); 223 224 // Add a column set that spans the whole dialog. 225 ColumnSet* whole_dialog_column_set = 226 layout->AddColumnSet(kWholeDialogViewSetId); 227 whole_dialog_column_set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 228 1, GridLayout::FIXED, 229 views::Window::GetLocalizedContentsWidth( 230 IDS_DEFAULT_SEARCH_WIDTH_CHARS), 231 0); 232 233 // Add a column set that spans the whole dialog but obeying padding. 234 ColumnSet* padded_whole_dialog_column_set = 235 layout->AddColumnSet(kPaddedWholeDialogViewSetId); 236 padded_whole_dialog_column_set->AddPaddingColumn(1, views::kPanelVertMargin); 237 padded_whole_dialog_column_set->AddColumn( 238 GridLayout::LEADING, GridLayout::LEADING, 239 1, GridLayout::USE_PREF, 0, 0); 240 padded_whole_dialog_column_set->AddPaddingColumn(1, views::kPanelVertMargin); 241 242 // Add a column set for the search engine choices. 243 ColumnSet* choices_column_set = layout->AddColumnSet(kChoicesViewSetId); 244 choices_column_set->AddPaddingColumn(1, views::kPanelVertMargin); 245 choices_column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 246 1, GridLayout::USE_PREF, 0, 0); 247 choices_column_set->AddPaddingColumn( 248 1, views::kRelatedControlHorizontalSpacing); 249 choices_column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 250 1, GridLayout::USE_PREF, 0, 0); 251 choices_column_set->LinkColumnSizes(0, 2, -1); 252 choices_column_set->AddPaddingColumn(1, views::kPanelVertMargin); 253 254 // Add the "search box" image. 255 layout->StartRow(0, kWholeDialogViewSetId); 256 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 257 background_image_ = new ImageView(); 258 background_image_->SetImage(rb.GetBitmapNamed(IDR_SEARCH_ENGINE_DIALOG_TOP)); 259 background_image_->EnableCanvasFlippingForRTLUI(true); 260 ImageView::Alignment horizontal_alignment = 261 base::i18n::IsRTL() ? ImageView::LEADING : ImageView::TRAILING; 262 background_image_->SetHorizontalAlignment(horizontal_alignment); 263 layout->AddView(background_image_); 264 265 // Add text informing the user about the requested default change. 266 layout->StartRowWithPadding(0, kPaddedWholeDialogViewSetId, 267 1, views::kLabelToControlVerticalSpacing); 268 Label* summary_label = new Label(UTF16ToWide(l10n_util::GetStringFUTF16( 269 IDS_DEFAULT_SEARCH_SUMMARY, 270 WideToUTF16(proposed_short_name)))); 271 summary_label->SetColor(SK_ColorBLACK); 272 summary_label->SetFont( 273 summary_label->font().DeriveFont(1, gfx::Font::NORMAL)); 274 summary_label->SetHorizontalAlignment(Label::ALIGN_LEFT); 275 layout->AddView(summary_label); 276 277 // Add the labels for the tops of the choices. 278 layout->StartRowWithPadding(0, kChoicesViewSetId, 279 0, views::kRelatedControlVerticalSpacing); 280 layout->AddView(CreateProviderLabel(IDS_DEFAULT_SEARCH_LABEL_CURRENT)); 281 layout->AddView(CreateProviderLabel(IDS_DEFAULT_SEARCH_LABEL_PROPOSED)); 282 283 // Add the logos. 284 layout->StartRowWithPadding(0, kChoicesViewSetId, 285 0, views::kRelatedControlVerticalSpacing); 286 layout->AddView(CreateProviderLogo(default_logo_id, default_short_name)); 287 layout->AddView(CreateProviderLogo(proposed_logo_id, proposed_short_name)); 288 289 // Add the buttons. 290 layout->StartRowWithPadding(0, kChoicesViewSetId, 291 0, views::kRelatedControlVerticalSpacing); 292 default_provider_button_ = CreateProviderChoiceButton( 293 this, 294 IDS_DEFAULT_SEARCH_PROMPT_CURRENT, 295 default_short_name); 296 layout->AddView(default_provider_button_); 297 proposed_provider_button_ = CreateProviderChoiceButton( 298 this, 299 IDS_DEFAULT_SEARCH_PROMPT_PROPOSED, 300 proposed_short_name); 301 layout->AddView(proposed_provider_button_); 302 } 303