Chromium Code Reviews| Index: ui/app_list/search_box_view.cc |
| diff --git a/ui/app_list/search_box_view.cc b/ui/app_list/search_box_view.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..1a046f088f9ea1b9b098ace72ae5f3cce452c72b |
| --- /dev/null |
| +++ b/ui/app_list/search_box_view.cc |
| @@ -0,0 +1,157 @@ |
| +// Copyright (c) 2012 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 "ui/app_list/search_box_view.h" |
| + |
| +#include <algorithm> |
| + |
| +#include "ui/app_list/search_box_model.h" |
| +#include "ui/app_list/search_box_view_delegate.h" |
| +#include "ui/app_list/view_ids.h" |
| +#include "ui/base/resource/resource_bundle.h" |
| +#include "ui/views/controls/image_view.h" |
| +#include "ui/views/controls/textfield/textfield.h" |
| + |
| +namespace app_list { |
| + |
| +namespace { |
| + |
| +const int kPadding = 9; |
| +const int kIconDimension = 32; |
| + |
| +// Amount of time to wait so that we coalesce query text changes. |
| +const int kQueryTextChangeCoalescingTimeMs = 100; |
| + |
| +} // namespace |
| + |
| +SearchBoxView::SearchBoxView(SearchBoxViewDelegate* delegate) |
| + : delegate_(delegate), |
| + model_(NULL) { |
|
sky
2012/05/22 22:16:06
I think it's worth initializing icon_view_ and sea
xiyuan
2012/05/23 21:25:22
Done. I agree and I don't know why I forgot this.
|
| + set_id(VIEW_ID_SEARCH_BOX); |
| + |
| + icon_view_ = new views::ImageView; |
| + AddChildView(icon_view_); |
| + |
| + search_box_ = new views::Textfield; |
| + search_box_->RemoveBorder(); |
| + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| + search_box_->SetFont(rb.GetFont(ResourceBundle::BaseFont).DeriveFont( |
| + 2, gfx::Font::BOLD)); |
| + search_box_->SetController(this); |
| + AddChildView(search_box_); |
| +} |
| + |
| +SearchBoxView::~SearchBoxView() { |
| + if (model_) |
| + model_->RemoveObserver(this); |
| +} |
| + |
| +void SearchBoxView::SetModel(SearchBoxModel* model) { |
| + if (model_ == model) |
| + return; |
| + |
| + if (model_) |
| + model_->RemoveObserver(this); |
| + |
| + model_ = model; |
| + if (model_) { |
| + model_->AddObserver(this); |
| + IconChanged(); |
| + HintTextChanged(); |
| + } |
| +} |
| + |
| +void SearchBoxView::UpdateModel() { |
| + // Temporarily remove from observer to ignore notifications caused by us. |
| + model_->RemoveObserver(this); |
| + model_->SetText(search_box_->text()); |
| + |
| + gfx::SelectionModel sel; |
| + search_box_->GetSelectionModel(&sel); |
| + model_->SetSelectionModel(sel); |
| + model_->AddObserver(this); |
| +} |
| + |
| +void SearchBoxView::NotifyQueryChanged() { |
| + UpdateModel(); |
|
sky
2012/05/22 22:16:06
Shouldn't this only update if the contents actuall
xiyuan
2012/05/23 21:25:22
Done. Moved this call to ContentsChanged handler.
|
| + delegate_->QueryChanged(this); |
| +} |
| + |
| +gfx::Size SearchBoxView::GetPreferredSize() { |
| + if (!parent()) |
| + return gfx::Size(); |
| + |
| + return gfx::Size(parent()->GetContentsBounds().width(), |
| + std::max(kIconDimension, |
| + search_box_->GetPreferredSize().height())); |
| +} |
| + |
| +void SearchBoxView::Layout() { |
| + gfx::Rect rect(GetContentsBounds()); |
| + if (rect.IsEmpty()) |
| + return; |
| + |
| + gfx::Size icon_size(kIconDimension, kIconDimension); |
| + gfx::Rect icon_frame(rect); |
| + icon_frame.set_width(icon_size.width() + 2 * kPadding); |
| + icon_view_->SetBoundsRect(icon_frame); |
| + |
| + gfx::Rect edit_frame(rect); |
| + edit_frame.set_x(icon_frame.right()); |
| + edit_frame.set_width(rect.width() - icon_frame.width() - kPadding); |
| + search_box_->SetBoundsRect(edit_frame); |
| +} |
| + |
| +void SearchBoxView::ContentsChanged(views::Textfield* sender, |
| + const string16& new_contents) { |
| + query_timer_.Stop(); |
|
sky
2012/05/22 22:16:06
If the delegate wants to throttle queries, shouldn
xiyuan
2012/05/23 21:25:22
Makes sense. Removed.
|
| + query_timer_.Start( |
| + FROM_HERE, |
| + base::TimeDelta::FromMilliseconds(kQueryTextChangeCoalescingTimeMs), |
| + this, |
| + &SearchBoxView::NotifyQueryChanged); |
| +} |
| + |
| +bool SearchBoxView::HandleKeyEvent(views::Textfield* sender, |
| + const views::KeyEvent& key_event) { |
| + bool has_query = !search_box_->text().empty(); |
| + |
| + // Escape with non-empty query text clears the search box. |
| + if (has_query && key_event.key_code() == ui::VKEY_ESCAPE) { |
| + search_box_->SetText(string16()); |
| + return true; |
| + } |
| + |
| + bool handled = false; |
| + if (has_query) { |
| + views::View* results_view = parent()->GetViewByID(VIEW_ID_SEARCH_RESULTS); |
|
sky
2012/05/22 22:16:06
This strikes me as very brittle. Could you explici
xiyuan
2012/05/23 21:25:22
Done.
|
| + if (results_view && results_view->visible()) |
| + handled = results_view->OnKeyPressed(key_event); |
| + } else { |
| + views::View* grid_view = parent()->GetViewByID(VIEW_ID_APPS_GRID); |
| + if (grid_view && grid_view->visible()) |
| + handled = grid_view->OnKeyPressed(key_event); |
| + } |
| + |
| + return handled; |
| +} |
| + |
| +void SearchBoxView::IconChanged() { |
| + icon_view_->SetImage(model_->icon()); |
| +} |
| + |
| +void SearchBoxView::HintTextChanged() { |
| + search_box_->set_placeholder_text(model_->hint_text()); |
| +} |
| + |
| +void SearchBoxView::SelectionModelChanged() { |
| + search_box_->SelectSelectionModel(model_->selection_model()); |
| +} |
| + |
| +void SearchBoxView::TextChanged() { |
| + search_box_->SetText(model_->text()); |
| +} |
| + |
| +} // namespace app_list |
| + |