• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <vector>
9 
10 #include "base/logging.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/events/event.h"
22 #include "ui/gfx/animation/tween.h"
23 #include "ui/resources/grit/ui_resources.h"
24 #include "ui/views/view_model.h"
25 #include "ui/views/view_model_utils.h"
26 
27 namespace app_list {
28 
ContentsView(AppListMainView * app_list_main_view)29 ContentsView::ContentsView(AppListMainView* app_list_main_view)
30     : search_results_view_(NULL),
31       start_page_view_(NULL),
32       app_list_main_view_(app_list_main_view),
33       contents_switcher_view_(NULL),
34       view_model_(new views::ViewModel),
35       page_before_search_(0) {
36   pagination_model_.SetTransitionDurations(kPageTransitionDurationInMs,
37                                            kOverscrollPageTransitionDurationMs);
38   pagination_model_.AddObserver(this);
39 }
40 
~ContentsView()41 ContentsView::~ContentsView() {
42   pagination_model_.RemoveObserver(this);
43   if (contents_switcher_view_)
44     pagination_model_.RemoveObserver(contents_switcher_view_);
45 }
46 
InitNamedPages(AppListModel * model,AppListViewDelegate * view_delegate)47 void ContentsView::InitNamedPages(AppListModel* model,
48                                   AppListViewDelegate* view_delegate) {
49   DCHECK(model);
50 
51   if (app_list::switches::IsExperimentalAppListEnabled()) {
52     std::vector<views::View*> custom_page_views =
53         view_delegate->CreateCustomPageWebViews(GetLocalBounds().size());
54     for (std::vector<views::View*>::const_iterator it =
55              custom_page_views.begin();
56          it != custom_page_views.end();
57          ++it) {
58       AddLauncherPage(*it, IDR_APP_LIST_NOTIFICATIONS_ICON);
59     }
60 
61     start_page_view_ = new StartPageView(app_list_main_view_, view_delegate);
62     AddLauncherPage(
63         start_page_view_, IDR_APP_LIST_SEARCH_ICON, NAMED_PAGE_START);
64   } else {
65     search_results_view_ =
66         new SearchResultListView(app_list_main_view_, view_delegate);
67     AddLauncherPage(search_results_view_, 0, NAMED_PAGE_SEARCH_RESULTS);
68     search_results_view_->SetResults(model->results());
69   }
70 
71   apps_container_view_ = new AppsContainerView(app_list_main_view_, model);
72 
73   AddLauncherPage(
74       apps_container_view_, IDR_APP_LIST_APPS_ICON, NAMED_PAGE_APPS);
75 
76   int initial_page_index = app_list::switches::IsExperimentalAppListEnabled()
77                                ? GetPageIndexForNamedPage(NAMED_PAGE_START)
78                                : GetPageIndexForNamedPage(NAMED_PAGE_APPS);
79   DCHECK_GE(initial_page_index, 0);
80 
81   page_before_search_ = initial_page_index;
82   pagination_model_.SelectPage(initial_page_index, false);
83 
84   // Needed to update the main search box visibility.
85   ActivePageChanged(false);
86 }
87 
CancelDrag()88 void ContentsView::CancelDrag() {
89   if (apps_container_view_->apps_grid_view()->has_dragged_view())
90     apps_container_view_->apps_grid_view()->EndDrag(true);
91   if (apps_container_view_->app_list_folder_view()
92           ->items_grid_view()
93           ->has_dragged_view()) {
94     apps_container_view_->app_list_folder_view()->items_grid_view()->EndDrag(
95         true);
96   }
97 }
98 
SetDragAndDropHostOfCurrentAppList(ApplicationDragAndDropHost * drag_and_drop_host)99 void ContentsView::SetDragAndDropHostOfCurrentAppList(
100     ApplicationDragAndDropHost* drag_and_drop_host) {
101   apps_container_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
102 }
103 
SetContentsSwitcherView(ContentsSwitcherView * contents_switcher_view)104 void ContentsView::SetContentsSwitcherView(
105     ContentsSwitcherView* contents_switcher_view) {
106   DCHECK(!contents_switcher_view_);
107   contents_switcher_view_ = contents_switcher_view;
108   if (contents_switcher_view_)
109     pagination_model_.AddObserver(contents_switcher_view_);
110 }
111 
SetActivePage(int page_index)112 void ContentsView::SetActivePage(int page_index) {
113   if (GetActivePageIndex() == page_index)
114     return;
115 
116   SetActivePageInternal(page_index, false);
117 }
118 
GetActivePageIndex() const119 int ContentsView::GetActivePageIndex() const {
120   // The active page is changed at the beginning of an animation, not the end.
121   return pagination_model_.SelectedTargetPage();
122 }
123 
IsNamedPageActive(NamedPage named_page) const124 bool ContentsView::IsNamedPageActive(NamedPage named_page) const {
125   int active_page_index = GetActivePageIndex();
126   return active_page_index >= 0 &&
127          GetPageIndexForNamedPage(named_page) == active_page_index;
128 }
129 
GetPageIndexForNamedPage(NamedPage named_page) const130 int ContentsView::GetPageIndexForNamedPage(NamedPage named_page) const {
131   // Find the index of the view corresponding to the given named_page.
132   std::map<NamedPage, int>::const_iterator it =
133       named_page_to_view_.find(named_page);
134   if (it == named_page_to_view_.end())
135     return -1;
136 
137   return it->second;
138 }
139 
NumLauncherPages() const140 int ContentsView::NumLauncherPages() const {
141   return pagination_model_.total_pages();
142 }
143 
SetActivePageInternal(int page_index,bool show_search_results)144 void ContentsView::SetActivePageInternal(int page_index,
145                                          bool show_search_results) {
146   if (!show_search_results)
147     page_before_search_ = page_index;
148   // Start animating to the new page.
149   pagination_model_.SelectPage(page_index, true);
150   ActivePageChanged(show_search_results);
151 }
152 
ActivePageChanged(bool show_search_results)153 void ContentsView::ActivePageChanged(bool show_search_results) {
154   // TODO(xiyuan): Highlight default match instead of the first.
155   if (IsNamedPageActive(NAMED_PAGE_SEARCH_RESULTS) &&
156       search_results_view_->visible()) {
157     search_results_view_->SetSelectedIndex(0);
158   }
159   if (search_results_view_)
160     search_results_view_->UpdateAutoLaunchState();
161 
162   if (IsNamedPageActive(NAMED_PAGE_START)) {
163     if (show_search_results)
164       start_page_view_->ShowSearchResults();
165     else
166       start_page_view_->Reset();
167   }
168 
169   // Notify parent AppListMainView of the page change.
170   app_list_main_view_->UpdateSearchBoxVisibility();
171 }
172 
ShowSearchResults(bool show)173 void ContentsView::ShowSearchResults(bool show) {
174   int search_page = GetPageIndexForNamedPage(
175       app_list::switches::IsExperimentalAppListEnabled()
176           ? NAMED_PAGE_START
177           : NAMED_PAGE_SEARCH_RESULTS);
178   DCHECK_GE(search_page, 0);
179 
180   SetActivePageInternal(show ? search_page : page_before_search_, show);
181 }
182 
IsShowingSearchResults() const183 bool ContentsView::IsShowingSearchResults() const {
184   return app_list::switches::IsExperimentalAppListEnabled()
185              ? IsNamedPageActive(NAMED_PAGE_START) &&
186                    start_page_view_->IsShowingSearchResults()
187              : IsNamedPageActive(NAMED_PAGE_SEARCH_RESULTS);
188 }
189 
GetOffscreenPageBounds(int page_index) const190 gfx::Rect ContentsView::GetOffscreenPageBounds(int page_index) const {
191   gfx::Rect bounds(GetContentsBounds());
192   // The start page and search page origins are above; all other pages' origins
193   // are below.
194   int page_height = bounds.height();
195   bool origin_above =
196       GetPageIndexForNamedPage(NAMED_PAGE_START) == page_index ||
197       GetPageIndexForNamedPage(NAMED_PAGE_SEARCH_RESULTS) == page_index;
198   bounds.set_y(origin_above ? -page_height : page_height);
199   return bounds;
200 }
201 
UpdatePageBounds()202 void ContentsView::UpdatePageBounds() {
203   // The bounds calculations will potentially be mid-transition (depending on
204   // the state of the PaginationModel).
205   int current_page = std::max(0, pagination_model_.selected_page());
206   int target_page = current_page;
207   double progress = 1;
208   if (pagination_model_.has_transition()) {
209     const PaginationModel::Transition& transition =
210         pagination_model_.transition();
211     if (pagination_model_.is_valid_page(transition.target_page)) {
212       target_page = transition.target_page;
213       progress = transition.progress;
214     }
215   }
216 
217   // Move |current_page| from 0 to its origin. Move |target_page| from its
218   // origin to 0.
219   gfx::Rect on_screen(GetContentsBounds());
220   gfx::Rect current_page_origin(GetOffscreenPageBounds(current_page));
221   gfx::Rect target_page_origin(GetOffscreenPageBounds(target_page));
222   gfx::Rect current_page_rect(
223       gfx::Tween::RectValueBetween(progress, on_screen, current_page_origin));
224   gfx::Rect target_page_rect(
225       gfx::Tween::RectValueBetween(progress, target_page_origin, on_screen));
226 
227   view_model_->view_at(current_page)->SetBoundsRect(current_page_rect);
228   view_model_->view_at(target_page)->SetBoundsRect(target_page_rect);
229 }
230 
GetAppsPaginationModel()231 PaginationModel* ContentsView::GetAppsPaginationModel() {
232   return apps_container_view_->apps_grid_view()->pagination_model();
233 }
234 
ShowFolderContent(AppListFolderItem * item)235 void ContentsView::ShowFolderContent(AppListFolderItem* item) {
236   apps_container_view_->ShowActiveFolder(item);
237 }
238 
Prerender()239 void ContentsView::Prerender() {
240   apps_container_view_->apps_grid_view()->Prerender();
241 }
242 
GetPageView(int index)243 views::View* ContentsView::GetPageView(int index) {
244   return view_model_->view_at(index);
245 }
246 
AddBlankPageForTesting()247 void ContentsView::AddBlankPageForTesting() {
248   AddLauncherPage(new views::View, 0);
249 }
250 
AddLauncherPage(views::View * view,int resource_id)251 int ContentsView::AddLauncherPage(views::View* view, int resource_id) {
252   int page_index = view_model_->view_size();
253   AddChildView(view);
254   view_model_->Add(view, page_index);
255   if (contents_switcher_view_ && resource_id)
256     contents_switcher_view_->AddSwitcherButton(resource_id, page_index);
257   pagination_model_.SetTotalPages(view_model_->view_size());
258   return page_index;
259 }
260 
AddLauncherPage(views::View * view,int resource_id,NamedPage named_page)261 int ContentsView::AddLauncherPage(views::View* view,
262                                   int resource_id,
263                                   NamedPage named_page) {
264   int page_index = AddLauncherPage(view, resource_id);
265   named_page_to_view_.insert(std::pair<NamedPage, int>(named_page, page_index));
266   return page_index;
267 }
268 
GetPreferredSize() const269 gfx::Size ContentsView::GetPreferredSize() const {
270   const gfx::Size container_size =
271       apps_container_view_->apps_grid_view()->GetPreferredSize();
272   const gfx::Size results_size = search_results_view_
273                                      ? search_results_view_->GetPreferredSize()
274                                      : gfx::Size();
275 
276   int width = std::max(container_size.width(), results_size.width());
277   int height = std::max(container_size.height(), results_size.height());
278   return gfx::Size(width, height);
279 }
280 
Layout()281 void ContentsView::Layout() {
282   // Immediately finish all current animations.
283   pagination_model_.FinishAnimation();
284 
285   // Move the current view onto the screen, and all other views off screen to
286   // the left. (Since we are not animating, we don't need to be careful about
287   // which side we place the off-screen views onto.)
288   gfx::Rect rect(GetContentsBounds());
289   if (rect.IsEmpty())
290     return;
291 
292   gfx::Rect offscreen_target(rect);
293   offscreen_target.set_x(-rect.width());
294 
295   for (int i = 0; i < view_model_->view_size(); ++i) {
296     view_model_->view_at(i)->SetBoundsRect(
297         i == pagination_model_.SelectedTargetPage() ? rect : offscreen_target);
298   }
299 }
300 
OnKeyPressed(const ui::KeyEvent & event)301 bool ContentsView::OnKeyPressed(const ui::KeyEvent& event) {
302   return view_model_->view_at(GetActivePageIndex())->OnKeyPressed(event);
303 }
304 
TotalPagesChanged()305 void ContentsView::TotalPagesChanged() {
306 }
307 
SelectedPageChanged(int old_selected,int new_selected)308 void ContentsView::SelectedPageChanged(int old_selected, int new_selected) {
309 }
310 
TransitionStarted()311 void ContentsView::TransitionStarted() {
312 }
313 
TransitionChanged()314 void ContentsView::TransitionChanged() {
315   UpdatePageBounds();
316 }
317 
318 }  // namespace app_list
319