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