Commit db178a11 authored by msw@chromium.org's avatar msw@chromium.org

Rebase ConfirmBubbleViews on DialogDelegateView.

This fixes the dialog-like confirm "bubble" class.
(make it a window-modal dialog delegate subclass)
Call new SpellingBubbleModel::SetPref(false) on 'No thanks'.
(clicking ok then cancel in two windows yields feature off)

See pics of the change at http://crbug.com/166075#c31

TODO(followup): Remove ConfirmBubble*? (only used by spelling).
TODO(followup): Fix insets after tweaking the new dialog style.
TODO(followup): Fix dialog 'extra view' placement.

BUG=166075
TEST=Spelling bubble (web textfield context menu -> "Spell-checker options" -> "Ask Google for suggestions") looks/works reasonable on Win/CrOS/Aura.
R=rlp@chromium.org,sky@chromium.org

Review URL: https://chromiumcodereview.appspot.com/12222003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@181975 0039d316-1c4b-4281-b951-d872f2087c98
parent fe1c641a
......@@ -51,14 +51,11 @@ string16 SpellingBubbleModel::GetButtonLabel(BubbleButton button) const {
}
void SpellingBubbleModel::Accept() {
PrefService* pref = profile_->GetPrefs();
DCHECK(pref);
pref->SetBoolean(prefs::kSpellCheckUseSpellingService, true);
if (include_autocorrect_)
pref->SetBoolean(prefs::kEnableAutoSpellCorrect, true);
SetPref(true);
}
void SpellingBubbleModel::Cancel() {
SetPref(false);
}
string16 SpellingBubbleModel::GetLinkText() const {
......@@ -71,3 +68,11 @@ void SpellingBubbleModel::LinkClicked() {
content::PAGE_TRANSITION_LINK, false);
web_contents_->OpenURL(params);
}
void SpellingBubbleModel::SetPref(bool enabled) {
PrefService* pref = profile_->GetPrefs();
DCHECK(pref);
pref->SetBoolean(prefs::kSpellCheckUseSpellingService, enabled);
if (include_autocorrect_)
pref->SetBoolean(prefs::kEnableAutoSpellCorrect, enabled);
}
......@@ -35,6 +35,9 @@ class SpellingBubbleModel : public ConfirmBubbleModel {
virtual void LinkClicked() OVERRIDE;
private:
// Set the profile preferences to enable or disable the feature.
void SetPref(bool enabled);
Profile* profile_;
content::WebContents* web_contents_;
bool include_autocorrect_;
......
......@@ -24,6 +24,8 @@
#include "chrome/common/spellcheck_result.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "content/public/common/context_menu_params.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
......@@ -265,10 +267,14 @@ void SpellingMenuObserver::ExecuteCommand(int command_id) {
if (!integrate_spelling_service_.GetValue()) {
content::RenderViewHost* rvh = proxy_->GetRenderViewHost();
gfx::Rect rect = rvh->GetView()->GetViewBounds();
chrome::ShowConfirmBubble(rvh->GetView()->GetNativeView(),
chrome::ShowConfirmBubble(
#if defined(TOOLKIT_VIEWS)
proxy_->GetWebContents()->GetView()->GetTopLevelNativeWindow(),
#else
rvh->GetView()->GetNativeView(),
#endif
gfx::Point(rect.CenterPoint().x(), rect.y()),
new SpellingBubbleModel(
proxy_->GetProfile(),
new SpellingBubbleModel(proxy_->GetProfile(),
proxy_->GetWebContents(),
false));
} else {
......
......@@ -6,153 +6,103 @@
#include "chrome/browser/ui/confirm_bubble.h"
#include "chrome/browser/ui/confirm_bubble_model.h"
#include "grit/ui_resources.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/image/image.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/button/text_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/link.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/layout/layout_constants.h"
#include "ui/views/widget/widget.h"
namespace {
// Maximum width for the message field. We will wrap the message text when its
// width is wider than this.
const int kMaxMessageWidth = 400;
ConfirmBubbleViews::ConfirmBubbleViews(ConfirmBubbleModel* model)
: model_(model),
link_(NULL) {
views::GridLayout* layout = new views::GridLayout(this);
// TODO(msw): Use layout constants and fix the new-style sizing.
layout->SetInsets(UseNewStyle() ? gfx::Insets(0, 0, 40, 0) :
gfx::Insets(views::kUnrelatedControlVerticalSpacing,
views::kUnrelatedControlHorizontalSpacing,
views::kUnrelatedControlVerticalSpacing,
views::kUnrelatedControlHorizontalSpacing));
SetLayoutManager(layout);
} // namespace
// Use a fixed maximum message width, so longer messages will wrap.
const int kMaxMessageWidth = 400;
views::ColumnSet* cs = layout->AddColumnSet(0);
cs->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, 0,
views::GridLayout::FIXED, kMaxMessageWidth, false);
// Add the message label.
views::Label* label = new views::Label(model_->GetMessageText());
DCHECK(!label->text().empty());
label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
label->SetMultiLine(true);
label->SizeToFit(kMaxMessageWidth);
layout->StartRow(0, 0);
layout->AddView(label);
ConfirmBubbleViews::ConfirmBubbleViews(gfx::NativeView parent,
const gfx::Point& anchor_point,
ConfirmBubbleModel* model)
: BubbleDelegateView(NULL, views::BubbleBorder::NONE),
model_(model) {
DCHECK(model);
set_anchor_point(anchor_point);
set_parent_window(parent);
// Initialize the link.
link_ = new views::Link(model_->GetLinkText());
link_->set_listener(this);
link_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
}
ConfirmBubbleViews::~ConfirmBubbleViews() {
}
void ConfirmBubbleViews::ButtonPressed(views::Button* sender,
const ui::Event& event) {
if (sender->tag() == ConfirmBubbleModel::BUTTON_OK)
model_->Accept();
else if (sender->tag() == ConfirmBubbleModel::BUTTON_CANCEL)
model_->Cancel();
GetWidget()->Close();
string16 ConfirmBubbleViews::GetDialogButtonLabel(
ui::DialogButton button) const {
switch (button) {
case ui::DIALOG_BUTTON_OK:
return model_->GetButtonLabel(ConfirmBubbleModel::BUTTON_OK);
case ui::DIALOG_BUTTON_CANCEL:
return model_->GetButtonLabel(ConfirmBubbleModel::BUTTON_CANCEL);
default:
NOTREACHED();
return DialogDelegateView::GetDialogButtonLabel(button);
}
}
void ConfirmBubbleViews::LinkClicked(views::Link* source, int event_flags) {
model_->LinkClicked();
bool ConfirmBubbleViews::IsDialogButtonEnabled(ui::DialogButton button) const {
return IsDialogButtonVisible(button);
}
gfx::Rect ConfirmBubbleViews::GetAnchorRect() {
return gfx::Rect(anchor_point(), gfx::Size());
bool ConfirmBubbleViews::IsDialogButtonVisible(ui::DialogButton button) const {
switch (button) {
case ui::DIALOG_BUTTON_OK:
return !!(model_->GetButtons() & ConfirmBubbleModel::BUTTON_OK);
case ui::DIALOG_BUTTON_CANCEL:
return !!(model_->GetButtons() & ConfirmBubbleModel::BUTTON_CANCEL);
default:
NOTREACHED();
return false;
}
}
void ConfirmBubbleViews::Init() {
views::GridLayout* layout = new views::GridLayout(this);
SetLayoutManager(layout);
views::View* ConfirmBubbleViews::GetExtraView() {
return link_;
}
// Add the icon, the title label and the close button to the first row.
views::ColumnSet* cs = layout->AddColumnSet(0);
cs->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0,
views::GridLayout::USE_PREF, 0, 0);
cs->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
cs->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0,
views::GridLayout::USE_PREF, 0, 0);
cs->AddPaddingColumn(1, views::kRelatedControlHorizontalSpacing);
cs->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0,
views::GridLayout::USE_PREF, 0, 0);
bool ConfirmBubbleViews::Cancel() {
model_->Cancel();
return true;
}
layout->StartRow(0, 0);
gfx::Image* icon_image = model_->GetIcon();
DCHECK(icon_image);
views::ImageView* icon_view = new views::ImageView;
icon_view->SetImage(icon_image->ToImageSkia());
layout->AddView(icon_view);
const string16 title_text = model_->GetTitle();
DCHECK(!title_text.empty());
views::Label* title_label = new views::Label(title_text);
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
title_label->SetFont(rb.GetFont(ui::ResourceBundle::MediumFont));
layout->AddView(title_label);
views::ImageButton* close_button = new views::ImageButton(this);
close_button->SetImage(views::CustomButton::STATE_NORMAL,
rb.GetImageSkiaNamed(IDR_CLOSE_DIALOG));
close_button->SetImage(views::CustomButton::STATE_HOVERED,
rb.GetImageSkiaNamed(IDR_CLOSE_DIALOG_H));
close_button->SetImage(views::CustomButton::STATE_PRESSED,
rb.GetImageSkiaNamed(IDR_CLOSE_DIALOG_P));
close_button->set_tag(ConfirmBubbleModel::BUTTON_NONE);
layout->AddView(close_button);
layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
// Add the message label to the second row.
cs = layout->AddColumnSet(1);
const string16 message_text = model_->GetMessageText();
DCHECK(!message_text.empty());
views::Label* message_label = new views::Label(message_text);
int message_width =
std::min(kMaxMessageWidth, message_label->GetPreferredSize().width());
cs->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, 0,
views::GridLayout::FIXED, message_width, false);
message_label->SetBounds(0, 0, message_width, 0);
message_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
message_label->SetMultiLine(true);
layout->StartRow(0, 1);
layout->AddView(message_label);
// Add the the link label to the third row if it exists.
const string16 link_text = model_->GetLinkText();
if (!link_text.empty()) {
layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
layout->StartRow(0, 1);
views::Link* link_label = new views::Link(link_text);
link_label->set_listener(this);
layout->AddView(link_label);
}
layout->AddPaddingRow(0, views::kLabelToControlVerticalSpacing);
// Add the ok button and the cancel button to the third (or fourth) row if we
// have either of them.
bool has_ok_button = !!(model_->GetButtons() & ConfirmBubbleModel::BUTTON_OK);
bool has_cancel_button =
!!(model_->GetButtons() & ConfirmBubbleModel::BUTTON_CANCEL);
if (has_ok_button || has_cancel_button) {
cs = layout->AddColumnSet(2);
cs->AddPaddingColumn(1, views::kRelatedControlHorizontalSpacing);
if (has_ok_button) {
cs->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0,
views::GridLayout::USE_PREF, 0, 0);
if (has_cancel_button)
cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
}
if (has_cancel_button) {
cs->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0,
views::GridLayout::USE_PREF, 0, 0);
}
layout->StartRow(0, 2);
if (has_ok_button) {
views::TextButton* ok_button = new views::NativeTextButton(
this, model_->GetButtonLabel(ConfirmBubbleModel::BUTTON_OK));
ok_button->set_tag(ConfirmBubbleModel::BUTTON_OK);
layout->AddView(ok_button);
}
if (has_cancel_button) {
views::TextButton* cancel_button = new views::NativeTextButton(
this, model_->GetButtonLabel(ConfirmBubbleModel::BUTTON_CANCEL));
cancel_button->set_tag(ConfirmBubbleModel::BUTTON_CANCEL);
layout->AddView(cancel_button);
}
bool ConfirmBubbleViews::Accept() {
model_->Accept();
return true;
}
ui::ModalType ConfirmBubbleViews::GetModalType() const {
return ui::MODAL_TYPE_WINDOW;
}
string16 ConfirmBubbleViews::GetWindowTitle() const {
return model_->GetTitle();
}
void ConfirmBubbleViews::LinkClicked(views::Link* source, int event_flags) {
if (source == link_) {
model_->LinkClicked();
GetWidget()->Close();
}
}
......@@ -161,9 +111,8 @@ namespace chrome {
void ShowConfirmBubble(gfx::NativeView view,
const gfx::Point& origin,
ConfirmBubbleModel* model) {
ConfirmBubbleViews* bubble = new ConfirmBubbleViews(view, origin, model);
views::BubbleDelegateView::CreateBubble(bubble);
bubble->Show();
views::DialogDelegateView::CreateDialogWidget(
new ConfirmBubbleViews(model), NULL, view)->Show();
}
} // namespace chrome
......@@ -7,57 +7,49 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "ui/views/bubble/bubble_delegate.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/link_listener.h"
#include "ui/views/window/dialog_delegate.h"
class ConfirmBubbleModel;
// A class that implements a bubble that consists of the following items:
// * one icon ("icon")
// * one title text ("title")
// * one message text ("message")
// * one optional link ("link")
// * two optional buttons ("ok" and "cancel")
//
// This bubble is convenient when we wish to ask transient, non-blocking
// questions. Unlike a dialog, a bubble menu disappears when we click outside of
// its window to avoid blocking user operations. A bubble is laid out as
// follows:
//
// A dialog (with the standard Title/(x)/[OK]/[Cancel] UI elements), as well as
// a message Label and optional Link. The dialog ultimately appears like this:
// +------------------------+
// | icon title x |
// | message |
// | link |
// | [OK] [Cancel] |
// | Title (x) |
// | Label |
// | Link [OK] [Cancel] |
// +------------------------+
//
class ConfirmBubbleViews : public views::BubbleDelegateView,
public views::ButtonListener,
// TODO(msw): Remove this class or merge it with DialogDelegateView.
class ConfirmBubbleViews : public views::DialogDelegateView,
public views::LinkListener {
public:
ConfirmBubbleViews(gfx::NativeView parent,
const gfx::Point& anchor_point,
ConfirmBubbleModel* model);
explicit ConfirmBubbleViews(ConfirmBubbleModel* model);
protected:
virtual ~ConfirmBubbleViews();
// views::ButtonListener implementation.
virtual void ButtonPressed(views::Button* sender,
const ui::Event& event) OVERRIDE;
// views::DialogDelegate implementation.
virtual string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE;
virtual bool IsDialogButtonEnabled(ui::DialogButton button) const OVERRIDE;
virtual bool IsDialogButtonVisible(ui::DialogButton button) const OVERRIDE;
virtual views::View* GetExtraView() OVERRIDE;
virtual bool Cancel() OVERRIDE;
virtual bool Accept() OVERRIDE;
// views::WidgetDelegate implementation.
virtual ui::ModalType GetModalType() const OVERRIDE;
virtual string16 GetWindowTitle() const OVERRIDE;
// views::LinkListener implementation.
virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
// views::BubbleDelegateView implementation.
virtual gfx::Rect GetAnchorRect() OVERRIDE;
virtual void Init() OVERRIDE;
private:
// The model to customize this bubble view.
scoped_ptr<ConfirmBubbleModel> model_;
views::Link* link_;
DISALLOW_COPY_AND_ASSIGN(ConfirmBubbleViews);
};
......
......@@ -26,17 +26,9 @@ TEST_F(ConfirmBubbleViewsTest, CreateAndClose) {
bool model_deleted = false;
TestConfirmBubbleModel* model =
new TestConfirmBubbleModel(&model_deleted, NULL, NULL, NULL);
ConfirmBubbleViews* bubble =
new ConfirmBubbleViews(parent_widget->GetNativeView(),
gfx::Point(12, 34),
model);
views::BubbleDelegateView::CreateBubble(bubble);
bubble->Show();
// We're anchored to a point, not a specific view or widget.
EXPECT_EQ("12,34", bubble->anchor_point().ToString());
EXPECT_FALSE(bubble->anchor_view());
EXPECT_FALSE(bubble->anchor_widget());
ConfirmBubbleViews* bubble = new ConfirmBubbleViews(model);
gfx::NativeView parent = parent_widget->GetNativeView();
views::DialogDelegateView::CreateDialogWidget(bubble, NULL, parent)->Show();
// Clean up.
bubble->GetWidget()->CloseNow();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment