diff options
24 files changed, 655 insertions, 266 deletions
diff --git a/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc b/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc index e1f951f8..3e78123 100644 --- a/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc +++ b/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc @@ -288,10 +288,6 @@ void CardUnmaskPromptViews::DeleteDelegate() { delete this; } -int CardUnmaskPromptViews::GetDialogButtons() const { - return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL; -} - base::string16 CardUnmaskPromptViews::GetDialogButtonLabel( ui::DialogButton button) const { if (button == ui::DIALOG_BUTTON_OK) diff --git a/chrome/browser/ui/views/autofill/card_unmask_prompt_views.h b/chrome/browser/ui/views/autofill/card_unmask_prompt_views.h index a677b1212..d6a206d 100644 --- a/chrome/browser/ui/views/autofill/card_unmask_prompt_views.h +++ b/chrome/browser/ui/views/autofill/card_unmask_prompt_views.h @@ -34,11 +34,11 @@ namespace autofill { class DecoratedTextfield; class CardUnmaskPromptViews : public CardUnmaskPromptView, - views::ComboboxListener, - views::DialogDelegateView, - views::TextfieldController, - views::LinkListener, - gfx::AnimationDelegate { + public views::ComboboxListener, + public views::DialogDelegateView, + public views::TextfieldController, + public views::LinkListener, + public gfx::AnimationDelegate { public: CardUnmaskPromptViews(CardUnmaskPromptController* controller, content::WebContents* web_contents); @@ -53,7 +53,7 @@ class CardUnmaskPromptViews : public CardUnmaskPromptView, // views::DialogDelegateView View* GetContentsView() override; - views::View* CreateFootnoteView() override; + View* CreateFootnoteView() override; // views::View gfx::Size GetPreferredSize() const override; @@ -63,11 +63,10 @@ class CardUnmaskPromptViews : public CardUnmaskPromptView, ui::ModalType GetModalType() const override; base::string16 GetWindowTitle() const override; void DeleteDelegate() override; - int GetDialogButtons() const override; base::string16 GetDialogButtonLabel(ui::DialogButton button) const override; bool ShouldDefaultButtonBeBlue() const override; bool IsDialogButtonEnabled(ui::DialogButton button) const override; - views::View* GetInitiallyFocusedView() override; + View* GetInitiallyFocusedView() override; bool Cancel() override; bool Accept() override; @@ -88,7 +87,7 @@ class CardUnmaskPromptViews : public CardUnmaskPromptView, friend class CardUnmaskPromptViewTesterViews; // A view that allows changing the opacity of its contents. - class FadeOutView : public views::View { + class FadeOutView : public View { public: FadeOutView(); ~FadeOutView() override; @@ -125,7 +124,7 @@ class CardUnmaskPromptViews : public CardUnmaskPromptView, CardUnmaskPromptController* controller_; content::WebContents* web_contents_; - views::View* main_contents_; + View* main_contents_; // Expository language at the top of the dialog. views::Label* instructions_; @@ -134,7 +133,7 @@ class CardUnmaskPromptViews : public CardUnmaskPromptView, views::Label* permanent_error_label_; // Holds the cvc and expiration inputs. - views::View* input_row_; + View* input_row_; DecoratedTextfield* cvc_input_; diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views.cc b/chrome/browser/ui/views/autofill/save_card_bubble_views.cc index 007c617..10706a8 100644 --- a/chrome/browser/ui/views/autofill/save_card_bubble_views.cc +++ b/chrome/browser/ui/views/autofill/save_card_bubble_views.cc @@ -78,12 +78,12 @@ void SaveCardBubbleViews::Hide() { Close(); } -scoped_ptr<views::View> SaveCardBubbleViews::CreateFootnoteView() { +views::View* SaveCardBubbleViews::CreateFootnoteView() { if (controller_->GetLegalMessageLines().empty()) return nullptr; // Use BoxLayout to provide insets around the label. - scoped_ptr<View> view(new View()); + View* view = new View(); view->SetLayoutManager( new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views.h b/chrome/browser/ui/views/autofill/save_card_bubble_views.h index 85c6a3d..34490c4 100644 --- a/chrome/browser/ui/views/autofill/save_card_bubble_views.h +++ b/chrome/browser/ui/views/autofill/save_card_bubble_views.h @@ -45,7 +45,7 @@ class SaveCardBubbleViews : public SaveCardBubbleView, void Hide() override; // views::BubbleDelegateView - scoped_ptr<views::View> CreateFootnoteView() override; + views::View* CreateFootnoteView() override; // views::View gfx::Size GetPreferredSize() const override; diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc index 6b8de33..81a488b 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc @@ -238,16 +238,15 @@ views::View* BookmarkBubbleView::GetInitiallyFocusedView() { return title_tf_; } -scoped_ptr<views::View> BookmarkBubbleView::CreateFootnoteView() { +views::View* BookmarkBubbleView::CreateFootnoteView() { if (!SyncPromoUI::ShouldShowSyncPromo(profile_)) return nullptr; content::RecordAction( base::UserMetricsAction("Signin_Impression_FromBookmarkBubble")); - return scoped_ptr<views::View>( - new BubbleSyncPromoView(delegate_.get(), IDS_BOOKMARK_SYNC_PROMO_LINK, - IDS_BOOKMARK_SYNC_PROMO_MESSAGE)); + return new BubbleSyncPromoView(delegate_.get(), IDS_BOOKMARK_SYNC_PROMO_LINK, + IDS_BOOKMARK_SYNC_PROMO_MESSAGE); } BookmarkBubbleView::BookmarkBubbleView( diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h index c8cd970..580f4d1 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h +++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h @@ -71,8 +71,8 @@ class BookmarkBubbleView : public views::BubbleDelegateView, // views::BubbleDelegateView: const char* GetClassName() const override; - views::View* GetInitiallyFocusedView() override; - scoped_ptr<views::View> CreateFootnoteView() override; + View* GetInitiallyFocusedView() override; + View* CreateFootnoteView() override; // Creates a BookmarkBubbleView. BookmarkBubbleView(views::View* anchor_view, diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc index 523516d..00f2019 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc @@ -87,14 +87,15 @@ TEST_F(BookmarkBubbleViewTest, SyncPromoSignedIn) { SetUpSigninManager("fake_username"); CreateBubbleView(); bubble_->Init(); - EXPECT_FALSE(bubble_->CreateFootnoteView()); + scoped_ptr<views::View> footnote(bubble_->CreateFootnoteView()); + EXPECT_FALSE(footnote); } // Verifies that the sync promo is displayed for a user that is not signed in. TEST_F(BookmarkBubbleViewTest, SyncPromoNotSignedIn) { CreateBubbleView(); bubble_->Init(); - scoped_ptr<views::View> footnote = bubble_->CreateFootnoteView(); + scoped_ptr<views::View> footnote(bubble_->CreateFootnoteView()); #if defined(OS_CHROMEOS) EXPECT_FALSE(footnote); #else // !defined(OS_CHROMEOS) diff --git a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc index 7b4d42e..9e86a81 100644 --- a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc +++ b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc @@ -176,13 +176,13 @@ void ExtensionInstalledBubbleView::UpdateAnchorView() { SetAnchorView(reference_view); } -scoped_ptr<views::View> ExtensionInstalledBubbleView::CreateFootnoteView() { +views::View* ExtensionInstalledBubbleView::CreateFootnoteView() { if (!(bubble_->options() & ExtensionInstalledBubble::SIGN_IN_PROMO)) return nullptr; - return scoped_ptr<views::View>( - new BubbleSyncPromoView(this, IDS_EXTENSION_INSTALLED_SYNC_PROMO_LINK_NEW, - IDS_EXTENSION_INSTALLED_SYNC_PROMO_NEW)); + return new BubbleSyncPromoView(this, + IDS_EXTENSION_INSTALLED_SYNC_PROMO_LINK_NEW, + IDS_EXTENSION_INSTALLED_SYNC_PROMO_NEW); } void ExtensionInstalledBubbleView::WindowClosing() { diff --git a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.h b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.h index 6d11e07..8eec05b 100644 --- a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.h +++ b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.h @@ -50,7 +50,7 @@ class ExtensionInstalledBubbleView : public BubbleSyncPromoDelegate, private: // views::BubbleDelegateView: - scoped_ptr<views::View> CreateFootnoteView() override; + View* CreateFootnoteView() override; void WindowClosing() override; gfx::Rect GetAnchorRect() const override; void OnWidgetClosing(views::Widget* widget) override; diff --git a/chrome/browser/ui/views/session_crashed_bubble_view.cc b/chrome/browser/ui/views/session_crashed_bubble_view.cc index ccde39b..bd75757 100644 --- a/chrome/browser/ui/views/session_crashed_bubble_view.cc +++ b/chrome/browser/ui/views/session_crashed_bubble_view.cc @@ -46,10 +46,10 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/views/bubble/bubble_frame_view.h" #include "ui/views/controls/button/checkbox.h" -#include "ui/views/controls/button/label_button.h" #include "ui/views/controls/label.h" #include "ui/views/controls/separator.h" #include "ui/views/controls/styled_label.h" +#include "ui/views/layout/fill_layout.h" #include "ui/views/layout/grid_layout.h" #include "ui/views/layout/layout_constants.h" #include "ui/views/widget/widget.h" @@ -213,7 +213,7 @@ void SessionCrashedBubbleView::ShowForReal( SessionCrashedBubbleView* crash_bubble = new SessionCrashedBubbleView(anchor_view, browser, web_contents, offer_uma_optin); - views::BubbleDelegateView::CreateBubble(crash_bubble)->Show(); + views::BubbleDialogDelegateView::CreateBubble(crash_bubble)->Show(); RecordBubbleHistogramValue(SESSION_CRASHED_BUBBLE_SHOWN); if (uma_opted_in_already) @@ -225,11 +225,10 @@ SessionCrashedBubbleView::SessionCrashedBubbleView( Browser* browser, content::WebContents* web_contents, bool offer_uma_optin) - : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT), + : BubbleDialogDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT), content::WebContentsObserver(web_contents), browser_(browser), web_contents_(web_contents), - restore_button_(NULL), uma_option_(NULL), offer_uma_optin_(offer_uma_optin), started_navigation_(false), @@ -247,10 +246,6 @@ SessionCrashedBubbleView::~SessionCrashedBubbleView() { browser_->tab_strip_model()->RemoveObserver(this); } -views::View* SessionCrashedBubbleView::GetInitiallyFocusedView() { - return restore_button_; -} - base::string16 SessionCrashedBubbleView::GetWindowTitle() const { return l10n_util::GetStringUTF16(IDS_SESSION_CRASHED_BUBBLE_TITLE); } @@ -266,10 +261,12 @@ bool SessionCrashedBubbleView::ShouldShowCloseButton() const { void SessionCrashedBubbleView::OnWidgetDestroying(views::Widget* widget) { if (!restored_) RecordBubbleHistogramValue(SESSION_CRASHED_BUBBLE_IGNORED); - BubbleDelegateView::OnWidgetDestroying(widget); + BubbleDialogDelegateView::OnWidgetDestroying(widget); } void SessionCrashedBubbleView::Init() { + SetLayoutManager(new views::FillLayout()); + // Description text label. views::Label* text_label = new views::Label( l10n_util::GetStringUTF16(IDS_SESSION_CRASHED_VIEW_MESSAGE)); @@ -277,37 +274,10 @@ void SessionCrashedBubbleView::Init() { text_label->SetLineHeight(20); text_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); text_label->SizeToFit(kWidthOfDescriptionText); - - // Restore button. - restore_button_ = new views::LabelButton( - this, l10n_util::GetStringUTF16(IDS_SESSION_CRASHED_VIEW_RESTORE_BUTTON)); - restore_button_->SetStyle(views::Button::STYLE_BUTTON); - restore_button_->SetIsDefault(true); - - GridLayout* layout = new GridLayout(this); - SetLayoutManager(layout); - - // Text row. - const int kTextColumnSetId = 0; - views::ColumnSet* cs = layout->AddColumnSet(kTextColumnSetId); - cs->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, - GridLayout::FIXED, kWidthOfDescriptionText, 0); - - // Restore button row. - const int kButtonColumnSetId = 1; - cs = layout->AddColumnSet(kButtonColumnSetId); - cs->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 1, - GridLayout::USE_PREF, 0, 0); - - layout->StartRow(0, kTextColumnSetId); - layout->AddView(text_label); - layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); - - layout->StartRow(0, kButtonColumnSetId); - layout->AddView(restore_button_); + AddChildView(text_label); } -scoped_ptr<views::View> SessionCrashedBubbleView::CreateFootnoteView() { +views::View* SessionCrashedBubbleView::CreateFootnoteView() { if (!offer_uma_optin_) return nullptr; @@ -346,8 +316,8 @@ scoped_ptr<views::View> SessionCrashedBubbleView::CreateFootnoteView() { uma_label->SetBorder(views::Border::CreateEmptyBorder(1, 0, 0, 0)); // Create a view to hold the checkbox and the text. - scoped_ptr<views::View> uma_view(new views::View()); - GridLayout* uma_layout = new GridLayout(uma_view.get()); + views::View* uma_view = new views::View(); + GridLayout* uma_layout = new GridLayout(uma_view); uma_view->SetLayoutManager(uma_layout); const int kReportColumnSetId = 0; @@ -365,10 +335,24 @@ scoped_ptr<views::View> SessionCrashedBubbleView::CreateFootnoteView() { return uma_view; } -void SessionCrashedBubbleView::ButtonPressed(views::Button* sender, - const ui::Event& event) { - DCHECK_EQ(sender, restore_button_); - RestorePreviousSession(sender); +bool SessionCrashedBubbleView::Accept() { + RestorePreviousSession(); + return true; +} + +bool SessionCrashedBubbleView::Close() { + // Don't default to Accept() just because that's the only choice. Instead, do + // nothing. + return true; +} + +int SessionCrashedBubbleView::GetDialogButtons() const { + return ui::DIALOG_BUTTON_OK; +} + +base::string16 SessionCrashedBubbleView::GetDialogButtonLabel( + ui::DialogButton button) const { + return l10n_util::GetStringUTF16(IDS_SESSION_CRASHED_VIEW_RESTORE_BUTTON); } void SessionCrashedBubbleView::StyledLabelLinkClicked(views::StyledLabel* label, @@ -418,7 +402,7 @@ void SessionCrashedBubbleView::TabDetachedAt(content::WebContents* contents, CloseBubble(); } -void SessionCrashedBubbleView::RestorePreviousSession(views::Button* sender) { +void SessionCrashedBubbleView::RestorePreviousSession() { SessionRestore::RestoreSessionAfterCrash(browser_); RecordBubbleHistogramValue(SESSION_CRASHED_BUBBLE_RESTORED); restored_ = true; diff --git a/chrome/browser/ui/views/session_crashed_bubble_view.h b/chrome/browser/ui/views/session_crashed_bubble_view.h index 869e92d..012dfd5 100644 --- a/chrome/browser/ui/views/session_crashed_bubble_view.h +++ b/chrome/browser/ui/views/session_crashed_bubble_view.h @@ -12,14 +12,12 @@ #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "content/public/browser/web_contents_observer.h" -#include "ui/views/bubble/bubble_delegate.h" -#include "ui/views/controls/button/button.h" +#include "ui/views/bubble/bubble_dialog_delegate.h" #include "ui/views/controls/styled_label_listener.h" namespace views { class Checkbox; class GridLayout; -class LabelButton; class Widget; } @@ -33,14 +31,12 @@ class Browser; // It creates a session restore request bubble when the previous session has // crashed. It also presents an option to enable metrics reporting, if it not // enabled already. -class SessionCrashedBubbleView - : public SessionCrashedBubble, - public views::BubbleDelegateView, - public views::ButtonListener, - public views::StyledLabelListener, - public content::WebContentsObserver, - public content::NotificationObserver, - public TabStripModelObserver { +class SessionCrashedBubbleView : public SessionCrashedBubble, + public views::BubbleDialogDelegateView, + public views::StyledLabelListener, + public content::WebContentsObserver, + public content::NotificationObserver, + public TabStripModelObserver { public: // A helper class that listens to browser removal event. class BrowserRemovalObserver; @@ -59,19 +55,19 @@ class SessionCrashedBubbleView ~SessionCrashedBubbleView() override; // WidgetDelegateView methods. - views::View* GetInitiallyFocusedView() override; base::string16 GetWindowTitle() const override; bool ShouldShowWindowTitle() const override; bool ShouldShowCloseButton() const override; void OnWidgetDestroying(views::Widget* widget) override; - scoped_ptr<views::View> CreateFootnoteView() override; + views::View* CreateFootnoteView() override; + bool Accept() override; + bool Close() override; + int GetDialogButtons() const override; + base::string16 GetDialogButtonLabel(ui::DialogButton button) const override; - // views::BubbleDelegateView methods. + // views::BubbleDialogDelegateView methods. void Init() override; - // views::ButtonListener methods. - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - // views::StyledLabelListener methods. void StyledLabelLinkClicked(views::StyledLabel* label, const gfx::Range& range, @@ -98,7 +94,7 @@ class SessionCrashedBubbleView void TabDetachedAt(content::WebContents* contents, int index) override; // Restore previous session after user selects so. - void RestorePreviousSession(views::Button* sender); + void RestorePreviousSession(); // Close and destroy the bubble. void CloseBubble(); @@ -111,9 +107,6 @@ class SessionCrashedBubbleView // The web content associated with current bubble. content::WebContents* web_contents_; - // Button for the user to confirm a session restore. - views::LabelButton* restore_button_; - // Checkbox for the user to opt-in to UMA reporting. views::Checkbox* uma_option_; diff --git a/ui/views/bubble/bubble_delegate.cc b/ui/views/bubble/bubble_delegate.cc index a18c088..698c4a4 100644 --- a/ui/views/bubble/bubble_delegate.cc +++ b/ui/views/bubble/bubble_delegate.cc @@ -207,7 +207,7 @@ void BubbleDelegateView::OnBeforeBubbleWidgetInit(Widget::InitParams* params, Widget* widget) const { } -scoped_ptr<View> BubbleDelegateView::CreateFootnoteView() { +View* BubbleDelegateView::CreateFootnoteView() { return nullptr; } diff --git a/ui/views/bubble/bubble_delegate.h b/ui/views/bubble/bubble_delegate.h index a0e3ccc..9392251 100644 --- a/ui/views/bubble/bubble_delegate.h +++ b/ui/views/bubble/bubble_delegate.h @@ -23,6 +23,7 @@ class BubbleFrameView; // BubbleDelegateView creates frame and client views for bubble Widgets. // BubbleDelegateView itself is the client's contents view. +// TODO(estade): remove this in favor of BubbleDialogDelegateView. class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView, public WidgetObserver { public: @@ -112,7 +113,7 @@ class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView, Widget* widget) const; // Creates and returns a view to be displayed at the bottom of the bubble. - virtual scoped_ptr<View> CreateFootnoteView(); + virtual View* CreateFootnoteView(); // Sets |margins_| to a default picked for smaller bubbles. void UseCompactMargins(); diff --git a/ui/views/bubble/bubble_dialog_delegate.cc b/ui/views/bubble/bubble_dialog_delegate.cc new file mode 100644 index 0000000..a893bcf --- /dev/null +++ b/ui/views/bubble/bubble_dialog_delegate.cc @@ -0,0 +1,341 @@ +// Copyright 2016 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 "ui/views/bubble/bubble_dialog_delegate.h" + +#include "build/build_config.h" +#include "ui/accessibility/ax_view_state.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/color_utils.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/native_theme/native_theme.h" +#include "ui/views/bubble/bubble_frame_view.h" +#include "ui/views/focus/view_storage.h" +#include "ui/views/layout/layout_constants.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_observer.h" +#include "ui/views/window/dialog_client_view.h" + +#if defined(OS_WIN) +#include "ui/base/win/shell.h" +#endif + +namespace views { + +namespace { + +// Create a widget to host the bubble. +Widget* CreateBubbleWidget(BubbleDialogDelegateView* bubble) { + Widget* bubble_widget = new Widget(); + Widget::InitParams bubble_params(Widget::InitParams::TYPE_BUBBLE); + bubble_params.delegate = bubble; + bubble_params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW; + bubble_params.accept_events = bubble->accept_events(); + if (bubble->parent_window()) + bubble_params.parent = bubble->parent_window(); + else if (bubble->anchor_widget()) + bubble_params.parent = bubble->anchor_widget()->GetNativeView(); + bubble_params.activatable = bubble->CanActivate() + ? Widget::InitParams::ACTIVATABLE_YES + : Widget::InitParams::ACTIVATABLE_NO; + bubble->OnBeforeBubbleWidgetInit(&bubble_params, bubble_widget); + bubble_widget->Init(bubble_params); + if (bubble_params.parent) + bubble_widget->StackAbove(bubble_params.parent); + return bubble_widget; +} + +} // namespace + +// static +const char BubbleDialogDelegateView::kViewClassName[] = + "BubbleDialogDelegateView"; + +BubbleDialogDelegateView::~BubbleDialogDelegateView() { + if (GetWidget()) + GetWidget()->RemoveObserver(this); + SetLayoutManager(NULL); + SetAnchorView(NULL); +} + +// static +Widget* BubbleDialogDelegateView::CreateBubble( + BubbleDialogDelegateView* bubble_delegate) { + bubble_delegate->Init(); + // Get the latest anchor widget from the anchor view at bubble creation time. + bubble_delegate->SetAnchorView(bubble_delegate->GetAnchorView()); + Widget* bubble_widget = CreateBubbleWidget(bubble_delegate); + +#if defined(OS_WIN) + // If glass is enabled, the bubble is allowed to extend outside the bounds of + // the parent frame and let DWM handle compositing. If not, then we don't + // want to allow the bubble to extend the frame because it will be clipped. + bubble_delegate->set_adjust_if_offscreen(ui::win::IsAeroGlassEnabled()); +#elif (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_MACOSX) + // Linux clips bubble windows that extend outside their parent window bounds. + // Mac never adjusts. + bubble_delegate->set_adjust_if_offscreen(false); +#endif + + bubble_delegate->SizeToContents(); + bubble_widget->AddObserver(bubble_delegate); + return bubble_widget; +} + +bool BubbleDialogDelegateView::ShouldShowCloseButton() const { + return false; +} + +ClientView* BubbleDialogDelegateView::CreateClientView(Widget* widget) { + DialogClientView* client = new DialogClientView(widget, GetContentsView()); + client->set_button_row_insets(gfx::Insets()); + return client; +} + +NonClientFrameView* BubbleDialogDelegateView::CreateNonClientFrameView( + Widget* widget) { + BubbleFrameView* frame = new BubbleFrameView( + gfx::Insets(kPanelVertMargin, kPanelHorizMargin, 0, kPanelHorizMargin), + margins()); + // Note: In CreateBubble, the call to SizeToContents() will cause + // the relayout that this call requires. + frame->SetTitleFontList(GetTitleFontList()); + frame->SetFootnoteView(CreateFootnoteView()); + + BubbleBorder::Arrow adjusted_arrow = arrow(); + if (base::i18n::IsRTL()) + adjusted_arrow = BubbleBorder::horizontal_mirror(adjusted_arrow); + frame->SetBubbleBorder(scoped_ptr<BubbleBorder>( + new BubbleBorder(adjusted_arrow, shadow(), color()))); + return frame; +} + +void BubbleDialogDelegateView::GetAccessibleState(ui::AXViewState* state) { + state->role = ui::AX_ROLE_DIALOG; +} + +const char* BubbleDialogDelegateView::GetClassName() const { + return kViewClassName; +} + +void BubbleDialogDelegateView::OnWidgetClosing(Widget* widget) { + DCHECK(GetBubbleFrameView()); + if (widget == GetWidget() && close_reason_ == CloseReason::UNKNOWN && + GetBubbleFrameView()->close_button_clicked()) { + close_reason_ = CloseReason::CLOSE_BUTTON; + } +} + +void BubbleDialogDelegateView::OnWidgetDestroying(Widget* widget) { + if (anchor_widget() == widget) + SetAnchorView(NULL); +} + +void BubbleDialogDelegateView::OnWidgetVisibilityChanging(Widget* widget, + bool visible) { +#if defined(OS_WIN) + // On Windows we need to handle this before the bubble is visible or hidden. + // Please see the comment on the OnWidgetVisibilityChanging function. On + // other platforms it is fine to handle it after the bubble is shown/hidden. + HandleVisibilityChanged(widget, visible); +#endif +} + +void BubbleDialogDelegateView::OnWidgetVisibilityChanged(Widget* widget, + bool visible) { +#if !defined(OS_WIN) + HandleVisibilityChanged(widget, visible); +#endif +} + +void BubbleDialogDelegateView::OnWidgetActivationChanged(Widget* widget, + bool active) { + if (close_on_deactivate() && widget == GetWidget() && !active) { + if (close_reason_ == CloseReason::UNKNOWN) + close_reason_ = CloseReason::DEACTIVATION; + GetWidget()->Close(); + } +} + +void BubbleDialogDelegateView::OnWidgetBoundsChanged( + Widget* widget, + const gfx::Rect& new_bounds) { + if (GetBubbleFrameView() && anchor_widget() == widget) + SizeToContents(); +} + +View* BubbleDialogDelegateView::GetAnchorView() const { + return ViewStorage::GetInstance()->RetrieveView(anchor_view_storage_id_); +} + +gfx::Rect BubbleDialogDelegateView::GetAnchorRect() const { + if (!GetAnchorView()) + return anchor_rect_; + + anchor_rect_ = GetAnchorView()->GetBoundsInScreen(); + anchor_rect_.Inset(anchor_view_insets_); + return anchor_rect_; +} + +void BubbleDialogDelegateView::OnBeforeBubbleWidgetInit( + Widget::InitParams* params, + Widget* widget) const {} + +void BubbleDialogDelegateView::UseCompactMargins() { + const int kCompactMargin = 6; + margins_.Set(kCompactMargin, kCompactMargin, kCompactMargin, kCompactMargin); +} + +void BubbleDialogDelegateView::SetAlignment( + BubbleBorder::BubbleAlignment alignment) { + GetBubbleFrameView()->bubble_border()->set_alignment(alignment); + SizeToContents(); +} + +void BubbleDialogDelegateView::SetArrowPaintType( + BubbleBorder::ArrowPaintType paint_type) { + GetBubbleFrameView()->bubble_border()->set_paint_arrow(paint_type); + SizeToContents(); +} + +void BubbleDialogDelegateView::OnAnchorBoundsChanged() { + SizeToContents(); +} + +BubbleDialogDelegateView::BubbleDialogDelegateView() + : BubbleDialogDelegateView(nullptr, BubbleBorder::TOP_LEFT) {} + +BubbleDialogDelegateView::BubbleDialogDelegateView(View* anchor_view, + BubbleBorder::Arrow arrow) + : close_on_esc_(true), + close_on_deactivate_(true), + anchor_view_storage_id_(ViewStorage::GetInstance()->CreateStorageID()), + anchor_widget_(NULL), + arrow_(arrow), + shadow_(BubbleBorder::SMALL_SHADOW), + color_explicitly_set_(false), + margins_(kPanelVertMargin, + kPanelHorizMargin, + kPanelVertMargin, + kPanelHorizMargin), + accept_events_(true), + border_accepts_events_(true), + adjust_if_offscreen_(true), + parent_window_(NULL), + close_reason_(CloseReason::UNKNOWN) { + if (anchor_view) + SetAnchorView(anchor_view); + AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); + UpdateColorsFromTheme(GetNativeTheme()); +} + +gfx::Rect BubbleDialogDelegateView::GetBubbleBounds() { + // The argument rect has its origin at the bubble's arrow anchor point; + // its size is the preferred size of the bubble's client view (this view). + bool anchor_minimized = anchor_widget() && anchor_widget()->IsMinimized(); + return GetBubbleFrameView()->GetUpdatedWindowBounds( + GetAnchorRect(), GetWidget()->client_view()->GetPreferredSize(), + adjust_if_offscreen_ && !anchor_minimized); +} + +const gfx::FontList& BubbleDialogDelegateView::GetTitleFontList() const { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + return rb.GetFontList(ui::ResourceBundle::MediumFont); +} + +bool BubbleDialogDelegateView::AcceleratorPressed( + const ui::Accelerator& accelerator) { + if (!close_on_esc() || accelerator.key_code() != ui::VKEY_ESCAPE) + return false; + close_reason_ = CloseReason::ESCAPE; + GetWidget()->Close(); + return true; +} + +void BubbleDialogDelegateView::OnNativeThemeChanged( + const ui::NativeTheme* theme) { + UpdateColorsFromTheme(theme); +} + +void BubbleDialogDelegateView::Init() {} + +void BubbleDialogDelegateView::SetAnchorView(View* anchor_view) { + // When the anchor view gets set the associated anchor widget might + // change as well. + if (!anchor_view || anchor_widget() != anchor_view->GetWidget()) { + if (anchor_widget()) { + anchor_widget_->RemoveObserver(this); + anchor_widget_ = NULL; + } + if (anchor_view) { + anchor_widget_ = anchor_view->GetWidget(); + if (anchor_widget_) + anchor_widget_->AddObserver(this); + } + } + + // Remove the old storage item and set the new (if there is one). + ViewStorage* view_storage = ViewStorage::GetInstance(); + if (view_storage->RetrieveView(anchor_view_storage_id_)) + view_storage->RemoveView(anchor_view_storage_id_); + if (anchor_view) + view_storage->StoreView(anchor_view_storage_id_, anchor_view); + + // Do not update anchoring for NULL views; this could indicate that our + // NativeWindow is being destroyed, so it would be dangerous for us to update + // our anchor bounds at that point. (It's safe to skip this, since if we were + // to update the bounds when |anchor_view| is NULL, the bubble won't move.) + if (anchor_view && GetWidget()) + OnAnchorBoundsChanged(); +} + +void BubbleDialogDelegateView::SetAnchorRect(const gfx::Rect& rect) { + anchor_rect_ = rect; + if (GetWidget()) + OnAnchorBoundsChanged(); +} + +void BubbleDialogDelegateView::SizeToContents() { + GetWidget()->SetBounds(GetBubbleBounds()); +} + +BubbleFrameView* BubbleDialogDelegateView::GetBubbleFrameView() const { + const NonClientView* view = + GetWidget() ? GetWidget()->non_client_view() : NULL; + return view ? static_cast<BubbleFrameView*>(view->frame_view()) : NULL; +} + +void BubbleDialogDelegateView::UpdateColorsFromTheme( + const ui::NativeTheme* theme) { + if (!color_explicitly_set_) + color_ = theme->GetSystemColor(ui::NativeTheme::kColorId_BubbleBackground); + set_background(Background::CreateSolidBackground(color())); + BubbleFrameView* frame_view = GetBubbleFrameView(); + if (frame_view) + frame_view->bubble_border()->set_background_color(color()); +} + +void BubbleDialogDelegateView::HandleVisibilityChanged(Widget* widget, + bool visible) { + if (widget == GetWidget() && anchor_widget() && + anchor_widget()->GetTopLevelWidget()) { + if (visible) + anchor_widget()->GetTopLevelWidget()->DisableInactiveRendering(); + else + anchor_widget()->GetTopLevelWidget()->EnableInactiveRendering(); + } + + // Fire AX_EVENT_ALERT for bubbles marked as AX_ROLE_ALERT_DIALOG; this + // instructs accessibility tools to read the bubble in its entirety rather + // than just its title and initially focused view. See + // http://crbug.com/474622 for details. + if (widget == GetWidget() && visible) { + ui::AXViewState state; + GetAccessibleState(&state); + if (state.role == ui::AX_ROLE_ALERT_DIALOG) + NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); + } +} + +} // namespace views diff --git a/ui/views/bubble/bubble_dialog_delegate.h b/ui/views/bubble/bubble_dialog_delegate.h new file mode 100644 index 0000000..fc61adc --- /dev/null +++ b/ui/views/bubble/bubble_dialog_delegate.h @@ -0,0 +1,215 @@ +// Copyright 2016 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 UI_VIEWS_BUBBLE_BUBBLE_DIALOG_DELEGATE_H_ +#define UI_VIEWS_BUBBLE_BUBBLE_DIALOG_DELEGATE_H_ + +#include "base/gtest_prod_util.h" +#include "base/macros.h" +#include "ui/views/bubble/bubble_border.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_observer.h" +#include "ui/views/window/dialog_delegate.h" + +namespace gfx { +class FontList; +class Rect; +} + +namespace views { + +class BubbleFrameView; + +// BubbleDialogDelegateView is a special DialogDelegateView for bubbles. +class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView, + public WidgetObserver { + public: + // Internal class name. + static const char kViewClassName[]; + + enum class CloseReason { + DEACTIVATION, + ESCAPE, + CLOSE_BUTTON, + UNKNOWN, + }; + + ~BubbleDialogDelegateView() override; + + // Create and initialize the bubble Widget(s) with proper bounds. + static Widget* CreateBubble(BubbleDialogDelegateView* bubble_delegate); + + // WidgetDelegateView overrides: + bool ShouldShowCloseButton() const override; + ClientView* CreateClientView(Widget* widget) override; + NonClientFrameView* CreateNonClientFrameView(Widget* widget) override; + void GetAccessibleState(ui::AXViewState* state) override; + const char* GetClassName() const override; + + // WidgetObserver overrides: + void OnWidgetClosing(Widget* widget) override; + void OnWidgetDestroying(Widget* widget) override; + void OnWidgetVisibilityChanging(Widget* widget, bool visible) override; + void OnWidgetVisibilityChanged(Widget* widget, bool visible) override; + void OnWidgetActivationChanged(Widget* widget, bool active) override; + void OnWidgetBoundsChanged(Widget* widget, + const gfx::Rect& new_bounds) override; + + bool close_on_esc() const { return close_on_esc_; } + void set_close_on_esc(bool close_on_esc) { close_on_esc_ = close_on_esc; } + + bool close_on_deactivate() const { return close_on_deactivate_; } + void set_close_on_deactivate(bool close) { close_on_deactivate_ = close; } + + View* GetAnchorView() const; + Widget* anchor_widget() const { return anchor_widget_; } + + // The anchor rect is used in the absence of an assigned anchor view. + const gfx::Rect& anchor_rect() const { return anchor_rect_; } + + BubbleBorder::Arrow arrow() const { return arrow_; } + void set_arrow(BubbleBorder::Arrow arrow) { arrow_ = arrow; } + + BubbleBorder::Shadow shadow() const { return shadow_; } + void set_shadow(BubbleBorder::Shadow shadow) { shadow_ = shadow; } + + SkColor color() const { return color_; } + void set_color(SkColor color) { + color_ = color; + color_explicitly_set_ = true; + } + + const gfx::Insets& margins() const { return margins_; } + void set_margins(const gfx::Insets& margins) { margins_ = margins; } + + const gfx::Insets& anchor_view_insets() const { return anchor_view_insets_; } + void set_anchor_view_insets(const gfx::Insets& i) { anchor_view_insets_ = i; } + + gfx::NativeView parent_window() const { return parent_window_; } + void set_parent_window(gfx::NativeView window) { parent_window_ = window; } + + bool accept_events() const { return accept_events_; } + void set_accept_events(bool accept_events) { accept_events_ = accept_events; } + + bool border_accepts_events() const { return border_accepts_events_; } + void set_border_accepts_events(bool event) { border_accepts_events_ = event; } + + bool adjust_if_offscreen() const { return adjust_if_offscreen_; } + void set_adjust_if_offscreen(bool adjust) { adjust_if_offscreen_ = adjust; } + + CloseReason close_reason() const { return close_reason_; } + + // Get the arrow's anchor rect in screen space. + virtual gfx::Rect GetAnchorRect() const; + + // Allows delegates to provide custom parameters before widget initialization. + virtual void OnBeforeBubbleWidgetInit(Widget::InitParams* params, + Widget* widget) const; + + // Sets |margins_| to a default picked for smaller bubbles. + void UseCompactMargins(); + + // Sets the bubble alignment relative to the anchor. This may only be called + // after calling CreateBubble. + void SetAlignment(BubbleBorder::BubbleAlignment alignment); + + // Sets the bubble arrow paint type. + void SetArrowPaintType(BubbleBorder::ArrowPaintType paint_type); + + // Call this method when the anchor bounds have changed to reposition the + // bubble. The bubble is automatically repositioned when the anchor view + // bounds change as a result of the widget's bounds changing. + void OnAnchorBoundsChanged(); + + protected: + BubbleDialogDelegateView(); + BubbleDialogDelegateView(View* anchor_view, BubbleBorder::Arrow arrow); + + // Get bubble bounds from the anchor rect and client view's preferred size. + virtual gfx::Rect GetBubbleBounds(); + + // Return a FontList to use for the title of the bubble. + // (The default is MediumFont). + virtual const gfx::FontList& GetTitleFontList() const; + + // View overrides: + bool AcceleratorPressed(const ui::Accelerator& accelerator) override; + void OnNativeThemeChanged(const ui::NativeTheme* theme) override; + + // Perform view initialization on the contents for bubble sizing. + virtual void Init(); + + // Sets the anchor view or rect and repositions the bubble. Note that if a + // valid view gets passed, the anchor rect will get ignored. If the view gets + // deleted, but no new view gets set, the last known anchor postion will get + // returned. + void SetAnchorView(View* anchor_view); + void SetAnchorRect(const gfx::Rect& rect); + + // Resize and potentially move the bubble to fit the content's preferred size. + void SizeToContents(); + + BubbleFrameView* GetBubbleFrameView() const; + + private: + friend class BubbleBorderDelegate; + friend class BubbleWindowTargeter; + + FRIEND_TEST_ALL_PREFIXES(BubbleDelegateTest, CreateDelegate); + FRIEND_TEST_ALL_PREFIXES(BubbleDelegateTest, NonClientHitTest); + + // Update the bubble color from |theme|, unless it was explicitly set. + void UpdateColorsFromTheme(const ui::NativeTheme* theme); + + // Handles widget visibility changes. + void HandleVisibilityChanged(Widget* widget, bool visible); + + // Flags controlling bubble closure on the escape key and deactivation. + bool close_on_esc_; + bool close_on_deactivate_; + + // The view and widget to which this bubble is anchored. Since an anchor view + // can be deleted without notice, we store it in the ViewStorage and retrieve + // it from there. It will make sure that the view is still valid. + const int anchor_view_storage_id_; + Widget* anchor_widget_; + + // The anchor rect used in the absence of an anchor view. + mutable gfx::Rect anchor_rect_; + + // The arrow's location on the bubble. + BubbleBorder::Arrow arrow_; + + // Bubble border shadow to use. + BubbleBorder::Shadow shadow_; + + // The background color of the bubble; and flag for when it's explicitly set. + SkColor color_; + bool color_explicitly_set_; + + // The margins between the content and the inside of the border. + gfx::Insets margins_; + + // Insets applied to the |anchor_view_| bounds. + gfx::Insets anchor_view_insets_; + + // Specifies whether the bubble (or its border) handles mouse events, etc. + bool accept_events_; + bool border_accepts_events_; + + // If true (defaults to true), the arrow may be mirrored and moved to fit the + // bubble on screen better. It would be a no-op if the bubble has no arrow. + bool adjust_if_offscreen_; + + // Parent native window of the bubble. + gfx::NativeView parent_window_; + + CloseReason close_reason_; + + DISALLOW_COPY_AND_ASSIGN(BubbleDialogDelegateView); +}; + +} // namespace views + +#endif // UI_VIEWS_BUBBLE_BUBBLE_DELEGATE2_H_ diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc index 64bf37c..0c1220c 100644 --- a/ui/views/bubble/bubble_frame_view.cc +++ b/ui/views/bubble/bubble_frame_view.cc @@ -78,7 +78,6 @@ BubbleFrameView::BubbleFrameView(const gfx::Insets& title_margins, title_icon_(new views::ImageView()), title_(nullptr), close_(nullptr), - titlebar_extra_view_(nullptr), footnote_container_(nullptr), close_button_clicked_(false) { AddChildView(title_icon_); @@ -308,19 +307,6 @@ void BubbleFrameView::Layout() { title_icon_size.width() + title_label_size.width() + padding); bounds.set_height(title_height); - if (titlebar_extra_view_) { - const int extra_width = close_->x() - bounds.right(); - gfx::Size size = titlebar_extra_view_->GetPreferredSize(); - size.SetToMin(gfx::Size(std::max(0, extra_width), size.height())); - gfx::Rect titlebar_extra_view_bounds( - close_->x() - size.width(), - bounds.y(), - size.width(), - bounds.height()); - titlebar_extra_view_bounds.Subtract(bounds); - titlebar_extra_view_->SetBoundsRect(titlebar_extra_view_bounds); - } - if (footnote_container_) { gfx::Rect local_bounds = GetContentsBounds(); int height = footnote_container_->GetHeightForWidth(local_bounds.width()); @@ -334,11 +320,6 @@ const char* BubbleFrameView::GetClassName() const { return kViewClassName; } -void BubbleFrameView::ChildPreferredSizeChanged(View* child) { - if (child == titlebar_extra_view_ || child == title_) - Layout(); -} - void BubbleFrameView::OnThemeChanged() { UpdateWindowTitle(); ResetWindowControls(); @@ -368,21 +349,11 @@ void BubbleFrameView::SetBubbleBorder(scoped_ptr<BubbleBorder> border) { set_background(new views::BubbleBackground(bubble_border_)); } -void BubbleFrameView::SetTitlebarExtraView(scoped_ptr<View> view) { - if (!view) - return; - - DCHECK(!titlebar_extra_view_); - titlebar_extra_view_ = view.release(); - AddChildView(titlebar_extra_view_); -} - -void BubbleFrameView::SetFootnoteView(scoped_ptr<View> view) { +void BubbleFrameView::SetFootnoteView(View* view) { if (!view) return; DCHECK(!footnote_container_); - footnote_container_ = new views::View(); footnote_container_->SetLayoutManager( new BoxLayout(BoxLayout::kVertical, content_margins_.left(), @@ -391,7 +362,7 @@ void BubbleFrameView::SetFootnoteView(scoped_ptr<View> view) { Background::CreateSolidBackground(kFootnoteBackgroundColor)); footnote_container_->SetBorder( Border::CreateSolidSidedBorder(1, 0, 0, 0, kFootnoteBorderColor)); - footnote_container_->AddChildView(view.release()); + footnote_container_->AddChildView(view); AddChildView(footnote_container_); } @@ -511,8 +482,6 @@ gfx::Size BubbleFrameView::GetSizeForClientSize( title_bar_width += title_icon_size.width(); if (close_->visible()) title_bar_width += close_->width() + 1; - if (titlebar_extra_view_) - title_bar_width += titlebar_extra_view_->GetPreferredSize().width(); gfx::Size size(client_size); gfx::Insets client_insets = GetInsets(); diff --git a/ui/views/bubble/bubble_frame_view.h b/ui/views/bubble/bubble_frame_view.h index ef19762..f9d3f30 100644 --- a/ui/views/bubble/bubble_frame_view.h +++ b/ui/views/bubble/bubble_frame_view.h @@ -59,7 +59,6 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView, gfx::Size GetMaximumSize() const override; void Layout() override; const char* GetClassName() const override; - void ChildPreferredSizeChanged(View* child) override; void OnThemeChanged() override; void OnNativeThemeChanged(const ui::NativeTheme* theme) override; @@ -72,9 +71,7 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView, gfx::Insets content_margins() const { return content_margins_; } - void SetTitlebarExtraView(scoped_ptr<View> view); - - void SetFootnoteView(scoped_ptr<View> view); + void SetFootnoteView(View* view); // Given the size of the contents and the rect to point at, returns the bounds // of the bubble window. The bubble's arrow location may change if the bubble @@ -124,10 +121,6 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView, Label* title_; LabelButton* close_; - // When supplied, this view is placed in the titlebar between the title and - // (x) close button. - View* titlebar_extra_view_; - // A view to contain the footnote view, if it exists. View* footnote_container_; diff --git a/ui/views/examples/widget_example.cc b/ui/views/examples/widget_example.cc index bcfb451..0165de3 100644 --- a/ui/views/examples/widget_example.cc +++ b/ui/views/examples/widget_example.cc @@ -28,7 +28,6 @@ class DialogExample : public DialogDelegateView { ~DialogExample() override; base::string16 GetWindowTitle() const override; View* CreateExtraView() override; - View* CreateTitlebarExtraView() override; View* CreateFootnoteView() override; }; @@ -61,12 +60,6 @@ View* DialogExample::CreateExtraView() { return button; } -View* DialogExample::CreateTitlebarExtraView() { - Label* label = new Label(ASCIIToUTF16("Extra view!")); - label->SetEnabledColor(SK_ColorBLUE); - return label; -} - View* DialogExample::CreateFootnoteView() { return new Label(ASCIIToUTF16("Footnote label!")); } diff --git a/ui/views/views.gyp b/ui/views/views.gyp index a6707a2..584513d 100644 --- a/ui/views/views.gyp +++ b/ui/views/views.gyp @@ -49,6 +49,8 @@ 'bubble/bubble_border.h', 'bubble/bubble_delegate.cc', 'bubble/bubble_delegate.h', + 'bubble/bubble_dialog_delegate.cc', + 'bubble/bubble_dialog_delegate.h', 'bubble/bubble_frame_view.cc', 'bubble/bubble_frame_view.h', 'button_drag_utils.cc', diff --git a/ui/views/window/dialog_client_view.cc b/ui/views/window/dialog_client_view.cc index 5f069ef..5a115e5 100644 --- a/ui/views/window/dialog_client_view.cc +++ b/ui/views/window/dialog_client_view.cc @@ -54,10 +54,13 @@ void LayoutButton(LabelButton* button, gfx::Rect* row_bounds) { DialogClientView::DialogClientView(Widget* owner, View* contents_view) : ClientView(owner, contents_view), + button_row_insets_(0, + kButtonHEdgeMarginNew, + kButtonVEdgeMarginNew, + kButtonHEdgeMarginNew), ok_button_(NULL), cancel_button_(NULL), extra_view_(NULL), - footnote_view_(NULL), delegate_allowed_close_(false) {} DialogClientView::~DialogClientView() { @@ -86,8 +89,6 @@ void DialogClientView::UpdateDialogButtons() { if (buttons & ui::DIALOG_BUTTON_OK) { if (!ok_button_) { ok_button_ = CreateDialogButton(ui::DIALOG_BUTTON_OK); - if (!(buttons & ui::DIALOG_BUTTON_CANCEL)) - ok_button_->AddAccelerator(escape); AddChildView(ok_button_); } @@ -110,8 +111,8 @@ void DialogClientView::UpdateDialogButtons() { cancel_button_ = NULL; } - // Use the escape key to close the window if there are no dialog buttons. - if (!has_dialog_buttons()) + // Use the escape key to close the window if there is no cancel button. + if (!cancel_button_) AddAccelerator(escape); else ResetAccelerators(); @@ -167,31 +168,12 @@ gfx::Size DialogClientView::GetPreferredSize() const { size.Enlarge(0, contents_size.height()); size.set_width(std::max(size.width(), contents_size.width())); - // Increase the size as needed to fit the footnote view. - if (ShouldShow(footnote_view_)) { - gfx::Size footnote_size = footnote_view_->GetPreferredSize(); - if (!footnote_size.IsEmpty()) - size.set_width(std::max(size.width(), footnote_size.width())); - - int footnote_height = footnote_view_->GetHeightForWidth(size.width()); - size.Enlarge(0, footnote_height); - } - return size; } void DialogClientView::Layout() { gfx::Rect bounds = GetContentsBounds(); - // Layout the footnote view. - if (ShouldShow(footnote_view_)) { - const int height = footnote_view_->GetHeightForWidth(bounds.width()); - footnote_view_->SetBounds(bounds.x(), bounds.bottom() - height, - bounds.width(), height); - if (height != 0) - bounds.Inset(0, 0, 0, height); - } - // Layout the row containing the buttons and the extra view. if (has_dialog_buttons() || ShouldShow(extra_view_)) { bounds.Inset(GetButtonRowInsets()); @@ -242,7 +224,6 @@ void DialogClientView::ViewHierarchyChanged( if (details.is_add && details.child == this) { UpdateDialogButtons(); CreateExtraView(); - CreateFootnoteView(); } else if (!details.is_add && details.child != this) { if (details.child == ok_button_) ok_button_ = nullptr; @@ -250,8 +231,6 @@ void DialogClientView::ViewHierarchyChanged( cancel_button_ = nullptr; else if (details.child == extra_view_) extra_view_ = nullptr; - else if (details.child == footnote_view_) - footnote_view_ = nullptr; } SetupFocusChain(); @@ -292,7 +271,6 @@ DialogClientView::DialogClientView(View* contents_view) ok_button_(NULL), cancel_button_(NULL), extra_view_(NULL), - footnote_view_(NULL), delegate_allowed_close_(false) {} DialogDelegate* DialogClientView::GetDialogDelegate() const { @@ -310,17 +288,8 @@ void DialogClientView::CreateExtraView() { } } -void DialogClientView::CreateFootnoteView() { - if (footnote_view_) - return; - - footnote_view_ = GetDialogDelegate()->CreateFootnoteView(); - if (footnote_view_) - AddChildView(footnote_view_); -} - void DialogClientView::ChildPreferredSizeChanged(View* child) { - if (child == footnote_view_ || child == extra_view_) + if (child == extra_view_) Layout(); } @@ -368,14 +337,10 @@ int DialogClientView::GetButtonsAndExtraViewRowHeight() const { } gfx::Insets DialogClientView::GetButtonRowInsets() const { - // NOTE: The insets only apply to the buttons, extra view, and footnote view. - return GetButtonsAndExtraViewRowHeight() == 0 ? gfx::Insets() : - gfx::Insets(0, kButtonHEdgeMarginNew, - kButtonVEdgeMarginNew, kButtonHEdgeMarginNew); + return GetButtonsAndExtraViewRowHeight() == 0 ? gfx::Insets() + : button_row_insets_; } - - void DialogClientView::SetupFocusChain() { // Create a vector of child views in the order of intended focus. std::vector<View*> child_views; @@ -388,7 +353,6 @@ void DialogClientView::SetupFocusChain() { child_views.push_back(cancel_button_); child_views.push_back(ok_button_); } - child_views.push_back(footnote_view_); // Remove all null views from the vector. child_views.erase( diff --git a/ui/views/window/dialog_client_view.h b/ui/views/window/dialog_client_view.h index 8f4e0fc..60080b0 100644 --- a/ui/views/window/dialog_client_view.h +++ b/ui/views/window/dialog_client_view.h @@ -19,14 +19,13 @@ class Widget; // DialogClientView provides adornments for a dialog's content view, including // custom-labeled [OK] and [Cancel] buttons with [Enter] and [Esc] accelerators. -// The view also displays the delegate's extra view alongside the buttons and -// the delegate's footnote view below the buttons. The view appears like below. -// NOTE: The contents view is not inset on the top or side client view edges. +// The view also displays the delegate's extra view alongside the buttons. The +// view appears like below. NOTE: The contents view is not inset on the top or +// side client view edges. // +------------------------------+ // | Contents View | // +------------------------------+ // | [Extra View] [OK] [Cancel] | -// | [ Footnote View ] | // +------------------------------+ class VIEWS_EXPORT DialogClientView : public ClientView, public ButtonListener { @@ -61,6 +60,10 @@ class VIEWS_EXPORT DialogClientView : public ClientView, // ButtonListener implementation: void ButtonPressed(Button* sender, const ui::Event& event) override; + void set_button_row_insets(const gfx::Insets& insets) { + button_row_insets_ = insets; + } + protected: // For testing. explicit DialogClientView(View* contents_view); @@ -71,9 +74,6 @@ class VIEWS_EXPORT DialogClientView : public ClientView, // Create and add the extra view, if supplied by the delegate. void CreateExtraView(); - // Creates and adds the footnote view, if supplied by the delegate. - void CreateFootnoteView(); - // View implementation. void ChildPreferredSizeChanged(View* child) override; void ChildVisibilityChanged(View* child) override; @@ -93,6 +93,9 @@ class VIEWS_EXPORT DialogClientView : public ClientView, // Returns the insets for the buttons and extra view. gfx::Insets GetButtonRowInsets() const; + // How much to inset the button row. + gfx::Insets button_row_insets_; + // Sets up the focus chain for the child views. This is required since the // delegate may choose to add/remove views at any time. void SetupFocusChain(); @@ -104,9 +107,6 @@ class VIEWS_EXPORT DialogClientView : public ClientView, // The extra view shown in the row of buttons; may be NULL. View* extra_view_; - // The footnote view shown below the buttons; may be NULL. - View* footnote_view_; - // True if we've notified the delegate the window is closing and the delegate // allowed the close. In some situations it's possible to get two closes (see // http://crbug.com/71940). This is used to avoid notifying the delegate diff --git a/ui/views/window/dialog_client_view_unittest.cc b/ui/views/window/dialog_client_view_unittest.cc index 751b21c..f4f72ee 100644 --- a/ui/views/window/dialog_client_view_unittest.cc +++ b/ui/views/window/dialog_client_view_unittest.cc @@ -30,7 +30,6 @@ class TestDialogClientView : public DialogClientView { void CreateExtraViews() { CreateExtraView(); - CreateFootnoteView(); } private: @@ -44,8 +43,7 @@ class DialogClientViewTest : public ViewsTestBase, public: DialogClientViewTest() : dialog_buttons_(ui::DIALOG_BUTTON_NONE), - extra_view_(NULL), - footnote_view_(NULL) {} + extra_view_(nullptr) {} ~DialogClientViewTest() override {} // testing::Test implementation. @@ -65,7 +63,6 @@ class DialogClientViewTest : public ViewsTestBase, *padding = *extra_view_padding_; return extra_view_padding_.get() != nullptr; } - View* CreateFootnoteView() override { return footnote_view_; } int GetDialogButtons() const override { return dialog_buttons_; } protected: @@ -106,13 +103,6 @@ class DialogClientViewTest : public ViewsTestBase, client_view_->Layout(); } - // Sets the footnote view. - void SetFootnoteView(View* view) { - DCHECK(!footnote_view_); - footnote_view_ = view; - client_view_->CreateExtraViews(); - } - TestDialogClientView* client_view() { return client_view_.get(); } private: @@ -124,7 +114,6 @@ class DialogClientViewTest : public ViewsTestBase, int dialog_buttons_; View* extra_view_; // weak scoped_ptr<int> extra_view_padding_; // Null by default. - View* footnote_view_; // weak DISALLOW_COPY_AND_ASSIGN(DialogClientViewTest); }; @@ -256,43 +245,4 @@ TEST_F(DialogClientViewTest, LayoutWithButtons) { EXPECT_GT(width_of_extra_view, extra_view->bounds().width()); } -// Test the effect of the footnote view on layout. -TEST_F(DialogClientViewTest, LayoutWithFootnote) { - CheckContentsIsSetToPreferredSize(); - gfx::Size no_footnote_size = client_view()->bounds().size(); - - View* footnote_view = new StaticSizedView(gfx::Size(200, 200)); - SetFootnoteView(footnote_view); - CheckContentsIsSetToPreferredSize(); - EXPECT_GT(client_view()->bounds().height(), no_footnote_size.height()); - EXPECT_EQ(200, footnote_view->bounds().height()); - gfx::Size with_footnote_size = client_view()->bounds().size(); - EXPECT_EQ(with_footnote_size.width(), footnote_view->bounds().width()); - - SetDialogButtons(ui::DIALOG_BUTTON_CANCEL); - CheckContentsIsSetToPreferredSize(); - EXPECT_LE(with_footnote_size.height(), client_view()->bounds().height()); - EXPECT_LE(with_footnote_size.width(), client_view()->bounds().width()); - gfx::Size with_footnote_and_button_size = client_view()->bounds().size(); - - SetDialogButtons(ui::DIALOG_BUTTON_NONE); - footnote_view->SetVisible(false); - CheckContentsIsSetToPreferredSize(); - EXPECT_EQ(no_footnote_size.height(), client_view()->bounds().height()); - EXPECT_EQ(no_footnote_size.width(), client_view()->bounds().width()); -} - -// Test that GetHeightForWidth is respected for the footnote view. -TEST_F(DialogClientViewTest, LayoutWithFootnoteHeightForWidth) { - CheckContentsIsSetToPreferredSize(); - gfx::Size no_footnote_size = client_view()->bounds().size(); - - View* footnote_view = new ProportionallySizedView(3); - SetFootnoteView(footnote_view); - CheckContentsIsSetToPreferredSize(); - EXPECT_GT(client_view()->bounds().height(), no_footnote_size.height()); - EXPECT_EQ(footnote_view->bounds().width() * 3, - footnote_view->bounds().height()); -} - } // namespace views diff --git a/ui/views/window/dialog_delegate.cc b/ui/views/window/dialog_delegate.cc index e6b179e..a7305d2 100644 --- a/ui/views/window/dialog_delegate.cc +++ b/ui/views/window/dialog_delegate.cc @@ -94,10 +94,6 @@ bool DialogDelegate::GetExtraViewPadding(int* padding) { return false; } -View* DialogDelegate::CreateTitlebarExtraView() { - return NULL; -} - View* DialogDelegate::CreateFootnoteView() { return NULL; } @@ -206,10 +202,8 @@ NonClientFrameView* DialogDelegate::CreateDialogFrameView(Widget* widget) { border->set_use_theme_background_color(true); frame->SetBubbleBorder(std::move(border)); DialogDelegate* delegate = widget->widget_delegate()->AsDialogDelegate(); - if (delegate) { - frame->SetTitlebarExtraView( - make_scoped_ptr(delegate->CreateTitlebarExtraView())); - } + if (delegate) + frame->SetFootnoteView(delegate->CreateFootnoteView()); return frame; } diff --git a/ui/views/window/dialog_delegate.h b/ui/views/window/dialog_delegate.h index 68b1f20..96bb96e 100644 --- a/ui/views/window/dialog_delegate.h +++ b/ui/views/window/dialog_delegate.h @@ -56,11 +56,6 @@ class VIEWS_EXPORT DialogDelegate : public ui::DialogModel, // If a custom padding should be used, returns true and populates |padding|. virtual bool GetExtraViewPadding(int* padding); - // Override this function to display an extra view in the titlebar. - // Overrides may construct the view; this will only be called once per dialog. - // Note: this only works for new style dialogs. - virtual View* CreateTitlebarExtraView(); - // Override this function to display a footnote view below the buttons. // Overrides may construct the view; this will only be called once per dialog. virtual View* CreateFootnoteView(); |
