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