diff options
author | rafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-06 23:27:01 +0000 |
---|---|---|
committer | rafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-06 23:27:01 +0000 |
commit | 11a4b1bd05f3d419a2164ecbe0e2ec12726f523b (patch) | |
tree | 3f3ba4dc644dc42ccaa4c959b1276f30c404ceb7 /chrome/browser/views/extensions | |
parent | 81a7e67a0dbb0133f5c016d3eb04ed1116ba6717 (diff) | |
download | chromium_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.cc | 229 | ||||
-rw-r--r-- | chrome/browser/views/extensions/extension_installed_bubble.h | 81 |
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_ |