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/strings/string_util.h"
14 #include "ui/app_list/app_list_constants.h"
15 #include "ui/app_list/app_list_folder_item.h"
16 #include "ui/app_list/app_list_item.h"
17 #include "ui/app_list/app_list_model.h"
18 #include "ui/app_list/app_list_view_delegate.h"
19 #include "ui/app_list/pagination_model.h"
20 #include "ui/app_list/search_box_model.h"
21 #include "ui/app_list/views/app_list_item_view.h"
22 #include "ui/app_list/views/contents_view.h"
23 #include "ui/app_list/views/search_box_view.h"
24 #include "ui/views/controls/textfield/textfield.h"
25 #include "ui/views/layout/box_layout.h"
26 #include "ui/views/widget/widget.h"
32 // Inner padding space in pixels of bubble contents.
33 const int kInnerPadding
= 1;
35 // The maximum allowed time to wait for icon loading in milliseconds.
36 const int kMaxIconLoadingWaitTimeInMs
= 50;
40 ////////////////////////////////////////////////////////////////////////////////
41 // AppListMainView::IconLoader
43 class AppListMainView::IconLoader
: public AppListItemObserver
{
45 IconLoader(AppListMainView
* owner
,
50 item_
->AddObserver(this);
52 // Triggers icon loading for given |scale_factor|.
53 item_
->icon().GetRepresentation(scale
);
56 virtual ~IconLoader() {
57 item_
->RemoveObserver(this);
61 // AppListItemObserver overrides:
62 virtual void ItemIconChanged() OVERRIDE
{
63 owner_
->OnItemIconLoaded(this);
64 // Note that IconLoader is released here.
66 virtual void ItemTitleChanged() OVERRIDE
{}
67 virtual void ItemHighlightedChanged() OVERRIDE
{}
68 virtual void ItemIsInstallingChanged() OVERRIDE
{}
69 virtual void ItemPercentDownloadedChanged() OVERRIDE
{}
71 AppListMainView
* owner_
;
74 DISALLOW_COPY_AND_ASSIGN(IconLoader
);
77 ////////////////////////////////////////////////////////////////////////////////
80 AppListMainView::AppListMainView(AppListViewDelegate
* delegate
,
81 PaginationModel
* pagination_model
,
82 gfx::NativeView parent
)
83 : delegate_(delegate
),
84 pagination_model_(pagination_model
),
85 model_(delegate
->GetModel()),
86 search_box_view_(NULL
),
88 weak_ptr_factory_(this) {
89 // Starts icon loading early.
92 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical
,
97 search_box_view_
= new SearchBoxView(this, delegate
);
98 AddChildView(search_box_view_
);
102 void AppListMainView::AddContentsView() {
103 contents_view_
= new ContentsView(
104 this, pagination_model_
, model_
, delegate_
);
105 AddChildView(contents_view_
);
107 search_box_view_
->set_contents_view(contents_view_
);
109 #if defined(USE_AURA)
110 contents_view_
->SetPaintToLayer(true);
111 contents_view_
->SetFillsBoundsOpaquely(false);
112 contents_view_
->layer()->SetMasksToBounds(true);
116 AppListMainView::~AppListMainView() {
117 pending_icon_loaders_
.clear();
120 void AppListMainView::ShowAppListWhenReady() {
121 if (pending_icon_loaders_
.empty()) {
122 icon_loading_wait_timer_
.Stop();
127 if (icon_loading_wait_timer_
.IsRunning())
130 icon_loading_wait_timer_
.Start(
132 base::TimeDelta::FromMilliseconds(kMaxIconLoadingWaitTimeInMs
),
133 this, &AppListMainView::OnIconLoadingWaitTimer
);
136 void AppListMainView::Close() {
137 icon_loading_wait_timer_
.Stop();
138 contents_view_
->CancelDrag();
141 void AppListMainView::Prerender() {
142 contents_view_
->Prerender();
145 void AppListMainView::ModelChanged() {
146 pending_icon_loaders_
.clear();
147 model_
= delegate_
->GetModel();
148 search_box_view_
->ModelChanged();
149 delete contents_view_
;
150 contents_view_
= NULL
;
151 pagination_model_
->SelectPage(0, false /* animate */);
156 void AppListMainView::SetDragAndDropHostOfCurrentAppList(
157 ApplicationDragAndDropHost
* drag_and_drop_host
) {
158 contents_view_
->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host
);
161 void AppListMainView::PreloadIcons(gfx::NativeView parent
) {
162 ui::ScaleFactor scale_factor
= ui::SCALE_FACTOR_100P
;
164 scale_factor
= ui::GetScaleFactorForNativeView(parent
);
166 float scale
= ui::GetImageScale(scale_factor
);
167 // |pagination_model| could have -1 as the initial selected page and
168 // assumes first page (i.e. index 0) will be used in this case.
169 const int selected_page
= std::max(0, pagination_model_
->selected_page());
171 const int tiles_per_page
= kPreferredCols
* kPreferredRows
;
172 const int start_model_index
= selected_page
* tiles_per_page
;
173 const int end_model_index
= std::min(
174 static_cast<int>(model_
->item_list()->item_count()),
175 start_model_index
+ tiles_per_page
);
177 pending_icon_loaders_
.clear();
178 for (int i
= start_model_index
; i
< end_model_index
; ++i
) {
179 AppListItem
* item
= model_
->item_list()->item_at(i
);
180 if (item
->icon().HasRepresentation(scale
))
183 pending_icon_loaders_
.push_back(new IconLoader(this, item
, scale
));
187 void AppListMainView::OnIconLoadingWaitTimer() {
191 void AppListMainView::OnItemIconLoaded(IconLoader
* loader
) {
192 ScopedVector
<IconLoader
>::iterator it
= std::find(
193 pending_icon_loaders_
.begin(), pending_icon_loaders_
.end(), loader
);
194 DCHECK(it
!= pending_icon_loaders_
.end());
195 pending_icon_loaders_
.erase(it
);
197 if (pending_icon_loaders_
.empty() && icon_loading_wait_timer_
.IsRunning()) {
198 icon_loading_wait_timer_
.Stop();
203 void AppListMainView::ActivateApp(AppListItem
* item
, int event_flags
) {
204 // TODO(jennyz): Activate the folder via AppListModel notification.
205 if (item
->GetItemType() == AppListFolderItem::kItemType
)
206 contents_view_
->ShowFolderContent(static_cast<AppListFolderItem
*>(item
));
208 item
->Activate(event_flags
);
211 void AppListMainView::GetShortcutPathForApp(
212 const std::string
& app_id
,
213 const base::Callback
<void(const base::FilePath
&)>& callback
) {
214 delegate_
->GetShortcutPathForApp(app_id
, callback
);
217 void AppListMainView::QueryChanged(SearchBoxView
* sender
) {
218 base::string16 query
;
219 TrimWhitespace(model_
->search_box()->text(), TRIM_ALL
, &query
);
220 bool should_show_search
= !query
.empty();
221 contents_view_
->ShowSearchResults(should_show_search
);
223 if (should_show_search
)
224 delegate_
->StartSearch();
226 delegate_
->StopSearch();
229 void AppListMainView::OpenResult(SearchResult
* result
, int event_flags
) {
230 delegate_
->OpenSearchResult(result
, event_flags
);
233 void AppListMainView::InvokeResultAction(SearchResult
* result
,
236 delegate_
->InvokeSearchResultAction(result
, action_index
, event_flags
);
239 void AppListMainView::OnResultInstalled(SearchResult
* result
) {
240 // Clears the search to show the apps grid. The last installed app
241 // should be highlighted and made visible already.
242 search_box_view_
->ClearSearch();
245 void AppListMainView::OnResultUninstalled(SearchResult
* result
) {
246 // Resubmit the query via a posted task so that all observers for the
247 // uninstall notification are notified.
248 base::MessageLoop::current()->PostTask(
250 base::Bind(&AppListMainView::QueryChanged
,
251 weak_ptr_factory_
.GetWeakPtr(),
255 } // namespace app_list