Task Manager: Remove goat teleporter.
[chromium-blink-merge.git] / ui / app_list / views / app_list_main_view.cc
blob80afe47337327df2a648cd5d75fc376ed364924e
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"
7 #include <algorithm>
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"
35 namespace app_list {
37 namespace {
39 // Inner padding space in pixels of bubble contents.
40 const int kInnerPadding = 1;
42 // The maximum allowed time to wait for icon loading in milliseconds.
43 const int kMaxIconLoadingWaitTimeInMs = 50;
45 // The padding around the search box in the experimental app list.
46 const int kSearchBoxViewPadding = 24;
47 const int kSearchBoxViewPaddingBottom = 12;
49 // A view that holds another view and takes its preferred size. This is used for
50 // wrapping the search box view so it still gets laid out while hidden. This is
51 // a separate class so it can notify the main view on search box visibility
52 // change.
53 class SearchBoxContainerView : public views::View {
54 public:
55 SearchBoxContainerView(AppListMainView* host, SearchBoxView* search_box)
56 : host_(host), search_box_(search_box) {
57 SetLayoutManager(new views::FillLayout());
58 AddChildView(search_box);
60 virtual ~SearchBoxContainerView() {}
62 private:
63 // Overridden from views::View:
64 virtual void ChildVisibilityChanged(views::View* child) OVERRIDE {
65 DCHECK_EQ(search_box_, child);
66 host_->NotifySearchBoxVisibilityChanged();
69 AppListMainView* host_;
70 SearchBoxView* search_box_;
72 DISALLOW_COPY_AND_ASSIGN(SearchBoxContainerView);
75 } // namespace
77 ////////////////////////////////////////////////////////////////////////////////
78 // AppListMainView::IconLoader
80 class AppListMainView::IconLoader : public AppListItemObserver {
81 public:
82 IconLoader(AppListMainView* owner,
83 AppListItem* item,
84 float scale)
85 : owner_(owner),
86 item_(item) {
87 item_->AddObserver(this);
89 // Triggers icon loading for given |scale_factor|.
90 item_->icon().GetRepresentation(scale);
93 virtual ~IconLoader() {
94 item_->RemoveObserver(this);
97 private:
98 // AppListItemObserver overrides:
99 virtual void ItemIconChanged() OVERRIDE {
100 owner_->OnItemIconLoaded(this);
101 // Note that IconLoader is released here.
104 AppListMainView* owner_;
105 AppListItem* item_;
107 DISALLOW_COPY_AND_ASSIGN(IconLoader);
110 ////////////////////////////////////////////////////////////////////////////////
111 // AppListMainView:
113 AppListMainView::AppListMainView(AppListViewDelegate* delegate,
114 int initial_apps_page,
115 gfx::NativeView parent)
116 : delegate_(delegate),
117 model_(delegate->GetModel()),
118 search_box_view_(NULL),
119 contents_view_(NULL),
120 contents_switcher_view_(NULL),
121 weak_ptr_factory_(this) {
122 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical,
123 kInnerPadding,
124 kInnerPadding,
125 kInnerPadding));
127 search_box_view_ = new SearchBoxView(this, delegate);
128 views::View* container = new SearchBoxContainerView(this, search_box_view_);
129 if (switches::IsExperimentalAppListEnabled()) {
130 container->SetBorder(
131 views::Border::CreateEmptyBorder(kSearchBoxViewPadding,
132 kSearchBoxViewPadding,
133 kSearchBoxViewPaddingBottom,
134 kSearchBoxViewPadding));
136 AddChildView(container);
137 AddContentsViews();
139 // Switch the apps grid view to the specified page.
140 app_list::PaginationModel* pagination_model = GetAppsPaginationModel();
141 if (pagination_model->is_valid_page(initial_apps_page))
142 pagination_model->SelectPage(initial_apps_page, false);
144 // Starts icon loading early.
145 PreloadIcons(parent);
148 void AppListMainView::AddContentsViews() {
149 contents_view_ = new ContentsView(this);
150 if (app_list::switches::IsExperimentalAppListEnabled()) {
151 contents_switcher_view_ = new ContentsSwitcherView(contents_view_);
152 contents_view_->SetContentsSwitcherView(contents_switcher_view_);
154 contents_view_->InitNamedPages(model_, delegate_);
155 AddChildView(contents_view_);
156 if (contents_switcher_view_)
157 AddChildView(contents_switcher_view_);
159 search_box_view_->set_contents_view(contents_view_);
161 contents_view_->SetPaintToLayer(true);
162 contents_view_->SetFillsBoundsOpaquely(false);
163 contents_view_->layer()->SetMasksToBounds(true);
165 delegate_->StartSearch();
168 AppListMainView::~AppListMainView() {
169 pending_icon_loaders_.clear();
172 void AppListMainView::ShowAppListWhenReady() {
173 if (pending_icon_loaders_.empty()) {
174 icon_loading_wait_timer_.Stop();
175 GetWidget()->Show();
176 return;
179 if (icon_loading_wait_timer_.IsRunning())
180 return;
182 icon_loading_wait_timer_.Start(
183 FROM_HERE,
184 base::TimeDelta::FromMilliseconds(kMaxIconLoadingWaitTimeInMs),
185 this, &AppListMainView::OnIconLoadingWaitTimer);
188 void AppListMainView::ResetForShow() {
189 contents_view_->apps_container_view()->ResetForShowApps();
190 // We clear the search when hiding so when app list appears it is not showing
191 // search results.
192 search_box_view_->ClearSearch();
195 void AppListMainView::Close() {
196 icon_loading_wait_timer_.Stop();
197 contents_view_->CancelDrag();
200 void AppListMainView::Prerender() {
201 contents_view_->Prerender();
204 void AppListMainView::ModelChanged() {
205 pending_icon_loaders_.clear();
206 model_ = delegate_->GetModel();
207 search_box_view_->ModelChanged();
208 delete contents_view_;
209 contents_view_ = NULL;
210 if (contents_switcher_view_) {
211 delete contents_switcher_view_;
212 contents_switcher_view_ = NULL;
214 AddContentsViews();
215 Layout();
218 void AppListMainView::UpdateSearchBoxVisibility() {
219 bool visible =
220 !contents_view_->IsNamedPageActive(ContentsView::NAMED_PAGE_START) ||
221 contents_view_->IsShowingSearchResults();
222 search_box_view_->SetVisible(visible);
223 if (visible && GetWidget() && GetWidget()->IsVisible())
224 search_box_view_->search_box()->RequestFocus();
227 void AppListMainView::OnStartPageSearchTextfieldChanged(
228 const base::string16& new_contents) {
229 search_box_view_->SetVisible(true);
230 search_box_view_->search_box()->SetText(new_contents);
231 search_box_view_->search_box()->RequestFocus();
234 void AppListMainView::SetDragAndDropHostOfCurrentAppList(
235 ApplicationDragAndDropHost* drag_and_drop_host) {
236 contents_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
239 bool AppListMainView::ShouldCenterWindow() const {
240 return delegate_->ShouldCenterWindow();
243 PaginationModel* AppListMainView::GetAppsPaginationModel() {
244 return contents_view_->apps_container_view()
245 ->apps_grid_view()
246 ->pagination_model();
249 void AppListMainView::PreloadIcons(gfx::NativeView parent) {
250 float scale_factor = 1.0f;
251 if (parent)
252 scale_factor = ui::GetScaleFactorForNativeView(parent);
254 // The PaginationModel could have -1 as the initial selected page and
255 // assumes first page (i.e. index 0) will be used in this case.
256 const int selected_page =
257 std::max(0, GetAppsPaginationModel()->selected_page());
259 const AppsGridView* const apps_grid_view =
260 contents_view_->apps_container_view()->apps_grid_view();
261 const int tiles_per_page =
262 apps_grid_view->cols() * apps_grid_view->rows_per_page();
264 const int start_model_index = selected_page * tiles_per_page;
265 const int end_model_index =
266 std::min(static_cast<int>(model_->top_level_item_list()->item_count()),
267 start_model_index + tiles_per_page);
269 pending_icon_loaders_.clear();
270 for (int i = start_model_index; i < end_model_index; ++i) {
271 AppListItem* item = model_->top_level_item_list()->item_at(i);
272 if (item->icon().HasRepresentation(scale_factor))
273 continue;
275 pending_icon_loaders_.push_back(new IconLoader(this, item, scale_factor));
279 void AppListMainView::OnIconLoadingWaitTimer() {
280 GetWidget()->Show();
283 void AppListMainView::OnItemIconLoaded(IconLoader* loader) {
284 ScopedVector<IconLoader>::iterator it = std::find(
285 pending_icon_loaders_.begin(), pending_icon_loaders_.end(), loader);
286 DCHECK(it != pending_icon_loaders_.end());
287 pending_icon_loaders_.erase(it);
289 if (pending_icon_loaders_.empty() && icon_loading_wait_timer_.IsRunning()) {
290 icon_loading_wait_timer_.Stop();
291 GetWidget()->Show();
295 void AppListMainView::NotifySearchBoxVisibilityChanged() {
296 // Repaint the AppListView's background which will repaint the background for
297 // the search box. This is needed because this view paints to a layer and
298 // won't propagate paints upward.
299 if (parent())
300 parent()->SchedulePaint();
303 void AppListMainView::ActivateApp(AppListItem* item, int event_flags) {
304 // TODO(jennyz): Activate the folder via AppListModel notification.
305 if (item->GetItemType() == AppListFolderItem::kItemType)
306 contents_view_->ShowFolderContent(static_cast<AppListFolderItem*>(item));
307 else
308 item->Activate(event_flags);
311 void AppListMainView::GetShortcutPathForApp(
312 const std::string& app_id,
313 const base::Callback<void(const base::FilePath&)>& callback) {
314 delegate_->GetShortcutPathForApp(app_id, callback);
317 void AppListMainView::CancelDragInActiveFolder() {
318 contents_view_->apps_container_view()
319 ->app_list_folder_view()
320 ->items_grid_view()
321 ->EndDrag(true);
324 void AppListMainView::QueryChanged(SearchBoxView* sender) {
325 base::string16 query;
326 base::TrimWhitespace(model_->search_box()->text(), base::TRIM_ALL, &query);
327 bool should_show_search = !query.empty();
328 contents_view_->ShowSearchResults(should_show_search);
329 UpdateSearchBoxVisibility();
331 delegate_->StartSearch();
334 void AppListMainView::OnResultInstalled(SearchResult* result) {
335 // Clears the search to show the apps grid. The last installed app
336 // should be highlighted and made visible already.
337 search_box_view_->ClearSearch();
340 void AppListMainView::OnResultUninstalled(SearchResult* result) {
341 // Resubmit the query via a posted task so that all observers for the
342 // uninstall notification are notified.
343 base::MessageLoop::current()->PostTask(
344 FROM_HERE,
345 base::Bind(&AppListMainView::QueryChanged,
346 weak_ptr_factory_.GetWeakPtr(),
347 search_box_view_));
350 } // namespace app_list