Index: chrome/browser/ui/views/notifications/balloon_view_views.cc |
diff --git a/chrome/browser/ui/views/notifications/balloon_view_views.cc b/chrome/browser/ui/views/notifications/balloon_view_views.cc |
deleted file mode 100644 |
index 551a68198d93edafc8a9d24f196013b82c9a70e8..0000000000000000000000000000000000000000 |
--- a/chrome/browser/ui/views/notifications/balloon_view_views.cc |
+++ /dev/null |
@@ -1,531 +0,0 @@ |
-// Copyright (c) 2012 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/ui/views/notifications/balloon_view_views.h" |
- |
-#include <algorithm> |
-#include <vector> |
- |
-#include "base/bind.h" |
-#include "base/message_loop/message_loop.h" |
-#include "base/strings/utf_string_conversions.h" |
-#include "chrome/browser/chrome_notification_types.h" |
-#include "chrome/browser/notifications/balloon_collection.h" |
-#include "chrome/browser/notifications/desktop_notification_service.h" |
-#include "chrome/browser/notifications/notification.h" |
-#include "chrome/browser/notifications/notification_options_menu_model.h" |
-#include "chrome/browser/ui/views/notifications/balloon_view_host.h" |
-#include "content/public/browser/notification_details.h" |
-#include "content/public/browser/notification_source.h" |
-#include "content/public/browser/notification_types.h" |
-#include "content/public/browser/render_view_host.h" |
-#include "content/public/browser/render_widget_host_view.h" |
-#include "content/public/browser/web_contents.h" |
-#include "grit/generated_resources.h" |
-#include "grit/theme_resources.h" |
-#include "ui/base/l10n/l10n_util.h" |
-#include "ui/base/resource/resource_bundle.h" |
-#include "ui/gfx/animation/slide_animation.h" |
-#include "ui/gfx/canvas.h" |
-#include "ui/gfx/native_widget_types.h" |
-#include "ui/gfx/path.h" |
-#include "ui/views/bubble/bubble_border.h" |
-#include "ui/views/controls/button/image_button.h" |
-#include "ui/views/controls/button/menu_button.h" |
-#include "ui/views/controls/button/text_button.h" |
-#include "ui/views/controls/label.h" |
-#include "ui/views/controls/menu/menu_item_view.h" |
-#include "ui/views/controls/menu/menu_runner.h" |
-#include "ui/views/controls/native/native_view_host.h" |
-#include "ui/views/widget/widget.h" |
- |
-namespace { |
- |
-const int kTopMargin = 2; |
-const int kBottomMargin = 0; |
-const int kLeftMargin = 4; |
-const int kRightMargin = 4; |
- |
-// Margin between various shelf buttons/label and the shelf border. |
-const int kShelfMargin = 2; |
- |
-// Spacing between the options and close buttons. |
-const int kOptionsDismissSpacing = 4; |
- |
-// Spacing between the options button and label text. |
-const int kLabelOptionsSpacing = 4; |
- |
-// Margin between shelf border and title label. |
-const int kLabelLeftMargin = 6; |
- |
-// Size of the drop shadow. The shadow is provided by BubbleBorder, |
-// not this class. |
-const int kLeftShadowWidth = 0; |
-const int kRightShadowWidth = 0; |
-const int kTopShadowWidth = 0; |
-const int kBottomShadowWidth = 6; |
- |
-// Optional animation. |
-const bool kAnimateEnabled = true; |
- |
-// Colors |
-const SkColor kControlBarBackgroundColor = SkColorSetRGB(245, 245, 245); |
-const SkColor kControlBarTextColor = SkColorSetRGB(125, 125, 125); |
-const SkColor kControlBarSeparatorLineColor = SkColorSetRGB(180, 180, 180); |
- |
-} // namespace |
- |
-// static |
-int BalloonView::GetHorizontalMargin() { |
- return kLeftMargin + kRightMargin + kLeftShadowWidth + kRightShadowWidth; |
-} |
- |
-BalloonViewImpl::BalloonViewImpl(BalloonCollection* collection) |
- : balloon_(NULL), |
- collection_(collection), |
- frame_container_(NULL), |
- html_container_(NULL), |
- close_button_(NULL), |
- options_menu_button_(NULL), |
- enable_web_ui_(false), |
- closed_by_user_(false), |
- closed_(false) { |
- // We're owned by Balloon and don't want to be deleted by our parent View. |
- set_owned_by_client(); |
- |
- SetBorder(scoped_ptr<views::Border>( |
- new views::BubbleBorder(views::BubbleBorder::FLOAT, |
- views::BubbleBorder::NO_SHADOW, |
- SK_ColorWHITE))); |
-} |
- |
-BalloonViewImpl::~BalloonViewImpl() { |
-} |
- |
-void BalloonViewImpl::Close(bool by_user) { |
- if (closed_) |
- return; |
- |
- closed_ = true; |
- animation_->Stop(); |
- html_contents_->Shutdown(); |
- // Detach contents from the widget before they close. |
- // This is necessary because a widget may be deleted |
- // after this when chrome is shutting down. |
- html_container_->GetRootView()->RemoveAllChildViews(true); |
- html_container_->Close(); |
- frame_container_->GetRootView()->RemoveAllChildViews(true); |
- frame_container_->Close(); |
- closed_by_user_ = by_user; |
- // |frame_container_->::Close()| is async. When processed it'll call back to |
- // DeleteDelegate() and we'll cleanup. |
-} |
- |
-gfx::Size BalloonViewImpl::GetSize() const { |
- // BalloonView has no size if it hasn't been shown yet (which is when |
- // balloon_ is set). |
- if (!balloon_) |
- return gfx::Size(0, 0); |
- |
- return gfx::Size(GetTotalWidth(), GetTotalHeight()); |
-} |
- |
-BalloonHost* BalloonViewImpl::GetHost() const { |
- return html_contents_.get(); |
-} |
- |
-void BalloonViewImpl::OnMenuButtonClicked(views::View* source, |
- const gfx::Point& point) { |
- CreateOptionsMenu(); |
- |
- menu_runner_.reset(new views::MenuRunner(options_menu_model_.get())); |
- |
- gfx::Point screen_location; |
- views::View::ConvertPointToScreen(options_menu_button_, &screen_location); |
- if (menu_runner_->RunMenuAt( |
- source->GetWidget()->GetTopLevelWidget(), |
- options_menu_button_, |
- gfx::Rect(screen_location, options_menu_button_->size()), |
- views::MenuItemView::TOPRIGHT, |
- ui::MENU_SOURCE_NONE, |
- views::MenuRunner::HAS_MNEMONICS) == views::MenuRunner::MENU_DELETED) |
- return; |
-} |
- |
-void BalloonViewImpl::OnDisplayChanged() { |
- collection_->DisplayChanged(); |
-} |
- |
-void BalloonViewImpl::OnWorkAreaChanged() { |
- collection_->DisplayChanged(); |
-} |
- |
-void BalloonViewImpl::DeleteDelegate() { |
- balloon_->OnClose(closed_by_user_); |
-} |
- |
-void BalloonViewImpl::ButtonPressed(views::Button* sender, const ui::Event&) { |
- // The only button currently is the close button. |
- DCHECK_EQ(close_button_, sender); |
- Close(true); |
-} |
- |
-gfx::Size BalloonViewImpl::GetPreferredSize() { |
- return gfx::Size(1000, 1000); |
-} |
- |
-void BalloonViewImpl::SizeContentsWindow() { |
- if (!html_container_ || !frame_container_) |
- return; |
- |
- gfx::Rect contents_rect = GetContentsRectangle(); |
- html_container_->SetBounds(contents_rect); |
- html_container_->StackAboveWidget(frame_container_); |
- |
- gfx::Path path; |
- GetContentsMask(contents_rect, &path); |
- html_container_->SetShape(path.CreateNativeRegion()); |
- |
- close_button_->SetBoundsRect(GetCloseButtonBounds()); |
- options_menu_button_->SetBoundsRect(GetOptionsButtonBounds()); |
- source_label_->SetBoundsRect(GetLabelBounds()); |
-} |
- |
-void BalloonViewImpl::RepositionToBalloon() { |
- if (closed_) |
- return; |
- |
- DCHECK(frame_container_); |
- DCHECK(html_container_); |
- DCHECK(balloon_); |
- |
- if (!kAnimateEnabled) { |
- frame_container_->SetBounds(GetBoundsForFrameContainer()); |
- gfx::Rect contents_rect = GetContentsRectangle(); |
- html_container_->SetBounds(contents_rect); |
- html_contents_->SetPreferredSize(contents_rect.size()); |
- content::RenderWidgetHostView* view = |
- html_contents_->web_contents()->GetRenderWidgetHostView(); |
- if (view) |
- view->SetSize(contents_rect.size()); |
- return; |
- } |
- |
- anim_frame_end_ = GetBoundsForFrameContainer(); |
- anim_frame_start_ = frame_container_->GetClientAreaBoundsInScreen(); |
- animation_.reset(new gfx::SlideAnimation(this)); |
- animation_->Show(); |
-} |
- |
-void BalloonViewImpl::Update() { |
- if (closed_) |
- return; |
- |
- // Tls might get called before html_contents_ is set in Show() if more than |
- // one update with the same replace_id occurs, or if an update occurs after |
- // the ballon has been closed (e.g. during shutdown) but before this has been |
- // destroyed. |
- if (!html_contents_.get() || !html_contents_->web_contents()) |
- return; |
- html_contents_->web_contents()->GetController().LoadURL( |
- balloon_->notification().content_url(), content::Referrer(), |
- content::PAGE_TRANSITION_LINK, std::string()); |
-} |
- |
-void BalloonViewImpl::AnimationProgressed(const gfx::Animation* animation) { |
- DCHECK_EQ(animation_.get(), animation); |
- |
- // Linear interpolation from start to end position. |
- gfx::Rect frame_position(animation_->CurrentValueBetween( |
- anim_frame_start_, anim_frame_end_)); |
- frame_container_->SetBounds(frame_position); |
- |
- gfx::Path path; |
- gfx::Rect contents_rect = GetContentsRectangle(); |
- html_container_->SetBounds(contents_rect); |
- GetContentsMask(contents_rect, &path); |
- html_container_->SetShape(path.CreateNativeRegion()); |
- |
- html_contents_->SetPreferredSize(contents_rect.size()); |
- content::RenderWidgetHostView* view = |
- html_contents_->web_contents()->GetRenderWidgetHostView(); |
- if (view) |
- view->SetSize(contents_rect.size()); |
-} |
- |
-gfx::Rect BalloonViewImpl::GetCloseButtonBounds() const { |
- gfx::Rect bounds(GetContentsBounds()); |
- bounds.set_height(GetShelfHeight()); |
- const gfx::Size& pref_size(close_button_->GetPreferredSize()); |
- bounds.Inset(bounds.width() - kShelfMargin - pref_size.width(), 0, |
- kShelfMargin, 0); |
- bounds.ClampToCenteredSize(pref_size); |
- return bounds; |
-} |
- |
-gfx::Rect BalloonViewImpl::GetOptionsButtonBounds() const { |
- gfx::Rect bounds(GetContentsBounds()); |
- bounds.set_height(GetShelfHeight()); |
- const gfx::Size& pref_size(options_menu_button_->GetPreferredSize()); |
- bounds.set_x(GetCloseButtonBounds().x() - kOptionsDismissSpacing - |
- pref_size.width()); |
- bounds.set_width(pref_size.width()); |
- bounds.ClampToCenteredSize(pref_size); |
- return bounds; |
-} |
- |
-gfx::Rect BalloonViewImpl::GetLabelBounds() const { |
- gfx::Rect bounds(GetContentsBounds()); |
- bounds.set_height(GetShelfHeight()); |
- gfx::Size pref_size(source_label_->GetPreferredSize()); |
- bounds.Inset(kLabelLeftMargin, 0, bounds.width() - |
- GetOptionsButtonBounds().x() + kLabelOptionsSpacing, 0); |
- pref_size.set_width(bounds.width()); |
- bounds.ClampToCenteredSize(pref_size); |
- return bounds; |
-} |
- |
-void BalloonViewImpl::Show(Balloon* balloon) { |
- if (closed_) |
- return; |
- |
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
- |
- balloon_ = balloon; |
- |
- const base::string16 source_label_text = l10n_util::GetStringFUTF16( |
- IDS_NOTIFICATION_BALLOON_SOURCE_LABEL, |
- balloon->notification().display_source()); |
- |
- source_label_ = new views::Label(source_label_text); |
- AddChildView(source_label_); |
- options_menu_button_ = |
- new views::MenuButton(NULL, base::string16(), this, false); |
- AddChildView(options_menu_button_); |
- close_button_ = new views::ImageButton(this); |
- close_button_->SetTooltipText(l10n_util::GetStringUTF16( |
- IDS_NOTIFICATION_BALLOON_DISMISS_LABEL)); |
- AddChildView(close_button_); |
- |
- // We have to create two windows: one for the contents and one for the |
- // frame. Why? |
- // * The contents is an html window which cannot be a |
- // layered window (because it may have child windows for instance). |
- // * The frame is a layered window so that we can have nicely rounded |
- // corners using alpha blending (and we may do other alpha blending |
- // effects). |
- // Unfortunately, layered windows cannot have child windows. (Well, they can |
- // but the child windows don't render). |
- // |
- // We carefully keep these two windows in sync to present the illusion of |
- // one window to the user. |
- // |
- // We don't let the OS manage the RTL layout of these widgets, because |
- // this code is already taking care of correctly reversing the layout. |
- html_contents_.reset(new BalloonViewHost(balloon)); |
- html_contents_->SetPreferredSize(gfx::Size(10000, 10000)); |
- if (enable_web_ui_) |
- html_contents_->EnableWebUI(); |
- |
- html_container_ = new views::Widget; |
- views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); |
- html_container_->Init(params); |
- html_container_->SetContentsView(html_contents_->view()); |
- |
- frame_container_ = new views::Widget; |
- params.delegate = this; |
- params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; |
- params.bounds = GetBoundsForFrameContainer(); |
- frame_container_->Init(params); |
- frame_container_->SetContentsView(this); |
- frame_container_->StackAboveWidget(html_container_); |
- |
- // GetContentsRectangle() is calculated relative to |frame_container_|. Make |
- // sure |frame_container_| has bounds before we ask for |
- // GetContentsRectangle(). |
- html_container_->SetBounds(GetContentsRectangle()); |
- |
- // SetAlwaysOnTop should be called after StackAboveWidget because otherwise |
- // the top-most flag will be removed. |
- html_container_->SetAlwaysOnTop(true); |
- frame_container_->SetAlwaysOnTop(true); |
- |
- close_button_->SetImage(views::CustomButton::STATE_NORMAL, |
- rb.GetImageSkiaNamed(IDR_CLOSE_1)); |
- close_button_->SetImage(views::CustomButton::STATE_HOVERED, |
- rb.GetImageSkiaNamed(IDR_CLOSE_1_H)); |
- close_button_->SetImage(views::CustomButton::STATE_PRESSED, |
- rb.GetImageSkiaNamed(IDR_CLOSE_1_P)); |
- close_button_->SetBoundsRect(GetCloseButtonBounds()); |
- close_button_->SetBackground(SK_ColorBLACK, |
- rb.GetImageSkiaNamed(IDR_CLOSE_1), |
- rb.GetImageSkiaNamed(IDR_CLOSE_1_MASK)); |
- |
- options_menu_button_->SetIcon(*rb.GetImageSkiaNamed(IDR_BALLOON_WRENCH)); |
- options_menu_button_->SetHoverIcon( |
- *rb.GetImageSkiaNamed(IDR_BALLOON_WRENCH_H)); |
- options_menu_button_->SetPushedIcon(*rb.GetImageSkiaNamed( |
- IDR_BALLOON_WRENCH_P)); |
- options_menu_button_->set_alignment(views::TextButton::ALIGN_CENTER); |
- options_menu_button_->SetBorder(views::Border::NullBorder()); |
- options_menu_button_->SetBoundsRect(GetOptionsButtonBounds()); |
- |
- source_label_->SetFontList(rb.GetFontList(ui::ResourceBundle::SmallFont)); |
- source_label_->SetBackgroundColor(kControlBarBackgroundColor); |
- source_label_->SetEnabledColor(kControlBarTextColor); |
- source_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
- source_label_->SetBoundsRect(GetLabelBounds()); |
- |
- SizeContentsWindow(); |
- html_container_->Show(); |
- frame_container_->Show(); |
- |
- notification_registrar_.Add( |
- this, chrome::NOTIFICATION_NOTIFY_BALLOON_DISCONNECTED, |
- content::Source<Balloon>(balloon)); |
-} |
- |
-void BalloonViewImpl::CreateOptionsMenu() { |
- if (options_menu_model_.get()) |
- return; |
- options_menu_model_.reset(new NotificationOptionsMenuModel(balloon_)); |
-} |
- |
-void BalloonViewImpl::GetContentsMask(const gfx::Rect& rect, |
- gfx::Path* path) const { |
- // This rounds the corners, and we also cut out a circle for the close |
- // button, since we can't guarantee the ordering of two top-most windows. |
- SkScalar radius = SkIntToScalar(views::BubbleBorder::GetCornerRadius()); |
- SkScalar spline_radius = radius - |
- SkScalarMul(radius, (SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3); |
- SkScalar left = SkIntToScalar(0); |
- SkScalar top = SkIntToScalar(0); |
- SkScalar right = SkIntToScalar(rect.width()); |
- SkScalar bottom = SkIntToScalar(rect.height()); |
- |
- path->moveTo(left, top); |
- path->lineTo(right, top); |
- path->lineTo(right, bottom - radius); |
- path->cubicTo(right, bottom - spline_radius, |
- right - spline_radius, bottom, |
- right - radius, bottom); |
- path->lineTo(left + radius, bottom); |
- path->cubicTo(left + spline_radius, bottom, |
- left, bottom - spline_radius, |
- left, bottom - radius); |
- path->lineTo(left, top); |
- path->close(); |
-} |
- |
-void BalloonViewImpl::GetFrameMask(const gfx::Rect& rect, |
- gfx::Path* path) const { |
- SkScalar radius = SkIntToScalar(views::BubbleBorder::GetCornerRadius()); |
- SkScalar spline_radius = radius - |
- SkScalarMul(radius, (SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3); |
- SkScalar left = SkIntToScalar(rect.x()); |
- SkScalar top = SkIntToScalar(rect.y()); |
- SkScalar right = SkIntToScalar(rect.right()); |
- SkScalar bottom = SkIntToScalar(rect.bottom()); |
- |
- path->moveTo(left, bottom); |
- path->lineTo(left, top + radius); |
- path->cubicTo(left, top + spline_radius, |
- left + spline_radius, top, |
- left + radius, top); |
- path->lineTo(right - radius, top); |
- path->cubicTo(right - spline_radius, top, |
- right, top + spline_radius, |
- right, top + radius); |
- path->lineTo(right, bottom); |
- path->lineTo(left, bottom); |
- path->close(); |
-} |
- |
-gfx::Point BalloonViewImpl::GetContentsOffset() const { |
- return gfx::Point(kLeftShadowWidth + kLeftMargin, |
- kTopShadowWidth + kTopMargin); |
-} |
- |
-gfx::Rect BalloonViewImpl::GetBoundsForFrameContainer() const { |
- return gfx::Rect(balloon_->GetPosition().x(), balloon_->GetPosition().y(), |
- GetTotalWidth(), GetTotalHeight()); |
-} |
- |
-int BalloonViewImpl::GetShelfHeight() const { |
- // TODO(johnnyg): add scaling here. |
- int max_button_height = std::max(std::max( |
- close_button_->GetPreferredSize().height(), |
- options_menu_button_->GetPreferredSize().height()), |
- source_label_->GetPreferredSize().height()); |
- return max_button_height + kShelfMargin * 2; |
-} |
- |
-int BalloonViewImpl::GetBalloonFrameHeight() const { |
- return GetTotalHeight() - GetShelfHeight(); |
-} |
- |
-int BalloonViewImpl::GetTotalWidth() const { |
- return balloon_->content_size().width() + |
- kLeftMargin + kRightMargin + kLeftShadowWidth + kRightShadowWidth; |
-} |
- |
-int BalloonViewImpl::GetTotalHeight() const { |
- return balloon_->content_size().height() + |
- kTopMargin + kBottomMargin + kTopShadowWidth + kBottomShadowWidth + |
- GetShelfHeight(); |
-} |
- |
-gfx::Rect BalloonViewImpl::GetContentsRectangle() const { |
- if (!frame_container_) |
- return gfx::Rect(); |
- |
- gfx::Size content_size = balloon_->content_size(); |
- gfx::Point offset = GetContentsOffset(); |
- gfx::Rect frame_rect = frame_container_->GetWindowBoundsInScreen(); |
- return gfx::Rect(frame_rect.x() + offset.x(), |
- frame_rect.y() + GetShelfHeight() + offset.y(), |
- content_size.width(), |
- content_size.height()); |
-} |
- |
-void BalloonViewImpl::OnPaint(gfx::Canvas* canvas) { |
- DCHECK(canvas); |
- // Paint the menu bar area white, with proper rounded corners. |
- gfx::Path path; |
- gfx::Rect rect = GetContentsBounds(); |
- rect.set_height(GetShelfHeight()); |
- GetFrameMask(rect, &path); |
- |
- SkPaint paint; |
- paint.setAntiAlias(true); |
- paint.setColor(kControlBarBackgroundColor); |
- canvas->DrawPath(path, paint); |
- |
- // Draw a 1-pixel gray line between the content and the menu bar. |
- int line_width = GetTotalWidth() - kLeftMargin - kRightMargin; |
- canvas->FillRect(gfx::Rect(kLeftMargin, rect.bottom(), line_width, 1), |
- kControlBarSeparatorLineColor); |
- View::OnPaint(canvas); |
- OnPaintBorder(canvas); |
-} |
- |
-void BalloonViewImpl::OnBoundsChanged(const gfx::Rect& previous_bounds) { |
- SizeContentsWindow(); |
-} |
- |
-void BalloonViewImpl::Observe(int type, |
- const content::NotificationSource& source, |
- const content::NotificationDetails& details) { |
- if (type != chrome::NOTIFICATION_NOTIFY_BALLOON_DISCONNECTED) { |
- NOTREACHED(); |
- return; |
- } |
- |
- // If the renderer process attached to this balloon is disconnected |
- // (e.g., because of a crash), we want to close the balloon. |
- notification_registrar_.Remove( |
- this, chrome::NOTIFICATION_NOTIFY_BALLOON_DISCONNECTED, |
- content::Source<Balloon>(balloon_)); |
- Close(false); |
-} |