Views Omnibox: tolerate minor click-to-select-all dragging.
[chromium-blink-merge.git] / ui / app_list / views / app_list_main_view.cc
blob7d2f6b7dff1450d82ee80edf3e77041e2c27ba5b
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_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"
28 namespace app_list {
30 namespace {
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;
38 } // namespace
40 ////////////////////////////////////////////////////////////////////////////////
41 // AppListMainView::IconLoader
43 class AppListMainView::IconLoader : public AppListItemObserver {
44 public:
45 IconLoader(AppListMainView* owner,
46 AppListItem* item,
47 float scale)
48 : owner_(owner),
49 item_(item) {
50 item_->AddObserver(this);
52 // Triggers icon loading for given |scale_factor|.
53 item_->icon().GetRepresentation(scale);
56 virtual ~IconLoader() {
57 item_->RemoveObserver(this);
60 private:
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_;
72 AppListItem* item_;
74 DISALLOW_COPY_AND_ASSIGN(IconLoader);
77 ////////////////////////////////////////////////////////////////////////////////
78 // AppListMainView:
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),
87 contents_view_(NULL),
88 weak_ptr_factory_(this) {
89 // Starts icon loading early.
90 PreloadIcons(parent);
92 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical,
93 kInnerPadding,
94 kInnerPadding,
95 kInnerPadding));
97 search_box_view_ = new SearchBoxView(this, delegate);
98 AddChildView(search_box_view_);
99 AddContentsView();
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);
113 #endif
116 AppListMainView::~AppListMainView() {
117 pending_icon_loaders_.clear();
120 void AppListMainView::ShowAppListWhenReady() {
121 if (pending_icon_loaders_.empty()) {
122 icon_loading_wait_timer_.Stop();
123 GetWidget()->Show();
124 return;
127 if (icon_loading_wait_timer_.IsRunning())
128 return;
130 icon_loading_wait_timer_.Start(
131 FROM_HERE,
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 */);
152 AddContentsView();
153 Layout();
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;
163 if (parent)
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))
181 continue;
183 pending_icon_loaders_.push_back(new IconLoader(this, item, scale));
187 void AppListMainView::OnIconLoadingWaitTimer() {
188 GetWidget()->Show();
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();
199 GetWidget()->Show();
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));
207 else
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();
225 else
226 delegate_->StopSearch();
229 void AppListMainView::OpenResult(SearchResult* result, int event_flags) {
230 delegate_->OpenSearchResult(result, event_flags);
233 void AppListMainView::InvokeResultAction(SearchResult* result,
234 int action_index,
235 int event_flags) {
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(
249 FROM_HERE,
250 base::Bind(&AppListMainView::QueryChanged,
251 weak_ptr_factory_.GetWeakPtr(),
252 search_box_view_));
255 } // namespace app_list