Logo Search packages:      
Sourcecode: chromium-browser version File versions  Download package

first_run_search_engine_view.cc

// 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.

#include "chrome/browser/views/first_run_search_engine_view.h"

#include <algorithm>
#include <map>

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/i18n/rtl.h"
#include "base/time.h"
#include "chrome/browser/options_window.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
#include "gfx/font.h"
#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
#include "grit/google_chrome_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "grit/theme_resources.h"
#include "views/controls/button/button.h"
#include "views/controls/image_view.h"
#include "views/controls/label.h"
#include "views/controls/separator.h"
#include "views/standard_layout.h"
#include "views/view_text_utils.h"
#include "views/window/window.h"

using base::Time;
using TemplateURLPrepopulateData::SearchEngineType;

namespace {

// Size to scale logos down to if showing 4 instead of 3 choices. Logo images
// are all originally sized at 180 x 120 pixels, with the logo text baseline
// located 74 pixels beneath the top of the image.
const int kSmallLogoWidth = 132;
const int kSmallLogoHeight = 88;

// Used to pad text label height so it fits nicely in view.
const int kLabelPadding = 25;

}  // namespace

SearchEngineChoice::SearchEngineChoice(views::ButtonListener* listener,
                                       const TemplateURL* search_engine,
                                       bool use_small_logos)
    : NativeButton(listener, l10n_util::GetString(IDS_FR_SEARCH_CHOOSE)),
      is_image_label_(false),
      search_engine_(search_engine) {
  bool use_images = false;
#if defined(GOOGLE_CHROME_BUILD)
  use_images = true;
#endif
  int logo_id = search_engine_->logo_id();
  if (use_images && logo_id > 0) {
    is_image_label_ = true;
    views::ImageView* logo_image = new views::ImageView();
    SkBitmap* logo_bmp =
        ResourceBundle::GetSharedInstance().GetBitmapNamed(logo_id);
    logo_image->SetImage(logo_bmp);
    if (use_small_logos)
      logo_image->SetImageSize(gfx::Size(kSmallLogoWidth, kSmallLogoHeight));
    // Tooltip text provides accessibility.
    logo_image->SetTooltipText(search_engine_->short_name());
    choice_view_ = logo_image;
  } else {
    // No logo -- we must show a text label.
    views::Label* logo_label = new views::Label(search_engine_->short_name());
    logo_label->SetColor(SK_ColorDKGRAY);
    logo_label->SetFont(logo_label->font().DeriveFont(3, gfx::Font::BOLD));
    logo_label->SetHorizontalAlignment(views::Label::ALIGN_CENTER);
    logo_label->SetTooltipText(search_engine_->short_name());
    logo_label->SetMultiLine(true);
    logo_label->SizeToFit(kSmallLogoWidth);
    choice_view_ = logo_label;
  }
}

int SearchEngineChoice::GetChoiceViewWidth() {
  if (is_image_label_)
    return choice_view_->GetPreferredSize().width();
  else
    return kSmallLogoWidth;
}

int SearchEngineChoice::GetChoiceViewHeight() {
  if (!is_image_label_) {
    // Labels need to be padded to look nicer.
    return choice_view_->GetPreferredSize().height() + kLabelPadding;
  } else {
    return choice_view_->GetPreferredSize().height();
  }
}

void SearchEngineChoice::SetChoiceViewBounds(int x, int y, int width,
                                             int height) {
  choice_view_->SetBounds(x, y, width, height);
}

FirstRunSearchEngineView::FirstRunSearchEngineView(
    Profile* profile, bool randomize)
    : background_image_(NULL),
      profile_(profile),
      text_direction_is_rtl_(base::i18n::IsRTL()),
      randomize_(randomize) {
  // Don't show ourselves until all the search engines have loaded from
  // the profile -- otherwise we have nothing to show.
  SetVisible(false);

  // Start loading the search engines for the given profile.
  search_engines_model_ = profile_->GetTemplateURLModel();
  if (search_engines_model_) {
    DCHECK(!search_engines_model_->loaded());
    search_engines_model_->AddObserver(this);
    search_engines_model_->Load();
  } else {
    NOTREACHED();
  }
  SetupControls();
}

FirstRunSearchEngineView::~FirstRunSearchEngineView() {
  search_engines_model_->RemoveObserver(this);
}

void FirstRunSearchEngineView::ButtonPressed(views::Button* sender,
                                             const views::Event& event) {
  SearchEngineChoice* choice = static_cast<SearchEngineChoice*>(sender);
  TemplateURLModel* template_url_model = profile_->GetTemplateURLModel();
  DCHECK(template_url_model);
  template_url_model->SetSearchEngineDialogSlot(choice->slot());
  const TemplateURL* default_search = choice->GetSearchEngine();
  if (default_search)
    template_url_model->SetDefaultSearchProvider(default_search);

  MessageLoop::current()->Quit();
}

