Home | History | Annotate | Download | only in views
      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