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 | |
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')
-rw-r--r-- | chrome/browser/extensions/extension_install_ui.cc | 23 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_install_ui.h | 6 | ||||
-rw-r--r-- | chrome/browser/views/browser_actions_container.cc | 12 | ||||
-rw-r--r-- | chrome/browser/views/browser_actions_container.h | 3 | ||||
-rw-r--r-- | chrome/browser/views/extensions/extension_installed_bubble.cc | 229 | ||||
-rw-r--r-- | chrome/browser/views/extensions/extension_installed_bubble.h | 81 | ||||
-rw-r--r-- | chrome/browser/views/info_bubble.cc | 37 | ||||
-rw-r--r-- | chrome/browser/views/info_bubble.h | 16 | ||||
-rw-r--r-- | chrome/browser/views/location_bar_view.cc | 36 | ||||
-rw-r--r-- | chrome/browser/views/location_bar_view.h | 19 |
10 files changed, 436 insertions, 26 deletions
diff --git a/chrome/browser/extensions/extension_install_ui.cc b/chrome/browser/extensions/extension_install_ui.cc index 1712791..3efe3db 100644 --- a/chrome/browser/extensions/extension_install_ui.cc +++ b/chrome/browser/extensions/extension_install_ui.cc @@ -16,6 +16,7 @@ #include "chrome/browser/extensions/theme_installed_infobar_delegate.h" #include "chrome/browser/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/views/extensions/extension_installed_bubble.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/notification_service.h" #include "grit/browser_resources.h" @@ -113,19 +114,35 @@ void ExtensionInstallUI::ConfirmInstall(Delegate* delegate, install_icon = ResourceBundle::GetSharedInstance().GetBitmapNamed( IDR_EXTENSIONS_SECTION); } + icon_ = *install_icon; NotificationService* service = NotificationService::current(); service->Notify(NotificationType::EXTENSION_WILL_SHOW_CONFIRM_DIALOG, Source<ExtensionInstallUI>(this), NotificationService::NoDetails()); - ShowExtensionInstallPrompt(profile_, delegate, extension, install_icon, + ShowExtensionInstallPrompt(profile_, delegate, extension, &icon_, GetInstallWarning(extension)); - } void ExtensionInstallUI::OnInstallSuccess(Extension* extension) { - ShowThemeInfoBar(extension); + if (extension->IsTheme()) { + ShowThemeInfoBar(extension); + return; + } + +#if defined(TOOLKIT_VIEWS) + // GetLastActiveWithProfile will fail on the build bots. This needs to + // implemented differently if any test is created which depends on + // ExtensionInstalledBubble showing. + Browser* browser = BrowserList::GetLastActiveWithProfile(profile_); + if (!browser) + return; + + ExtensionInstalledBubble::Show(extension, browser, icon_); +#else +// TODO(port) crbug.com/26973 (linux) crbug.com/26974 (mac) +#endif // TOOLKIT_VIEWS } void ExtensionInstallUI::OnInstallFailure(const std::string& error) { diff --git a/chrome/browser/extensions/extension_install_ui.h b/chrome/browser/extensions/extension_install_ui.h index 18811a5..f2ddf8d 100644 --- a/chrome/browser/extensions/extension_install_ui.h +++ b/chrome/browser/extensions/extension_install_ui.h @@ -8,6 +8,8 @@ #include "app/gfx/native_widget_types.h" #include "base/file_path.h" #include "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "third_party/skia/include/core/SkBitmap.h" #include <string> @@ -17,7 +19,6 @@ class MessageLoop; class Profile; class InfoBarDelegate; class SandboxedExtensionUnpacker; -class SkBitmap; class TabContents; // Displays all the UI around extension installation. @@ -42,7 +43,7 @@ class ExtensionInstallUI { const std::wstring& warning_text); static void ShowExtensionInstallError(const std::string& error); - ExtensionInstallUI(Profile* profile); + explicit ExtensionInstallUI(Profile* profile); // This is called by the installer to verify whether the installation should // proceed. @@ -75,6 +76,7 @@ class ExtensionInstallUI { Profile* profile_; MessageLoop* ui_loop_; std::string previous_theme_id_; // Used to undo theme installation. + SkBitmap icon_; // The extensions installation icon. #if defined(TOOLKIT_GTK) // Also needed to undo theme installation in the linux UI. diff --git a/chrome/browser/views/browser_actions_container.cc b/chrome/browser/views/browser_actions_container.cc index 23c3402..dbae46b 100644 --- a/chrome/browser/views/browser_actions_container.cc +++ b/chrome/browser/views/browser_actions_container.cc @@ -256,6 +256,18 @@ int BrowserActionsContainer::GetCurrentTabId() { return tab_contents->controller().session_id().id(); } +BrowserActionView* BrowserActionsContainer::GetBrowserActionView( + Extension* extension) { + for (std::vector<BrowserActionView*>::iterator iter = + browser_action_views_.begin(); iter != browser_action_views_.end(); + ++iter) { + if ((*iter)->button()->extension() == extension) + return *iter; + } + + return NULL; +} + void BrowserActionsContainer::RefreshBrowserActionViews() { for (size_t i = 0; i < browser_action_views_.size(); ++i) browser_action_views_[i]->button()->UpdateState(); diff --git a/chrome/browser/views/browser_actions_container.h b/chrome/browser/views/browser_actions_container.h index a3ba6fe..cd308c2 100644 --- a/chrome/browser/views/browser_actions_container.h +++ b/chrome/browser/views/browser_actions_container.h @@ -152,6 +152,9 @@ class BrowserActionsContainer : public views::View, return browser_action_views_[index]; } + // Retrieve the BrowserActionView for |extension|. + BrowserActionView* GetBrowserActionView(Extension* extension); + // Update the views to reflect the state of the browser action icons. void RefreshBrowserActionViews(); 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_ diff --git a/chrome/browser/views/info_bubble.cc b/chrome/browser/views/info_bubble.cc index 1218f46..4f39ba9 100644 --- a/chrome/browser/views/info_bubble.cc +++ b/chrome/browser/views/info_bubble.cc @@ -35,17 +35,16 @@ class BorderContents : public views::View { // Given the size of the contents and the rect to point at, initializes the // bubble and returns the bounds of both the border // and the contents inside the bubble. - // |is_rtl| is true if the UI is RTL and thus the arrow should default to the - // right side of the bubble; otherwise it defaults to the left top corner, and - // then is moved as necessary to try and fit the whole bubble on the same - // monitor as the rect being pointed to. + // |prefer_arrow_on_right| specifies the preferred location for the arrow + // anchor. If the bubble does not fit on the monitor, the arrow location may + // changed so it can. // // TODO(pkasting): Maybe this should use mirroring transformations instead, // which would hopefully simplify this code. void InitAndGetBounds( const gfx::Rect& position_relative_to, // In screen coordinates const gfx::Size& contents_size, - bool is_rtl, + bool prefer_arrow_on_right, gfx::Rect* contents_bounds, // Returned in window coordinates gfx::Rect* window_bounds); // Returned in screen coordinates @@ -61,7 +60,7 @@ class BorderContents : public views::View { void BorderContents::InitAndGetBounds( const gfx::Rect& position_relative_to, const gfx::Size& contents_size, - bool is_rtl, + bool prefer_arrow_on_right, gfx::Rect* contents_bounds, gfx::Rect* window_bounds) { // Margins between the contents and the inside of the border, in pixels. @@ -80,8 +79,9 @@ void BorderContents::InitAndGetBounds( local_contents_size.Enlarge(kLeftMargin + kRightMargin, kTopMargin + kBottomMargin); - // Try putting the arrow in its default location, and calculating the bounds. - BubbleBorder::ArrowLocation arrow_location(is_rtl ? + // Try putting the arrow in its initial location, and calculating the + // bounds. + BubbleBorder::ArrowLocation arrow_location(prefer_arrow_on_right ? BubbleBorder::TOP_RIGHT : BubbleBorder::TOP_LEFT); bubble_border->set_arrow_location(arrow_location); *window_bounds = @@ -94,9 +94,9 @@ void BorderContents::InitAndGetBounds( monitor_provider->GetMonitorWorkAreaMatching(position_relative_to)); if (!monitor_bounds.IsEmpty() && !monitor_bounds.Contains(*window_bounds)) { // The bounds don't fit. Move the arrow to try and improve things. - bool arrow_on_left = - (is_rtl ? (window_bounds->x() < monitor_bounds.x()) : - (window_bounds->right() <= monitor_bounds.right())); + bool arrow_on_left = prefer_arrow_on_right ? + (window_bounds->x() < monitor_bounds.x()) : + (window_bounds->right() <= monitor_bounds.right()); if (window_bounds->bottom() > monitor_bounds.bottom()) { arrow_location = arrow_on_left ? BubbleBorder::BOTTOM_LEFT : BubbleBorder::BOTTOM_RIGHT; @@ -155,13 +155,14 @@ gfx::Rect BorderWidget::InitAndGetBounds( HWND owner, const gfx::Rect& position_relative_to, const gfx::Size& contents_size, - bool is_rtl) { + bool prefer_arrow_on_right) { // Set up the border view and ask it to calculate our bounds (and our // contents'). BorderContents* border_contents = new BorderContents; gfx::Rect contents_bounds, window_bounds; - border_contents->InitAndGetBounds(position_relative_to, contents_size, is_rtl, - &contents_bounds, &window_bounds); + border_contents->InitAndGetBounds(position_relative_to, contents_size, + prefer_arrow_on_right, &contents_bounds, + &window_bounds); // Initialize ourselves. WidgetWin::Init(GetAncestor(owner, GA_ROOT), window_bounds); @@ -247,12 +248,16 @@ void InfoBubble::Init(views::Window* parent, // Calculate and set the bounds for all windows and views. gfx::Rect window_bounds; + + bool prefer_arrow_on_right = + (contents->UILayoutIsRightToLeft() == delegate->PreferOriginSideAnchor()); + #if defined(OS_WIN) border_.reset(new BorderWidget); // Initialize and position the border window. window_bounds = border_->InitAndGetBounds(GetNativeView(), position_relative_to, contents->GetPreferredSize(), - contents->UILayoutIsRightToLeft()); + prefer_arrow_on_right); // Make |contents| take up the entire contents view. contents_view->SetLayoutManager(new views::FillLayout); @@ -265,7 +270,7 @@ void InfoBubble::Init(views::Window* parent, BorderContents* border_contents = new BorderContents; gfx::Rect contents_bounds; border_contents->InitAndGetBounds(position_relative_to, - contents->GetPreferredSize(), contents->UILayoutIsRightToLeft(), + contents->GetPreferredSize(), prefer_arrow_on_right, &contents_bounds, &window_bounds); // This new view must be added before |contents| so it will paint under it. contents_view->AddChildView(0, border_contents); diff --git a/chrome/browser/views/info_bubble.h b/chrome/browser/views/info_bubble.h index 996413a..0e7e622 100644 --- a/chrome/browser/views/info_bubble.h +++ b/chrome/browser/views/info_bubble.h @@ -74,6 +74,12 @@ class InfoBubbleDelegate { // Whether the InfoBubble should be closed when the Esc key is pressed. virtual bool CloseOnEscape() = 0; + + // Whether the default placement of the anchor is on the origin side of the + // text direction. For example: if true (the default) in LTR text direction, + // the ArrowLocation will be TOP_LEFT, if false it will be TOP_RIGHT. + // RTL is the reverse. + virtual bool PreferOriginSideAnchor() { return true; } }; // TODO: this code is ifdef-tastic. It might be cleaner to refactor the @@ -92,9 +98,13 @@ class InfoBubble // screen coordinates at which the InfoBubble will point. Show() takes // ownership of |contents| and deletes the created InfoBubble when another // window is activated. You can explicitly close the bubble by invoking - // Close(). You may provide an optional |delegate| to be notified when the - // InfoBubble is closed and/or to prevent the InfoBubble from being closed - // when the Escape key is pressed (the default behavior). + // Close(). You may provide an optional |delegate| to: + // - Be notified when the InfoBubble is closed. + // - Prevent the InfoBubble from being closed when the Escape key is + // pressed (the default behavior). + // - Have the InfoBubble prefer to anchor its arrow to the non-origin + // side of text direction. (see comment above + // InfoBubbleDelegate::PreferOriginSideAnchor); . static InfoBubble* Show(views::Window* parent, const gfx::Rect& position_relative_to, views::View* contents, diff --git a/chrome/browser/views/location_bar_view.cc b/chrome/browser/views/location_bar_view.cc index f159d7e..09175be 100644 --- a/chrome/browser/views/location_bar_view.cc +++ b/chrome/browser/views/location_bar_view.cc @@ -338,6 +338,36 @@ void LocationBarView::SetProfile(Profile* profile) { } } +void LocationBarView::SetPreviewEnabledPageAction(ExtensionAction *page_action, + bool preview_enabled) { + DCHECK(page_action); + TabContents* contents = delegate_->GetTabContents(); + + RefreshPageActionViews(); + PageActionWithBadgeView* page_action_view = + static_cast<PageActionWithBadgeView*>(GetPageActionView(page_action)); + DCHECK(page_action_view); + if (!page_action_view) + return; + + page_action_view->image_view()->set_preview_enabled(preview_enabled); + page_action_view->UpdateVisibility(contents, + GURL(WideToUTF8(model_->GetText()))); + Layout(); + SchedulePaint(); +} + +views::View* LocationBarView::GetPageActionView( + ExtensionAction *page_action) { + DCHECK(page_action); + for (std::vector<PageActionWithBadgeView*>::iterator iter = + page_action_views_.begin(); iter != page_action_views_.end(); + ++iter) { + if ((*iter)->image_view()->page_action() == page_action) + return *iter; + } + return NULL; +} gfx::Size LocationBarView::GetPreferredSize() { return gfx::Size(0, (popup_window_mode_ ? kPopupBackground : kBackground)->height()); @@ -1263,7 +1293,8 @@ LocationBarView::PageActionImageView::PageActionImageView( owner_(owner), profile_(profile), page_action_(page_action), - current_tab_id_(-1) { + current_tab_id_(-1), + preview_enabled_(false) { Extension* extension = profile->GetExtensionsService()->GetExtensionById( page_action->extension_id()); DCHECK(extension); @@ -1370,7 +1401,8 @@ void LocationBarView::PageActionImageView::UpdateVisibility( current_tab_id_ = ExtensionTabUtil::GetTabId(contents); current_url_ = url; - bool visible = page_action_->GetIsVisible(current_tab_id_); + bool visible = preview_enabled_ || + page_action_->GetIsVisible(current_tab_id_); if (visible) { // Set the tooltip. tooltip_ = page_action_->GetTitle(current_tab_id_); diff --git a/chrome/browser/views/location_bar_view.h b/chrome/browser/views/location_bar_view.h index 8bac242..26d562b 100644 --- a/chrome/browser/views/location_bar_view.h +++ b/chrome/browser/views/location_bar_view.h @@ -95,6 +95,17 @@ class LocationBarView : public LocationBar, void SetProfile(Profile* profile); Profile* profile() { return profile_; } + // Sets |preview_enabled| for the PageAction View associated with this + // |page_action|. If |preview_enabled| is true, the view will display the + // PageActions icon even though it has not been activated by the extension. + // This is used by the ExtensionInstalledBubble to preview what the icon + // will look like for the user upon installation of the extension. + void SetPreviewEnabledPageAction(ExtensionAction *page_action, + bool preview_enabled); + + // Retrieves the PageAction View which is associated with |page_action| + views::View* GetPageActionView(ExtensionAction* page_action); + // Sizing functions virtual gfx::Size GetPreferredSize(); @@ -360,6 +371,10 @@ class LocationBarView : public LocationBar, int current_tab_id() { return current_tab_id_; } + void set_preview_enabled(bool preview_enabled) { + preview_enabled_ = preview_enabled; + } + // Overridden from view. virtual void OnMouseMoved(const views::MouseEvent& event); virtual bool OnMousePressed(const views::MouseEvent& event); @@ -406,6 +421,10 @@ class LocationBarView : public LocationBar, // The string to show for a tooltip; std::string tooltip_; + // This is used for post-install visual feedback. The page_action icon + // is briefly shown even if it hasn't been enabled by it's extension. + bool preview_enabled_; + DISALLOW_COPY_AND_ASSIGN(PageActionImageView); }; friend class PageActionImageView; |