void FirstRunSearchEngineView::OnTemplateURLModelChanged() {
  using views::ImageView;

  // We only watch the search engine model change once, on load.  Remove
  // observer so we don't try to redraw if engines change under us.
  search_engines_model_->RemoveObserver(this);

  // Add search engines in search_engines_model_ to buttons list.  The
  // first three will always be from prepopulated data.
  std::vector<const TemplateURL*> template_urls =
      search_engines_model_->GetTemplateURLs();

  // If we have fewer than two search engines, end search engine dialog
  // immediately, leaving imported default search engine setting intact.
  if (template_urls.size() < 2) {
    MessageLoop::current()->Quit();
    return;
  }

  std::vector<const TemplateURL*>::iterator search_engine_iter;

  // Is user's default search engine included in first three prepopulated
  // set?  If not, we need to expand the dialog to include a fourth engine.
  const TemplateURL* default_search_engine =
      search_engines_model_->GetDefaultSearchProvider();
  // If the user's default choice is not in the first three search engines
  // in template_urls, store it in |default_choice| and provide it as a
  // fourth option.
  SearchEngineChoice* default_choice = NULL;

  // First, see if we have 4 logos to show (in which case we use small logos).
  // We show 4 logos when the default search engine the user has chosen is
  // not one of the first three prepopulated engines.
  if (template_urls.size() > 3) {
    for (search_engine_iter = template_urls.begin() + 3;
         search_engine_iter != template_urls.end();
         ++search_engine_iter) {
      if (default_search_engine == *search_engine_iter) {
        default_choice = new SearchEngineChoice(this, *search_engine_iter,
                                                true);
      }
    }
  }

  // Now that we know what size the logos should be, create new search engine
  // choices for the view.  If there are 2 search engines, only show 2
  // choices; for 3 or more, show 3 (unless the default is not one of the
  // top 3, in which case show 4).
  for (search_engine_iter = template_urls.begin();
       search_engine_iter < template_urls.begin() +
           (template_urls.size() < 3 ? 2 : 3);
       ++search_engine_iter) {
    // Push first three engines into buttons:
    SearchEngineChoice* choice = new SearchEngineChoice(this,
        *search_engine_iter, default_choice != NULL);
    search_engine_choices_.push_back(choice);
    AddChildView(choice->GetView());  // The logo or text view.
    AddChildView(choice);  // The button associated with the choice.
  }
  // Push the default choice to the fourth position.
  if (default_choice) {
    search_engine_choices_.push_back(default_choice);
    AddChildView(default_choice->GetView());  // The logo or text view.
    AddChildView(default_choice);  // The button associated with the choice.
  }

  // Randomize order of logos if option has been set.
  if (randomize_) {
    int seed = static_cast<int>(Time::Now().ToInternalValue());
    srand(seed);
    std::random_shuffle(search_engine_choices_.begin(),
                        search_engine_choices_.end());
    // Assign to each choice the position in which it is shown on the screen.
    std::vector<SearchEngineChoice*>::iterator it;
    int slot = 0;
    for (it = search_engine_choices_.begin();
         it != search_engine_choices_.end();
         it++) {
      (*it)->set_slot(slot++);
    }
  }

  // Now that we know how many logos to show, lay out and become visible.
  SetVisible(true);
  Layout();
  SchedulePaint();
}

gfx::Size FirstRunSearchEngineView::GetPreferredSize() {
  return views::Window::GetLocalizedContentsSize(
      IDS_FIRSTRUN_SEARCH_ENGINE_SELECTION_WIDTH_CHARS,
      IDS_FIRSTRUN_SEARCH_ENGINE_SELECTION_HEIGHT_LINES);
}

void FirstRunSearchEngineView::SetupControls() {
  using views::Background;
  using views::ImageView;
  using views::Label;
  using views::NativeButton;

  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  background_image_ = new views::ImageView();
  if (text_direction_is_rtl_) {
    background_image_->SetImage(rb.GetBitmapNamed(
        IDR_SEARCH_ENGINE_DIALOG_TOP_RTL));
  } else {
    background_image_->SetImage(rb.GetBitmapNamed(
        IDR_SEARCH_ENGINE_DIALOG_TOP));
  }
  background_image_->SetHorizontalAlignment(ImageView::TRAILING);
  AddChildView(background_image_);

  int label_width = GetPreferredSize().width() - 2 * kPanelHorizMargin;

  set_background(Background::CreateSolidBackground(SK_ColorWHITE));

  // Add title and text asking the user to choose a search engine:
  title_label_ = new Label(l10n_util::GetString(
      IDS_FR_SEARCH_MAIN_LABEL));
  title_label_->SetColor(SK_ColorBLACK);
  title_label_->SetFont(title_label_->font().DeriveFont(3, gfx::Font::BOLD));
  title_label_->SetMultiLine(true);
  title_label_->SetHorizontalAlignment(Label::ALIGN_LEFT);
  title_label_->SizeToFit(label_width);
  AddChildView(title_label_);

  text_label_ = new Label(l10n_util::GetStringF(IDS_FR_SEARCH_TEXT,
      l10n_util::GetString(IDS_PRODUCT_NAME)));
  text_label_->SetColor(SK_ColorBLACK);
  text_label_->SetFont(text_label_->font().DeriveFont(1, gfx::Font::NORMAL));
  text_label_->SetMultiLine(true);
  text_label_->SetHorizontalAlignment(Label::ALIGN_LEFT);
  text_label_->SizeToFit(label_width);
  AddChildView(text_label_);
}

