Performance histograms for extension content verification
[chromium-blink-merge.git] / ui / app_list / views / contents_view.cc
blob1b4e12447eb1e73549cd5da1639ff07d6851d3a3
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/contents_view.h"
7 #include <algorithm>
9 #include "base/logging.h"
10 #include "grit/ui_resources.h"
11 #include "ui/app_list/app_list_constants.h"
12 #include "ui/app_list/app_list_switches.h"
13 #include "ui/app_list/app_list_view_delegate.h"
14 #include "ui/app_list/views/app_list_folder_view.h"
15 #include "ui/app_list/views/app_list_main_view.h"
16 #include "ui/app_list/views/apps_container_view.h"
17 #include "ui/app_list/views/apps_grid_view.h"
18 #include "ui/app_list/views/contents_switcher_view.h"
19 #include "ui/app_list/views/search_result_list_view.h"
20 #include "ui/app_list/views/start_page_view.h"
21 #include "ui/base/resource/resource_bundle.h"
22 #include "ui/events/event.h"
23 #include "ui/views/view_model.h"
24 #include "ui/views/view_model_utils.h"
26 namespace app_list {
28 namespace {
30 const int kMinMouseWheelToSwitchPage = 20;
31 const int kMinScrollToSwitchPage = 20;
32 const int kMinHorizVelocityToSwitchPage = 800;
34 const double kFinishTransitionThreshold = 0.33;
36 } // namespace
38 ContentsView::ContentsView(AppListMainView* app_list_main_view)
39 : search_results_view_(NULL),
40 start_page_view_(NULL),
41 app_list_main_view_(app_list_main_view),
42 contents_switcher_view_(NULL),
43 view_model_(new views::ViewModel) {
44 pagination_model_.AddObserver(this);
47 ContentsView::~ContentsView() {
48 pagination_model_.RemoveObserver(this);
51 void ContentsView::InitNamedPages(AppListModel* model,
52 AppListViewDelegate* view_delegate) {
53 DCHECK(model);
55 if (app_list::switches::IsExperimentalAppListEnabled()) {
56 start_page_view_ = new StartPageView(app_list_main_view_, view_delegate);
57 AddLauncherPage(
58 start_page_view_, IDR_APP_LIST_SEARCH_ICON, NAMED_PAGE_START);
59 } else {
60 search_results_view_ =
61 new SearchResultListView(app_list_main_view_, view_delegate);
62 AddLauncherPage(search_results_view_, 0, NAMED_PAGE_SEARCH_RESULTS);
63 search_results_view_->SetResults(model->results());
66 apps_container_view_ = new AppsContainerView(app_list_main_view_, model);
67 int apps_page_index = AddLauncherPage(
68 apps_container_view_, IDR_APP_LIST_APPS_ICON, NAMED_PAGE_APPS);
70 pagination_model_.SelectPage(apps_page_index, false);
73 void ContentsView::CancelDrag() {
74 if (apps_container_view_->apps_grid_view()->has_dragged_view())
75 apps_container_view_->apps_grid_view()->EndDrag(true);
76 if (apps_container_view_->app_list_folder_view()
77 ->items_grid_view()
78 ->has_dragged_view()) {
79 apps_container_view_->app_list_folder_view()->items_grid_view()->EndDrag(
80 true);
84 void ContentsView::SetDragAndDropHostOfCurrentAppList(
85 ApplicationDragAndDropHost* drag_and_drop_host) {
86 apps_container_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
89 void ContentsView::SetActivePage(int page_index) {
90 if (GetActivePageIndex() == page_index)
91 return;
93 SetActivePageInternal(page_index, false);
96 int ContentsView::GetActivePageIndex() const {
97 // The active page is changed at the beginning of an animation, not the end.
98 return pagination_model_.SelectedTargetPage();
101 bool ContentsView::IsNamedPageActive(NamedPage named_page) const {
102 std::map<NamedPage, int>::const_iterator it =
103 named_page_to_view_.find(named_page);
104 if (it == named_page_to_view_.end())
105 return false;
106 return it->second == GetActivePageIndex();
109 int ContentsView::GetPageIndexForNamedPage(NamedPage named_page) const {
110 // Find the index of the view corresponding to the given named_page.
111 std::map<NamedPage, int>::const_iterator it =
112 named_page_to_view_.find(named_page);
113 // GetPageIndexForNamedPage should never be called on a named_page that does
114 // not have a corresponding view.
115 DCHECK(it != named_page_to_view_.end());
116 return it->second;
119 int ContentsView::NumLauncherPages() const {
120 return pagination_model_.total_pages();
123 void ContentsView::SetActivePageInternal(int page_index,
124 bool show_search_results) {
125 // Start animating to the new page.
126 pagination_model_.SelectPage(page_index, true);
127 ActivePageChanged(show_search_results);
130 void ContentsView::ActivePageChanged(bool show_search_results) {
131 // TODO(xiyuan): Highlight default match instead of the first.
132 if (IsNamedPageActive(NAMED_PAGE_SEARCH_RESULTS) &&
133 search_results_view_->visible()) {
134 search_results_view_->SetSelectedIndex(0);
136 if (search_results_view_)
137 search_results_view_->UpdateAutoLaunchState();
139 if (IsNamedPageActive(NAMED_PAGE_START)) {
140 if (show_search_results)
141 start_page_view_->ShowSearchResults();
142 else
143 start_page_view_->Reset();
146 // Notify parent AppListMainView of the page change.
147 app_list_main_view_->UpdateSearchBoxVisibility();
150 void ContentsView::ShowSearchResults(bool show) {
151 NamedPage new_named_page = show ? NAMED_PAGE_SEARCH_RESULTS : NAMED_PAGE_APPS;
152 if (app_list::switches::IsExperimentalAppListEnabled())
153 new_named_page = NAMED_PAGE_START;
155 SetActivePageInternal(GetPageIndexForNamedPage(new_named_page), show);
158 bool ContentsView::IsShowingSearchResults() const {
159 return app_list::switches::IsExperimentalAppListEnabled()
160 ? IsNamedPageActive(NAMED_PAGE_START) &&
161 start_page_view_->IsShowingSearchResults()
162 : IsNamedPageActive(NAMED_PAGE_SEARCH_RESULTS);
165 void ContentsView::UpdatePageBounds() {
166 gfx::Rect rect(GetContentsBounds());
167 if (rect.IsEmpty())
168 return;
170 // The bounds calculations will potentially be mid-transition (depending on
171 // the state of the PaginationModel).
172 int current_page = std::max(0, pagination_model_.selected_page());
173 int target_page = current_page;
174 double progress = 1;
175 if (pagination_model_.has_transition()) {
176 const PaginationModel::Transition& transition =
177 pagination_model_.transition();
178 if (pagination_model_.is_valid_page(transition.target_page)) {
179 target_page = transition.target_page;
180 progress = transition.progress;
184 gfx::Rect incoming_target(rect);
185 gfx::Rect outgoing_target(rect);
186 int dir = target_page > current_page ? -1 : 1;
188 if (app_list::switches::IsExperimentalAppListEnabled()) {
189 // The experimental app list transitions horizontally.
190 int page_width = rect.width();
191 int transition_offset = progress * page_width * dir;
193 outgoing_target.set_x(transition_offset);
194 incoming_target.set_x(dir < 0 ? transition_offset + page_width
195 : transition_offset - page_width);
196 } else {
197 // The normal app list transitions vertically.
198 int page_height = rect.height();
199 int transition_offset = progress * page_height * dir;
201 outgoing_target.set_y(transition_offset);
202 incoming_target.set_y(dir < 0 ? transition_offset + page_height
203 : transition_offset - page_height);
206 view_model_->view_at(current_page)->SetBoundsRect(outgoing_target);
207 view_model_->view_at(target_page)->SetBoundsRect(incoming_target);
210 PaginationModel* ContentsView::GetAppsPaginationModel() {
211 return apps_container_view_->apps_grid_view()->pagination_model();
214 void ContentsView::ShowFolderContent(AppListFolderItem* item) {
215 apps_container_view_->ShowActiveFolder(item);
218 void ContentsView::Prerender() {
219 const int selected_page =
220 std::max(0, GetAppsPaginationModel()->selected_page());
221 apps_container_view_->apps_grid_view()->Prerender(selected_page);
224 views::View* ContentsView::GetPageView(int index) {
225 return view_model_->view_at(index);
228 void ContentsView::AddBlankPageForTesting() {
229 AddLauncherPage(new views::View, 0);
232 int ContentsView::AddLauncherPage(views::View* view, int resource_id) {
233 int page_index = view_model_->view_size();
234 AddChildView(view);
235 view_model_->Add(view, page_index);
236 pagination_model_.SetTotalPages(view_model_->view_size());
237 if (contents_switcher_view_)
238 contents_switcher_view_->AddSwitcherButton(resource_id, page_index);
239 return page_index;
242 int ContentsView::AddLauncherPage(views::View* view,
243 int resource_id,
244 NamedPage named_page) {
245 int page_index = AddLauncherPage(view, resource_id);
246 named_page_to_view_.insert(std::pair<NamedPage, int>(named_page, page_index));
247 return page_index;
250 gfx::Size ContentsView::GetPreferredSize() const {
251 const gfx::Size container_size =
252 apps_container_view_->apps_grid_view()->GetPreferredSize();
253 const gfx::Size results_size = search_results_view_
254 ? search_results_view_->GetPreferredSize()
255 : gfx::Size();
257 int width = std::max(container_size.width(), results_size.width());
258 int height = std::max(container_size.height(), results_size.height());
259 return gfx::Size(width, height);
262 void ContentsView::Layout() {
263 // Immediately finish all current animations.
264 pagination_model_.FinishAnimation();
266 // Move the current view onto the screen, and all other views off screen to
267 // the left. (Since we are not animating, we don't need to be careful about
268 // which side we place the off-screen views onto.)
269 gfx::Rect rect(GetContentsBounds());
270 if (rect.IsEmpty())
271 return;
273 gfx::Rect offscreen_target(rect);
274 offscreen_target.set_x(-rect.width());
276 for (int i = 0; i < view_model_->view_size(); ++i) {
277 view_model_->view_at(i)->SetBoundsRect(
278 i == pagination_model_.SelectedTargetPage() ? rect : offscreen_target);
282 bool ContentsView::OnKeyPressed(const ui::KeyEvent& event) {
283 return view_model_->view_at(GetActivePageIndex())->OnKeyPressed(event);
286 bool ContentsView::OnMouseWheel(const ui::MouseWheelEvent& event) {
287 if (!IsNamedPageActive(NAMED_PAGE_APPS))
288 return false;
290 int offset;
291 if (abs(event.x_offset()) > abs(event.y_offset()))
292 offset = event.x_offset();
293 else
294 offset = event.y_offset();
296 if (abs(offset) > kMinMouseWheelToSwitchPage) {
297 if (!GetAppsPaginationModel()->has_transition()) {
298 GetAppsPaginationModel()->SelectPageRelative(offset > 0 ? -1 : 1, true);
300 return true;
303 return false;
306 void ContentsView::TotalPagesChanged() {
309 void ContentsView::SelectedPageChanged(int old_selected, int new_selected) {
312 void ContentsView::TransitionStarted() {
315 void ContentsView::TransitionChanged() {
316 UpdatePageBounds();
319 void ContentsView::OnGestureEvent(ui::GestureEvent* event) {
320 if (!IsNamedPageActive(NAMED_PAGE_APPS))
321 return;
323 switch (event->type()) {
324 case ui::ET_GESTURE_SCROLL_BEGIN:
325 GetAppsPaginationModel()->StartScroll();
326 event->SetHandled();
327 return;
328 case ui::ET_GESTURE_SCROLL_UPDATE:
329 // event->details.scroll_x() > 0 means moving contents to right. That is,
330 // transitioning to previous page.
331 GetAppsPaginationModel()->UpdateScroll(event->details().scroll_x() /
332 GetContentsBounds().width());
333 event->SetHandled();
334 return;
335 case ui::ET_GESTURE_SCROLL_END:
336 GetAppsPaginationModel()->EndScroll(
337 GetAppsPaginationModel()->transition().progress <
338 kFinishTransitionThreshold);
339 event->SetHandled();
340 return;
341 case ui::ET_SCROLL_FLING_START: {
342 GetAppsPaginationModel()->EndScroll(true);
343 if (fabs(event->details().velocity_x()) > kMinHorizVelocityToSwitchPage) {
344 GetAppsPaginationModel()->SelectPageRelative(
345 event->details().velocity_x() < 0 ? 1 : -1, true);
347 event->SetHandled();
348 return;
350 default:
351 break;
355 void ContentsView::OnScrollEvent(ui::ScrollEvent* event) {
356 if (!IsNamedPageActive(NAMED_PAGE_APPS) ||
357 event->type() == ui::ET_SCROLL_FLING_CANCEL) {
358 return;
361 float offset;
362 if (std::abs(event->x_offset()) > std::abs(event->y_offset()))
363 offset = event->x_offset();
364 else
365 offset = event->y_offset();
367 if (std::abs(offset) > kMinScrollToSwitchPage) {
368 if (!GetAppsPaginationModel()->has_transition()) {
369 GetAppsPaginationModel()->SelectPageRelative(offset > 0 ? -1 : 1, true);
371 event->SetHandled();
372 event->StopPropagation();
376 } // namespace app_list