ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / ui / app_list / views / app_list_main_view.cc
blobdceae0faa72d4f49bddc4e827b990d5bc0c64783
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/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/search_result_page_view.h"
30 #include "ui/app_list/views/start_page_view.h"
31 #include "ui/views/border.h"
32 #include "ui/views/controls/button/button.h"
33 #include "ui/views/controls/button/custom_button.h"
34 #include "ui/views/controls/textfield/textfield.h"
35 #include "ui/views/layout/box_layout.h"
36 #include "ui/views/layout/fill_layout.h"
37 #include "ui/views/widget/widget.h"
39 namespace app_list {
41 namespace {
43 // The maximum allowed time to wait for icon loading in milliseconds.
44 const int kMaxIconLoadingWaitTimeInMs = 50;
46 } // namespace
48 ////////////////////////////////////////////////////////////////////////////////
49 // AppListMainView::IconLoader
51 class AppListMainView::IconLoader : public AppListItemObserver {
52 public:
53 IconLoader(AppListMainView* owner,
54 AppListItem* item,
55 float scale)
56 : owner_(owner),
57 item_(item) {
58 item_->AddObserver(this);
60 // Triggers icon loading for given |scale_factor|.
61 item_->icon().GetRepresentation(scale);
64 ~IconLoader() override { item_->RemoveObserver(this); }
66 private:
67 // AppListItemObserver overrides:
68 void ItemIconChanged() override {
69 owner_->OnItemIconLoaded(this);
70 // Note that IconLoader is released here.
73 AppListMainView* owner_;
74 AppListItem* item_;
76 DISALLOW_COPY_AND_ASSIGN(IconLoader);
79 ////////////////////////////////////////////////////////////////////////////////
80 // AppListMainView:
82 AppListMainView::AppListMainView(AppListViewDelegate* delegate)
83 : delegate_(delegate),
84 model_(delegate->GetModel()),
85 search_box_view_(nullptr),
86 contents_view_(nullptr),
87 weak_ptr_factory_(this) {
88 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
89 model_->AddObserver(this);
92 AppListMainView::~AppListMainView() {
93 pending_icon_loaders_.clear();
94 model_->RemoveObserver(this);
97 void AppListMainView::Init(gfx::NativeView parent,
98 int initial_apps_page,
99 SearchBoxView* search_box_view) {
100 search_box_view_ = search_box_view;
101 AddContentsViews();
103 // Switch the apps grid view to the specified page.
104 app_list::PaginationModel* pagination_model = GetAppsPaginationModel();
105 if (pagination_model->is_valid_page(initial_apps_page))
106 pagination_model->SelectPage(initial_apps_page, false);
108 // Starts icon loading early.
109 PreloadIcons(parent);
111 OnSearchEngineIsGoogleChanged(model_->search_engine_is_google());
114 void AppListMainView::AddContentsViews() {
115 DCHECK(search_box_view_);
117 contents_view_ = new ContentsView(this);
118 contents_view_->Init(model_);
119 AddChildView(contents_view_);
121 search_box_view_->set_contents_view(contents_view_);
123 contents_view_->SetPaintToLayer(true);
124 contents_view_->SetFillsBoundsOpaquely(false);
125 contents_view_->layer()->SetMasksToBounds(true);
127 delegate_->StartSearch();
130 void AppListMainView::ShowAppListWhenReady() {
131 if (pending_icon_loaders_.empty()) {
132 icon_loading_wait_timer_.Stop();
133 GetWidget()->Show();
134 return;
137 if (icon_loading_wait_timer_.IsRunning())
138 return;
140 icon_loading_wait_timer_.Start(
141 FROM_HERE,
142 base::TimeDelta::FromMilliseconds(kMaxIconLoadingWaitTimeInMs),
143 this, &AppListMainView::OnIconLoadingWaitTimer);
146 void AppListMainView::ResetForShow() {
147 if (switches::IsExperimentalAppListEnabled()) {
148 contents_view_->SetActivePage(
149 contents_view_->GetPageIndexForState(AppListModel::STATE_START));
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();
157 void AppListMainView::Close() {
158 icon_loading_wait_timer_.Stop();
159 contents_view_->CancelDrag();
162 void AppListMainView::Prerender() {
163 contents_view_->Prerender();
166 void AppListMainView::ModelChanged() {
167 pending_icon_loaders_.clear();
168 model_->RemoveObserver(this);
169 model_ = delegate_->GetModel();
170 model_->AddObserver(this);
171 search_box_view_->ModelChanged();
172 delete contents_view_;
173 contents_view_ = NULL;
174 AddContentsViews();
175 Layout();
178 void AppListMainView::SetDragAndDropHostOfCurrentAppList(
179 ApplicationDragAndDropHost* drag_and_drop_host) {
180 contents_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
183 bool AppListMainView::ShouldCenterWindow() const {
184 return delegate_->ShouldCenterWindow();
187 PaginationModel* AppListMainView::GetAppsPaginationModel() {
188 return contents_view_->apps_container_view()
189 ->apps_grid_view()
190 ->pagination_model();
193 void AppListMainView::PreloadIcons(gfx::NativeView parent) {
194 float scale_factor = 1.0f;
195 if (parent)
196 scale_factor = ui::GetScaleFactorForNativeView(parent);
198 // The PaginationModel could have -1 as the initial selected page and
199 // assumes first page (i.e. index 0) will be used in this case.
200 const int selected_page =
201 std::max(0, GetAppsPaginationModel()->selected_page());
203 const AppsGridView* const apps_grid_view =
204 contents_view_->apps_container_view()->apps_grid_view();
205 const int tiles_per_page =
206 apps_grid_view->cols() * apps_grid_view->rows_per_page();
208 const int start_model_index = selected_page * tiles_per_page;
209 const int end_model_index =
210 std::min(static_cast<int>(model_->top_level_item_list()->item_count()),
211 start_model_index + tiles_per_page);
213 pending_icon_loaders_.clear();
214 for (int i = start_model_index; i < end_model_index; ++i) {
215 AppListItem* item = model_->top_level_item_list()->item_at(i);
216 if (item->icon().HasRepresentation(scale_factor))
217 continue;
219 pending_icon_loaders_.push_back(new IconLoader(this, item, scale_factor));
223 void AppListMainView::OnIconLoadingWaitTimer() {
224 GetWidget()->Show();
227 void AppListMainView::OnItemIconLoaded(IconLoader* loader) {
228 ScopedVector<IconLoader>::iterator it = std::find(
229 pending_icon_loaders_.begin(), pending_icon_loaders_.end(), loader);
230 DCHECK(it != pending_icon_loaders_.end());
231 pending_icon_loaders_.erase(it);
233 if (pending_icon_loaders_.empty() && icon_loading_wait_timer_.IsRunning()) {
234 icon_loading_wait_timer_.Stop();
235 GetWidget()->Show();
239 void AppListMainView::NotifySearchBoxVisibilityChanged() {
240 // Repaint the AppListView's background which will repaint the background for
241 // the search box. This is needed because this view paints to a layer and
242 // won't propagate paints upward.
243 if (parent())
244 parent()->SchedulePaint();
247 bool AppListMainView::ShouldShowCustomLauncherPage() const {
248 return contents_view_->custom_page_view() &&
249 model_->custom_launcher_page_enabled() &&
250 model_->search_engine_is_google();
253 void AppListMainView::UpdateCustomLauncherPageVisibility() {
254 if (ShouldShowCustomLauncherPage()) {
255 // Make the custom page view visible again.
256 contents_view_->custom_page_view()->SetVisible(true);
257 } else if (contents_view_->IsStateActive(
258 AppListModel::STATE_CUSTOM_LAUNCHER_PAGE)) {
259 // Animate to the start page if currently on the custom page view. The view
260 // will hide on animation completion.
261 contents_view_->SetActivePage(
262 contents_view_->GetPageIndexForState(AppListModel::STATE_START));
263 } else {
264 // Hide the view immediately otherwise.
265 contents_view_->custom_page_view()->SetVisible(false);
269 void AppListMainView::OnCustomLauncherPageEnabledStateChanged(bool enabled) {
270 views::View* custom_page = contents_view_->custom_page_view();
271 if (!custom_page)
272 return;
274 if (ShouldShowCustomLauncherPage()) {
275 // Make the custom page view visible again.
276 custom_page->SetVisible(true);
277 } else if (contents_view_->IsStateActive(
278 AppListModel::STATE_CUSTOM_LAUNCHER_PAGE)) {
279 // Animate to the start page if currently on the custom page view. The view
280 // will hide on animation completion.
281 contents_view_->SetActivePage(
282 contents_view_->GetPageIndexForState(AppListModel::STATE_START));
283 } else {
284 // Hide the view immediately otherwise.
285 custom_page->SetVisible(false);
289 void AppListMainView::OnSearchEngineIsGoogleChanged(bool is_google) {
290 if (contents_view_->custom_page_view())
291 OnCustomLauncherPageEnabledStateChanged(is_google);
293 if (contents_view_->start_page_view()) {
294 contents_view_->start_page_view()->instant_container()->SetVisible(
295 is_google);
299 void AppListMainView::ActivateApp(AppListItem* item, int event_flags) {
300 // TODO(jennyz): Activate the folder via AppListModel notification.
301 if (item->GetItemType() == AppListFolderItem::kItemType)
302 contents_view_->ShowFolderContent(static_cast<AppListFolderItem*>(item));
303 else
304 item->Activate(event_flags);
307 void AppListMainView::GetShortcutPathForApp(
308 const std::string& app_id,
309 const base::Callback<void(const base::FilePath&)>& callback) {
310 delegate_->GetShortcutPathForApp(app_id, callback);
313 void AppListMainView::CancelDragInActiveFolder() {
314 contents_view_->apps_container_view()
315 ->app_list_folder_view()
316 ->items_grid_view()
317 ->EndDrag(true);
320 void AppListMainView::QueryChanged(SearchBoxView* sender) {
321 base::string16 query;
322 base::TrimWhitespace(model_->search_box()->text(), base::TRIM_ALL, &query);
323 bool should_show_search = !query.empty();
324 contents_view_->ShowSearchResults(should_show_search);
326 delegate_->StartSearch();
329 void AppListMainView::BackButtonPressed() {
330 contents_view_->Back();
333 void AppListMainView::SetSearchResultSelection(bool select) {
334 if (contents_view_->GetActiveState() == AppListModel::STATE_SEARCH_RESULTS)
335 contents_view_->search_results_page_view()->SetSelection(select);
338 void AppListMainView::OnResultInstalled(SearchResult* result) {
339 // Clears the search to show the apps grid. The last installed app
340 // should be highlighted and made visible already.
341 search_box_view_->ClearSearch();
344 } // namespace app_list