Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / chrome / browser / ui / app_list / extension_app_model_builder.cc
blob32bc979c3ef93d7dd8c0e15be375feded99f70bc
1 // Copyright (c) 2012 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 "chrome/browser/ui/app_list/extension_app_model_builder.h"
7 #include <algorithm>
9 #include "base/auto_reset.h"
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "chrome/browser/extensions/extension_ui_util.h"
13 #include "chrome/browser/extensions/extension_util.h"
14 #include "chrome/browser/extensions/install_tracker.h"
15 #include "chrome/browser/extensions/install_tracker_factory.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
18 #include "chrome/browser/ui/app_list/app_list_syncable_service.h"
19 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
20 #include "chrome/browser/ui/app_list/extension_app_item.h"
21 #include "chrome/common/pref_names.h"
22 #include "extensions/browser/extension_prefs.h"
23 #include "extensions/browser/extension_registry.h"
24 #include "extensions/browser/extension_system.h"
25 #include "extensions/browser/extensions_browser_client.h"
26 #include "extensions/browser/pref_names.h"
27 #include "extensions/common/constants.h"
28 #include "extensions/common/extension.h"
29 #include "extensions/common/extension_set.h"
30 #include "ui/gfx/image/image_skia.h"
31 #include "ui/gfx/image/image_skia_operations.h"
33 using extensions::Extension;
35 ExtensionAppModelBuilder::ExtensionAppModelBuilder(
36 AppListControllerDelegate* controller)
37 : service_(NULL),
38 profile_(NULL),
39 controller_(controller),
40 model_(NULL),
41 tracker_(NULL),
42 extension_registry_(NULL) {
45 ExtensionAppModelBuilder::~ExtensionAppModelBuilder() {
46 OnShutdown();
47 OnShutdown(extension_registry_);
48 if (!service_)
49 model_->top_level_item_list()->RemoveObserver(this);
52 void ExtensionAppModelBuilder::InitializeWithService(
53 app_list::AppListSyncableService* service,
54 app_list::AppListModel* model) {
55 DCHECK(!service_ && !profile_);
56 model_ = model;
57 service_ = service;
58 profile_ = service->profile();
59 InitializePrefChangeRegistrars();
61 BuildModel();
64 void ExtensionAppModelBuilder::InitializeWithProfile(
65 Profile* profile,
66 app_list::AppListModel* model) {
67 DCHECK(!service_ && !profile_);
68 model_ = model;
69 model_->top_level_item_list()->AddObserver(this);
70 profile_ = profile;
71 InitializePrefChangeRegistrars();
73 BuildModel();
76 void ExtensionAppModelBuilder::InitializePrefChangeRegistrars() {
77 profile_pref_change_registrar_.Init(profile_->GetPrefs());
78 profile_pref_change_registrar_.Add(
79 prefs::kHideWebStoreIcon,
80 base::Bind(&ExtensionAppModelBuilder::OnProfilePreferenceChanged,
81 base::Unretained(this)));
83 if (!extensions::util::IsNewBookmarkAppsEnabled())
84 return;
86 // TODO(calamity): analyze the performance impact of doing this every
87 // extension pref change.
88 extensions::ExtensionsBrowserClient* client =
89 extensions::ExtensionsBrowserClient::Get();
90 extension_pref_change_registrar_.Init(
91 client->GetPrefServiceForContext(profile_));
92 extension_pref_change_registrar_.Add(
93 extensions::pref_names::kExtensions,
94 base::Bind(&ExtensionAppModelBuilder::OnExtensionPreferenceChanged,
95 base::Unretained(this)));
98 void ExtensionAppModelBuilder::OnProfilePreferenceChanged() {
99 extensions::ExtensionSet extensions;
100 controller_->GetApps(profile_, &extensions);
102 for (extensions::ExtensionSet::const_iterator app = extensions.begin();
103 app != extensions.end(); ++app) {
104 bool should_display =
105 extensions::ui_util::ShouldDisplayInAppLauncher(app->get(), profile_);
106 bool does_display = GetExtensionAppItem((*app)->id()) != NULL;
108 if (should_display == does_display)
109 continue;
111 if (should_display) {
112 InsertApp(CreateAppItem((*app)->id(),
114 gfx::ImageSkia(),
115 (*app)->is_platform_app()));
116 } else {
117 if (service_)
118 service_->RemoveItem((*app)->id());
119 else
120 model_->DeleteItem((*app)->id());
125 void ExtensionAppModelBuilder::OnExtensionPreferenceChanged() {
126 model_->NotifyExtensionPreferenceChanged();
129 void ExtensionAppModelBuilder::OnBeginExtensionInstall(
130 const ExtensionInstallParams& params) {
131 if (!params.is_app || params.is_ephemeral)
132 return;
134 DVLOG(2) << service_ << ": OnBeginExtensionInstall: "
135 << params.extension_id.substr(0, 8);
136 ExtensionAppItem* existing_item = GetExtensionAppItem(params.extension_id);
137 if (existing_item) {
138 existing_item->SetIsInstalling(true);
139 return;
142 // Icons from the webstore can be unusual sizes. Once installed,
143 // ExtensionAppItem uses extension_misc::EXTENSION_ICON_MEDIUM (48) to load
144 // it, so be consistent with that.
145 gfx::Size icon_size(extension_misc::EXTENSION_ICON_MEDIUM,
146 extension_misc::EXTENSION_ICON_MEDIUM);
147 gfx::ImageSkia resized(gfx::ImageSkiaOperations::CreateResizedImage(
148 params.installing_icon, skia::ImageOperations::RESIZE_BEST, icon_size));
150 InsertApp(CreateAppItem(params.extension_id,
151 params.extension_name,
152 resized,
153 params.is_platform_app));
156 void ExtensionAppModelBuilder::OnDownloadProgress(
157 const std::string& extension_id,
158 int percent_downloaded) {
159 ExtensionAppItem* item = GetExtensionAppItem(extension_id);
160 if (!item)
161 return;
162 item->SetPercentDownloaded(percent_downloaded);
165 void ExtensionAppModelBuilder::OnInstallFailure(
166 const std::string& extension_id) {
167 model_->DeleteItem(extension_id);
170 void ExtensionAppModelBuilder::OnExtensionLoaded(
171 content::BrowserContext* browser_context,
172 const extensions::Extension* extension) {
173 if (!extensions::ui_util::ShouldDisplayInAppLauncher(extension, profile_))
174 return;
176 DVLOG(2) << service_ << ": OnExtensionLoaded: "
177 << extension->id().substr(0, 8);
178 ExtensionAppItem* existing_item = GetExtensionAppItem(extension->id());
179 if (existing_item) {
180 existing_item->Reload();
181 if (service_)
182 service_->UpdateItem(existing_item);
183 return;
186 InsertApp(CreateAppItem(extension->id(),
188 gfx::ImageSkia(),
189 extension->is_platform_app()));
192 void ExtensionAppModelBuilder::OnExtensionUnloaded(
193 content::BrowserContext* browser_context,
194 const extensions::Extension* extension,
195 extensions::UnloadedExtensionInfo::Reason reason) {
196 ExtensionAppItem* item = GetExtensionAppItem(extension->id());
197 if (!item)
198 return;
199 item->UpdateIcon();
202 void ExtensionAppModelBuilder::OnExtensionUninstalled(
203 content::BrowserContext* browser_context,
204 const extensions::Extension* extension,
205 extensions::UninstallReason reason) {
206 if (service_) {
207 DVLOG(2) << service_ << ": OnExtensionUninstalled: "
208 << extension->id().substr(0, 8);
209 service_->RemoveUninstalledItem(extension->id());
210 return;
212 model_->DeleteUninstalledItem(extension->id());
215 void ExtensionAppModelBuilder::OnDisabledExtensionUpdated(
216 const Extension* extension) {
217 if (!extensions::ui_util::ShouldDisplayInAppLauncher(extension, profile_))
218 return;
220 ExtensionAppItem* existing_item = GetExtensionAppItem(extension->id());
221 if (existing_item)
222 existing_item->Reload();
225 void ExtensionAppModelBuilder::OnShutdown() {
226 if (tracker_) {
227 tracker_->RemoveObserver(this);
228 tracker_ = NULL;
232 void ExtensionAppModelBuilder::OnShutdown(
233 extensions::ExtensionRegistry* registry) {
234 if (!extension_registry_)
235 return;
237 DCHECK_EQ(extension_registry_, registry);
238 extension_registry_->RemoveObserver(this);
239 extension_registry_ = NULL;
242 scoped_ptr<ExtensionAppItem> ExtensionAppModelBuilder::CreateAppItem(
243 const std::string& extension_id,
244 const std::string& extension_name,
245 const gfx::ImageSkia& installing_icon,
246 bool is_platform_app) {
247 const app_list::AppListSyncableService::SyncItem* sync_item =
248 service_ ? service_->GetSyncItem(extension_id) : NULL;
249 return make_scoped_ptr(new ExtensionAppItem(profile_,
250 sync_item,
251 extension_id,
252 extension_name,
253 installing_icon,
254 is_platform_app));
257 void ExtensionAppModelBuilder::BuildModel() {
258 DCHECK(!tracker_);
259 tracker_ = controller_->GetInstallTrackerFor(profile_);
260 extension_registry_ = extensions::ExtensionRegistry::Get(profile_);
262 PopulateApps();
264 // Start observing after model is built.
265 if (tracker_)
266 tracker_->AddObserver(this);
268 if (extension_registry_)
269 extension_registry_->AddObserver(this);
272 void ExtensionAppModelBuilder::PopulateApps() {
273 extensions::ExtensionSet extensions;
274 controller_->GetApps(profile_, &extensions);
276 for (extensions::ExtensionSet::const_iterator app = extensions.begin();
277 app != extensions.end(); ++app) {
278 if (!extensions::ui_util::ShouldDisplayInAppLauncher(app->get(), profile_))
279 continue;
280 InsertApp(CreateAppItem((*app)->id(),
282 gfx::ImageSkia(),
283 (*app)->is_platform_app()));
287 void ExtensionAppModelBuilder::InsertApp(scoped_ptr<ExtensionAppItem> app) {
288 if (service_) {
289 service_->AddItem(app.Pass());
290 return;
292 model_->AddItem(app.Pass());
295 ExtensionAppItem* ExtensionAppModelBuilder::GetExtensionAppItem(
296 const std::string& extension_id) {
297 app_list::AppListItem* item = model_->FindItem(extension_id);
298 LOG_IF(ERROR, item &&
299 item->GetItemType() != ExtensionAppItem::kItemType)
300 << "App Item matching id: " << extension_id
301 << " has incorrect type: '" << item->GetItemType() << "'";
302 return static_cast<ExtensionAppItem*>(item);
305 void ExtensionAppModelBuilder::OnListItemMoved(size_t from_index,
306 size_t to_index,
307 app_list::AppListItem* item) {
308 DCHECK(!service_);
310 // This will get called from AppListItemList::ListItemMoved after
311 // set_position is called for the item.
312 if (item->GetItemType() != ExtensionAppItem::kItemType)
313 return;
315 app_list::AppListItemList* item_list = model_->top_level_item_list();
316 ExtensionAppItem* prev = NULL;
317 for (size_t idx = to_index; idx > 0; --idx) {
318 app_list::AppListItem* item = item_list->item_at(idx - 1);
319 if (item->GetItemType() == ExtensionAppItem::kItemType) {
320 prev = static_cast<ExtensionAppItem*>(item);
321 break;
324 ExtensionAppItem* next = NULL;
325 for (size_t idx = to_index; idx < item_list->item_count() - 1; ++idx) {
326 app_list::AppListItem* item = item_list->item_at(idx + 1);
327 if (item->GetItemType() == ExtensionAppItem::kItemType) {
328 next = static_cast<ExtensionAppItem*>(item);
329 break;
332 // item->Move will call set_position, overriding the item's position.
333 if (prev || next)
334 static_cast<ExtensionAppItem*>(item)->Move(prev, next);