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