- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / app_list / extension_app_model_builder.cc
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.
4
5 #include "chrome/browser/ui/app_list/extension_app_model_builder.h"
6
7 #include <algorithm>
8
9 #include "base/auto_reset.h"
10 #include "base/prefs/pref_service.h"
11 #include "chrome/browser/chrome_notification_types.h"
12 #include "chrome/browser/extensions/extension_prefs.h"
13 #include "chrome/browser/extensions/install_tracker.h"
14 #include "chrome/browser/extensions/install_tracker_factory.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
17 #include "chrome/browser/ui/app_list/extension_app_item.h"
18 #include "chrome/common/extensions/extension.h"
19 #include "chrome/common/extensions/extension_constants.h"
20 #include "chrome/common/extensions/extension_set.h"
21 #include "chrome/common/pref_names.h"
22 #include "content/public/browser/notification_service.h"
23 #include "ui/gfx/image/image_skia.h"
24
25 using extensions::Extension;
26
27 namespace {
28
29 bool ShouldDisplayInAppLauncher(Profile* profile,
30                                 scoped_refptr<const Extension> app) {
31   // If it's the web store, check the policy.
32   bool blocked_by_policy =
33       (app->id() == extension_misc::kWebStoreAppId ||
34        app->id() == extension_misc::kEnterpriseWebStoreAppId) &&
35       profile->GetPrefs()->GetBoolean(prefs::kHideWebStoreIcon);
36   return app->ShouldDisplayInAppLauncher() && !blocked_by_policy;
37 }
38
39 }  // namespace
40
41 ExtensionAppModelBuilder::ExtensionAppModelBuilder(
42     Profile* profile,
43     app_list::AppListModel* model,
44     AppListControllerDelegate* controller)
45     : profile_(NULL),
46       controller_(controller),
47       model_(model),
48       highlighted_app_pending_(false),
49       tracker_(NULL) {
50   model_->item_list()->AddObserver(this);
51   SwitchProfile(profile);  // Builds the model.
52 }
53
54 ExtensionAppModelBuilder::~ExtensionAppModelBuilder() {
55   OnShutdown();
56   model_->item_list()->RemoveObserver(this);
57 }
58
59 void ExtensionAppModelBuilder::OnBeginExtensionInstall(
60     const std::string& extension_id,
61     const std::string& extension_name,
62     const gfx::ImageSkia& installing_icon,
63     bool is_app,
64     bool is_platform_app) {
65   if (!is_app)
66     return;
67
68   ExtensionAppItem* existing_item = GetExtensionAppItem(extension_id);
69   if (existing_item) {
70     existing_item->SetIsInstalling(true);
71     return;
72   }
73
74   InsertApp(new ExtensionAppItem(profile_,
75                                  extension_id,
76                                  controller_,
77                                  extension_name,
78                                  installing_icon,
79                                  is_platform_app));
80   SetHighlightedApp(extension_id);
81 }
82
83 void ExtensionAppModelBuilder::OnDownloadProgress(
84     const std::string& extension_id,
85     int percent_downloaded) {
86   ExtensionAppItem* item = GetExtensionAppItem(extension_id);
87   if (!item)
88     return;
89   item->SetPercentDownloaded(percent_downloaded);
90 }
91
92 void ExtensionAppModelBuilder::OnInstallFailure(
93     const std::string& extension_id) {
94   // Do nothing, item will be disabled
95 }
96
97 void ExtensionAppModelBuilder::OnExtensionLoaded(const Extension* extension) {
98   if (!extension->ShouldDisplayInAppLauncher())
99     return;
100
101   ExtensionAppItem* existing_item = GetExtensionAppItem(extension->id());
102   if (existing_item) {
103     existing_item->Reload();
104     return;
105   }
106
107   InsertApp(new ExtensionAppItem(profile_,
108                                  extension->id(),
109                                  controller_,
110                                  "",
111                                  gfx::ImageSkia(),
112                                  extension->is_platform_app()));
113   UpdateHighlight();
114 }
115
116 void ExtensionAppModelBuilder::OnExtensionUnloaded(const Extension* extension) {
117   ExtensionAppItem* item = GetExtensionAppItem(extension->id());
118   if (!item)
119     return;
120   item->UpdateIcon();
121 }
122
123 void ExtensionAppModelBuilder::OnExtensionUninstalled(
124     const Extension* extension) {
125   model_->item_list()->DeleteItem(extension->id());
126 }
127
128 void ExtensionAppModelBuilder::OnAppsReordered() {
129   // Do nothing; App List order does not track extensions order.
130 }
131
132 void ExtensionAppModelBuilder::OnAppInstalledToAppList(
133     const std::string& extension_id) {
134   SetHighlightedApp(extension_id);
135 }
136
137 void ExtensionAppModelBuilder::OnShutdown() {
138   if (tracker_) {
139     tracker_->RemoveObserver(this);
140     tracker_ = NULL;
141   }
142 }
143
144 void ExtensionAppModelBuilder::AddApps(const ExtensionSet* extensions,
145                                        ExtensionAppList* apps) {
146   for (ExtensionSet::const_iterator app = extensions->begin();
147        app != extensions->end(); ++app) {
148     if (ShouldDisplayInAppLauncher(profile_, *app))
149       apps->push_back(new ExtensionAppItem(profile_,
150                                            (*app)->id(),
151                                            controller_,
152                                            "",
153                                            gfx::ImageSkia(),
154                                            (*app)->is_platform_app()));
155   }
156 }
157
158 void ExtensionAppModelBuilder::SwitchProfile(Profile* profile) {
159   if (profile_ == profile)
160     return;
161   profile_ = profile;
162
163   // Delete any extension apps.
164   model_->item_list()->DeleteItemsByType(ExtensionAppItem::kAppType);
165
166   if (tracker_)
167     tracker_->RemoveObserver(this);
168
169   tracker_ = controller_->GetInstallTrackerFor(profile_);
170
171   PopulateApps();
172   UpdateHighlight();
173
174   // Start observing after model is built.
175   if (tracker_)
176     tracker_->AddObserver(this);
177 }
178
179 void ExtensionAppModelBuilder::PopulateApps() {
180   ExtensionSet extensions;
181   controller_->GetApps(profile_, &extensions);
182   ExtensionAppList apps;
183   AddApps(&extensions, &apps);
184
185   if (apps.empty())
186     return;
187
188   for (size_t i = 0; i < apps.size(); ++i)
189     InsertApp(apps[i]);
190 }
191
192 void ExtensionAppModelBuilder::InsertApp(ExtensionAppItem* app) {
193   model_->item_list()->AddItem(app);
194 }
195
196 void ExtensionAppModelBuilder::SetHighlightedApp(
197     const std::string& extension_id) {
198   if (extension_id == highlight_app_id_)
199     return;
200   ExtensionAppItem* old_app = GetExtensionAppItem(highlight_app_id_);
201   if (old_app)
202     old_app->SetHighlighted(false);
203   highlight_app_id_ = extension_id;
204   ExtensionAppItem* new_app = GetExtensionAppItem(highlight_app_id_);
205   highlighted_app_pending_ = !new_app;
206   if (new_app)
207     new_app->SetHighlighted(true);
208 }
209
210 ExtensionAppItem* ExtensionAppModelBuilder::GetExtensionAppItem(
211     const std::string& extension_id) {
212   app_list::AppListItemModel* item =
213       model_->item_list()->FindItem(extension_id);
214   LOG_IF(ERROR, item &&
215          item->GetAppType() != ExtensionAppItem::kAppType)
216       << "App Item matching id: " << extension_id
217       << " has incorrect type: '" << item->GetAppType() << "'";
218   return static_cast<ExtensionAppItem*>(item);
219 }
220
221 void ExtensionAppModelBuilder::UpdateHighlight() {
222   DCHECK(model_);
223   if (!highlighted_app_pending_ || highlight_app_id_.empty())
224     return;
225   ExtensionAppItem* item = GetExtensionAppItem(highlight_app_id_);
226   if (!item)
227     return;
228   item->SetHighlighted(true);
229   highlighted_app_pending_ = false;
230 }
231
232 void ExtensionAppModelBuilder::OnListItemMoved(
233     size_t from_index,
234     size_t to_index,
235     app_list::AppListItemModel* item) {
236   // This will get called from AppListItemList::ListItemMoved after
237   // set_position is called for the item.
238   app_list::AppListItemList* item_list = model_->item_list();
239   if (item->GetAppType() != ExtensionAppItem::kAppType)
240     return;
241
242   ExtensionAppItem* prev = NULL;
243   for (size_t idx = to_index; idx > 0; --idx) {
244     app_list::AppListItemModel* item = item_list->item_at(idx - 1);
245     if (item->GetAppType() == ExtensionAppItem::kAppType) {
246       prev = static_cast<ExtensionAppItem*>(item);
247       break;
248     }
249   }
250   ExtensionAppItem* next = NULL;
251   for (size_t idx = to_index; idx < item_list->item_count() - 1; ++idx) {
252     app_list::AppListItemModel* item = item_list->item_at(idx + 1);
253     if (item->GetAppType() == ExtensionAppItem::kAppType) {
254       next = static_cast<ExtensionAppItem*>(item);
255       break;
256     }
257   }
258   // item->Move will call set_position, overriding the item's position.
259   if (prev || next)
260     static_cast<ExtensionAppItem*>(item)->Move(prev, next);
261 }