Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ui / app_list / views / search_result_list_view.cc
blob76e7898a536092801cd0c3291005f54d698bf45f
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.
5 #include "ui/app_list/views/search_result_list_view.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/time/time.h"
12 #include "third_party/skia/include/core/SkColor.h"
13 #include "ui/app_list/app_list_switches.h"
14 #include "ui/app_list/app_list_view_delegate.h"
15 #include "ui/app_list/search_result.h"
16 #include "ui/app_list/views/search_result_list_view_delegate.h"
17 #include "ui/app_list/views/search_result_view.h"
18 #include "ui/events/event.h"
19 #include "ui/gfx/animation/linear_animation.h"
20 #include "ui/views/background.h"
21 #include "ui/views/layout/box_layout.h"
23 namespace {
25 const int kMaxResults = 6;
26 const int kExperimentAppListMaxResults = 3;
27 const int kTimeoutIndicatorHeight = 2;
28 const int kTimeoutFramerate = 60;
29 const SkColor kTimeoutIndicatorColor = SkColorSetRGB(30, 144, 255);
31 } // namespace
33 namespace app_list {
35 SearchResultListView::SearchResultListView(
36 SearchResultListViewDelegate* delegate,
37 AppListViewDelegate* view_delegate)
38 : delegate_(delegate),
39 view_delegate_(view_delegate),
40 results_(NULL),
41 results_container_(new views::View),
42 auto_launch_indicator_(new views::View),
43 last_visible_index_(0),
44 selected_index_(-1),
45 update_factory_(this) {
46 results_container_->SetLayoutManager(
47 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
49 int max_results = kMaxResults;
50 if (app_list::switches::IsExperimentalAppListEnabled())
51 max_results = kExperimentAppListMaxResults;
53 for (int i = 0; i < max_results; ++i)
54 results_container_->AddChildView(new SearchResultView(this));
55 AddChildView(results_container_);
57 auto_launch_indicator_->set_background(
58 views::Background::CreateSolidBackground(kTimeoutIndicatorColor));
59 auto_launch_indicator_->SetVisible(false);
61 AddChildView(auto_launch_indicator_);
64 SearchResultListView::~SearchResultListView() {
65 if (results_)
66 results_->RemoveObserver(this);
69 void SearchResultListView::SetResults(AppListModel::SearchResults* results) {
70 if (results_)
71 results_->RemoveObserver(this);
73 results_ = results;
74 if (results_)
75 results_->AddObserver(this);
77 Update();
80 void SearchResultListView::SetSelectedIndex(int selected_index) {
81 if (selected_index_ == selected_index)
82 return;
84 if (selected_index_ >= 0) {
85 SearchResultView* selected_view = GetResultViewAt(selected_index_);
86 selected_view->ClearSelectedAction();
87 selected_view->SchedulePaint();
90 selected_index_ = selected_index;
92 if (selected_index_ >= 0) {
93 SearchResultView* selected_view = GetResultViewAt(selected_index_);
94 selected_view->ClearSelectedAction();
95 selected_view->SchedulePaint();
96 selected_view->NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS,
97 true);
99 if (auto_launch_animation_)
100 CancelAutoLaunchTimeout();
103 bool SearchResultListView::IsResultViewSelected(
104 const SearchResultView* result_view) const {
105 if (selected_index_ < 0)
106 return false;
108 return static_cast<const SearchResultView*>(
109 results_container_->child_at(selected_index_)) == result_view;
112 void SearchResultListView::UpdateAutoLaunchState() {
113 SetAutoLaunchTimeout(view_delegate_->GetAutoLaunchTimeout());
116 bool SearchResultListView::OnKeyPressed(const ui::KeyEvent& event) {
117 if (selected_index_ >= 0 &&
118 results_container_->child_at(selected_index_)->OnKeyPressed(event)) {
119 return true;
122 switch (event.key_code()) {
123 case ui::VKEY_TAB:
124 if (event.IsShiftDown())
125 SetSelectedIndex(std::max(selected_index_ - 1, 0));
126 else
127 SetSelectedIndex(std::min(selected_index_ + 1, last_visible_index_));
128 return true;
129 case ui::VKEY_UP:
130 SetSelectedIndex(std::max(selected_index_ - 1, 0));
131 return true;
132 case ui::VKEY_DOWN:
133 SetSelectedIndex(std::min(selected_index_ + 1, last_visible_index_));
134 return true;
135 default:
136 break;
139 return false;
142 void SearchResultListView::SetAutoLaunchTimeout(
143 const base::TimeDelta& timeout) {
144 if (timeout > base::TimeDelta()) {
145 auto_launch_indicator_->SetVisible(true);
146 auto_launch_indicator_->SetBounds(0, 0, 0, kTimeoutIndicatorHeight);
147 auto_launch_animation_.reset(new gfx::LinearAnimation(
148 timeout.InMilliseconds(), kTimeoutFramerate, this));
149 auto_launch_animation_->Start();
150 } else {
151 auto_launch_indicator_->SetVisible(false);
152 auto_launch_animation_.reset();
156 void SearchResultListView::CancelAutoLaunchTimeout() {
157 SetAutoLaunchTimeout(base::TimeDelta());
158 view_delegate_->AutoLaunchCanceled();
161 SearchResultView* SearchResultListView::GetResultViewAt(int index) {
162 DCHECK(index >= 0 && index < results_container_->child_count());
163 return static_cast<SearchResultView*>(results_container_->child_at(index));
166 void SearchResultListView::Update() {
167 std::vector<SearchResult*> display_results =
168 AppListModel::FilterSearchResultsByDisplayType(
169 results_,
170 SearchResult::DISPLAY_LIST,
171 results_container_->child_count());
172 last_visible_index_ = display_results.size() - 1;
174 for (size_t i = 0; i < static_cast<size_t>(results_container_->child_count());
175 ++i) {
176 SearchResultView* result_view = GetResultViewAt(i);
177 if (i < display_results.size()) {
178 result_view->SetResult(display_results[i]);
179 result_view->SetVisible(true);
180 } else {
181 result_view->SetResult(NULL);
182 result_view->SetVisible(false);
185 if (selected_index_ > last_visible_index_)
186 SetSelectedIndex(last_visible_index_);
188 Layout();
189 update_factory_.InvalidateWeakPtrs();
190 UpdateAutoLaunchState();
193 void SearchResultListView::ScheduleUpdate() {
194 // When search results are added one by one, each addition generates an update
195 // request. Consolidates those update requests into one Update call.
196 if (!update_factory_.HasWeakPtrs()) {
197 base::MessageLoop::current()->PostTask(
198 FROM_HERE,
199 base::Bind(&SearchResultListView::Update,
200 update_factory_.GetWeakPtr()));
204 void SearchResultListView::ForceAutoLaunchForTest() {
205 if (auto_launch_animation_)
206 AnimationEnded(auto_launch_animation_.get());
209 void SearchResultListView::Layout() {
210 results_container_->SetBoundsRect(GetLocalBounds());
213 gfx::Size SearchResultListView::GetPreferredSize() const {
214 return results_container_->GetPreferredSize();
217 int SearchResultListView::GetHeightForWidth(int w) const {
218 return results_container_->GetHeightForWidth(w);
221 void SearchResultListView::VisibilityChanged(views::View* starting_from,
222 bool is_visible) {
223 if (is_visible)
224 UpdateAutoLaunchState();
225 else
226 CancelAutoLaunchTimeout();
229 void SearchResultListView::AnimationEnded(const gfx::Animation* animation) {
230 DCHECK_EQ(auto_launch_animation_.get(), animation);
231 view_delegate_->OpenSearchResult(results_->GetItemAt(0), true, ui::EF_NONE);
233 // The auto-launch has to be canceled explicitly. Think that one of searcher
234 // is extremely slow. Sometimes the events would happen in the following
235 // order:
236 // 1. The search results arrive, auto-launch is dispatched
237 // 2. Timed out and auto-launch the first search result
238 // 3. Then another searcher adds search results more
239 // At the step 3, we shouldn't dispatch the auto-launch again.
240 CancelAutoLaunchTimeout();
243 void SearchResultListView::AnimationProgressed(
244 const gfx::Animation* animation) {
245 DCHECK_EQ(auto_launch_animation_.get(), animation);
246 int indicator_width = auto_launch_animation_->CurrentValueBetween(0, width());
247 auto_launch_indicator_->SetBounds(
248 0, 0, indicator_width, kTimeoutIndicatorHeight);
251 void SearchResultListView::ListItemsAdded(size_t start, size_t count) {
252 ScheduleUpdate();
255 void SearchResultListView::ListItemsRemoved(size_t start, size_t count) {
256 size_t last = std::min(
257 start + count,
258 static_cast<size_t>(results_container_->child_count()));
259 for (size_t i = start; i < last; ++i)
260 GetResultViewAt(i)->ClearResultNoRepaint();
262 ScheduleUpdate();
265 void SearchResultListView::ListItemMoved(size_t index, size_t target_index) {
266 NOTREACHED();
269 void SearchResultListView::ListItemsChanged(size_t start, size_t count) {
270 NOTREACHED();
273 void SearchResultListView::SearchResultActivated(SearchResultView* view,
274 int event_flags) {
275 if (view_delegate_ && view->result())
276 view_delegate_->OpenSearchResult(view->result(), false, event_flags);
279 void SearchResultListView::SearchResultActionActivated(SearchResultView* view,
280 size_t action_index,
281 int event_flags) {
282 if (view_delegate_ && view->result()) {
283 view_delegate_->InvokeSearchResultAction(
284 view->result(), action_index, event_flags);
288 void SearchResultListView::OnSearchResultInstalled(SearchResultView* view) {
289 if (delegate_ && view->result())
290 delegate_->OnResultInstalled(view->result());
293 void SearchResultListView::OnSearchResultUninstalled(SearchResultView* view) {
294 if (delegate_ && view->result())
295 delegate_->OnResultUninstalled(view->result());
298 } // namespace app_list