1 // Copyright 2013 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/app_list_main_view.h"
10 #include "base/callback.h"
11 #include "base/files/file_path.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/profiler/scoped_tracker.h"
14 #include "base/strings/string_util.h"
15 #include "ui/app_list/app_list_constants.h"
16 #include "ui/app_list/app_list_folder_item.h"
17 #include "ui/app_list/app_list_item.h"
18 #include "ui/app_list/app_list_model.h"
19 #include "ui/app_list/app_list_switches.h"
20 #include "ui/app_list/app_list_view_delegate.h"
21 #include "ui/app_list/pagination_model.h"
22 #include "ui/app_list/search_box_model.h"
23 #include "ui/app_list/views/app_list_folder_view.h"
24 #include "ui/app_list/views/app_list_item_view.h"
25 #include "ui/app_list/views/apps_container_view.h"
26 #include "ui/app_list/views/apps_grid_view.h"
27 #include "ui/app_list/views/contents_view.h"
28 #include "ui/app_list/views/search_box_view.h"
29 #include "ui/app_list/views/start_page_view.h"
30 #include "ui/views/border.h"
31 #include "ui/views/controls/button/button.h"
32 #include "ui/views/controls/button/custom_button.h"
33 #include "ui/views/controls/textfield/textfield.h"
34 #include "ui/views/layout/box_layout.h"
35 #include "ui/views/layout/fill_layout.h"
36 #include "ui/views/widget/widget.h"
42 // The maximum allowed time to wait for icon loading in milliseconds.
43 const int kMaxIconLoadingWaitTimeInMs
= 50;
47 ////////////////////////////////////////////////////////////////////////////////
48 // AppListMainView::IconLoader
50 class AppListMainView::IconLoader
: public AppListItemObserver
{
52 IconLoader(AppListMainView
* owner
,
57 item_
->AddObserver(this);
59 // Triggers icon loading for given |scale_factor|.
60 item_
->icon().GetRepresentation(scale
);
63 ~IconLoader() override
{ item_
->RemoveObserver(this); }
66 // AppListItemObserver overrides:
67 void ItemIconChanged() override
{
68 owner_
->OnItemIconLoaded(this);
69 // Note that IconLoader is released here.
72 AppListMainView
* owner_
;
75 DISALLOW_COPY_AND_ASSIGN(IconLoader
);
78 ////////////////////////////////////////////////////////////////////////////////
81 AppListMainView::AppListMainView(AppListViewDelegate
* delegate
)
82 : delegate_(delegate
),
83 model_(delegate
->GetModel()),
84 search_box_view_(nullptr),
85 contents_view_(nullptr),
86 weak_ptr_factory_(this) {
87 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical
, 0, 0, 0));
88 model_
->AddObserver(this);
91 AppListMainView::~AppListMainView() {
92 pending_icon_loaders_
.clear();
93 model_
->RemoveObserver(this);
96 void AppListMainView::Init(gfx::NativeView parent
,
97 int initial_apps_page
,
98 SearchBoxView
* search_box_view
) {
99 search_box_view_
= search_box_view
;
102 // Switch the apps grid view to the specified page.
103 app_list::PaginationModel
* pagination_model
= GetAppsPaginationModel();
104 if (pagination_model
->is_valid_page(initial_apps_page
))
105 pagination_model
->SelectPage(initial_apps_page
, false);
107 // Starts icon loading early.
108 PreloadIcons(parent
);
111 void AppListMainView::AddContentsViews() {
112 DCHECK(search_box_view_
);
114 contents_view_
= new ContentsView(this);
115 contents_view_
->Init(model_
);
116 AddChildView(contents_view_
);
118 search_box_view_
->set_contents_view(contents_view_
);
120 contents_view_
->SetPaintToLayer(true);
121 contents_view_
->SetFillsBoundsOpaquely(false);
122 contents_view_
->layer()->SetMasksToBounds(true);
124 delegate_
->StartSearch();
127 void AppListMainView::ShowAppListWhenReady() {
128 if (pending_icon_loaders_
.empty()) {
129 icon_loading_wait_timer_
.Stop();
134 if (icon_loading_wait_timer_
.IsRunning())
137 icon_loading_wait_timer_
.Start(
139 base::TimeDelta::FromMilliseconds(kMaxIconLoadingWaitTimeInMs
),
140 this, &AppListMainView::OnIconLoadingWaitTimer
);
143 void AppListMainView::ResetForShow() {
144 if (switches::IsExperimentalAppListEnabled()) {
145 contents_view_
->SetActivePage(
146 contents_view_
->GetPageIndexForState(AppListModel::STATE_START
));
148 contents_view_
->apps_container_view()->ResetForShowApps();
149 // We clear the search when hiding so when app list appears it is not showing
151 search_box_view_
->ClearSearch();
154 void AppListMainView::Close() {
155 icon_loading_wait_timer_
.Stop();
156 contents_view_
->CancelDrag();
159 void AppListMainView::Prerender() {
160 contents_view_
->Prerender();
163 void AppListMainView::ModelChanged() {
164 pending_icon_loaders_
.clear();
165 model_
->RemoveObserver(this);
166 model_
= delegate_
->GetModel();
167 model_
->AddObserver(this);
168 search_box_view_
->ModelChanged();
169 delete contents_view_
;
170 contents_view_
= NULL
;
175 void AppListMainView::SetDragAndDropHostOfCurrentAppList(
176 ApplicationDragAndDropHost
* drag_and_drop_host
) {
177 contents_view_
->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host
);
180 bool AppListMainView::ShouldCenterWindow() const {
181 return delegate_
->ShouldCenterWindow();
184 PaginationModel
* AppListMainView::GetAppsPaginationModel() {
185 return contents_view_
->apps_container_view()
187 ->pagination_model();
190 void AppListMainView::PreloadIcons(gfx::NativeView parent
) {
191 float scale_factor
= 1.0f
;
193 scale_factor
= ui::GetScaleFactorForNativeView(parent
);
195 // The PaginationModel could have -1 as the initial selected page and
196 // assumes first page (i.e. index 0) will be used in this case.
197 const int selected_page
=
198 std::max(0, GetAppsPaginationModel()->selected_page());
200 const AppsGridView
* const apps_grid_view
=
201 contents_view_
->apps_container_view()->apps_grid_view();
202 const int tiles_per_page
=
203 apps_grid_view
->cols() * apps_grid_view
->rows_per_page();
205 const int start_model_index
= selected_page
* tiles_per_page
;
206 const int end_model_index
=
207 std::min(static_cast<int>(model_
->top_level_item_list()->item_count()),
208 start_model_index
+ tiles_per_page
);
210 pending_icon_loaders_
.clear();
211 for (int i
= start_model_index
; i
< end_model_index
; ++i
) {
212 AppListItem
* item
= model_
->top_level_item_list()->item_at(i
);
213 if (item
->icon().HasRepresentation(scale_factor
))
216 pending_icon_loaders_
.push_back(new IconLoader(this, item
, scale_factor
));
220 void AppListMainView::OnIconLoadingWaitTimer() {
224 void AppListMainView::OnItemIconLoaded(IconLoader
* loader
) {
225 ScopedVector
<IconLoader
>::iterator it
= std::find(
226 pending_icon_loaders_
.begin(), pending_icon_loaders_
.end(), loader
);
227 DCHECK(it
!= pending_icon_loaders_
.end());
228 pending_icon_loaders_
.erase(it
);
230 if (pending_icon_loaders_
.empty() && icon_loading_wait_timer_
.IsRunning()) {
231 icon_loading_wait_timer_
.Stop();
236 void AppListMainView::NotifySearchBoxVisibilityChanged() {
237 // Repaint the AppListView's background which will repaint the background for
238 // the search box. This is needed because this view paints to a layer and
239 // won't propagate paints upward.
241 parent()->SchedulePaint();
244 void AppListMainView::OnCustomLauncherPageEnabledStateChanged(bool enabled
) {
246 // Make the custom page view visible again.
247 contents_view_
->custom_page_view()->SetVisible(true);
248 } else if (contents_view_
->IsStateActive(
249 AppListModel::STATE_CUSTOM_LAUNCHER_PAGE
)) {
250 // Animate to the start page if currently on the custom page view. The view
251 // will hide on animation completion.
252 contents_view_
->SetActivePage(
253 contents_view_
->GetPageIndexForState(AppListModel::STATE_START
));
255 // Hide the view immediately otherwise.
256 contents_view_
->custom_page_view()->SetVisible(false);
260 void AppListMainView::ActivateApp(AppListItem
* item
, int event_flags
) {
261 // TODO(jennyz): Activate the folder via AppListModel notification.
262 if (item
->GetItemType() == AppListFolderItem::kItemType
)
263 contents_view_
->ShowFolderContent(static_cast<AppListFolderItem
*>(item
));
265 item
->Activate(event_flags
);
268 void AppListMainView::GetShortcutPathForApp(
269 const std::string
& app_id
,
270 const base::Callback
<void(const base::FilePath
&)>& callback
) {
271 delegate_
->GetShortcutPathForApp(app_id
, callback
);
274 void AppListMainView::CancelDragInActiveFolder() {
275 contents_view_
->apps_container_view()
276 ->app_list_folder_view()
281 void AppListMainView::QueryChanged(SearchBoxView
* sender
) {
282 base::string16 query
;
283 base::TrimWhitespace(model_
->search_box()->text(), base::TRIM_ALL
, &query
);
284 bool should_show_search
= !query
.empty();
285 contents_view_
->ShowSearchResults(should_show_search
);
287 delegate_
->StartSearch();
290 void AppListMainView::BackButtonPressed() {
291 contents_view_
->Back();
294 void AppListMainView::OnResultInstalled(SearchResult
* result
) {
295 // Clears the search to show the apps grid. The last installed app
296 // should be highlighted and made visible already.
297 search_box_view_
->ClearSearch();
300 } // namespace app_list