Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / ui / app_list / views / app_list_main_view.cc
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.
4
5 #include "ui/app_list/views/app_list_main_view.h"
6
7 #include <algorithm>
8
9 #include "base/bind.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_switches.h"
19 #include "ui/app_list/app_list_view_delegate.h"
20 #include "ui/app_list/pagination_model.h"
21 #include "ui/app_list/search_box_model.h"
22 #include "ui/app_list/views/app_list_folder_view.h"
23 #include "ui/app_list/views/app_list_item_view.h"
24 #include "ui/app_list/views/apps_container_view.h"
25 #include "ui/app_list/views/apps_grid_view.h"
26 #include "ui/app_list/views/contents_switcher_view.h"
27 #include "ui/app_list/views/contents_view.h"
28 #include "ui/app_list/views/search_box_view.h"
29 #include "ui/views/border.h"
30 #include "ui/views/controls/textfield/textfield.h"
31 #include "ui/views/layout/box_layout.h"
32 #include "ui/views/layout/fill_layout.h"
33 #include "ui/views/widget/widget.h"
34
35 namespace app_list {
36
37 namespace {
38
39 // The maximum allowed time to wait for icon loading in milliseconds.
40 const int kMaxIconLoadingWaitTimeInMs = 50;
41
42 }  // namespace
43
44 ////////////////////////////////////////////////////////////////////////////////
45 // AppListMainView::IconLoader
46
47 class AppListMainView::IconLoader : public AppListItemObserver {
48  public:
49   IconLoader(AppListMainView* owner,
50              AppListItem* item,
51              float scale)
52       : owner_(owner),
53         item_(item) {
54     item_->AddObserver(this);
55
56     // Triggers icon loading for given |scale_factor|.
57     item_->icon().GetRepresentation(scale);
58   }
59
60   ~IconLoader() override { item_->RemoveObserver(this); }
61
62  private:
63   // AppListItemObserver overrides:
64   void ItemIconChanged() override {
65     owner_->OnItemIconLoaded(this);
66     // Note that IconLoader is released here.
67   }
68
69   AppListMainView* owner_;
70   AppListItem* item_;
71
72   DISALLOW_COPY_AND_ASSIGN(IconLoader);
73 };
74
75 ////////////////////////////////////////////////////////////////////////////////
76 // AppListMainView:
77
78 AppListMainView::AppListMainView(AppListViewDelegate* delegate)
79     : delegate_(delegate),
80       model_(delegate->GetModel()),
81       search_box_view_(NULL),
82       contents_view_(NULL),
83       contents_switcher_view_(NULL),
84       weak_ptr_factory_(this) {
85   SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
86 }
87
88 AppListMainView::~AppListMainView() {
89   pending_icon_loaders_.clear();
90 }
91
92 void AppListMainView::Init(gfx::NativeView parent,
93                            int initial_apps_page,
94                            SearchBoxView* search_box_view) {
95   search_box_view_ = search_box_view;
96   AddContentsViews();
97
98   // Switch the apps grid view to the specified page.
99   app_list::PaginationModel* pagination_model = GetAppsPaginationModel();
100   if (pagination_model->is_valid_page(initial_apps_page))
101     pagination_model->SelectPage(initial_apps_page, false);
102
103   // Starts icon loading early.
104   PreloadIcons(parent);
105 }
106
107 void AppListMainView::AddContentsViews() {
108   DCHECK(search_box_view_);
109
110   contents_view_ = new ContentsView(this);
111   if (app_list::switches::IsExperimentalAppListEnabled()) {
112     contents_switcher_view_ = new ContentsSwitcherView(contents_view_);
113     contents_view_->SetContentsSwitcherView(contents_switcher_view_);
114   }
115   contents_view_->Init(model_, delegate_);
116   AddChildView(contents_view_);
117   if (contents_switcher_view_)
118     AddChildView(contents_switcher_view_);
119
120   search_box_view_->set_contents_view(contents_view_);
121   UpdateSearchBoxVisibility();
122
123   contents_view_->SetPaintToLayer(true);
124   contents_view_->SetFillsBoundsOpaquely(false);
125   contents_view_->layer()->SetMasksToBounds(true);
126
127   delegate_->StartSearch();
128 }
129
130 void AppListMainView::ShowAppListWhenReady() {
131   if (pending_icon_loaders_.empty()) {
132     icon_loading_wait_timer_.Stop();
133     GetWidget()->Show();
134     return;
135   }
136
137   if (icon_loading_wait_timer_.IsRunning())
138     return;
139
140   icon_loading_wait_timer_.Start(
141       FROM_HERE,
142       base::TimeDelta::FromMilliseconds(kMaxIconLoadingWaitTimeInMs),
143       this, &AppListMainView::OnIconLoadingWaitTimer);
144 }
145
146 void AppListMainView::ResetForShow() {
147   if (switches::IsExperimentalAppListEnabled()) {
148     contents_view_->SetActivePage(
149         contents_view_->GetPageIndexForState(AppListModel::STATE_START));
150   }
151   contents_view_->apps_container_view()->ResetForShowApps();
152   // We clear the search when hiding so when app list appears it is not showing
153   // search results.
154   search_box_view_->ClearSearch();
155 }
156
157 void AppListMainView::Close() {
158   icon_loading_wait_timer_.Stop();
159   contents_view_->CancelDrag();
160 }
161
162 void AppListMainView::Prerender() {
163   contents_view_->Prerender();
164 }
165
166 void AppListMainView::ModelChanged() {
167   pending_icon_loaders_.clear();
168   model_ = delegate_->GetModel();
169   search_box_view_->ModelChanged();
170   delete contents_view_;
171   contents_view_ = NULL;
172   if (contents_switcher_view_) {
173     delete contents_switcher_view_;
174     contents_switcher_view_ = NULL;
175   }
176   AddContentsViews();
177   Layout();
178 }
179
180 void AppListMainView::UpdateSearchBoxVisibility() {
181   bool visible = !contents_view_->IsStateActive(AppListModel::STATE_START) ||
182                  contents_view_->IsShowingSearchResults();
183   search_box_view_->SetVisible(visible);
184   if (visible && GetWidget() && GetWidget()->IsVisible())
185     search_box_view_->search_box()->RequestFocus();
186 }
187
188 void AppListMainView::OnStartPageSearchTextfieldChanged(
189     const base::string16& new_contents) {
190   search_box_view_->SetVisible(true);
191   search_box_view_->search_box()->SetText(new_contents);
192   search_box_view_->search_box()->RequestFocus();
193 }
194
195 void AppListMainView::SetDragAndDropHostOfCurrentAppList(
196     ApplicationDragAndDropHost* drag_and_drop_host) {
197   contents_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
198 }
199
200 bool AppListMainView::ShouldCenterWindow() const {
201   return delegate_->ShouldCenterWindow();
202 }
203
204 PaginationModel* AppListMainView::GetAppsPaginationModel() {
205   return contents_view_->apps_container_view()
206       ->apps_grid_view()
207       ->pagination_model();
208 }
209
210 void AppListMainView::PreloadIcons(gfx::NativeView parent) {
211   float scale_factor = 1.0f;
212   if (parent)
213     scale_factor = ui::GetScaleFactorForNativeView(parent);
214
215   // The PaginationModel could have -1 as the initial selected page and
216   // assumes first page (i.e. index 0) will be used in this case.
217   const int selected_page =
218       std::max(0, GetAppsPaginationModel()->selected_page());
219
220   const AppsGridView* const apps_grid_view =
221       contents_view_->apps_container_view()->apps_grid_view();
222   const int tiles_per_page =
223       apps_grid_view->cols() * apps_grid_view->rows_per_page();
224
225   const int start_model_index = selected_page * tiles_per_page;
226   const int end_model_index =
227       std::min(static_cast<int>(model_->top_level_item_list()->item_count()),
228                start_model_index + tiles_per_page);
229
230   pending_icon_loaders_.clear();
231   for (int i = start_model_index; i < end_model_index; ++i) {
232     AppListItem* item = model_->top_level_item_list()->item_at(i);
233     if (item->icon().HasRepresentation(scale_factor))
234       continue;
235
236     pending_icon_loaders_.push_back(new IconLoader(this, item, scale_factor));
237   }
238 }
239
240 void AppListMainView::OnIconLoadingWaitTimer() {
241   GetWidget()->Show();
242 }
243
244 void AppListMainView::OnItemIconLoaded(IconLoader* loader) {
245   ScopedVector<IconLoader>::iterator it = std::find(
246       pending_icon_loaders_.begin(), pending_icon_loaders_.end(), loader);
247   DCHECK(it != pending_icon_loaders_.end());
248   pending_icon_loaders_.erase(it);
249
250   if (pending_icon_loaders_.empty() && icon_loading_wait_timer_.IsRunning()) {
251     icon_loading_wait_timer_.Stop();
252     GetWidget()->Show();
253   }
254 }
255
256 void AppListMainView::NotifySearchBoxVisibilityChanged() {
257   // Repaint the AppListView's background which will repaint the background for
258   // the search box. This is needed because this view paints to a layer and
259   // won't propagate paints upward.
260   if (parent())
261     parent()->SchedulePaint();
262 }
263
264 void AppListMainView::ActivateApp(AppListItem* item, int event_flags) {
265   // TODO(jennyz): Activate the folder via AppListModel notification.
266   if (item->GetItemType() == AppListFolderItem::kItemType)
267     contents_view_->ShowFolderContent(static_cast<AppListFolderItem*>(item));
268   else
269     item->Activate(event_flags);
270 }
271
272 void AppListMainView::GetShortcutPathForApp(
273     const std::string& app_id,
274     const base::Callback<void(const base::FilePath&)>& callback) {
275   delegate_->GetShortcutPathForApp(app_id, callback);
276 }
277
278 void AppListMainView::CancelDragInActiveFolder() {
279   contents_view_->apps_container_view()
280       ->app_list_folder_view()
281       ->items_grid_view()
282       ->EndDrag(true);
283 }
284
285 void AppListMainView::QueryChanged(SearchBoxView* sender) {
286   base::string16 query;
287   base::TrimWhitespace(model_->search_box()->text(), base::TRIM_ALL, &query);
288   bool should_show_search = !query.empty();
289   contents_view_->ShowSearchResults(should_show_search);
290   UpdateSearchBoxVisibility();
291
292   delegate_->StartSearch();
293 }
294
295 void AppListMainView::OnResultInstalled(SearchResult* result) {
296   // Clears the search to show the apps grid. The last installed app
297   // should be highlighted and made visible already.
298   search_box_view_->ClearSearch();
299 }
300
301 void AppListMainView::OnResultUninstalled(SearchResult* result) {
302   // Resubmit the query via a posted task so that all observers for the
303   // uninstall notification are notified.
304   base::MessageLoop::current()->PostTask(
305       FROM_HERE,
306       base::Bind(&AppListMainView::QueryChanged,
307                  weak_ptr_factory_.GetWeakPtr(),
308                  search_box_view_));
309 }
310
311 }  // namespace app_list