Home | History | Annotate | Download | only in views
      1 // Copyright (c) 2012 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 "ui/app_list/views/search_box_view.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "grit/ui_resources.h"
     10 #include "ui/app_list/app_list_model.h"
     11 #include "ui/app_list/search_box_model.h"
     12 #include "ui/app_list/search_box_view_delegate.h"
     13 #include "ui/app_list/views/app_list_menu_views.h"
     14 #include "ui/base/events/event.h"
     15 #include "ui/base/resource/resource_bundle.h"
     16 #include "ui/views/controls/button/menu_button.h"
     17 #include "ui/views/controls/image_view.h"
     18 #include "ui/views/controls/textfield/textfield.h"
     19 
     20 namespace app_list {
     21 
     22 namespace {
     23 
     24 const int kPadding = 14;
     25 const int kIconDimension = 32;
     26 const int kPreferredWidth = 360;
     27 const int kPreferredHeight = 48;
     28 const int kMenuButtonDimension = 29;
     29 
     30 const SkColor kHintTextColor = SkColorSetRGB(0xA0, 0xA0, 0xA0);
     31 
     32 // Menu offset relative to the bottom-right corner of the menu button.
     33 const int kMenuYOffsetFromButton = -4;
     34 const int kMenuXOffsetFromButton = -7;
     35 
     36 }  // namespace
     37 
     38 SearchBoxView::SearchBoxView(SearchBoxViewDelegate* delegate,
     39                              AppListViewDelegate* view_delegate,
     40                              AppListModel* model)
     41     : delegate_(delegate),
     42       view_delegate_(view_delegate),
     43       model_(model->search_box()),
     44       icon_view_(new views::ImageView),
     45       search_box_(new views::Textfield),
     46       contents_view_(NULL) {
     47   DCHECK(model_);
     48   AddChildView(icon_view_);
     49 
     50   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
     51 
     52 #if !defined(OS_CHROMEOS)
     53   menu_button_ = new views::MenuButton(NULL, base::string16(), this, false);
     54   menu_button_->set_border(NULL);
     55   menu_button_->SetIcon(*rb.GetImageSkiaNamed(IDR_APP_LIST_TOOLS_NORMAL));
     56   menu_button_->SetHoverIcon(*rb.GetImageSkiaNamed(IDR_APP_LIST_TOOLS_HOVER));
     57   menu_button_->SetPushedIcon(*rb.GetImageSkiaNamed(
     58       IDR_APP_LIST_TOOLS_PRESSED));
     59   AddChildView(menu_button_);
     60 #endif
     61 
     62   search_box_->RemoveBorder();
     63   search_box_->SetFont(rb.GetFont(ui::ResourceBundle::MediumFont));
     64   search_box_->set_placeholder_text_color(kHintTextColor);
     65   search_box_->SetController(this);
     66   AddChildView(search_box_);
     67 
     68   model_->AddObserver(this);
     69   IconChanged();
     70   HintTextChanged();
     71 }
     72 
     73 SearchBoxView::~SearchBoxView() {
     74   model_->RemoveObserver(this);
     75 }
     76 
     77 bool SearchBoxView::HasSearch() const {
     78   return !search_box_->text().empty();
     79 }
     80 
     81 void SearchBoxView::ClearSearch() {
     82   search_box_->SetText(base::string16());
     83   // Updates model and fires query changed manually because SetText() above
     84   // does not generate ContentsChanged() notification.
     85   UpdateModel();
     86   NotifyQueryChanged();
     87 }
     88 
     89 void SearchBoxView::InvalidateMenu() {
     90   menu_.reset();
     91 }
     92 
     93 gfx::Size SearchBoxView::GetPreferredSize() {
     94   return gfx::Size(kPreferredWidth, kPreferredHeight);
     95 }
     96 
     97 void SearchBoxView::Layout() {
     98   gfx::Rect rect(GetContentsBounds());
     99   if (rect.IsEmpty())
    100     return;
    101 
    102   gfx::Rect icon_frame(rect);
    103   icon_frame.set_width(kIconDimension + 2 * kPadding);
    104   icon_view_->SetBoundsRect(icon_frame);
    105 
    106   gfx::Rect menu_button_frame(rect);
    107 #if !defined(OS_CHROMEOS)
    108   menu_button_frame.set_width(kMenuButtonDimension);
    109   menu_button_frame.set_x(rect.right() - menu_button_frame.width() - kPadding);
    110   menu_button_frame.ClampToCenteredSize(gfx::Size(menu_button_frame.width(),
    111                                                   kMenuButtonDimension));
    112   menu_button_->SetBoundsRect(menu_button_frame);
    113 #else
    114   menu_button_frame.set_width(0);
    115 #endif
    116 
    117   gfx::Rect edit_frame(rect);
    118   edit_frame.set_x(icon_frame.right());
    119   edit_frame.set_width(
    120       rect.width() - icon_frame.width() - kPadding - menu_button_frame.width());
    121   edit_frame.ClampToCenteredSize(
    122       gfx::Size(edit_frame.width(), search_box_->GetPreferredSize().height()));
    123   search_box_->SetBoundsRect(edit_frame);
    124 }
    125 
    126 bool SearchBoxView::OnMouseWheel(const ui::MouseWheelEvent& event) {
    127   if (contents_view_)
    128     return contents_view_->OnMouseWheel(event);
    129 
    130   return false;
    131 }
    132 
    133 void SearchBoxView::UpdateModel() {
    134   // Temporarily remove from observer to ignore notifications caused by us.
    135   model_->RemoveObserver(this);
    136   model_->SetText(search_box_->text());
    137   model_->SetSelectionModel(search_box_->GetSelectionModel());
    138   model_->AddObserver(this);
    139 }
    140 
    141 void SearchBoxView::NotifyQueryChanged() {
    142   DCHECK(delegate_);
    143   delegate_->QueryChanged(this);
    144 }
    145 
    146 void SearchBoxView::ContentsChanged(views::Textfield* sender,
    147                                     const base::string16& new_contents) {
    148   UpdateModel();
    149   NotifyQueryChanged();
    150 }
    151 
    152 bool SearchBoxView::HandleKeyEvent(views::Textfield* sender,
    153                                    const ui::KeyEvent& key_event) {
    154   bool handled = false;
    155   if (contents_view_ && contents_view_->visible())
    156     handled = contents_view_->OnKeyPressed(key_event);
    157 
    158   return handled;
    159 }
    160 
    161 void SearchBoxView::OnMenuButtonClicked(View* source, const gfx::Point& point) {
    162   if (!menu_)
    163     menu_.reset(new AppListMenuViews(view_delegate_));
    164 
    165   const gfx::Point menu_location =
    166       menu_button_->GetBoundsInScreen().bottom_right() +
    167       gfx::Vector2d(kMenuXOffsetFromButton, kMenuYOffsetFromButton);
    168   menu_->RunMenuAt(menu_button_, menu_location);
    169 }
    170 
    171 void SearchBoxView::IconChanged() {
    172   icon_view_->SetImage(model_->icon());
    173 }
    174 
    175 void SearchBoxView::HintTextChanged() {
    176   search_box_->set_placeholder_text(model_->hint_text());
    177 }
    178 
    179 void SearchBoxView::SelectionModelChanged() {
    180   search_box_->SelectSelectionModel(model_->selection_model());
    181 }
    182 
    183 void SearchBoxView::TextChanged() {
    184   search_box_->SetText(model_->text());
    185 }
    186 
    187 }  // namespace app_list
    188