This source file includes following definitions.
- ShowExtensionInstalledBubble
- manage_shortcut_
- ButtonPressed
- LinkClicked
- GetKeybinding
- GetHowToUseDescription
- LayoutSigninPromo
- GetPreferredSize
- Layout
- OnPaint
- Show
- MaybeShowNow
- GetAnchorRect
- WindowClosing
#include "chrome/browser/ui/views/extensions/extension_installed_bubble_view.h"
#include <algorithm>
#include <string>
#include "base/i18n/rtl.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/api/commands/command_service.h"
#include "chrome/browser/extensions/extension_action.h"
#include "chrome/browser/extensions/extension_action_manager.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/signin_promo.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/singleton_tabs.h"
#include "chrome/browser/ui/sync/sync_promo_ui.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
#include "chrome/browser/ui/views/location_bar/page_action_with_badge_view.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "chrome/browser/ui/views/toolbar/browser_action_view.h"
#include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
#include "chrome/common/extensions/api/omnibox/omnibox_handler.h"
#include "chrome/common/extensions/sync_helper.h"
#include "chrome/common/url_constants.h"
#include "extensions/common/extension.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/ui_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/render_text.h"
#include "ui/gfx/text_elider.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/link.h"
#include "ui/views/controls/link_listener.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/layout/layout_constants.h"
using extensions::Extension;
namespace {
const int kIconSize = 43;
const int kRightColumnWidth = 285;
const int kOuterMarginInset = 10;
const int kHorizOuterMargin = views::kPanelHorizMargin - kOuterMarginInset;
const int kVertOuterMargin = views::kPanelVertMargin - kOuterMarginInset;
const int kVertInnerMargin = views::kPanelVertMargin - 8;
const int kRightcolumnVerticalShift = -4;
}
namespace chrome {
void ShowExtensionInstalledBubble(const Extension* extension,
Browser* browser,
const SkBitmap& icon) {
ExtensionInstalledBubbleView::Show(extension, browser, icon);
}
}
class InstalledBubbleContent : public views::View,
public views::ButtonListener,
public views::LinkListener {
public:
InstalledBubbleContent(Browser* browser,
const Extension* extension,
ExtensionInstalledBubble::BubbleType type,
const SkBitmap* icon,
ExtensionInstalledBubbleView* bubble)
: browser_(browser),
extension_id_(extension->id()),
bubble_(bubble),
type_(type),
flavors_(NONE),
height_of_signin_promo_(0u),
how_to_use_(NULL),
sign_in_link_(NULL),
manage_(NULL),
manage_shortcut_(NULL) {
extensions::Command command;
bool has_keybinding = GetKeybinding(&command);
base::string16 key;
if (extensions::sync_helper::IsSyncableExtension(extension) &&
SyncPromoUI::ShouldShowSyncPromo(browser->profile()))
flavors_ |= SIGN_IN_PROMO;
switch (type_) {
case ExtensionInstalledBubble::BROWSER_ACTION:
case ExtensionInstalledBubble::PAGE_ACTION: {
flavors_ |= HOW_TO_USE;
if (has_keybinding) {
flavors_ |= SHOW_KEYBINDING;
key = command.accelerator().GetShortcutText();
} else {
flavors_ |= HOW_TO_MANAGE;
}
break;
}
case ExtensionInstalledBubble::OMNIBOX_KEYWORD: {
flavors_ |= HOW_TO_USE | HOW_TO_MANAGE;
key = base::UTF8ToUTF16(extensions::OmniboxInfo::GetKeyword(extension));
break;
}
case ExtensionInstalledBubble::GENERIC: {
break;
}
default: {
COMPILE_ASSERT(ExtensionInstalledBubble::GENERIC == 3,
kBubbleTypeEnumHasChangedButNotThisSwitchStatement);
break;
}
}
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
const gfx::FontList& font_list =
rb.GetFontList(ui::ResourceBundle::BaseFont);
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(gfx::ImageSkia::CreateFrom1xBitmap(*icon));
AddChildView(icon_);
base::string16 extension_name = base::UTF8ToUTF16(extension->name());
base::i18n::AdjustStringForLocaleDirection(&extension_name);
heading_ = new views::Label(l10n_util::GetStringFUTF16(
IDS_EXTENSION_INSTALLED_HEADING, extension_name));
heading_->SetFontList(rb.GetFontList(ui::ResourceBundle::MediumFont));
heading_->SetMultiLine(true);
heading_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
AddChildView(heading_);
if (flavors_ & HOW_TO_USE) {
how_to_use_ = new views::Label(GetHowToUseDescription(key));
how_to_use_->SetFontList(font_list);
how_to_use_->SetMultiLine(true);
how_to_use_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
AddChildView(how_to_use_);
}
if (flavors_ & SHOW_KEYBINDING) {
manage_shortcut_ = new views::Link(
l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_MANAGE_SHORTCUTS));
manage_shortcut_->set_listener(this);
AddChildView(manage_shortcut_);
}
if (flavors_ & HOW_TO_MANAGE) {
manage_ = new views::Label(l10n_util::GetStringUTF16(
#if defined(OS_CHROMEOS)
IDS_EXTENSION_INSTALLED_MANAGE_INFO_CHROMEOS));
#else
IDS_EXTENSION_INSTALLED_MANAGE_INFO));
#endif
manage_->SetFontList(font_list);
manage_->SetMultiLine(true);
manage_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
AddChildView(manage_);
}
if (flavors_ & SIGN_IN_PROMO) {
signin_promo_text_ =
l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_SIGNIN_PROMO);
signin_promo_link_text_ =
l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_SIGNIN_PROMO_LINK);
sign_in_link_ = new views::Link(signin_promo_link_text_);
sign_in_link_->SetFontList(font_list);
sign_in_link_->set_listener(this);
AddChildView(sign_in_link_);
}
close_button_ = new views::ImageButton(this);
close_button_->SetImage(views::CustomButton::STATE_NORMAL,
rb.GetImageSkiaNamed(IDR_CLOSE_2));
close_button_->SetImage(views::CustomButton::STATE_HOVERED,
rb.GetImageSkiaNamed(IDR_CLOSE_2_H));
close_button_->SetImage(views::CustomButton::STATE_PRESSED,
rb.GetImageSkiaNamed(IDR_CLOSE_2_P));
AddChildView(close_button_);
}
virtual void ButtonPressed(views::Button* sender,
const ui::Event& event) OVERRIDE {
DCHECK_EQ(sender, close_button_);
GetWidget()->Close();
}
virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE {
GetWidget()->Close();
std::string configure_url;
if (source == manage_shortcut_) {
configure_url = chrome::kChromeUIExtensionsURL;
configure_url += chrome::kExtensionConfigureCommandsSubPage;
} else if (source == sign_in_link_) {
configure_url = signin::GetPromoURL(
signin::SOURCE_EXTENSION_INSTALL_BUBBLE, false).spec();
} else {
NOTREACHED();
return;
}
chrome::NavigateParams params(
chrome::GetSingletonTabNavigateParams(
browser_, GURL(configure_url.c_str())));
chrome::Navigate(¶ms);
}
private:
enum Flavors {
NONE = 0,
HOW_TO_USE = 1 << 0,
HOW_TO_MANAGE = 1 << 1,
SHOW_KEYBINDING = 1 << 2,
SIGN_IN_PROMO = 1 << 3,
};
bool GetKeybinding(extensions::Command* command) {
extensions::CommandService* command_service =
extensions::CommandService::Get(browser_->profile());
if (type_ == ExtensionInstalledBubble::BROWSER_ACTION) {
return command_service->GetBrowserActionCommand(
extension_id_,
extensions::CommandService::ACTIVE_ONLY,
command,
NULL);
} else if (type_ == ExtensionInstalledBubble::PAGE_ACTION) {
return command_service->GetPageActionCommand(
extension_id_,
extensions::CommandService::ACTIVE_ONLY,
command,
NULL);
} else {
return false;
}
}
base::string16 GetHowToUseDescription(const base::string16& key) {
switch (type_) {
case ExtensionInstalledBubble::BROWSER_ACTION:
if (!key.empty()) {
return l10n_util::GetStringFUTF16(
IDS_EXTENSION_INSTALLED_BROWSER_ACTION_INFO_WITH_SHORTCUT, key);
} else {
return l10n_util::GetStringUTF16(
IDS_EXTENSION_INSTALLED_BROWSER_ACTION_INFO);
}
break;
case ExtensionInstalledBubble::PAGE_ACTION:
if (!key.empty()) {
return l10n_util::GetStringFUTF16(
IDS_EXTENSION_INSTALLED_PAGE_ACTION_INFO_WITH_SHORTCUT, key);
} else {
return l10n_util::GetStringUTF16(
IDS_EXTENSION_INSTALLED_PAGE_ACTION_INFO);
}
break;
case ExtensionInstalledBubble::OMNIBOX_KEYWORD:
return l10n_util::GetStringFUTF16(
IDS_EXTENSION_INSTALLED_OMNIBOX_KEYWORD_INFO, key);
break;
default:
NOTREACHED();
break;
}
return base::string16();
}
int LayoutSigninPromo(int offset_x, int offset_y) {
sign_in_promo_lines_.clear();
int height = 0;
gfx::Rect contents_area = GetContentsBounds();
if (contents_area.IsEmpty())
return height;
contents_area.set_width(kRightColumnWidth);
base::string16 full_text = signin_promo_link_text_ + signin_promo_text_;
const gfx::Size link_size = sign_in_link_->GetPreferredSize();
sign_in_link_->SetBounds(
offset_x, offset_y, link_size.width(), link_size.height());
const gfx::FontList font_list;
std::vector<base::string16> lines;
gfx::ElideRectangleText(full_text, font_list, contents_area.width(),
contents_area.height(), gfx::ELIDE_LONG_WORDS,
&lines);
gfx::Point position = gfx::Point(
contents_area.origin().x() + offset_x,
contents_area.origin().y() + offset_y + 1);
if (base::i18n::IsRTL()) {
position -= gfx::Vector2d(
2 * views::kPanelHorizMargin + kHorizOuterMargin, 0);
}
for (std::vector<base::string16>::const_iterator it = lines.begin();
it != lines.end(); ++it) {
gfx::RenderText* line = gfx::RenderText::CreateInstance();
line->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_UI);
line->SetText(*it);
const gfx::Size size(contents_area.width(),
line->GetStringSize().height());
line->SetDisplayRect(gfx::Rect(position, size));
position.set_y(position.y() + size.height());
sign_in_promo_lines_.push_back(line);
height += size.height();
}
sign_in_promo_lines_.front()->ApplyColor(SK_ColorTRANSPARENT,
gfx::Range(0, signin_promo_link_text_.size()));
return height;
}
virtual gfx::Size GetPreferredSize() OVERRIDE {
int width = kHorizOuterMargin;
width += kIconSize;
width += views::kPanelHorizMargin;
width += kRightColumnWidth;
width += 2 * views::kPanelHorizMargin;
width += kHorizOuterMargin;
int height = kVertOuterMargin;
height += heading_->GetHeightForWidth(kRightColumnWidth);
height += kVertInnerMargin;
if (flavors_ & HOW_TO_USE) {
height += how_to_use_->GetHeightForWidth(kRightColumnWidth);
height += kVertInnerMargin;
}
if (flavors_ & HOW_TO_MANAGE) {
height += manage_->GetHeightForWidth(kRightColumnWidth);
height += kVertInnerMargin;
}
if (flavors_ & SIGN_IN_PROMO && height_of_signin_promo_ > 0u) {
height += height_of_signin_promo_;
height += kVertInnerMargin;
}
if (flavors_ & SHOW_KEYBINDING) {
height += manage_shortcut_->GetHeightForWidth(kRightColumnWidth);
height += kVertInnerMargin;
}
return gfx::Size(width, std::max(height, kIconSize + 2 * kVertOuterMargin));
}
virtual void Layout() OVERRIDE {
int x = kHorizOuterMargin;
int y = kVertOuterMargin;
icon_->SetBounds(x, y, kIconSize, kIconSize);
x += kIconSize;
x += views::kPanelHorizMargin;
y += kRightcolumnVerticalShift;
heading_->SizeToFit(kRightColumnWidth);
heading_->SetX(x);
heading_->SetY(y);
y += heading_->height();
y += kVertInnerMargin;
if (flavors_ & HOW_TO_USE) {
how_to_use_->SizeToFit(kRightColumnWidth);
how_to_use_->SetX(x);
how_to_use_->SetY(y);
y += how_to_use_->height();
y += kVertInnerMargin;
}
if (flavors_ & HOW_TO_MANAGE) {
manage_->SizeToFit(kRightColumnWidth);
manage_->SetX(x);
manage_->SetY(y);
y += manage_->height();
y += kVertInnerMargin;
}
if (flavors_ & SIGN_IN_PROMO) {
height_of_signin_promo_ = LayoutSigninPromo(x, y);
y += height_of_signin_promo_;
y += kVertInnerMargin;
}
if (flavors_ & SHOW_KEYBINDING) {
gfx::Size sz = manage_shortcut_->GetPreferredSize();
manage_shortcut_->SetBounds(width() - 2 * kHorizOuterMargin - sz.width(),
y,
sz.width(),
sz.height());
y += manage_shortcut_->height();
y += kVertInnerMargin;
}
gfx::Size sz;
x += kRightColumnWidth + 2 * views::kPanelHorizMargin + kHorizOuterMargin -
close_button_->GetPreferredSize().width();
y = kVertOuterMargin;
sz = close_button_->GetPreferredSize();
close_button_->SetBounds(x - 1, y - 1, sz.width(), sz.height());
}
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
for (ScopedVector<gfx::RenderText>::const_iterator it =
sign_in_promo_lines_.begin();
it != sign_in_promo_lines_.end(); ++it)
(*it)->Draw(canvas);
views::View::OnPaint(canvas);
}
Browser* browser_;
const std::string extension_id_;
ExtensionInstalledBubbleView* bubble_;
base::string16 signin_promo_link_text_;
base::string16 signin_promo_text_;
ScopedVector<gfx::RenderText> sign_in_promo_lines_;
ExtensionInstalledBubble::BubbleType type_;
int flavors_;
size_t height_of_signin_promo_;
views::ImageView* icon_;
views::Label* heading_;
views::Label* how_to_use_;
views::Link* sign_in_link_;
views::Label* manage_;
views::Link* manage_shortcut_;
views::ImageButton* close_button_;
DISALLOW_COPY_AND_ASSIGN(InstalledBubbleContent);
};
void ExtensionInstalledBubbleView::Show(const Extension* extension,
Browser *browser,
const SkBitmap& icon) {
new ExtensionInstalledBubbleView(extension, browser, icon);
}
ExtensionInstalledBubbleView::ExtensionInstalledBubbleView(
const Extension* extension, Browser *browser, const SkBitmap& icon)
: bubble_(this, extension, browser, icon) {
}
ExtensionInstalledBubbleView::~ExtensionInstalledBubbleView() {}
bool ExtensionInstalledBubbleView::MaybeShowNow() {
BrowserView* browser_view =
BrowserView::GetBrowserViewForBrowser(bubble_.browser());
extensions::ExtensionActionManager* extension_action_manager =
extensions::ExtensionActionManager::Get(bubble_.browser()->profile());
views::View* reference_view = NULL;
if (bubble_.type() == bubble_.BROWSER_ACTION) {
BrowserActionsContainer* container =
browser_view->GetToolbarView()->browser_actions();
if (container->animating())
return false;
reference_view = container->GetBrowserActionView(
extension_action_manager->GetBrowserAction(*bubble_.extension()));
if (!reference_view || !reference_view->visible()) {
reference_view = container->chevron();
if (!reference_view || !reference_view->visible())
reference_view = NULL;
}
} else if (bubble_.type() == bubble_.PAGE_ACTION) {
LocationBarView* location_bar_view = browser_view->GetLocationBarView();
ExtensionAction* page_action =
extension_action_manager->GetPageAction(*bubble_.extension());
location_bar_view->SetPreviewEnabledPageAction(page_action,
true);
reference_view = location_bar_view->GetPageActionView(page_action);
DCHECK(reference_view);
} else if (bubble_.type() == bubble_.OMNIBOX_KEYWORD) {
LocationBarView* location_bar_view = browser_view->GetLocationBarView();
reference_view = location_bar_view;
DCHECK(reference_view);
}
if (reference_view == NULL)
reference_view = browser_view->GetToolbarView()->app_menu();
SetAnchorView(reference_view);
set_arrow(bubble_.type() == bubble_.OMNIBOX_KEYWORD ?
views::BubbleBorder::TOP_LEFT :
views::BubbleBorder::TOP_RIGHT);
SetLayoutManager(new views::FillLayout());
AddChildView(new InstalledBubbleContent(
bubble_.browser(), bubble_.extension(), bubble_.type(),
&bubble_.icon(), this));
views::BubbleDelegateView::CreateBubble(this)->Show();
bubble_.IgnoreBrowserClosing();
return true;
}
gfx::Rect ExtensionInstalledBubbleView::GetAnchorRect() {
if (bubble_.type() == bubble_.OMNIBOX_KEYWORD) {
LocationBarView* location_bar_view =
BrowserView::GetBrowserViewForBrowser(bubble_.browser())->
GetLocationBarView();
return gfx::Rect(location_bar_view->GetOmniboxViewOrigin(),
gfx::Size(0, location_bar_view->omnibox_view()->height()));
}
return views::BubbleDelegateView::GetAnchorRect();
}
void ExtensionInstalledBubbleView::WindowClosing() {
if (bubble_.extension() && bubble_.type() == bubble_.PAGE_ACTION) {
BrowserView* browser_view =
BrowserView::GetBrowserViewForBrowser(bubble_.browser());
browser_view->GetLocationBarView()->SetPreviewEnabledPageAction(
extensions::ExtensionActionManager::Get(bubble_.browser()->profile())->
GetPageAction(*bubble_.extension()),
false);
}
}