172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/extensions/extension_installed_bubble.h" 672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include <algorithm> 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/i18n/rtl.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h" 113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h" 1221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h" 134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser.h" 14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser_window.h" 1572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/browser_actions_container.h" 1672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/frame/browser_view.h" 1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/location_bar/location_bar_view.h" 1872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/toolbar_view.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension.h" 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_action.h" 21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_details.h" 22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_source.h" 23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_type.h" 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h" 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h" 2672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h" 2772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h" 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/button/image_button.h" 293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "views/controls/image_view.h" 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/label.h" 3172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "views/layout/layout_constants.h" 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/view.h" 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kIconSize = 43; 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kRightColumnWidth = 285; 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// The Bubble uses a BubbleBorder which adds about 6 pixels of whitespace 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// around the content view. We compensate by reducing our outer borders by this 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// amount + 4px. 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kOuterMarginInset = 10; 44dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenconst int kHorizOuterMargin = views::kPanelHorizMargin - kOuterMarginInset; 45dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenconst int kVertOuterMargin = views::kPanelVertMargin - kOuterMarginInset; 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Interior vertical margin is 8px smaller than standard 48dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenconst int kVertInnerMargin = views::kPanelVertMargin - 8; 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The image we use for the close button has three pixels of whitespace padding. 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kCloseButtonPadding = 3; 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// We want to shift the right column (which contains the header and text) up 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 4px to align with icon. 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kRightcolumnVerticalShift = -4; 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// How long to wait for browser action animations to complete before retrying. 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kAnimationWaitTime = 50; 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// How often we retry when waiting for browser action animation to end. 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kAnimationWaitMaxRetry = 10; 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsennamespace browser { 6672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 6772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ShowExtensionInstalledBubble( 6872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const Extension* extension, 6972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen Browser* browser, 70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const SkBitmap& icon, 7172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen Profile* profile) { 7272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ExtensionInstalledBubble::Show(extension, browser, icon); 7372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 7472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 7572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} // namespace browser 7672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// InstalledBubbleContent is the content view which is placed in the 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// ExtensionInstalledBubble. It displays the install icon and explanatory 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// text about the installed extension. 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass InstalledBubbleContent : public views::View, 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public views::ButtonListener { 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 83513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch InstalledBubbleContent(const Extension* extension, 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ExtensionInstalledBubble::BubbleType type, 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkBitmap* icon) 86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen : bubble_(NULL), 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch type_(type), 884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch info_(NULL) { 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const gfx::Font& font = rb.GetFont(ResourceBundle::BaseFont); 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Scale down to 43x43, but allow smaller icons (don't scale up). 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Size size(icon->width(), icon->height()); 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (size.width() > kIconSize || size.height() > kIconSize) 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size = gfx::Size(kIconSize, kIconSize); 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch icon_ = new views::ImageView(); 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch icon_->SetImageSize(size); 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch icon_->SetImage(*icon); 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddChildView(icon_); 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1013f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen string16 extension_name = UTF8ToUTF16(extension->name()); 10221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen base::i18n::AdjustStringForLocaleDirection(&extension_name); 1033f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen heading_ = new views::Label(UTF16ToWide( 1043f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen l10n_util::GetStringFUTF16(IDS_EXTENSION_INSTALLED_HEADING, 1053f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen extension_name))); 106201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch heading_->SetFont(rb.GetFont(ResourceBundle::MediumFont)); 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch heading_->SetMultiLine(true); 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch heading_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddChildView(heading_); 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (type_ == ExtensionInstalledBubble::PAGE_ACTION) { 1123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen info_ = new views::Label(UTF16ToWide(l10n_util::GetStringUTF16( 1133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen IDS_EXTENSION_INSTALLED_PAGE_ACTION_INFO))); 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch info_->SetFont(font); 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch info_->SetMultiLine(true); 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch info_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddChildView(info_); 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (type_ == ExtensionInstalledBubble::OMNIBOX_KEYWORD) { 1213f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen info_ = new views::Label(UTF16ToWide(l10n_util::GetStringFUTF16( 1224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch IDS_EXTENSION_INSTALLED_OMNIBOX_KEYWORD_INFO, 1233f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen UTF8ToUTF16(extension->omnibox_keyword())))); 1244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch info_->SetFont(font); 1254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch info_->SetMultiLine(true); 1264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch info_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); 1274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch AddChildView(info_); 1284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 1294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1303f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen manage_ = new views::Label(UTF16ToWide( 1313f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_MANAGE_INFO))); 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manage_->SetFont(font); 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manage_->SetMultiLine(true); 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manage_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddChildView(manage_); 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch close_button_ = new views::ImageButton(this); 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch close_button_->SetImage(views::CustomButton::BS_NORMAL, 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch rb.GetBitmapNamed(IDR_CLOSE_BAR)); 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch close_button_->SetImage(views::CustomButton::BS_HOT, 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch rb.GetBitmapNamed(IDR_CLOSE_BAR_H)); 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch close_button_->SetImage(views::CustomButton::BS_PUSHED, 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch rb.GetBitmapNamed(IDR_CLOSE_BAR_P)); 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddChildView(close_button_); 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen void set_bubble(Bubble* bubble) { bubble_ = bubble; } 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void ButtonPressed( 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Button* sender, 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const views::Event& event) { 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (sender == close_button_) { 153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bubble_->set_fade_away_on_close(true); 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetWidget()->Close(); 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Unknown view"; 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual gfx::Size GetPreferredSize() { 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int width = kHorizOuterMargin; 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch width += kIconSize; 164dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen width += views::kPanelHorizMargin; 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch width += kRightColumnWidth; 166dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen width += 2 * views::kPanelHorizMargin; 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch width += kHorizOuterMargin; 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int height = kVertOuterMargin; 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch height += heading_->GetHeightForWidth(kRightColumnWidth); 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch height += kVertInnerMargin; 1724a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (type_ == ExtensionInstalledBubble::PAGE_ACTION || 1734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch type_ == ExtensionInstalledBubble::OMNIBOX_KEYWORD) { 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch height += info_->GetHeightForWidth(kRightColumnWidth); 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch height += kVertInnerMargin; 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch height += manage_->GetHeightForWidth(kRightColumnWidth); 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch height += kVertOuterMargin; 1794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return gfx::Size(width, std::max(height, kIconSize + 2 * kVertOuterMargin)); 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void Layout() { 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int x = kHorizOuterMargin; 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int y = kVertOuterMargin; 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch icon_->SetBounds(x, y, kIconSize, kIconSize); 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch x += kIconSize; 189dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen x += views::kPanelHorizMargin; 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch y += kRightcolumnVerticalShift; 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch heading_->SizeToFit(kRightColumnWidth); 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch heading_->SetX(x); 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch heading_->SetY(y); 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch y += heading_->height(); 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch y += kVertInnerMargin; 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (type_ == ExtensionInstalledBubble::PAGE_ACTION || 1994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch type_ == ExtensionInstalledBubble::OMNIBOX_KEYWORD) { 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch info_->SizeToFit(kRightColumnWidth); 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch info_->SetX(x); 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch info_->SetY(y); 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch y += info_->height(); 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch y += kVertInnerMargin; 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manage_->SizeToFit(kRightColumnWidth); 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manage_->SetX(x); 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manage_->SetY(y); 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch y += manage_->height(); 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch y += kVertInnerMargin; 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Size sz; 214dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen x += kRightColumnWidth + 2 * views::kPanelHorizMargin + kHorizOuterMargin - 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch close_button_->GetPreferredSize().width(); 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch y = kVertOuterMargin; 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sz = close_button_->GetPreferredSize(); 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // x-1 & y-1 is just slop to get the close button visually aligned with the 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // title text and bubble arrow. 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch close_button_->SetBounds(x - 1, y - 1, sz.width(), sz.height()); 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // The Bubble showing us. 224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Bubble* bubble_; 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ExtensionInstalledBubble::BubbleType type_; 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::ImageView* icon_; 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Label* heading_; 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Label* info_; 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Label* manage_; 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::ImageButton* close_button_; 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DISALLOW_COPY_AND_ASSIGN(InstalledBubbleContent); 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 236513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid ExtensionInstalledBubble::Show(const Extension* extension, 237513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch Browser *browser, 238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const SkBitmap& icon) { 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new ExtensionInstalledBubble(extension, browser, icon); 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 242513209b27ff55e2841eac0e4120199c23acce758Ben MurdochExtensionInstalledBubble::ExtensionInstalledBubble(const Extension* extension, 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Browser *browser, 244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const SkBitmap& icon) 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : extension_(extension), 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch browser_(browser), 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch icon_(icon), 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_wait_retries_(0) { 249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen AddRef(); // Balanced in BubbleClosing. 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2514a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (!extension_->omnibox_keyword().empty()) { 2524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch type_ = OMNIBOX_KEYWORD; 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (extension_->browser_action()) { 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch type_ = BROWSER_ACTION; 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (extension->page_action() && 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch !extension->page_action()->default_icon_path().empty()) { 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch type_ = PAGE_ACTION; 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch type_ = GENERIC; 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |extension| has been initialized but not loaded at this point. We need 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to wait on showing the Bubble until not only the EXTENSION_LOADED gets 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // fired, but all of the EXTENSION_LOADED Observers have run. Only then can we 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // be sure that a BrowserAction or PageAction has had views created which we 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // can inspect for the purpose of previewing of pointing to them. 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch registrar_.Add(this, NotificationType::EXTENSION_LOADED, 268513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch Source<Profile>(browser->profile())); 269513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, 270513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch Source<Profile>(browser->profile())); 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 273dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenExtensionInstalledBubble::~ExtensionInstalledBubble() {} 274dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionInstalledBubble::Observe(NotificationType type, 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationSource& source, 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationDetails& details) { 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (type == NotificationType::EXTENSION_LOADED) { 279513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const Extension* extension = Details<const Extension>(details).ptr(); 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (extension == extension_) { 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_wait_retries_ = 0; 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // PostTask to ourself to allow all EXTENSION_LOADED Observers to run. 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoopForUI::current()->PostTask(FROM_HERE, NewRunnableMethod(this, 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &ExtensionInstalledBubble::ShowInternal)); 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 286513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } else if (type == NotificationType::EXTENSION_UNLOADED) { 28721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const Extension* extension = 28821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen Details<UnloadedExtensionInfo>(details)->extension; 289513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (extension == extension_) 290513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch extension_ = NULL; 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << L"Received unexpected notification"; 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionInstalledBubble::ShowInternal() { 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BrowserView* browser_view = BrowserView::GetBrowserViewForNativeWindow( 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch browser_->window()->GetNativeHandle()); 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const views::View* reference_view = NULL; 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (type_ == BROWSER_ACTION) { 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BrowserActionsContainer* container = 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch browser_view->GetToolbarView()->browser_actions(); 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (container->animating() && 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_wait_retries_++ < kAnimationWaitMaxRetry) { 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We don't know where the view will be until the container has stopped 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // animating, so check back in a little while. 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoopForUI::current()->PostDelayedTask( 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FROM_HERE, NewRunnableMethod(this, 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &ExtensionInstalledBubble::ShowInternal), kAnimationWaitTime); 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch reference_view = container->GetBrowserActionView( 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_->browser_action()); 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the view is not visible then it is in the chevron, so point the 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // install bubble to the chevron instead. If this is an incognito window, 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // both could be invisible. 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!reference_view || !reference_view->IsVisible()) { 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch reference_view = container->chevron(); 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!reference_view || !reference_view->IsVisible()) 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch reference_view = NULL; // fall back to app menu below. 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (type_ == PAGE_ACTION) { 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LocationBarView* location_bar_view = browser_view->GetLocationBarView(); 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch location_bar_view->SetPreviewEnabledPageAction(extension_->page_action(), 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch true); // preview_enabled 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch reference_view = location_bar_view->GetPageActionView( 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_->page_action()); 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(reference_view); 3304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else if (type_ == OMNIBOX_KEYWORD) { 3314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch LocationBarView* location_bar_view = browser_view->GetLocationBarView(); 3324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch reference_view = location_bar_view; 3334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(reference_view); 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Default case. 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (reference_view == NULL) 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch reference_view = browser_view->GetToolbarView()->app_menu(); 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point origin; 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View::ConvertPointToScreen(reference_view, &origin); 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect bounds = reference_view->bounds(); 3434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch bounds.set_origin(origin); 3444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch BubbleBorder::ArrowLocation arrow_location = BubbleBorder::TOP_RIGHT; 3454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 3464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // For omnibox keyword bubbles, move the arrow to point to the left edge 3474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // of the omnibox, just to the right of the icon. 3484a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (type_ == OMNIBOX_KEYWORD) { 3494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch bounds.set_origin( 3504a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch browser_view->GetLocationBarView()->GetLocationEntryOrigin()); 3514a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch bounds.set_width(0); 3524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch arrow_location = BubbleBorder::TOP_LEFT; 3534a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch bubble_content_ = new InstalledBubbleContent(extension_, type_, &icon_); 356ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Bubble* bubble = Bubble::Show(browser_view->GetWidget(), bounds, 357ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen arrow_location, bubble_content_, this); 358ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bubble_content_->set_bubble(bubble); 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 361ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// BubbleDelegate 362ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ExtensionInstalledBubble::BubbleClosing(Bubble* bubble, 363ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool closed_by_escape) { 3644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (extension_ && type_ == PAGE_ACTION) { 3654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch BrowserView* browser_view = BrowserView::GetBrowserViewForNativeWindow( 3664a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch browser_->window()->GetNativeHandle()); 3674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch browser_view->GetLocationBarView()->SetPreviewEnabledPageAction( 3684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch extension_->page_action(), 3694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch false); // preview_enabled 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Release(); // Balanced in ctor. 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 374dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 375dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool ExtensionInstalledBubble::CloseOnEscape() { 376dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return true; 377dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 378dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 379dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool ExtensionInstalledBubble::FadeInOnShow() { 380dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return true; 381dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 382