summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorestade <estade@chromium.org>2016-03-01 12:16:31 -0800
committerCommit bot <commit-bot@chromium.org>2016-03-01 20:17:42 +0000
commit4c499dc1bed6d263ffd30dff5e9abab76ffc6094 (patch)
treef38e3cc00f63a142aef3397feb4b992c50b5d1e3
parent50b71b0f0e8bafb497ec8eea9bc491cb55479233 (diff)
downloadchromium_src-4c499dc1bed6d263ffd30dff5e9abab76ffc6094.zip
chromium_src-4c499dc1bed6d263ffd30dff5e9abab76ffc6094.tar.gz
chromium_src-4c499dc1bed6d263ffd30dff5e9abab76ffc6094.tar.bz2
Introduce BubbleDialogDelegateView, which extends DialogDelegateView
and shares more code with it than BubbleDelegateView. The idea is to eventually replace BubbleDelegateView. I'd just have modified BubbleDelegateView in place, but it requires updates to many bubbles, so the two classes coexist for now. This CL also removes redundant code in DialogClientView for laying out the footnote view. I verified this doesn't affect the one place that was using the code (CardUnmaskPromptViews). SessionCrashedBubbleView is the only bubble using the new parent class so far. It got a bit simpler because it didn't have to reimplement the button strip. BUG=585312 Review URL: https://codereview.chromium.org/1717453003 Cr-Commit-Position: refs/heads/master@{#378545}
-rw-r--r--chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc4
-rw-r--r--chrome/browser/ui/views/autofill/card_unmask_prompt_views.h21
-rw-r--r--chrome/browser/ui/views/autofill/save_card_bubble_views.cc4
-rw-r--r--chrome/browser/ui/views/autofill/save_card_bubble_views.h2
-rw-r--r--chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc7
-rw-r--r--chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h4
-rw-r--r--chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc5
-rw-r--r--chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc8
-rw-r--r--chrome/browser/ui/views/extensions/extension_installed_bubble_view.h2
-rw-r--r--chrome/browser/ui/views/session_crashed_bubble_view.cc74
-rw-r--r--chrome/browser/ui/views/session_crashed_bubble_view.h35
-rw-r--r--ui/views/bubble/bubble_delegate.cc2
-rw-r--r--ui/views/bubble/bubble_delegate.h3
-rw-r--r--ui/views/bubble/bubble_dialog_delegate.cc341
-rw-r--r--ui/views/bubble/bubble_dialog_delegate.h215
-rw-r--r--ui/views/bubble/bubble_frame_view.cc35
-rw-r--r--ui/views/bubble/bubble_frame_view.h9
-rw-r--r--ui/views/examples/widget_example.cc7
-rw-r--r--ui/views/views.gyp2
-rw-r--r--ui/views/window/dialog_client_view.cc54
-rw-r--r--ui/views/window/dialog_client_view.h20
-rw-r--r--ui/views/window/dialog_client_view_unittest.cc52
-rw-r--r--ui/views/window/dialog_delegate.cc10
-rw-r--r--ui/views/window/dialog_delegate.h5
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();