void FirstRunSearchEngineView::Layout() {
  // Disable the close button.
  GetWindow()->EnableClose(false);

  gfx::Size pref_size = background_image_->GetPreferredSize();
  background_image_->SetBounds(0, 0, GetPreferredSize().width(),
                               pref_size.height());

  // General vertical spacing between elements:
  const int kVertSpacing = 8;
  // Percentage of vertical space around logos to use for upper padding.
  const double kUpperPaddingPercent = 0.4;

  int num_choices = search_engine_choices_.size();
  int label_width = GetPreferredSize().width() - 2 * kPanelHorizMargin;
  int label_height = GetPreferredSize().height() - 2 * kPanelVertMargin;

  // Set title.
  title_label_->SetBounds(kPanelHorizMargin,
      pref_size.height() / 2 - title_label_->GetPreferredSize().height() / 2,
      label_width, title_label_->GetPreferredSize().height());

  int next_v_space = background_image_->height() + kVertSpacing * 2;

  // Set text describing search engine hooked into omnibox.
  text_label_->SetBounds(kPanelHorizMargin, next_v_space,
                         label_width,
                         text_label_->GetPreferredSize().height());
  next_v_space = text_label_->y() +
                 text_label_->height() + kVertSpacing;

  // Logos and buttons
  if (num_choices > 0) {
    // All search engine logos are sized the same, so the size of the first is
    // generally valid as the size of all.
    int logo_width = search_engine_choices_[0]->GetChoiceViewWidth();
    int logo_height = search_engine_choices_[0]->GetChoiceViewHeight();
    int button_width = search_engine_choices_[0]->GetPreferredSize().width();
    int button_height = search_engine_choices_[0]->GetPreferredSize().height();

    int logo_section_height = logo_height + kVertSpacing + button_height;
    // Upper logo margin gives the amount of whitespace between the text label
    // and the logo field.  The total amount of whitespace available is equal
    // to the height of the whole label subtracting the heights of the logo
    // section itself, the top image, the text label, and vertical spacing
    // between those elements.
    int upper_logo_margin =
        static_cast<int>((label_height - logo_section_height -
            background_image_->height() - text_label_->height()
            - kVertSpacing + kPanelVertMargin) * kUpperPaddingPercent);

    next_v_space = text_label_->y() + text_label_->height() +
                   upper_logo_margin;

    // The search engine logos (which all have equal size):
    int logo_padding =
        (label_width - (num_choices * logo_width)) / (num_choices + 1);

    search_engine_choices_[0]->SetChoiceViewBounds(
        kPanelHorizMargin + logo_padding, next_v_space, logo_width,
        logo_height);

    int next_h_space = search_engine_choices_[0]->GetView()->x() +
                       logo_width + logo_padding;
    search_engine_choices_[1]->SetChoiceViewBounds(
        next_h_space, next_v_space, logo_width, logo_height);

    next_h_space = search_engine_choices_[1]->GetView()->x() + logo_width +
                   logo_padding;
    if (num_choices > 2) {
      search_engine_choices_[2]->SetChoiceViewBounds(
          next_h_space, next_v_space, logo_width, logo_height);
    }

    if (num_choices > 3) {
      next_h_space = search_engine_choices_[2]->GetView()->x() + logo_width +
                     logo_padding;
      search_engine_choices_[3]->SetChoiceViewBounds(
          next_h_space, next_v_space, logo_width, logo_height);
    }

    next_v_space = search_engine_choices_[0]->GetView()->y() + logo_height +
                   kVertSpacing;

    // The buttons for search engine selection:
    int button_padding = logo_padding + logo_width / 2 - button_width / 2;

    search_engine_choices_[0]->SetBounds(kPanelHorizMargin + button_padding,
                                         next_v_space, button_width,
                                         button_height);

    next_h_space = search_engine_choices_[0]->x() + logo_width + logo_padding;
    search_engine_choices_[1]->SetBounds(next_h_space, next_v_space,
                                         button_width, button_height);
    next_h_space = search_engine_choices_[1]->x() + logo_width + logo_padding;
    if (num_choices > 2) {
      search_engine_choices_[2]->SetBounds(next_h_space, next_v_space,
                                           button_width, button_height);
    }

    if (num_choices > 3) {
      next_h_space = search_engine_choices_[2]->x() + logo_width +
                     logo_padding;
      search_engine_choices_[3]->SetBounds(next_h_space, next_v_space,
                                           button_width, button_height);
    }
  }  // if (search_engine_choices.size() > 0)
}

std::wstring FirstRunSearchEngineView::GetWindowTitle() const {
  return l10n_util::GetString(IDS_FIRSTRUN_DLG_TITLE);
}

Generated by  Doxygen 1.6.0   Back to index