summaryrefslogtreecommitdiffstats
path: root/chrome/browser/views/extensions
diff options
context:
space:
mode:
authorrafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-06 23:27:01 +0000
committerrafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-06 23:27:01 +0000
commit11a4b1bd05f3d419a2164ecbe0e2ec12726f523b (patch)
tree3f3ba4dc644dc42ccaa4c959b1276f30c404ceb7 /chrome/browser/views/extensions
parent81a7e67a0dbb0133f5c016d3eb04ed1116ba6717 (diff)
downloadchromium_src-11a4b1bd05f3d419a2164ecbe0e2ec12726f523b.zip
chromium_src-11a4b1bd05f3d419a2164ecbe0e2ec12726f523b.tar.gz
chromium_src-11a4b1bd05f3d419a2164ecbe0e2ec12726f523b.tar.bz2
Extension Installed InfoBubble
This creates UI feedback upon successful installation of an extension. An InfoBubble is shown containing the install icon and some information about how to manage extensions. TEST=Install a packaged extension. Verify the InfoBubble is shown, with the install icon and some description. The InfoBubble should disappear when the bubble looses focus (click elsewhere). For a browserAction, the bubble should point to the browserAction icon. For a pageAction **that has a "default_icon" set in it's manifest (see the samples/subscribe_page_action in this CL)**, it should point to a temporarily shown pageAction icon that will be hidden when the bubble closes. Otherwise it should point to the wrench menu. BUG=21412 Review URL: http://codereview.chromium.org/362022 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31322 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/views/extensions')
-rw-r--r--chrome/browser/views/extensions/extension_installed_bubble.cc229
-rw-r--r--chrome/browser/views/extensions/extension_installed_bubble.h81
2 files changed, 310 insertions, 0 deletions
diff --git a/chrome/browser/views/extensions/extension_installed_bubble.cc b/chrome/browser/views/extensions/extension_installed_bubble.cc
new file mode 100644
index 0000000..396ca6c
--- /dev/null
+++ b/chrome/browser/views/extensions/extension_installed_bubble.cc
@@ -0,0 +1,229 @@
+// Copyright (c) 2009 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/extensions/extension_installed_bubble.h"
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/message_loop.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_window.h"
+#include "chrome/browser/views/browser_actions_container.h"
+#include "chrome/browser/views/frame/browser_view.h"
+#include "chrome/browser/views/location_bar_view.h"
+#include "chrome/browser/views/toolbar_view.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "grit/generated_resources.h"
+#include "views/controls/label.h"
+#include "views/standard_layout.h"
+#include "views/view.h"
+
+namespace {
+
+const int kIconSize = 43;
+
+const int kRightColumnWidth = 270;
+
+// The InfoBubble uses a BubbleBorder which adds about 6 pixels of whitespace
+// around the content view. We compensate by reducing our outer borders by this
+// amount.
+const int kBubbleBorderInsert = 6;
+const int kHorizOuterMargin = kPanelHorizMargin - kBubbleBorderInsert;
+const int kVertOuterMargin = kPanelVertMargin - kBubbleBorderInsert;
+
+// InstalledBubbleContent is the content view which is placed in the
+// ExtensionInstalledBubble. It displays the install icon and explanatory
+// text about the installed extension.
+class InstalledBubbleContent : public views::View {
+ public:
+ InstalledBubbleContent(Extension* extension,
+ ExtensionInstalledBubble::BubbleType type,
+ SkBitmap* icon)
+ : type_(type),
+ info_(NULL) {
+ const gfx::Font& font =
+ ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont);
+
+ // Scale down to 43x43, but allow smaller icons (don't scale up).
+ gfx::Size size(icon->width(), icon->height());
+ if (size.width() > kIconSize || size.height() > kIconSize)
+ size = gfx::Size(kIconSize, kIconSize);
+ icon_ = new views::ImageView();
+ icon_->SetImageSize(size);
+ icon_->SetImage(*icon);
+ AddChildView(icon_);
+
+ heading_ = new views::Label(
+ l10n_util::GetStringF(IDS_EXTENSION_INSTALLED_HEADING,
+ UTF8ToWide(extension->name())));
+ heading_->SetFont(font.DeriveFont(3, gfx::Font::NORMAL));
+ heading_->SetMultiLine(true);
+ heading_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+ AddChildView(heading_);
+
+ if (type_ == ExtensionInstalledBubble::PAGE_ACTION) {
+ info_ = new views::Label(l10n_util::GetString(
+ IDS_EXTENSION_INSTALLED_PAGE_ACTION_INFO));
+ info_->SetFont(font);
+ info_->SetMultiLine(true);
+ info_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+ AddChildView(info_);
+ }
+
+ manage_ = new views::Label(l10n_util::GetString(
+ IDS_EXTENSION_INSTALLED_MANAGE_INFO));
+ manage_->SetFont(font);
+ manage_->SetMultiLine(true);
+ manage_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+ AddChildView(manage_);
+ }
+
+ private:
+ virtual gfx::Size GetPreferredSize() {
+ int width = kRightColumnWidth + kHorizOuterMargin + kHorizOuterMargin;
+ width += kIconSize;
+ width += kPanelHorizMargin;
+
+ int height = kVertOuterMargin * 2;
+ height += heading_->GetHeightForWidth(kRightColumnWidth);
+ height += kPanelVertMargin;
+ if (type_ == ExtensionInstalledBubble::PAGE_ACTION) {
+ height += info_->GetHeightForWidth(kRightColumnWidth);
+ height += kPanelVertMargin;
+ }
+ height += manage_->GetHeightForWidth(kRightColumnWidth);
+
+ return gfx::Size(width, std::max(height, kIconSize + kVertOuterMargin * 2));
+ }
+
+ virtual void Layout() {
+ int x = kHorizOuterMargin;
+ int y = kVertOuterMargin;
+
+ icon_->SetBounds(x, y, kIconSize, kIconSize);
+ x += kIconSize;
+ x += kPanelHorizMargin;
+
+ heading_->SizeToFit(kRightColumnWidth);
+ heading_->SetX(x);
+ heading_->SetY(y);
+ y += heading_->height();
+ y += kPanelVertMargin;
+
+ if (type_ == ExtensionInstalledBubble::PAGE_ACTION) {
+ info_->SizeToFit(kRightColumnWidth);
+ info_->SetX(x);
+ info_->SetY(y);
+ y += info_->height();
+ y += kPanelVertMargin;
+ }
+
+ manage_->SizeToFit(kRightColumnWidth);
+ manage_->SetX(x);
+ manage_->SetY(y);
+ }
+
+ ExtensionInstalledBubble::BubbleType type_;
+ views::ImageView* icon_;
+ views::Label* heading_;
+ views::Label* info_;
+ views::Label* manage_;
+
+ DISALLOW_COPY_AND_ASSIGN(InstalledBubbleContent);
+};
+
+} // namespace
+
+void ExtensionInstalledBubble::Show(Extension *extension, Browser *browser,
+ SkBitmap icon) {
+ new ExtensionInstalledBubble(extension, browser, icon);
+}
+
+ExtensionInstalledBubble::ExtensionInstalledBubble(Extension *extension,
+ Browser *browser,
+ SkBitmap icon)
+ : extension_(extension),
+ browser_(browser),
+ icon_(icon) {
+ AddRef(); // Balanced in InfoBubbleClosing.
+
+ if (extension_->browser_action()) {
+ type_ = BROWSER_ACTION;
+ } else if (extension->page_action() &&
+ !extension->page_action()->default_icon_path().empty()) {
+ type_ = PAGE_ACTION;
+ } else {
+ type_ = GENERIC;
+ }
+
+ // |extension| has been initialized but not loaded at this point. We need
+ // to wait on showing the Bubble until not only the EXTENSION_LOADED gets
+ // fired, but all of the EXTENSION_LOADED Observers have run. Only then can we
+ // be sure that a BrowserAction or PageAction has had views created which we
+ // can inspect for the purpose of previewing of pointing to them.
+ registrar_.Add(this, NotificationType::EXTENSION_LOADED,
+ NotificationService::AllSources());
+}
+
+void ExtensionInstalledBubble::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::EXTENSION_LOADED) {
+ Extension* extension = Details<Extension>(details).ptr();
+ if (extension == extension_) {
+ // PostTask to ourself to allow all EXTENSION_LOADED Observers to run.
+ MessageLoopForUI::current()->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &ExtensionInstalledBubble::ShowInternal));
+ }
+ } else {
+ NOTREACHED() << L"Received unexpected notification";
+ }
+}
+
+void ExtensionInstalledBubble::ShowInternal() {
+ BrowserView* browser_view = BrowserView::GetBrowserViewForNativeWindow(
+ browser_->window()->GetNativeHandle());
+
+ views::View* reference_view = NULL;
+ if (type_ == BROWSER_ACTION) {
+ reference_view = browser_view->GetToolbarView()->browser_actions()
+ ->GetBrowserActionView(extension_);
+ DCHECK(reference_view);
+ } else if (type_ == PAGE_ACTION) {
+ LocationBarView* location_bar_view = browser_view->GetLocationBarView();
+ location_bar_view->SetPreviewEnabledPageAction(extension_->page_action(),
+ true); // preview_enabled
+ reference_view = location_bar_view->GetPageActionView(
+ extension_->page_action());
+ DCHECK(reference_view);
+ }
+
+ // Default case.
+ if (reference_view == NULL)
+ reference_view = browser_view->GetToolbarView()->app_menu();
+
+ gfx::Point origin;
+ views::View::ConvertPointToScreen(reference_view, &origin);
+ gfx::Rect bounds = reference_view->bounds();
+ bounds.set_x(origin.x());
+ bounds.set_y(origin.y());
+
+ views::View* bubble_content = new InstalledBubbleContent(extension_, type_,
+ &icon_);
+ InfoBubble::Show(browser_view->GetWindow(), bounds, bubble_content, this);
+}
+
+// InfoBubbleDelegate
+void ExtensionInstalledBubble::InfoBubbleClosing(InfoBubble* info_bubble,
+ bool closed_by_escape) {
+ if (extension_->page_action()) {
+ BrowserView* browser_view = BrowserView::GetBrowserViewForNativeWindow(
+ browser_->window()->GetNativeHandle());
+ browser_view->GetLocationBarView()->SetPreviewEnabledPageAction(
+ extension_->page_action(),
+ false); // preview_enabled
+ }
+ Release(); // Balanced in ctor.
+}
diff --git a/chrome/browser/views/extensions/extension_installed_bubble.h b/chrome/browser/views/extensions/extension_installed_bubble.h
new file mode 100644
index 0000000..def9fcb
--- /dev/null
+++ b/chrome/browser/views/extensions/extension_installed_bubble.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_VIEWS_EXTENSIONS_EXTENSION_INSTALLED_BUBBLE_H_
+#define CHROME_BROWSER_VIEWS_EXTENSIONS_EXTENSION_INSTALLED_BUBBLE_H_
+
+#include "base/ref_counted.h"
+#include "chrome/browser/views/info_bubble.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+class Browser;
+class Extension;
+class SkBitmap;
+
+// Provides feedback to the user upon successful installation of an
+// extension. Depending on the type of extension, the InfoBubble will
+// point to:
+// BROWSER_ACTION -> The browserAction icon in the toolbar.
+// PAGE_ACTION -> A preview of the pageAction icon in the location
+// bar which is shown while the InfoBubble is shown.
+// GENERIC -> The wrench menu. This case includes pageActions that
+// don't specify a default icon.
+//
+// ExtensionInstallBubble manages its own lifetime.
+class ExtensionInstalledBubble :
+ public InfoBubbleDelegate,
+ public NotificationObserver,
+ public base::RefCountedThreadSafe<ExtensionInstalledBubble> {
+ public:
+ // The behavior and content of this InfoBubble comes in three varieties.
+ enum BubbleType {
+ BROWSER_ACTION,
+ PAGE_ACTION,
+ GENERIC
+ };
+
+ // Creates the ExtensionInstalledBubble and schedules it to be shown once
+ // the extension has loaded. |extension| is the installed extension. |browser|
+ // is the browser window which will host the bubble. |icon| is the install
+ // icon of the extension.
+ static void Show(Extension *extension, Browser *browser, SkBitmap icon);
+
+private:
+ friend class base::RefCountedThreadSafe<ExtensionInstalledBubble>;
+
+ // Private ctor. Registers a listener for EXTENSION_LOADED.
+ ExtensionInstalledBubble(Extension *extension, Browser *browser,
+ SkBitmap icon);
+
+ ~ExtensionInstalledBubble() {}
+
+ // Shows the bubble. Called internally via PostTask.
+ void ShowInternal();
+
+ // NotificationObserver
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // InfoBubbleDelegate
+ virtual void InfoBubbleClosing(InfoBubble* info_bubble,
+ bool closed_by_escape);
+ virtual bool CloseOnEscape() { return true; }
+
+ // Arrow subjects appear on the right side (for RTL), so do not prefer
+ // origin side anchor.
+ virtual bool PreferOriginSideAnchor() { return false; }
+
+ Extension *extension_;
+ Browser *browser_;
+ SkBitmap icon_;
+ NotificationRegistrar registrar_;
+ BubbleType type_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionInstalledBubble);
+};
+
+#endif // CHROME_BROWSER_VIEWS_EXTENSIONS_EXTENSION_INSTALLED_BUBBLE_H_