summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/views/infobars/extension_infobar.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/ui/views/infobars/extension_infobar.cc')
-rw-r--r--chrome/browser/ui/views/infobars/extension_infobar.cc183
1 files changed, 183 insertions, 0 deletions
diff --git a/chrome/browser/ui/views/infobars/extension_infobar.cc b/chrome/browser/ui/views/infobars/extension_infobar.cc
new file mode 100644
index 0000000..e2fb43f
--- /dev/null
+++ b/chrome/browser/ui/views/infobars/extension_infobar.cc
@@ -0,0 +1,183 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/views/infobars/extension_infobar.h"
+
+#include "app/resource_bundle.h"
+#include "app/slide_animation.h"
+#include "chrome/browser/extensions/extension_context_menu_model.h"
+#include "chrome/browser/extensions/extension_infobar_delegate.h"
+#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/browser/platform_util.h"
+#include "chrome/browser/views/frame/browser_view.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_icon_set.h"
+#include "chrome/common/extensions/extension_resource.h"
+#include "gfx/canvas_skia.h"
+#include "grit/theme_resources.h"
+#include "views/controls/button/menu_button.h"
+#include "views/controls/menu/menu_2.h"
+#include "views/widget/widget.h"
+
+// The horizontal margin between the menu and the Extension (HTML) view.
+static const int kMenuHorizontalMargin = 1;
+
+// The amount of space to the right of the Extension (HTML) view (to avoid
+// overlapping the close button for the InfoBar).
+static const int kFarRightMargin = 30;
+
+// The margin between the extension icon and the drop-down arrow bitmap.
+static const int kDropArrowLeftMargin = 3;
+
+ExtensionInfoBar::ExtensionInfoBar(ExtensionInfoBarDelegate* delegate)
+ : InfoBar(delegate),
+ delegate_(delegate),
+ ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)) {
+ delegate_->set_observer(this);
+
+ ExtensionHost* extension_host = delegate_->extension_host();
+
+ // We set the target height for the InfoBar to be the height of the
+ // ExtensionView it contains (plus 1 because the view should not overlap the
+ // separator line at the bottom). When the InfoBar is first created, however,
+ // this value is 0 but becomes positive after the InfoBar has been shown. See
+ // function: OnExtensionPreferredSizeChanged.
+ gfx::Size sz = extension_host->view()->GetPreferredSize();
+ if (sz.height() > 0)
+ sz.set_height(sz.height() + 1);
+ set_target_height(sz.height());
+
+ // Setup the extension icon and its associated drop down menu.
+ SetupIconAndMenu();
+
+ // Get notified of resize events for the ExtensionView.
+ extension_host->view()->SetContainer(this);
+ // We show the ExtensionView, but we don't want it deleted when we get
+ // destroyed, which happens on tab switching (for example).
+ extension_host->view()->set_parent_owned(false);
+ AddChildView(extension_host->view());
+}
+
+ExtensionInfoBar::~ExtensionInfoBar() {
+ if (delegate_) {
+ delegate_->extension_host()->view()->SetContainer(NULL);
+ delegate_->set_observer(NULL);
+ }
+}
+
+void ExtensionInfoBar::OnExtensionPreferredSizeChanged(ExtensionView* view) {
+ DCHECK(view == delegate_->extension_host()->view());
+
+ // When the infobar is closed, it animates to 0 vertical height. We'll
+ // continue to get size changed notifications from the ExtensionView, but we
+ // need to ignore them otherwise we'll try to re-animate open (and leak the
+ // infobar view).
+ if (delegate_->closing())
+ return;
+
+ delegate_->extension_host()->view()->SetVisible(true);
+
+ gfx::Size sz = view->GetPreferredSize();
+ // Clamp height to a min and a max size of between 1 and 2 InfoBars.
+ int default_height = static_cast<int>(InfoBar::kDefaultTargetHeight);
+ sz.set_height(std::max(default_height, sz.height()));
+ sz.set_height(std::min(2 * default_height, sz.height()));
+
+ if (height() == 0)
+ animation()->Reset(0.0);
+ set_target_height(sz.height());
+ animation()->Show();
+}
+
+void ExtensionInfoBar::Layout() {
+ // Layout the close button and the background.
+ InfoBar::Layout();
+
+ // Layout the extension icon + drop down menu.
+ int x = 0;
+ gfx::Size sz = menu_->GetPreferredSize();
+ menu_->SetBounds(x,
+ (height() - sz.height()) / 2,
+ sz.width(), sz.height());
+ x += sz.width() + kMenuHorizontalMargin;
+
+ // Layout the ExtensionView, showing the HTML InfoBar.
+ ExtensionView* view = delegate_->extension_host()->view();
+ view->SetBounds(x, 0, width() - x - kFarRightMargin - 1, height() - 1);
+}
+
+void ExtensionInfoBar::OnImageLoaded(
+ SkBitmap* image, ExtensionResource resource, int index) {
+ if (!delegate_)
+ return; // The delegate can go away while we asynchronously load images.
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+
+ // We fall back on the default extension icon on failure.
+ SkBitmap* icon;
+ if (!image || image->empty())
+ icon = rb.GetBitmapNamed(IDR_EXTENSIONS_SECTION);
+ else
+ icon = image;
+
+ SkBitmap* drop_image = rb.GetBitmapNamed(IDR_APP_DROPARROW);
+
+ int image_size = Extension::EXTENSION_ICON_BITTY;
+ scoped_ptr<gfx::CanvasSkia> canvas(
+ new gfx::CanvasSkia(
+ image_size + kDropArrowLeftMargin + drop_image->width(),
+ image_size, false));
+ canvas->DrawBitmapInt(*icon,
+ 0, 0, icon->width(), icon->height(),
+ 0, 0, image_size, image_size,
+ false);
+ canvas->DrawBitmapInt(*drop_image,
+ image_size + kDropArrowLeftMargin,
+ image_size / 2);
+ menu_->SetIcon(canvas->ExtractBitmap());
+ menu_->SetVisible(true);
+
+ Layout();
+}
+
+void ExtensionInfoBar::OnDelegateDeleted() {
+ delegate_->extension_host()->view()->SetContainer(NULL);
+ delegate_ = NULL;
+}
+
+void ExtensionInfoBar::RunMenu(View* source, const gfx::Point& pt) {
+ if (!options_menu_contents_.get()) {
+ Browser* browser = BrowserView::GetBrowserViewForNativeWindow(
+ platform_util::GetTopLevel(source->GetWidget()->GetNativeView()))->
+ browser();
+ options_menu_contents_ = new ExtensionContextMenuModel(
+ delegate_->extension_host()->extension(), browser, NULL);
+ }
+
+ options_menu_menu_.reset(new views::Menu2(options_menu_contents_.get()));
+ options_menu_menu_->RunMenuAt(pt, views::Menu2::ALIGN_TOPLEFT);
+}
+
+void ExtensionInfoBar::SetupIconAndMenu() {
+ menu_ = new views::MenuButton(NULL, std::wstring(), this, false);
+ menu_->SetVisible(false);
+ AddChildView(menu_);
+
+ const Extension* extension = delegate_->extension_host()->extension();
+ ExtensionResource icon_resource = extension->GetIconResource(
+ Extension::EXTENSION_ICON_BITTY, ExtensionIconSet::MATCH_EXACTLY);
+ if (!icon_resource.relative_path().empty()) {
+ // Create a tracker to load the image. It will report back on OnImageLoaded.
+ tracker_.LoadImage(extension, icon_resource,
+ gfx::Size(Extension::EXTENSION_ICON_BITTY,
+ Extension::EXTENSION_ICON_BITTY),
+ ImageLoadingTracker::DONT_CACHE);
+ } else {
+ OnImageLoaded(NULL, icon_resource, 0); // |image|, |index|.
+ }
+}
+
+InfoBar* ExtensionInfoBarDelegate::CreateInfoBar() {
+ return new ExtensionInfoBar(this);
+}