diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-21 22:27:24 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-21 22:27:24 +0000 |
commit | 616ed5a653d4bc13b4633d7c7b85d2f0c73bfd72 (patch) | |
tree | 04b8cd92d18cd6e1ff54e46c6c32b0d70391a831 /chrome/browser/views/infobars | |
parent | c7eeed7fa25e06ec3d0367a74d2b43671958c5d3 (diff) | |
download | chromium_src-616ed5a653d4bc13b4633d7c7b85d2f0c73bfd72.zip chromium_src-616ed5a653d4bc13b4633d7c7b85d2f0c73bfd72.tar.gz chromium_src-616ed5a653d4bc13b4633d7c7b85d2f0c73bfd72.tar.bz2 |
Beginnings of a new InfoBar system.
This implements AlertInfoBar and InfoBarContainer. It also makes the crashed plugin/js oom infobars use this new system.
Design Doc: http://dev.chromium.org/developers/design-documents/info-barshttp://crbug.com/4620
Review URL: http://codereview.chromium.org/11318
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@5856 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/views/infobars')
-rw-r--r-- | chrome/browser/views/infobars/infobar_container.cc | 131 | ||||
-rw-r--r-- | chrome/browser/views/infobars/infobar_container.h | 73 | ||||
-rw-r--r-- | chrome/browser/views/infobars/infobars.cc | 291 | ||||
-rw-r--r-- | chrome/browser/views/infobars/infobars.h | 138 |
4 files changed, 633 insertions, 0 deletions
diff --git a/chrome/browser/views/infobars/infobar_container.cc b/chrome/browser/views/infobars/infobar_container.cc new file mode 100644 index 0000000..2fe7a35 --- /dev/null +++ b/chrome/browser/views/infobars/infobar_container.cc @@ -0,0 +1,131 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/views/infobars/infobar_container.h" + +#include "chrome/browser/infobar_delegate.h" +#include "chrome/browser/tab_contents.h" +#include "chrome/browser/views/frame/browser_view.h" +#include "chrome/browser/views/infobars/infobars.h" +#include "chrome/common/notification_types.h" + +// InfoBarContainer, public: --------------------------------------------------- + +InfoBarContainer::InfoBarContainer(BrowserView* browser_view) + : browser_view_(browser_view), + tab_contents_(NULL) { + +} + +InfoBarContainer::~InfoBarContainer() { + ChangeTabContents(NULL); +} + +void InfoBarContainer::ChangeTabContents(TabContents* contents) { + if (tab_contents_) { + NotificationService::current()->RemoveObserver( + this, NOTIFY_TAB_CONTENTS_INFOBAR_ADDED, + Source<TabContents>(tab_contents_)); + NotificationService::current()->RemoveObserver( + this, NOTIFY_TAB_CONTENTS_INFOBAR_REMOVED, + Source<TabContents>(tab_contents_)); + } + tab_contents_ = contents; + if (tab_contents_) { + UpdateInfoBars(); + NotificationService::current()->AddObserver( + this, NOTIFY_TAB_CONTENTS_INFOBAR_ADDED, + Source<TabContents>(tab_contents_)); + NotificationService::current()->AddObserver( + this, NOTIFY_TAB_CONTENTS_INFOBAR_REMOVED, + Source<TabContents>(tab_contents_)); + } +} + +void InfoBarContainer::InfoBarAnimated(bool completed) { + browser_view_->SelectedTabToolbarSizeChanged(!completed); +} + +void InfoBarContainer::RemoveDelegate(InfoBarDelegate* delegate) { + tab_contents_->RemoveInfoBar(delegate); +} + +// InfoBarContainer, views::View overrides: ------------------------------------ + +gfx::Size InfoBarContainer::GetPreferredSize() { + // We do not have a preferred width (we will expand to fit the available width + // of the BrowserView). Our preferred height is the sum of the preferred + // heights of the InfoBars contained within us. + int height = 0; + for (int i = 0; i < GetChildViewCount(); ++i) + height += GetChildViewAt(i)->GetPreferredSize().height(); + return gfx::Size(0, height); +} + +void InfoBarContainer::Layout() { + int top = 0; + for (int i = 0; i < GetChildViewCount(); ++i) { + views::View* child = GetChildViewAt(i); + gfx::Size ps = child->GetPreferredSize(); + child->SetBounds(0, top, width(), ps.height()); + top += ps.height(); + } +} + +void InfoBarContainer::ViewHierarchyChanged(bool is_add, + views::View* parent, + views::View* child) { + if (parent == this && child->GetParent() == this) { + // An InfoBar child was added or removed. Tell the BrowserView it needs to + // re-layout since our preferred size will have changed. + browser_view_->SelectedTabToolbarSizeChanged(false); + } +} + +// InfoBarContainer, NotificationObserver implementation: ---------------------- + +void InfoBarContainer::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (type == NOTIFY_TAB_CONTENTS_INFOBAR_ADDED) { + AddInfoBar(Details<InfoBarDelegate>(details).ptr()); + } else if (type == NOTIFY_TAB_CONTENTS_INFOBAR_REMOVED) { + RemoveInfoBar(Details<InfoBarDelegate>(details).ptr()); + } else { + NOTREACHED(); + } +} + +// InfoBarContainer, private: -------------------------------------------------- + +void InfoBarContainer::UpdateInfoBars() { + // Clear out all the old child views. + RemoveAllChildViews(true); + + for (size_t i = 0; i < tab_contents_->infobar_delegate_count(); ++i) { + InfoBarDelegate* delegate = tab_contents_->GetInfoBarDelegateAt(i); + InfoBar* infobar = delegate->CreateInfoBar(); + infobar->set_container(this); + AddChildView(infobar); + infobar->Open(); + } +} + +void InfoBarContainer::AddInfoBar(InfoBarDelegate* delegate) { + InfoBar* infobar = delegate->CreateInfoBar(); + infobar->set_container(this); + infobar->AnimateOpen(); + AddChildView(infobar); +} + +void InfoBarContainer::RemoveInfoBar(InfoBarDelegate* delegate) { + size_t index = 0; + for (; index < tab_contents_->infobar_delegate_count(); ++index) { + if (tab_contents_->GetInfoBarDelegateAt(index) == delegate) + break; + } + + // The View will be removed once the Close animation completes. + static_cast<InfoBar*>(GetChildViewAt(index))->AnimateClose(); +} diff --git a/chrome/browser/views/infobars/infobar_container.h b/chrome/browser/views/infobars/infobar_container.h new file mode 100644 index 0000000..43c5280 --- /dev/null +++ b/chrome/browser/views/infobars/infobar_container.h @@ -0,0 +1,73 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_VIEWS_INFOBARS_INFOBAR_CONTAINER_H_ +#define CHROME_BROWSER_VIEWS_INFOBARS_INFOBAR_CONTAINER_H_ + +#include "chrome/common/notification_service.h" +#include "chrome/views/view.h" + +class BrowserView; +class InfoBarDelegate; +class TabContents; + +// A views::View subclass that contains a collection of InfoBars associated with +// a TabContents. +class InfoBarContainer : public views::View, + public NotificationObserver { + public: + explicit InfoBarContainer(BrowserView* browser_view); + virtual ~InfoBarContainer(); + + // Changes the TabContents for which this container is showing InfoBars. Can + // be NULL. + void ChangeTabContents(TabContents* contents); + + // Called by child InfoBars as they animate. If |completed| is true, the + // animation has finished running. + void InfoBarAnimated(bool completed); + + // Remove the specified InfoBarDelegate from the selected TabContents. This + // will notify us back and cause us to close the View. This is called from + // the InfoBar's close button handler. + void RemoveDelegate(InfoBarDelegate* delegate); + + // Overridden from views::View: + virtual gfx::Size GetPreferredSize(); + virtual void Layout(); + protected: + virtual void ViewHierarchyChanged(bool is_add, + views::View* parent, + views::View* child); + + private: + // Overridden from NotificationObserver: + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + // Constructs the InfoBars needed to reflect the state of the current + // TabContents associated with this container. No animations are run during + // this process. + void UpdateInfoBars(); + + // Adds an InfoBar for the specified delegate, in response to a notification + // from the selected TabContents. The InfoBar's appearance will be animated. + void AddInfoBar(InfoBarDelegate* delegate); + + // Removes an InfoBar for the specified delegate, in response to a + // notification from the selected TabContents. The InfoBar's disappearance + // will be animated. + void RemoveInfoBar(InfoBarDelegate* delegate); + + // The BrowserView that hosts this InfoBarContainer. + BrowserView* browser_view_; + + // The TabContents for which we are currently showing InfoBars. + TabContents* tab_contents_; + + DISALLOW_COPY_AND_ASSIGN(InfoBarContainer); +}; + +#endif // #ifndef CHROME_BROWSER_VIEWS_INFOBARS_INFOBAR_CONTAINER_H_ diff --git a/chrome/browser/views/infobars/infobars.cc b/chrome/browser/views/infobars/infobars.cc new file mode 100644 index 0000000..5733d33 --- /dev/null +++ b/chrome/browser/views/infobars/infobars.cc @@ -0,0 +1,291 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/views/infobars/infobars.h" + +#include "chrome/app/theme/theme_resources.h" +#include "chrome/browser/views/infobars/infobar_container.h" +#include "chrome/common/l10n_util.h" +#include "chrome/common/resource_bundle.h" +#include "chrome/common/slide_animation.h" +#include "chrome/views/background.h" +#include "chrome/views/button.h" +#include "chrome/views/image_view.h" +#include "chrome/views/label.h" + +#include "generated_resources.h" + +const double kInfoBarHeight = 37.0; + +static const int kVerticalPadding = 3; +static const int kHorizontalPadding = 3; +static const int kIconLabelSpacing = 5; +static const int kButtonSpacing = 5; + +static const SkColor kBackgroundColorTop = SkColorSetRGB(255, 242, 183); +static const SkColor kBackgroundColorBottom = SkColorSetRGB(250, 230, 145); + +static const int kSeparatorLineHeight = 1; +static const SkColor kSeparatorColor = SkColorSetRGB(165, 165, 165); + +namespace { +int OffsetY(views::View* parent, const gfx::Size prefsize) { + return std::max((parent->height() - prefsize.height()) / 2, 0); +} +} + +// InfoBarBackground ----------------------------------------------------------- + +class InfoBarBackground : public views::Background { + public: + InfoBarBackground() { + gradient_background_.reset( + views::Background::CreateVerticalGradientBackground( + kBackgroundColorTop, kBackgroundColorBottom)); + } + + // Overridden from views::View: + virtual void Paint(ChromeCanvas* canvas, views::View* view) const { + // First paint the gradient background. + gradient_background_->Paint(canvas, view); + + // Now paint the separator line. + canvas->FillRectInt(kSeparatorColor, 0, + view->height() - kSeparatorLineHeight, view->width(), + kSeparatorLineHeight); + } + + private: + scoped_ptr<views::Background> gradient_background_; + + DISALLOW_COPY_AND_ASSIGN(InfoBarBackground); +}; + +// InfoBar, public: ------------------------------------------------------------ + +InfoBar::InfoBar(InfoBarDelegate* delegate) + : delegate_(delegate), + close_button_(new views::Button) { + set_background(new InfoBarBackground); + + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + close_button_->SetImage(views::Button::BS_NORMAL, + rb.GetBitmapNamed(IDR_CLOSE_BAR)); + close_button_->SetImage(views::Button::BS_HOT, + rb.GetBitmapNamed(IDR_CLOSE_BAR_H)); + close_button_->SetImage(views::Button::BS_PUSHED, + rb.GetBitmapNamed(IDR_CLOSE_BAR_P)); + close_button_->SetListener(this, 0); + close_button_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_CLOSE)); + AddChildView(close_button_); + + animation_.reset(new SlideAnimation(this)); + animation_->SetTweenType(SlideAnimation::NONE); +} + +InfoBar::~InfoBar() { +} + +void InfoBar::AnimateOpen() { + animation_->Show(); +} + +void InfoBar::Open() { + animation_->Reset(1.0); + animation_->Show(); +} + +void InfoBar::AnimateClose() { + animation_->Hide(); +} + +void InfoBar::Close() { + GetParent()->RemoveChildView(this); + if (delegate()) + delegate()->InfoBarClosed(); + delete this; +} + +// InfoBar, views::View overrides: --------------------------------------------- + +gfx::Size InfoBar::GetPreferredSize() { + int height = static_cast<int>(kInfoBarHeight * animation_->GetCurrentValue()); + return gfx::Size(0, height); +} + +void InfoBar::Layout() { + gfx::Size button_ps = close_button_->GetPreferredSize(); + close_button_->SetBounds(width() - kHorizontalPadding - button_ps.width(), + OffsetY(this, button_ps), button_ps.width(), + button_ps.height()); + +} + +// InfoBar, protected: --------------------------------------------------------- + +int InfoBar::GetAvailableWidth() const { + return close_button_->x() - kIconLabelSpacing; +} + +// InfoBar, views::BaseButton::ButtonListener implementation: ------------------ + +void InfoBar::ButtonPressed(views::BaseButton* sender) { + if (sender == close_button_) + container_->RemoveDelegate(delegate()); +} + +// InfoBar, AnimationDelegate implementation: ---------------------------------- + +void InfoBar::AnimationProgressed(const Animation* animation) { + container_->InfoBarAnimated(true); +} + +void InfoBar::AnimationEnded(const Animation* animation) { + container_->InfoBarAnimated(false); + + if (!animation_->IsShowing()) + Close(); +} + +// AlertInfoBar, public: ------------------------------------------------------- + +AlertInfoBar::AlertInfoBar(AlertInfoBarDelegate* delegate) + : InfoBar(delegate) { + label_ = new views::Label( + delegate->GetMessageText(), + ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont)); + label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + AddChildView(label_); + + icon_ = new views::ImageView; + if (delegate->GetIcon()) + icon_->SetImage(delegate->GetIcon()); + AddChildView(icon_); +} + +AlertInfoBar::~AlertInfoBar() { + +} + +// AlertInfoBar, views::View overrides: ---------------------------------------- + +void AlertInfoBar::Layout() { + // Layout the close button. + InfoBar::Layout(); + + // Layout the icon and text. + gfx::Size icon_ps = icon_->GetPreferredSize(); + icon_->SetBounds(kHorizontalPadding, OffsetY(this, icon_ps), icon_ps.width(), + icon_ps.height()); + + gfx::Size text_ps = label_->GetPreferredSize(); + int text_width = + GetAvailableWidth() - icon_->bounds().right() - kIconLabelSpacing; + label_->SetBounds(icon_->bounds().right() + kIconLabelSpacing, + OffsetY(this, text_ps), text_width, text_ps.height()); +} + +// AlertInfoBar, private: ------------------------------------------------------ + +AlertInfoBarDelegate* AlertInfoBar::GetDelegate() { + return delegate()->AsAlertInfoBarDelegate(); +} + +// ConfirmInfoBar, public: ----------------------------------------------------- + +ConfirmInfoBar::ConfirmInfoBar(ConfirmInfoBarDelegate* delegate) + : ok_button_(NULL), + cancel_button_(NULL), + initialized_(false), + AlertInfoBar(delegate) { +} + +ConfirmInfoBar::~ConfirmInfoBar() { +} + +// ConfirmInfoBar, views::View overrides: -------------------------------------- + +void ConfirmInfoBar::Layout() { + InfoBar::Layout(); + int available_width = InfoBar::GetAvailableWidth(); + int ok_button_width = 0; + int cancel_button_width = 0; + gfx::Size ok_ps = ok_button_->GetPreferredSize(); + gfx::Size cancel_ps = cancel_button_->GetPreferredSize(); + + if (GetDelegate()->GetButtons() & ConfirmInfoBarDelegate::BUTTON_OK) + ok_button_width = ok_ps.width(); + if (GetDelegate()->GetButtons() & ConfirmInfoBarDelegate::BUTTON_CANCEL) + cancel_button_width = cancel_ps.width(); + + cancel_button_->SetBounds(available_width - cancel_button_width, + OffsetY(this, cancel_ps), cancel_ps.width(), + cancel_ps.height()); + int spacing = cancel_button_width > 0 ? kButtonSpacing : 0; + ok_button_->SetBounds(cancel_button_->x() - spacing - ok_button_width, + OffsetY(this, ok_ps), ok_ps.width(), ok_ps.height()); + + AlertInfoBar::Layout(); +} + +void ConfirmInfoBar::ViewHierarchyChanged(bool is_add, + views::View* parent, + views::View* child) { + if (is_add && child == this && !initialized_) { + Init(); + initialized_ = true; + } +} + +// ConfirmInfoBar, views::NativeButton::Listener implementation: --------------- + +void ConfirmInfoBar::ButtonPressed(views::NativeButton* sender) { + if (sender == ok_button_) { + GetDelegate()->Accept(); + } else if (sender == cancel_button_) { + GetDelegate()->Cancel(); + } else { + NOTREACHED(); + } +} + +// ConfirmInfoBar, InfoBar overrides: ------------------------------------------ + +int ConfirmInfoBar::GetAvailableWidth() const { + if (ok_button_) + return ok_button_->x() - kButtonSpacing; + if (cancel_button_) + return cancel_button_->x() - kButtonSpacing; + return InfoBar::GetAvailableWidth(); +} + +// ConfirmInfoBar, private: ---------------------------------------------------- + +ConfirmInfoBarDelegate* ConfirmInfoBar::GetDelegate() { + return delegate()->AsConfirmInfoBarDelegate(); +} + +void ConfirmInfoBar::Init() { + ok_button_ = new views::NativeButton( + GetDelegate()->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_OK)); + ok_button_->SetListener(this); + AddChildView(ok_button_); + + cancel_button_ = new views::NativeButton( + GetDelegate()->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_CANCEL)); + cancel_button_->SetListener(this); + AddChildView(cancel_button_); +} + +// AlertInfoBarDelegate, InfoBarDelegate overrides: ---------------------------- + +InfoBar* AlertInfoBarDelegate::CreateInfoBar() { + return new AlertInfoBar(this); +} + +// ConfirmInfoBarDelegate, InfoBarDelegate overrides: -------------------------- + +InfoBar* ConfirmInfoBarDelegate::CreateInfoBar() { + return new ConfirmInfoBar(this); +} diff --git a/chrome/browser/views/infobars/infobars.h b/chrome/browser/views/infobars/infobars.h new file mode 100644 index 0000000..1e02f96 --- /dev/null +++ b/chrome/browser/views/infobars/infobars.h @@ -0,0 +1,138 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_VIEWS_INFOBARS_INFOBARS_H_ +#define CHROME_BROWSER_VIEWS_INFOBARS_INFOBARS_H_ + +#include "chrome/browser/infobar_delegate.h" +#include "chrome/views/base_button.h" +#include "chrome/views/native_button.h" + +class InfoBarContainer; +class SlideAnimation; +namespace views { +class Button; +class ImageView; +class Label; +} + +// This file contains implementations for some general purpose InfoBars. See +// chrome/browser/infobar_delegate.h for the delegate interface(s) that you must +// implement to use these. + +class InfoBar : public views::View, + public views::BaseButton::ButtonListener, + public AnimationDelegate { + public: + explicit InfoBar(InfoBarDelegate* delegate); + virtual ~InfoBar(); + + InfoBarDelegate* delegate() const { return delegate_; } + + void set_container(InfoBarContainer* container) { container_ = container; } + + // Starts animating the InfoBar open. + void AnimateOpen(); + + // Opens the InfoBar immediately. + void Open(); + + // Starts animating the InfoBar closed. It will not be closed until the + // animation has completed, when |Close| will be called. + void AnimateClose(); + + // Closes the InfoBar immediately and removes it from its container. Notifies + // the delegate that it has closed. The InfoBar is deleted after this function + // is called. + void Close(); + + // Overridden from views::View: + virtual gfx::Size GetPreferredSize(); + virtual void Layout(); + + protected: + // Returns the available width of the View for use by child view layout, + // excluding the close button. + virtual int GetAvailableWidth() const; + + private: + // Overridden from views::Button::ButtonListener: + virtual void ButtonPressed(views::BaseButton* sender); + + // Overridden from AnimationDelegate: + virtual void AnimationProgressed(const Animation* animation); + virtual void AnimationEnded(const Animation* animation); + + // The InfoBar's container + InfoBarContainer* container_; + + // The InfoBar's delegate. + InfoBarDelegate* delegate_; + + // The Close Button at the right edge of the InfoBar. + views::Button* close_button_; + + // The animation that runs when the InfoBar is opened or closed. + scoped_ptr<SlideAnimation> animation_; + + DISALLOW_COPY_AND_ASSIGN(InfoBar); +}; + +class AlertInfoBar : public InfoBar { + public: + explicit AlertInfoBar(AlertInfoBarDelegate* delegate); + virtual ~AlertInfoBar(); + + // Overridden from views::View: + virtual void Layout(); + + protected: + views::Label* label() const { return label_; } + views::ImageView* icon() const { return icon_; } + + private: + AlertInfoBarDelegate* GetDelegate(); + + views::Label* label_; + views::ImageView* icon_; + + DISALLOW_COPY_AND_ASSIGN(AlertInfoBar); +}; + +class ConfirmInfoBar : public AlertInfoBar, + public views::NativeButton::Listener { + public: + explicit ConfirmInfoBar(ConfirmInfoBarDelegate* delegate); + virtual ~ConfirmInfoBar(); + + // Overridden from views::View: + virtual void Layout(); + + protected: + // Overridden from views::View: + virtual void ViewHierarchyChanged(bool is_add, + views::View* parent, + views::View* child); + + // Overridden from views::NativeButton::Listener: + virtual void ButtonPressed(views::NativeButton* sender); + + // Overridden from InfoBar: + virtual int GetAvailableWidth() const; + + private: + void Init(); + + ConfirmInfoBarDelegate* GetDelegate(); + + views::NativeButton* ok_button_; + views::NativeButton* cancel_button_; + + bool initialized_; + + DISALLOW_COPY_AND_ASSIGN(ConfirmInfoBar); +}; + + +#endif // #ifndef CHROME_BROWSER_VIEWS_INFOBARS_INFOBARS_H_ |