Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ui / app_list / views / search_result_list_view.cc
blob281e84facedad3f50986642971b7edbb8bac7c7e
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>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/time/time.h"
13 #include "third_party/skia/include/core/SkColor.h"
14 #include "ui/app_list/app_list_switches.h"
15 #include "ui/app_list/app_list_view_delegate.h"
16 #include "ui/app_list/search_result.h"
17 #include "ui/app_list/views/search_result_list_view_delegate.h"
18 #include "ui/app_list/views/search_result_view.h"
19 #include "ui/events/event.h"
20 #include "ui/gfx/animation/linear_animation.h"
21 #include "ui/views/background.h"
22 #include "ui/views/layout/box_layout.h"
24 namespace {
26 const int kMaxResults = 6;
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_container_(new views::View),
41 auto_launch_indicator_(new views::View) {
42 results_container_->SetLayoutManager(
43 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
45 for (int i = 0; i < kMaxResults; ++i)
46 results_container_->AddChildView(new SearchResultView(this));
47 AddChildView(results_container_);
49 auto_launch_indicator_->set_background(
50 views::Background::CreateSolidBackground(kTimeoutIndicatorColor));
51 auto_launch_indicator_->SetVisible(false);
53 AddChildView(auto_launch_indicator_);
56 SearchResultListView::~SearchResultListView() {
59 bool SearchResultListView::IsResultViewSelected(
60 const SearchResultView* result_view) const {
61 if (selected_index() < 0)
62 return false;
64 return static_cast<const SearchResultView*>(
65 results_container_->child_at(selected_index())) == result_view;
68 void SearchResultListView::UpdateAutoLaunchState() {
69 SetAutoLaunchTimeout(view_delegate_->GetAutoLaunchTimeout());
72 bool SearchResultListView::OnKeyPressed(const ui::KeyEvent& event) {
73 if (selected_index() >= 0 &&
74 results_container_->child_at(selected_index())->OnKeyPressed(event)) {
75 return true;
78 int selection_index = -1;
79 switch (event.key_code()) {
80 case ui::VKEY_TAB:
81 if (event.IsShiftDown())
82 selection_index = selected_index() - 1;
83 else
84 selection_index = selected_index() + 1;
85 break;
86 case ui::VKEY_UP:
87 selection_index = selected_index() - 1;
88 break;
89 case ui::VKEY_DOWN:
90 selection_index = selected_index() + 1;
91 break;
92 default:
93 break;
96 if (IsValidSelectionIndex(selection_index)) {
97 SetSelectedIndex(selection_index);
98 if (auto_launch_animation_)
99 CancelAutoLaunchTimeout();
100 return true;
103 return false;
106 void SearchResultListView::SetAutoLaunchTimeout(
107 const base::TimeDelta& timeout) {
108 if (timeout > base::TimeDelta()) {
109 auto_launch_indicator_->SetVisible(true);
110 auto_launch_indicator_->SetBounds(0, 0, 0, kTimeoutIndicatorHeight);
111 auto_launch_animation_.reset(new gfx::LinearAnimation(
112 timeout.InMilliseconds(), kTimeoutFramerate, this));
113 auto_launch_animation_->Start();
114 } else {
115 auto_launch_indicator_->SetVisible(false);
116 auto_launch_animation_.reset();
120 void SearchResultListView::CancelAutoLaunchTimeout() {
121 SetAutoLaunchTimeout(base::TimeDelta());
122 view_delegate_->AutoLaunchCanceled();
125 SearchResultView* SearchResultListView::GetResultViewAt(int index) {
126 DCHECK(index >= 0 && index < results_container_->child_count());
127 return static_cast<SearchResultView*>(results_container_->child_at(index));
130 void SearchResultListView::ListItemsRemoved(size_t start, size_t count) {
131 size_t last = std::min(
132 start + count, static_cast<size_t>(results_container_->child_count()));
133 for (size_t i = start; i < last; ++i)
134 GetResultViewAt(i)->ClearResultNoRepaint();
136 SearchResultContainerView::ListItemsRemoved(start, count);
139 void SearchResultListView::OnContainerSelected(bool from_bottom,
140 bool /*directional_movement*/) {
141 if (num_results() == 0)
142 return;
144 SetSelectedIndex(from_bottom ? num_results() - 1 : 0);
147 void SearchResultListView::NotifyFirstResultYIndex(int y_index) {
148 for (size_t i = 0; i < static_cast<size_t>(num_results()); ++i)
149 GetResultViewAt(i)->result()->set_distance_from_origin(i + y_index);
152 int SearchResultListView::GetYSize() {
153 return num_results();
156 int SearchResultListView::Update() {
157 std::vector<SearchResult*> display_results =
158 AppListModel::FilterSearchResultsByDisplayType(
159 results(),
160 SearchResult::DISPLAY_LIST,
161 results_container_->child_count());
163 for (size_t i = 0; i < static_cast<size_t>(results_container_->child_count());
164 ++i) {
165 SearchResultView* result_view = GetResultViewAt(i);
166 result_view->set_is_last_result(i == display_results.size() - 1);
167 if (i < display_results.size()) {
168 result_view->SetResult(display_results[i]);
169 result_view->SetVisible(true);
170 } else {
171 result_view->SetResult(NULL);
172 result_view->SetVisible(false);
175 UpdateAutoLaunchState();
177 set_container_score(
178 display_results.empty() ? 0 : display_results.front()->relevance());
180 return display_results.size();
183 void SearchResultListView::UpdateSelectedIndex(int old_selected,
184 int new_selected) {
185 if (old_selected >= 0) {
186 SearchResultView* selected_view = GetResultViewAt(old_selected);
187 selected_view->ClearSelectedAction();
188 selected_view->SchedulePaint();
191 if (new_selected >= 0) {
192 SearchResultView* selected_view = GetResultViewAt(new_selected);
193 selected_view->ClearSelectedAction();
194 selected_view->SchedulePaint();
195 selected_view->NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true);
199 void SearchResultListView::ForceAutoLaunchForTest() {
200 if (auto_launch_animation_)
201 AnimationEnded(auto_launch_animation_.get());
204 void SearchResultListView::Layout() {
205 results_container_->SetBoundsRect(GetLocalBounds());
208 gfx::Size SearchResultListView::GetPreferredSize() const {
209 return results_container_->GetPreferredSize();
212 int SearchResultListView::GetHeightForWidth(int w) const {
213 return results_container_->GetHeightForWidth(w);
216 void SearchResultListView::VisibilityChanged(views::View* starting_from,
217 bool is_visible) {
218 if (is_visible)
219 UpdateAutoLaunchState();
220 else
221 CancelAutoLaunchTimeout();
224 void SearchResultListView::AnimationEnded(const gfx::Animation* animation) {
225 DCHECK_EQ(auto_launch_animation_.get(), animation);
226 view_delegate_->OpenSearchResult(results()->GetItemAt(0), true, ui::EF_NONE);
228 // The auto-launch has to be canceled explicitly. Think that one of searcher
229 // is extremely slow. Sometimes the events would happen in the following
230 // order:
231 // 1. The search results arrive, auto-launch is dispatched
232 // 2. Timed out and auto-launch the first search result
233 // 3. Then another searcher adds search results more
234 // At the step 3, we shouldn't dispatch the auto-launch again.
235 CancelAutoLaunchTimeout();
238 void SearchResultListView::AnimationProgressed(
239 const gfx::Animation* animation) {
240 DCHECK_EQ(auto_launch_animation_.get(), animation);
241 int indicator_width = auto_launch_animation_->CurrentValueBetween(0, width());
242 auto_launch_indicator_->SetBounds(
243 0, 0, indicator_width, kTimeoutIndicatorHeight);
246 void SearchResultListView::SearchResultActivated(SearchResultView* view,
247 int event_flags) {
248 if (view_delegate_ && view->result())
249 view_delegate_->OpenSearchResult(view->result(), false, event_flags);
252 void SearchResultListView::SearchResultActionActivated(SearchResultView* view,
253 size_t action_index,
254 int event_flags) {
255 if (view_delegate_ && view->result()) {
256 view_delegate_->InvokeSearchResultAction(
257 view->result(), action_index, event_flags);
261 void SearchResultListView::OnSearchResultInstalled(SearchResultView* view) {
262 if (delegate_ && view->result())
263 delegate_->OnResultInstalled(view->result());
266 } // namespace app_list