OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/app_list/views/search_result_list_view.h" | 5 #include "ui/app_list/views/search_result_list_view.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
11 #include "base/time/time.h" | 11 #include "base/time/time.h" |
12 #include "third_party/skia/include/core/SkColor.h" | 12 #include "third_party/skia/include/core/SkColor.h" |
| 13 #include "ui/app_list/app_list_view_delegate.h" |
13 #include "ui/app_list/views/search_result_list_view_delegate.h" | 14 #include "ui/app_list/views/search_result_list_view_delegate.h" |
14 #include "ui/app_list/views/search_result_view.h" | 15 #include "ui/app_list/views/search_result_view.h" |
15 #include "ui/events/event.h" | 16 #include "ui/events/event.h" |
16 #include "ui/gfx/animation/linear_animation.h" | 17 #include "ui/gfx/animation/linear_animation.h" |
17 #include "ui/views/background.h" | 18 #include "ui/views/background.h" |
18 #include "ui/views/layout/box_layout.h" | 19 #include "ui/views/layout/box_layout.h" |
19 | 20 |
20 namespace { | 21 namespace { |
21 | 22 |
22 const int kMaxResults = 6; | 23 const int kMaxResults = 6; |
23 const int kTimeoutIndicatorHeight = 2; | 24 const int kTimeoutIndicatorHeight = 2; |
24 const int kTimeoutFramerate = 60; | 25 const int kTimeoutFramerate = 60; |
25 const SkColor kTimeoutIndicatorColor = SkColorSetRGB(30, 144, 255); | 26 const SkColor kTimeoutIndicatorColor = SkColorSetRGB(30, 144, 255); |
26 | 27 |
27 } // namespace | 28 } // namespace |
28 | 29 |
29 namespace app_list { | 30 namespace app_list { |
30 | 31 |
31 SearchResultListView::SearchResultListView( | 32 SearchResultListView::SearchResultListView( |
32 SearchResultListViewDelegate* delegate) | 33 SearchResultListViewDelegate* delegate, |
| 34 AppListViewDelegate* view_delegate) |
33 : delegate_(delegate), | 35 : delegate_(delegate), |
| 36 view_delegate_(view_delegate), |
34 results_(NULL), | 37 results_(NULL), |
35 results_container_(new views::View), | 38 results_container_(new views::View), |
36 auto_launch_indicator_(new views::View), | 39 auto_launch_indicator_(new views::View), |
37 last_visible_index_(0), | 40 last_visible_index_(0), |
38 selected_index_(-1), | 41 selected_index_(-1), |
39 update_factory_(this) { | 42 update_factory_(this) { |
40 results_container_->SetLayoutManager( | 43 results_container_->SetLayoutManager( |
41 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); | 44 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); |
42 | 45 |
43 for (int i = 0; i < kMaxResults; ++i) | 46 for (int i = 0; i < kMaxResults; ++i) |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
79 | 82 |
80 selected_index_ = selected_index; | 83 selected_index_ = selected_index; |
81 | 84 |
82 if (selected_index_ >= 0) { | 85 if (selected_index_ >= 0) { |
83 SearchResultView* selected_view = GetResultViewAt(selected_index_); | 86 SearchResultView* selected_view = GetResultViewAt(selected_index_); |
84 selected_view->ClearSelectedAction(); | 87 selected_view->ClearSelectedAction(); |
85 selected_view->SchedulePaint(); | 88 selected_view->SchedulePaint(); |
86 selected_view->NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS, | 89 selected_view->NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS, |
87 true); | 90 true); |
88 } | 91 } |
| 92 if (auto_launch_animation_) |
| 93 CancelAutoLaunchTimeout(); |
89 } | 94 } |
90 | 95 |
91 bool SearchResultListView::IsResultViewSelected( | 96 bool SearchResultListView::IsResultViewSelected( |
92 const SearchResultView* result_view) const { | 97 const SearchResultView* result_view) const { |
93 if (selected_index_ < 0) | 98 if (selected_index_ < 0) |
94 return false; | 99 return false; |
95 | 100 |
96 return static_cast<const SearchResultView*>( | 101 return static_cast<const SearchResultView*>( |
97 results_container_->child_at(selected_index_)) == result_view; | 102 results_container_->child_at(selected_index_)) == result_view; |
98 } | 103 } |
99 | 104 |
100 void SearchResultListView::SetAutoLaunchTimeout( | 105 void SearchResultListView::UpdateAutoLaunchState() { |
101 const base::TimeDelta& timeout) { | 106 SetAutoLaunchTimeout(view_delegate_->GetAutoLaunchTimeout()); |
102 if (timeout > base::TimeDelta()) { | |
103 auto_launch_indicator_->SetVisible(true); | |
104 auto_launch_indicator_->SetBounds(0, 0, 0, kTimeoutIndicatorHeight); | |
105 auto_launch_animation_.reset(new gfx::LinearAnimation( | |
106 timeout.InMilliseconds(), kTimeoutFramerate, this)); | |
107 } else { | |
108 auto_launch_indicator_->SetVisible(false); | |
109 auto_launch_animation_.reset(); | |
110 } | |
111 } | |
112 | |
113 void SearchResultListView::CancelAutoLaunchTimeout() { | |
114 SetAutoLaunchTimeout(base::TimeDelta()); | |
115 } | 107 } |
116 | 108 |
117 bool SearchResultListView::OnKeyPressed(const ui::KeyEvent& event) { | 109 bool SearchResultListView::OnKeyPressed(const ui::KeyEvent& event) { |
118 if (selected_index_ >= 0 && | 110 if (selected_index_ >= 0 && |
119 results_container_->child_at(selected_index_)->OnKeyPressed(event)) { | 111 results_container_->child_at(selected_index_)->OnKeyPressed(event)) { |
120 return true; | 112 return true; |
121 } | 113 } |
122 | 114 |
123 switch (event.key_code()) { | 115 switch (event.key_code()) { |
124 case ui::VKEY_TAB: | 116 case ui::VKEY_TAB: |
125 if (event.IsShiftDown()) | 117 if (event.IsShiftDown()) |
126 SetSelectedIndex(std::max(selected_index_ - 1, 0)); | 118 SetSelectedIndex(std::max(selected_index_ - 1, 0)); |
127 else | 119 else |
128 SetSelectedIndex(std::min(selected_index_ + 1, last_visible_index_)); | 120 SetSelectedIndex(std::min(selected_index_ + 1, last_visible_index_)); |
129 return true; | 121 return true; |
130 case ui::VKEY_UP: | 122 case ui::VKEY_UP: |
131 SetSelectedIndex(std::max(selected_index_ - 1, 0)); | 123 SetSelectedIndex(std::max(selected_index_ - 1, 0)); |
132 return true; | 124 return true; |
133 case ui::VKEY_DOWN: | 125 case ui::VKEY_DOWN: |
134 SetSelectedIndex(std::min(selected_index_ + 1, last_visible_index_)); | 126 SetSelectedIndex(std::min(selected_index_ + 1, last_visible_index_)); |
135 return true; | 127 return true; |
136 default: | 128 default: |
137 break; | 129 break; |
138 } | 130 } |
139 | 131 |
140 return false; | 132 return false; |
141 } | 133 } |
142 | 134 |
| 135 void SearchResultListView::SetAutoLaunchTimeout( |
| 136 const base::TimeDelta& timeout) { |
| 137 if (timeout > base::TimeDelta()) { |
| 138 auto_launch_indicator_->SetVisible(true); |
| 139 auto_launch_indicator_->SetBounds(0, 0, 0, kTimeoutIndicatorHeight); |
| 140 auto_launch_animation_.reset(new gfx::LinearAnimation( |
| 141 timeout.InMilliseconds(), kTimeoutFramerate, this)); |
| 142 auto_launch_animation_->Start(); |
| 143 } else { |
| 144 auto_launch_indicator_->SetVisible(false); |
| 145 auto_launch_animation_.reset(); |
| 146 } |
| 147 } |
| 148 |
| 149 void SearchResultListView::CancelAutoLaunchTimeout() { |
| 150 SetAutoLaunchTimeout(base::TimeDelta()); |
| 151 view_delegate_->AutoLaunchCanceled(); |
| 152 } |
| 153 |
143 SearchResultView* SearchResultListView::GetResultViewAt(int index) { | 154 SearchResultView* SearchResultListView::GetResultViewAt(int index) { |
144 DCHECK(index >= 0 && index < results_container_->child_count()); | 155 DCHECK(index >= 0 && index < results_container_->child_count()); |
145 return static_cast<SearchResultView*>(results_container_->child_at(index)); | 156 return static_cast<SearchResultView*>(results_container_->child_at(index)); |
146 } | 157 } |
147 | 158 |
148 void SearchResultListView::Update() { | 159 void SearchResultListView::Update() { |
149 last_visible_index_ = 0; | 160 last_visible_index_ = 0; |
150 for (size_t i = 0; i < static_cast<size_t>(results_container_->child_count()); | 161 for (size_t i = 0; i < static_cast<size_t>(results_container_->child_count()); |
151 ++i) { | 162 ++i) { |
152 SearchResultView* result_view = GetResultViewAt(i); | 163 SearchResultView* result_view = GetResultViewAt(i); |
153 if (i < results_->item_count()) { | 164 if (i < results_->item_count()) { |
154 result_view->SetResult(results_->GetItemAt(i)); | 165 result_view->SetResult(results_->GetItemAt(i)); |
155 result_view->SetVisible(true); | 166 result_view->SetVisible(true); |
156 last_visible_index_ = i; | 167 last_visible_index_ = i; |
157 } else { | 168 } else { |
158 result_view->SetResult(NULL); | 169 result_view->SetResult(NULL); |
159 result_view->SetVisible(false); | 170 result_view->SetVisible(false); |
160 } | 171 } |
161 } | 172 } |
162 if (selected_index_ > last_visible_index_) | 173 if (selected_index_ > last_visible_index_) |
163 SetSelectedIndex(last_visible_index_); | 174 SetSelectedIndex(last_visible_index_); |
164 | 175 |
165 Layout(); | 176 Layout(); |
166 update_factory_.InvalidateWeakPtrs(); | 177 update_factory_.InvalidateWeakPtrs(); |
167 if (auto_launch_animation_) | 178 UpdateAutoLaunchState(); |
168 auto_launch_animation_->Start(); | |
169 } | 179 } |
170 | 180 |
171 void SearchResultListView::ScheduleUpdate() { | 181 void SearchResultListView::ScheduleUpdate() { |
172 // When search results are added one by one, each addition generates an update | 182 // When search results are added one by one, each addition generates an update |
173 // request. Consolidates those update requests into one Update call. | 183 // request. Consolidates those update requests into one Update call. |
174 if (!update_factory_.HasWeakPtrs()) { | 184 if (!update_factory_.HasWeakPtrs()) { |
175 base::MessageLoop::current()->PostTask( | 185 base::MessageLoop::current()->PostTask( |
176 FROM_HERE, | 186 FROM_HERE, |
177 base::Bind(&SearchResultListView::Update, | 187 base::Bind(&SearchResultListView::Update, |
178 update_factory_.GetWeakPtr())); | 188 update_factory_.GetWeakPtr())); |
179 } | 189 } |
180 } | 190 } |
181 | 191 |
| 192 void SearchResultListView::ForceAutoLaunchForTest() { |
| 193 if (auto_launch_animation_) |
| 194 AnimationEnded(auto_launch_animation_.get()); |
| 195 } |
| 196 |
182 void SearchResultListView::Layout() { | 197 void SearchResultListView::Layout() { |
183 results_container_->SetBoundsRect(GetLocalBounds()); | 198 results_container_->SetBoundsRect(GetLocalBounds()); |
184 } | 199 } |
185 | 200 |
186 gfx::Size SearchResultListView::GetPreferredSize() { | 201 gfx::Size SearchResultListView::GetPreferredSize() { |
187 return results_container_->GetPreferredSize(); | 202 return results_container_->GetPreferredSize(); |
188 } | 203 } |
189 | 204 |
190 int SearchResultListView::GetHeightForWidth(int w) { | 205 int SearchResultListView::GetHeightForWidth(int w) { |
191 return results_container_->GetHeightForWidth(w); | 206 return results_container_->GetHeightForWidth(w); |
192 } | 207 } |
193 | 208 |
194 void SearchResultListView::VisibilityChanged(views::View* starting_from, | 209 void SearchResultListView::VisibilityChanged(views::View* starting_from, |
195 bool is_visible) { | 210 bool is_visible) { |
196 if (!is_visible) { | 211 if (is_visible) |
197 auto_launch_indicator_->SetVisible(false); | 212 UpdateAutoLaunchState(); |
198 auto_launch_animation_.reset(); | 213 else |
199 } | 214 CancelAutoLaunchTimeout(); |
200 } | 215 } |
201 | 216 |
202 void SearchResultListView::AnimationEnded(const gfx::Animation* animation) { | 217 void SearchResultListView::AnimationEnded(const gfx::Animation* animation) { |
203 DCHECK_EQ(auto_launch_animation_.get(), animation); | 218 DCHECK_EQ(auto_launch_animation_.get(), animation); |
204 delegate_->OpenResult(results_->GetItemAt(0), true, ui::EF_NONE); | 219 delegate_->OpenResult(results_->GetItemAt(0), true, ui::EF_NONE); |
| 220 |
| 221 // The auto-launch has to be canceled explicitly. Think that one of searcher |
| 222 // is extremely slow. Sometimes the events would happen in the following |
| 223 // order: |
| 224 // 1. The search results arrive, auto-launch is dispatched |
| 225 // 2. Timed out and auto-launch the first search result |
| 226 // 3. Then another searcher adds search results more |
| 227 // At the step 3, we shouldn't dispatch the auto-launch again. |
| 228 CancelAutoLaunchTimeout(); |
205 } | 229 } |
206 | 230 |
207 void SearchResultListView::AnimationProgressed( | 231 void SearchResultListView::AnimationProgressed( |
208 const gfx::Animation* animation) { | 232 const gfx::Animation* animation) { |
209 DCHECK_EQ(auto_launch_animation_.get(), animation); | 233 DCHECK_EQ(auto_launch_animation_.get(), animation); |
210 int indicator_width = auto_launch_animation_->CurrentValueBetween(0, width()); | 234 int indicator_width = auto_launch_animation_->CurrentValueBetween(0, width()); |
211 auto_launch_indicator_->SetBounds( | 235 auto_launch_indicator_->SetBounds( |
212 0, 0, indicator_width, kTimeoutIndicatorHeight); | 236 0, 0, indicator_width, kTimeoutIndicatorHeight); |
213 } | 237 } |
214 | 238 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
253 if (delegate_ && view->result()) | 277 if (delegate_ && view->result()) |
254 delegate_->OnResultInstalled(view->result()); | 278 delegate_->OnResultInstalled(view->result()); |
255 } | 279 } |
256 | 280 |
257 void SearchResultListView::OnSearchResultUninstalled(SearchResultView* view) { | 281 void SearchResultListView::OnSearchResultUninstalled(SearchResultView* view) { |
258 if (delegate_ && view->result()) | 282 if (delegate_ && view->result()) |
259 delegate_->OnResultUninstalled(view->result()); | 283 delegate_->OnResultUninstalled(view->result()); |
260 } | 284 } |
261 | 285 |
262 } // namespace app_list | 286 } // namespace app_list |
OLD | NEW |