Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ui / app_list / views / contents_view.cc
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.
4
5 #include "ui/app_list/views/contents_view.h"
6
7 #include <algorithm>
8
9 #include "base/logging.h"
10 #include "ui/app_list/app_list_constants.h"
11 #include "ui/app_list/app_list_switches.h"
12 #include "ui/app_list/app_list_view_delegate.h"
13 #include "ui/app_list/pagination_model.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/search_result_list_view.h"
19 #include "ui/events/event.h"
20 #include "ui/views/animation/bounds_animator.h"
21 #include "ui/views/view_model.h"
22 #include "ui/views/view_model_utils.h"
23
24 namespace app_list {
25
26 namespace {
27
28 // Indexes of interesting views in ViewModel of ContentsView.
29 const int kIndexAppsContainer = 0;
30 const int kIndexSearchResults = 1;
31
32 const int kMinMouseWheelToSwitchPage = 20;
33 const int kMinScrollToSwitchPage = 20;
34 const int kMinHorizVelocityToSwitchPage = 800;
35
36 const double kFinishTransitionThreshold = 0.33;
37
38 AppsContainerView* GetAppsContainerView(views::ViewModel* model) {
39   return static_cast<AppsContainerView*>(model->view_at(kIndexAppsContainer));
40 }
41
42 SearchResultListView* GetSearchResultListView(views::ViewModel* model) {
43   return static_cast<SearchResultListView*>(
44       model->view_at(kIndexSearchResults));
45 }
46
47 }  // namespace
48
49 ContentsView::ContentsView(AppListMainView* app_list_main_view,
50                            PaginationModel* pagination_model,
51                            AppListModel* model,
52                            AppListViewDelegate* view_delegate)
53     : show_state_(SHOW_APPS),
54       pagination_model_(pagination_model),
55       view_model_(new views::ViewModel),
56       bounds_animator_(new views::BoundsAnimator(this)) {
57   DCHECK(model);
58   pagination_model_->SetTransitionDurations(
59       kPageTransitionDurationInMs,
60       kOverscrollPageTransitionDurationMs);
61
62   apps_container_view_ =
63       new AppsContainerView(app_list_main_view, pagination_model, model);
64   AddChildView(apps_container_view_);
65   view_model_->Add(apps_container_view_, kIndexAppsContainer);
66
67   SearchResultListView* search_results_view = new SearchResultListView(
68       app_list_main_view, view_delegate);
69   AddChildView(search_results_view);
70   view_model_->Add(search_results_view, kIndexSearchResults);
71
72   GetSearchResultListView(view_model_.get())->SetResults(model->results());
73 }
74
75 ContentsView::~ContentsView() {
76 }
77
78 void ContentsView::CancelDrag() {
79   if (apps_container_view_->apps_grid_view()->has_dragged_view())
80     apps_container_view_->apps_grid_view()->EndDrag(true);
81   if (apps_container_view_->app_list_folder_view()
82           ->items_grid_view()
83           ->has_dragged_view()) {
84     apps_container_view_->app_list_folder_view()->items_grid_view()->EndDrag(
85         true);
86   }
87 }
88
89 void ContentsView::SetDragAndDropHostOfCurrentAppList(
90     ApplicationDragAndDropHost* drag_and_drop_host) {
91   apps_container_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
92 }
93
94 void ContentsView::SetShowState(ShowState show_state) {
95   if (show_state_ == show_state)
96     return;
97
98   show_state_ = show_state;
99   ShowStateChanged();
100 }
101
102 void ContentsView::ShowStateChanged() {
103   SearchResultListView* results_view =
104       GetSearchResultListView(view_model_.get());
105   // TODO(xiyuan): Highlight default match instead of the first.
106   if (show_state_ == SHOW_SEARCH_RESULTS && results_view->visible())
107     results_view->SetSelectedIndex(0);
108   results_view->UpdateAutoLaunchState();
109
110   AnimateToIdealBounds();
111 }
112
113 void ContentsView::CalculateIdealBounds() {
114   gfx::Rect rect(GetContentsBounds());
115   if (rect.IsEmpty())
116     return;
117
118   if (app_list::switches::IsExperimentalAppListEnabled()) {
119     int incoming_view_index = 0;
120     switch (show_state_) {
121       case SHOW_APPS:
122         incoming_view_index = kIndexAppsContainer;
123         break;
124       case SHOW_SEARCH_RESULTS:
125         incoming_view_index = kIndexSearchResults;
126         break;
127       default:
128         NOTREACHED();
129     }
130
131     gfx::Rect incoming_target(rect);
132     gfx::Rect outgoing_target(rect);
133     outgoing_target.set_y(-outgoing_target.height());
134
135     for (int i = 0; i < view_model_->view_size(); ++i) {
136       view_model_->set_ideal_bounds(i,
137                                     i == incoming_view_index ? incoming_target
138                                                              : outgoing_target);
139     }
140     return;
141   }
142
143   gfx::Rect container_frame(rect);
144   gfx::Rect results_frame(rect);
145
146   // Offsets apps grid and result list based on |show_state_|.
147   // SearchResultListView is on top of apps grid. Visible view is left in
148   // visible area and invisible ones is put out of the visible area.
149   int contents_area_height = rect.height();
150   switch (show_state_) {
151     case SHOW_APPS:
152       results_frame.Offset(0, -contents_area_height);
153       break;
154     case SHOW_SEARCH_RESULTS:
155       container_frame.Offset(0, contents_area_height);
156       break;
157     default:
158       NOTREACHED() << "Unknown show_state_ " << show_state_;
159       break;
160   }
161
162   view_model_->set_ideal_bounds(kIndexAppsContainer, container_frame);
163   view_model_->set_ideal_bounds(kIndexSearchResults, results_frame);
164 }
165
166 void ContentsView::AnimateToIdealBounds() {
167   CalculateIdealBounds();
168   for (int i = 0; i < view_model_->view_size(); ++i) {
169     bounds_animator_->AnimateViewTo(view_model_->view_at(i),
170                                     view_model_->ideal_bounds(i));
171   }
172 }
173
174 void ContentsView::ShowSearchResults(bool show) {
175   SetShowState(show ? SHOW_SEARCH_RESULTS : SHOW_APPS);
176 }
177
178 void ContentsView::ShowFolderContent(AppListFolderItem* item) {
179   apps_container_view_->ShowActiveFolder(item);
180 }
181
182 void ContentsView::Prerender() {
183   const int selected_page = std::max(0, pagination_model_->selected_page());
184   apps_container_view_->apps_grid_view()->Prerender(selected_page);
185 }
186
187 gfx::Size ContentsView::GetPreferredSize() {
188   const gfx::Size container_size = GetAppsContainerView(view_model_.get())->
189       apps_grid_view()->GetPreferredSize();
190   const gfx::Size results_size =
191       GetSearchResultListView(view_model_.get())->GetPreferredSize();
192
193   int width = std::max(container_size.width(), results_size.width());
194   int height = std::max(container_size.height(), results_size.height());
195   return gfx::Size(width, height);
196 }
197
198 void ContentsView::Layout() {
199   CalculateIdealBounds();
200   views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_);
201 }
202
203 bool ContentsView::OnKeyPressed(const ui::KeyEvent& event) {
204   switch (show_state_) {
205     case SHOW_APPS:
206       return GetAppsContainerView(view_model_.get())->OnKeyPressed(event);
207     case SHOW_SEARCH_RESULTS:
208       return GetSearchResultListView(view_model_.get())->OnKeyPressed(event);
209     default:
210       NOTREACHED() << "Unknown show state " << show_state_;
211   }
212   return false;
213 }
214
215 bool ContentsView::OnMouseWheel(const ui::MouseWheelEvent& event) {
216   if (show_state_ != SHOW_APPS)
217     return false;
218
219   int offset;
220   if (abs(event.x_offset()) > abs(event.y_offset()))
221     offset = event.x_offset();
222   else
223     offset = event.y_offset();
224
225   if (abs(offset) > kMinMouseWheelToSwitchPage) {
226     if (!pagination_model_->has_transition()) {
227       pagination_model_->SelectPageRelative(
228           offset > 0 ? -1 : 1, true);
229     }
230     return true;
231   }
232
233   return false;
234 }
235
236 void ContentsView::OnGestureEvent(ui::GestureEvent* event) {
237   if (show_state_ != SHOW_APPS)
238     return;
239
240   switch (event->type()) {
241     case ui::ET_GESTURE_SCROLL_BEGIN:
242       pagination_model_->StartScroll();
243       event->SetHandled();
244       return;
245     case ui::ET_GESTURE_SCROLL_UPDATE:
246       // event->details.scroll_x() > 0 means moving contents to right. That is,
247       // transitioning to previous page.
248       pagination_model_->UpdateScroll(
249           event->details().scroll_x() / GetContentsBounds().width());
250       event->SetHandled();
251       return;
252     case ui::ET_GESTURE_SCROLL_END:
253       pagination_model_->EndScroll(pagination_model_->
254           transition().progress < kFinishTransitionThreshold);
255       event->SetHandled();
256       return;
257     case ui::ET_SCROLL_FLING_START: {
258       pagination_model_->EndScroll(true);
259       if (fabs(event->details().velocity_x()) > kMinHorizVelocityToSwitchPage) {
260         pagination_model_->SelectPageRelative(
261             event->details().velocity_x() < 0 ? 1 : -1,
262             true);
263       }
264       event->SetHandled();
265       return;
266     }
267     default:
268       break;
269   }
270 }
271
272 void ContentsView::OnScrollEvent(ui::ScrollEvent* event) {
273   if (show_state_ != SHOW_APPS ||
274       event->type() == ui::ET_SCROLL_FLING_CANCEL) {
275     return;
276   }
277
278   float offset;
279   if (abs(event->x_offset()) > abs(event->y_offset()))
280     offset = event->x_offset();
281   else
282     offset = event->y_offset();
283
284   if (abs(offset) > kMinScrollToSwitchPage) {
285     if (!pagination_model_->has_transition()) {
286       pagination_model_->SelectPageRelative(offset > 0 ? -1 : 1,
287                                             true);
288     }
289     event->SetHandled();
290     event->StopPropagation();
291   }
292 }
293
294 }  // namespace app_list