- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / infobars / extension_infobar.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/views/infobars/extension_infobar.h"
6
7 #include "chrome/browser/extensions/extension_context_menu_model.h"
8 #include "chrome/browser/extensions/extension_host.h"
9 #include "chrome/browser/extensions/extension_infobar_delegate.h"
10 #include "chrome/browser/extensions/image_loader.h"
11 #include "chrome/browser/platform_util.h"
12 #include "chrome/browser/ui/views/frame/browser_view.h"
13 #include "chrome/common/extensions/extension.h"
14 #include "chrome/common/extensions/extension_constants.h"
15 #include "chrome/common/extensions/extension_icon_set.h"
16 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
17 #include "extensions/common/extension_resource.h"
18 #include "grit/theme_resources.h"
19 #include "ui/base/resource/resource_bundle.h"
20 #include "ui/gfx/animation/slide_animation.h"
21 #include "ui/gfx/canvas.h"
22 #include "ui/gfx/image/canvas_image_source.h"
23 #include "ui/gfx/image/image.h"
24 #include "ui/views/controls/button/menu_button.h"
25 #include "ui/views/controls/image_view.h"
26 #include "ui/views/controls/menu/menu_item_view.h"
27 #include "ui/views/widget/widget.h"
28
29
30 // ExtensionInfoBarDelegate ----------------------------------------------------
31
32 InfoBar* ExtensionInfoBarDelegate::CreateInfoBar(InfoBarService* owner) {
33   return new ExtensionInfoBar(owner, this, browser_);
34 }
35
36
37 // ExtensionInfoBar ------------------------------------------------------------
38
39 namespace {
40 // The horizontal margin between the infobar icon and the Extension (HTML) view.
41 const int kIconHorizontalMargin = 1;
42
43 class MenuImageSource: public gfx::CanvasImageSource {
44  public:
45   MenuImageSource(const gfx::ImageSkia& icon, const gfx::ImageSkia& drop_image)
46       : gfx::CanvasImageSource(ComputeSize(drop_image), false),
47         icon_(icon),
48         drop_image_(drop_image) {
49   }
50
51   virtual ~MenuImageSource() {
52   }
53
54   // Overridden from gfx::CanvasImageSource
55   virtual void Draw(gfx::Canvas* canvas) OVERRIDE {
56     int image_size = extension_misc::EXTENSION_ICON_BITTY;
57     canvas->DrawImageInt(icon_, 0, 0, icon_.width(), icon_.height(), 0, 0,
58                          image_size, image_size, false);
59     canvas->DrawImageInt(drop_image_, image_size + kDropArrowLeftMargin,
60                          image_size / 2);
61   }
62
63  private:
64   gfx::Size ComputeSize(const gfx::ImageSkia& drop_image) const {
65     int image_size = extension_misc::EXTENSION_ICON_BITTY;
66     return gfx::Size(image_size + kDropArrowLeftMargin + drop_image.width(),
67                      image_size);
68   }
69
70   // The margin between the extension icon and the drop-down arrow image.
71   static const int kDropArrowLeftMargin = 3;
72
73   const gfx::ImageSkia icon_;
74   const gfx::ImageSkia drop_image_;
75
76   DISALLOW_COPY_AND_ASSIGN(MenuImageSource);
77 };
78
79 }  // namespace
80
81 ExtensionInfoBar::ExtensionInfoBar(InfoBarService* owner,
82                                    ExtensionInfoBarDelegate* delegate,
83                                    Browser* browser)
84     : InfoBarView(owner, delegate),
85       delegate_(delegate),
86       browser_(browser),
87       infobar_icon_(NULL),
88       icon_as_menu_(NULL),
89       icon_as_image_(NULL),
90       weak_ptr_factory_(this) {
91   GetDelegate()->set_observer(this);
92
93   int height = GetDelegate()->height();
94   SetBarTargetHeight((height > 0) ? (height + kSeparatorLineHeight) : 0);
95 }
96
97 ExtensionInfoBar::~ExtensionInfoBar() {
98   if (GetDelegate())
99     GetDelegate()->set_observer(NULL);
100 }
101
102 void ExtensionInfoBar::Layout() {
103   InfoBarView::Layout();
104
105   gfx::Size size = infobar_icon_->GetPreferredSize();
106   infobar_icon_->SetBounds(StartX(), OffsetY(size), size.width(),
107                            size.height());
108
109   GetDelegate()->extension_host()->view()->SetBounds(
110       infobar_icon_->bounds().right() + kIconHorizontalMargin,
111       arrow_height(),
112       std::max(0, EndX() - StartX() - ContentMinimumWidth()),
113       height() - arrow_height() - 1);
114 }
115
116 void ExtensionInfoBar::ViewHierarchyChanged(
117     const ViewHierarchyChangedDetails& details) {
118   if (!details.is_add || (details.child != this) || (infobar_icon_ != NULL)) {
119     InfoBarView::ViewHierarchyChanged(details);
120     return;
121   }
122
123   extensions::ExtensionHost* extension_host = GetDelegate()->extension_host();
124
125   if (extension_host->extension()->ShowConfigureContextMenus()) {
126     icon_as_menu_ = new views::MenuButton(NULL, string16(), this, false);
127     icon_as_menu_->set_focusable(true);
128     infobar_icon_ = icon_as_menu_;
129   } else {
130     icon_as_image_ = new views::ImageView();
131     infobar_icon_ = icon_as_image_;
132   }
133
134   // Wait until the icon image is loaded before showing it.
135   infobar_icon_->SetVisible(false);
136   AddChildView(infobar_icon_);
137
138   AddChildView(extension_host->view());
139
140   // This must happen after adding all other children so InfoBarView can ensure
141   // the close button is the last child.
142   InfoBarView::ViewHierarchyChanged(details);
143
144   // This must happen after adding all children because it can trigger layout,
145   // which assumes that particular children (e.g. the close button) have already
146   // been added.
147   const extensions::Extension* extension = extension_host->extension();
148   extension_misc::ExtensionIcons image_size =
149       extension_misc::EXTENSION_ICON_BITTY;
150   extensions::ExtensionResource icon_resource =
151       extensions::IconsInfo::GetIconResource(
152           extension, image_size, ExtensionIconSet::MATCH_EXACTLY);
153   extensions::ImageLoader* loader =
154       extensions::ImageLoader::Get(extension_host->profile());
155   loader->LoadImageAsync(
156       extension,
157       icon_resource,
158       gfx::Size(image_size, image_size),
159       base::Bind(&ExtensionInfoBar::OnImageLoaded,
160                  weak_ptr_factory_.GetWeakPtr()));
161 }
162
163 int ExtensionInfoBar::ContentMinimumWidth() const {
164   return infobar_icon_->GetPreferredSize().width() + kIconHorizontalMargin;
165
166 }
167
168 void ExtensionInfoBar::OnDelegateDeleted() {
169   delegate_ = NULL;
170 }
171
172 void ExtensionInfoBar::OnMenuButtonClicked(views::View* source,
173                                            const gfx::Point& point) {
174   if (!owner())
175     return;  // We're closing; don't call anything, it might access the owner.
176   const extensions::Extension* extension =
177       GetDelegate()->extension_host()->extension();
178   DCHECK(icon_as_menu_);
179
180   scoped_refptr<ExtensionContextMenuModel> options_menu_contents =
181       new ExtensionContextMenuModel(extension, browser_);
182   DCHECK_EQ(icon_as_menu_, source);
183   RunMenuAt(options_menu_contents.get(),
184             icon_as_menu_,
185             views::MenuItemView::TOPLEFT);
186 }
187
188 void ExtensionInfoBar::OnImageLoaded(const gfx::Image& image) {
189   if (!GetDelegate())
190     return;  // The delegate can go away while we asynchronously load images.
191
192   const gfx::ImageSkia* icon = NULL;
193   // Fall back on the default extension icon on failure.
194   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
195   if (image.IsEmpty())
196     icon = rb.GetImageNamed(IDR_EXTENSIONS_SECTION).ToImageSkia();
197   else
198     icon = image.ToImageSkia();
199
200   if (icon_as_menu_) {
201     const gfx::ImageSkia* drop_image =
202         rb.GetImageNamed(IDR_APP_DROPARROW).ToImageSkia();
203
204     gfx::CanvasImageSource* source = new MenuImageSource(*icon, *drop_image);
205     gfx::ImageSkia menu_image = gfx::ImageSkia(source, source->size());
206     icon_as_menu_->SetIcon(menu_image);
207   } else {
208     icon_as_image_->SetImage(*icon);
209   }
210
211   infobar_icon_->SetVisible(true);
212
213   Layout();
214 }
215
216 ExtensionInfoBarDelegate* ExtensionInfoBar::GetDelegate() {
217   return delegate_ ? delegate_->AsExtensionInfoBarDelegate() : NULL;
218 }