Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / app_list / extension_app_item.cc
blobe0bff9db1e50ae9363d1439c3bfefefd195ae7a7
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_item.h"
7 #include "base/prefs/pref_service.h"
8 #include "chrome/browser/extensions/extension_prefs.h"
9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/extensions/extension_system.h"
11 #include "chrome/browser/extensions/extension_util.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/ui/app_list/app_context_menu.h"
14 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
15 #include "chrome/browser/ui/app_list/app_list_service.h"
16 #include "chrome/browser/ui/extensions/extension_enable_flow.h"
17 #include "chrome/browser/ui/host_desktop.h"
18 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
19 #include "chrome/common/extensions/extension_constants.h"
20 #include "chrome/common/extensions/extension_icon_set.h"
21 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
22 #include "chrome/common/extensions/manifest_url_handler.h"
23 #include "content/public/browser/user_metrics.h"
24 #include "extensions/browser/app_sorting.h"
25 #include "extensions/common/extension.h"
26 #include "grit/theme_resources.h"
27 #include "sync/api/string_ordinal.h"
28 #include "ui/base/resource/resource_bundle.h"
29 #include "ui/gfx/canvas.h"
30 #include "ui/gfx/color_utils.h"
31 #include "ui/gfx/image/canvas_image_source.h"
32 #include "ui/gfx/image/image_skia_operations.h"
34 using extensions::Extension;
36 namespace {
38 // Overlays a shortcut icon over the bottom left corner of a given image.
39 class ShortcutOverlayImageSource : public gfx::CanvasImageSource {
40 public:
41 explicit ShortcutOverlayImageSource(const gfx::ImageSkia& icon)
42 : gfx::CanvasImageSource(icon.size(), false),
43 icon_(icon) {
45 virtual ~ShortcutOverlayImageSource() {}
47 private:
48 // gfx::CanvasImageSource overrides:
49 virtual void Draw(gfx::Canvas* canvas) OVERRIDE {
50 canvas->DrawImageInt(icon_, 0, 0);
52 // Draw the overlay in the bottom left corner of the icon.
53 const gfx::ImageSkia& overlay = *ui::ResourceBundle::GetSharedInstance().
54 GetImageSkiaNamed(IDR_APP_LIST_TAB_OVERLAY);
55 canvas->DrawImageInt(overlay, 0, icon_.height() - overlay.height());
58 gfx::ImageSkia icon_;
60 DISALLOW_COPY_AND_ASSIGN(ShortcutOverlayImageSource);
63 extensions::AppSorting* GetAppSorting(Profile* profile) {
64 ExtensionService* service =
65 extensions::ExtensionSystem::Get(profile)->extension_service();
66 return service->extension_prefs()->app_sorting();
69 const color_utils::HSL shift = {-1, 0, 0.6};
71 } // namespace
73 ExtensionAppItem::ExtensionAppItem(
74 Profile* profile,
75 const app_list::AppListSyncableService::SyncItem* sync_item,
76 const std::string& extension_id,
77 const std::string& extension_name,
78 const gfx::ImageSkia& installing_icon,
79 bool is_platform_app)
80 : app_list::AppListItem(extension_id),
81 profile_(profile),
82 extension_id_(extension_id),
83 extension_enable_flow_controller_(NULL),
84 extension_name_(extension_name),
85 installing_icon_(
86 gfx::ImageSkiaOperations::CreateHSLShiftedImage(installing_icon,
87 shift)),
88 is_platform_app_(is_platform_app) {
89 Reload();
90 if (sync_item && sync_item->item_ordinal.IsValid()) {
91 // An existing synced position exists, use that.
92 set_position(sync_item->item_ordinal);
93 return;
95 GetAppSorting(profile_)->EnsureValidOrdinals(extension_id_,
96 syncer::StringOrdinal());
97 UpdatePositionFromExtensionOrdering();
100 ExtensionAppItem::~ExtensionAppItem() {
103 bool ExtensionAppItem::HasOverlay() const {
104 #if defined(OS_CHROMEOS)
105 return false;
106 #else
107 return !is_platform_app_ && extension_id_ != extension_misc::kChromeAppId;
108 #endif
111 void ExtensionAppItem::Reload() {
112 const Extension* extension = GetExtension();
113 bool is_installing = !extension;
114 SetIsInstalling(is_installing);
115 if (is_installing) {
116 SetTitleAndFullName(extension_name_, extension_name_);
117 UpdateIcon();
118 return;
120 SetTitleAndFullName(extension->short_name(), extension->name());
121 LoadImage(extension);
124 void ExtensionAppItem::UpdateIcon() {
125 if (!GetExtension()) {
126 gfx::ImageSkia icon = installing_icon_;
127 if (HasOverlay())
128 icon = gfx::ImageSkia(new ShortcutOverlayImageSource(icon), icon.size());
129 SetIcon(icon, !HasOverlay());
130 return;
132 gfx::ImageSkia icon = icon_->image_skia();
134 const ExtensionService* service =
135 extensions::ExtensionSystem::Get(profile_)->extension_service();
136 const bool enabled = extension_util::IsAppLaunchable(extension_id_, service);
137 if (!enabled) {
138 const color_utils::HSL shift = {-1, 0, 0.6};
139 icon = gfx::ImageSkiaOperations::CreateHSLShiftedImage(icon, shift);
142 if (HasOverlay())
143 icon = gfx::ImageSkia(new ShortcutOverlayImageSource(icon), icon.size());
145 SetIcon(icon, !HasOverlay());
148 void ExtensionAppItem::Move(const ExtensionAppItem* prev,
149 const ExtensionAppItem* next) {
150 if (!prev && !next)
151 return; // No reordering necessary
153 ExtensionService* service =
154 extensions::ExtensionSystem::Get(profile_)->extension_service();
155 extensions::AppSorting* sorting = service->extension_prefs()->app_sorting();
157 syncer::StringOrdinal page;
158 std::string prev_id, next_id;
159 if (!prev) {
160 next_id = next->extension_id();
161 page = sorting->GetPageOrdinal(next_id);
162 } else if (!next) {
163 prev_id = prev->extension_id();
164 page = sorting->GetPageOrdinal(prev_id);
165 } else {
166 prev_id = prev->extension_id();
167 page = sorting->GetPageOrdinal(prev_id);
168 // Only set |next_id| if on the same page, otherwise just insert after prev.
169 if (page.Equals(sorting->GetPageOrdinal(next->extension_id())))
170 next_id = next->extension_id();
172 service->extension_prefs()->SetAppDraggedByUser(extension_id_);
173 sorting->SetPageOrdinal(extension_id_, page);
174 service->OnExtensionMoved(extension_id_, prev_id, next_id);
175 UpdatePositionFromExtensionOrdering();
178 const Extension* ExtensionAppItem::GetExtension() const {
179 const ExtensionService* service =
180 extensions::ExtensionSystem::Get(profile_)->extension_service();
181 const Extension* extension = service->GetInstalledExtension(extension_id_);
182 return extension;
185 void ExtensionAppItem::LoadImage(const Extension* extension) {
186 icon_.reset(new extensions::IconImage(
187 profile_,
188 extension,
189 extensions::IconsInfo::GetIcons(extension),
190 extension_misc::EXTENSION_ICON_MEDIUM,
191 extensions::IconsInfo::GetDefaultAppIcon(),
192 this));
193 UpdateIcon();
196 bool ExtensionAppItem::RunExtensionEnableFlow() {
197 const ExtensionService* service =
198 extensions::ExtensionSystem::Get(profile_)->extension_service();
199 if (extension_util::IsAppLaunchableWithoutEnabling(extension_id_, service))
200 return false;
202 if (!extension_enable_flow_) {
203 extension_enable_flow_controller_ = GetController();
204 extension_enable_flow_controller_->OnShowExtensionPrompt();
206 extension_enable_flow_.reset(new ExtensionEnableFlow(
207 profile_, extension_id_, this));
208 extension_enable_flow_->StartForNativeWindow(
209 extension_enable_flow_controller_->GetAppListWindow());
211 return true;
214 void ExtensionAppItem::Launch(int event_flags) {
215 // |extension| could be NULL when it is being unloaded for updating.
216 const Extension* extension = GetExtension();
217 if (!extension)
218 return;
220 if (RunExtensionEnableFlow())
221 return;
223 GetController()->LaunchApp(profile_,
224 extension,
225 AppListControllerDelegate::LAUNCH_FROM_APP_LIST,
226 event_flags);
229 void ExtensionAppItem::OnExtensionIconImageChanged(
230 extensions::IconImage* image) {
231 DCHECK(icon_.get() == image);
232 UpdateIcon();
235 void ExtensionAppItem::ExtensionEnableFlowFinished() {
236 extension_enable_flow_.reset();
237 extension_enable_flow_controller_->OnCloseExtensionPrompt();
238 extension_enable_flow_controller_ = NULL;
240 // Automatically launch app after enabling.
241 Launch(ui::EF_NONE);
244 void ExtensionAppItem::ExtensionEnableFlowAborted(bool user_initiated) {
245 extension_enable_flow_.reset();
246 extension_enable_flow_controller_->OnCloseExtensionPrompt();
247 extension_enable_flow_controller_ = NULL;
250 void ExtensionAppItem::Activate(int event_flags) {
251 // |extension| could be NULL when it is being unloaded for updating.
252 const Extension* extension = GetExtension();
253 if (!extension)
254 return;
256 if (RunExtensionEnableFlow())
257 return;
259 content::RecordAction(base::UserMetricsAction("AppList_ClickOnApp"));
260 CoreAppLauncherHandler::RecordAppListMainLaunch(extension);
261 GetController()->ActivateApp(profile_,
262 extension,
263 AppListControllerDelegate::LAUNCH_FROM_APP_LIST,
264 event_flags);
267 ui::MenuModel* ExtensionAppItem::GetContextMenuModel() {
268 if (!context_menu_) {
269 context_menu_.reset(new app_list::AppContextMenu(
270 this, profile_, extension_id_, GetController(),
271 is_platform_app_, false));
274 return context_menu_->GetMenuModel();
277 // static
278 const char ExtensionAppItem::kAppType[] = "ExtensionAppItem";
280 const char* ExtensionAppItem::GetAppType() const {
281 return ExtensionAppItem::kAppType;
284 void ExtensionAppItem::ExecuteLaunchCommand(int event_flags) {
285 Launch(event_flags);
288 void ExtensionAppItem::UpdatePositionFromExtensionOrdering() {
289 const syncer::StringOrdinal& page =
290 GetAppSorting(profile_)->GetPageOrdinal(extension_id_);
291 const syncer::StringOrdinal& launch =
292 GetAppSorting(profile_)->GetAppLaunchOrdinal(extension_id_);
293 set_position(syncer::StringOrdinal(
294 page.ToInternalValue() + launch.ToInternalValue()));
297 AppListControllerDelegate* ExtensionAppItem::GetController() {
298 return AppListService::Get(chrome::GetActiveDesktop())->
299 GetControllerDelegate();