1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/strings/utf_string_conversions.h"
6 #include "ui/base/hit_test.h"
7 #include "ui/views/bubble/bubble_border.h"
8 #include "ui/views/bubble/bubble_frame_view.h"
9 #include "ui/views/controls/button/checkbox.h"
10 #include "ui/views/controls/button/label_button.h"
11 #include "ui/views/test/views_test_base.h"
12 #include "ui/views/widget/widget.h"
13 #include "ui/views/window/dialog_client_view.h"
14 #include "ui/views/window/dialog_delegate.h"
20 class TestDialog
: public DialogDelegateView
, public ButtonListener
{
26 last_pressed_button_(NULL
) {}
27 ~TestDialog() override
{}
29 // DialogDelegateView overrides:
30 bool Cancel() override
{
34 bool Accept() override
{
39 // DialogDelegateView overrides:
40 gfx::Size
GetPreferredSize() const override
{ return gfx::Size(200, 200); }
41 base::string16
GetWindowTitle() const override
{ return title_
; }
42 bool UseNewStyleForThisDialog() const override
{ return true; }
44 // ButtonListener override:
45 void ButtonPressed(Button
* sender
, const ui::Event
& event
) override
{
46 last_pressed_button_
= sender
;
49 Button
* last_pressed_button() const { return last_pressed_button_
; }
51 void PressEnterAndCheckStates(Button
* button
) {
52 ui::KeyEvent
key_event(ui::ET_KEY_PRESSED
, ui::VKEY_RETURN
, ui::EF_NONE
);
53 GetFocusManager()->OnKeyEvent(key_event
);
54 const DialogClientView
* client_view
= GetDialogClientView();
55 EXPECT_EQ(canceled_
, client_view
->cancel_button()->is_default());
56 EXPECT_EQ(accepted_
, client_view
->ok_button()->is_default());
57 // This view does not listen for ok or cancel clicks, DialogClientView does.
58 CheckAndResetStates(button
== client_view
->cancel_button(),
59 button
== client_view
->ok_button(),
60 (canceled_
|| accepted_
) ? NULL
: button
);
63 void CheckAndResetStates(bool canceled
, bool accepted
, Button
* last_pressed
) {
64 EXPECT_EQ(canceled
, canceled_
);
66 EXPECT_EQ(accepted
, accepted_
);
68 EXPECT_EQ(last_pressed
, last_pressed_button_
);
69 last_pressed_button_
= NULL
;
77 void set_title(const base::string16
& title
) { title_
= title
; }
82 // Prevent the dialog from closing, for repeated ok and cancel button clicks.
84 Button
* last_pressed_button_
;
85 base::string16 title_
;
87 DISALLOW_COPY_AND_ASSIGN(TestDialog
);
90 class DialogTest
: public ViewsTestBase
{
92 DialogTest() : dialog_(NULL
) {}
93 ~DialogTest() override
{}
95 void SetUp() override
{
96 ViewsTestBase::SetUp();
97 dialog_
= new TestDialog();
98 DialogDelegate::CreateDialogWidget(dialog_
, GetContext(), NULL
)->Show();
101 void TearDown() override
{
103 ViewsTestBase::TearDown();
106 TestDialog
* dialog() const { return dialog_
; }
111 DISALLOW_COPY_AND_ASSIGN(DialogTest
);
116 TEST_F(DialogTest
, DefaultButtons
) {
117 DialogClientView
* client_view
= dialog()->GetDialogClientView();
118 LabelButton
* ok_button
= client_view
->ok_button();
120 // DialogDelegate's default button (ok) should be default (and handle enter).
121 EXPECT_EQ(ui::DIALOG_BUTTON_OK
, dialog()->GetDefaultDialogButton());
122 dialog()->PressEnterAndCheckStates(ok_button
);
124 // Focus another button in the dialog, it should become the default.
125 LabelButton
* button_1
= new LabelButton(dialog(), base::string16());
126 client_view
->AddChildView(button_1
);
127 client_view
->OnWillChangeFocus(ok_button
, button_1
);
128 EXPECT_TRUE(button_1
->is_default());
129 dialog()->PressEnterAndCheckStates(button_1
);
131 // Focus a Checkbox (not a push button), OK should become the default again.
132 Checkbox
* checkbox
= new Checkbox(base::string16());
133 client_view
->AddChildView(checkbox
);
134 client_view
->OnWillChangeFocus(button_1
, checkbox
);
135 EXPECT_FALSE(button_1
->is_default());
136 dialog()->PressEnterAndCheckStates(ok_button
);
138 // Focus yet another button in the dialog, it should become the default.
139 LabelButton
* button_2
= new LabelButton(dialog(), base::string16());
140 client_view
->AddChildView(button_2
);
141 client_view
->OnWillChangeFocus(checkbox
, button_2
);
142 EXPECT_FALSE(button_1
->is_default());
143 EXPECT_TRUE(button_2
->is_default());
144 dialog()->PressEnterAndCheckStates(button_2
);
146 // Focus nothing, OK should become the default again.
147 client_view
->OnWillChangeFocus(button_2
, NULL
);
148 EXPECT_FALSE(button_1
->is_default());
149 EXPECT_FALSE(button_2
->is_default());
150 dialog()->PressEnterAndCheckStates(ok_button
);
153 TEST_F(DialogTest
, AcceptAndCancel
) {
154 DialogClientView
* client_view
= dialog()->GetDialogClientView();
155 LabelButton
* ok_button
= client_view
->ok_button();
156 LabelButton
* cancel_button
= client_view
->cancel_button();
158 // Check that return/escape accelerators accept/cancel dialogs.
159 const ui::KeyEvent
return_key(
160 ui::ET_KEY_PRESSED
, ui::VKEY_RETURN
, ui::EF_NONE
);
161 dialog()->GetFocusManager()->OnKeyEvent(return_key
);
162 dialog()->CheckAndResetStates(false, true, NULL
);
163 const ui::KeyEvent
escape_key(
164 ui::ET_KEY_PRESSED
, ui::VKEY_ESCAPE
, ui::EF_NONE
);
165 dialog()->GetFocusManager()->OnKeyEvent(escape_key
);
166 dialog()->CheckAndResetStates(true, false, NULL
);
168 // Check ok and cancel button behavior on a directed return key events.
169 ok_button
->OnKeyPressed(return_key
);
170 dialog()->CheckAndResetStates(false, true, NULL
);
171 cancel_button
->OnKeyPressed(return_key
);
172 dialog()->CheckAndResetStates(true, false, NULL
);
174 // Check that return accelerators cancel dialogs if cancel is focused.
175 cancel_button
->RequestFocus();
176 dialog()->GetFocusManager()->OnKeyEvent(return_key
);
177 dialog()->CheckAndResetStates(true, false, NULL
);
180 TEST_F(DialogTest
, RemoveDefaultButton
) {
181 // Removing buttons from the dialog here should not cause a crash on close.
182 delete dialog()->GetDialogClientView()->ok_button();
183 delete dialog()->GetDialogClientView()->cancel_button();
186 TEST_F(DialogTest
, HitTest
) {
187 // Ensure that the new style's BubbleFrameView hit-tests as expected.
188 const NonClientView
* view
= dialog()->GetWidget()->non_client_view();
189 BubbleFrameView
* frame
= static_cast<BubbleFrameView
*>(view
->frame_view());
190 const int border
= frame
->bubble_border()->GetBorderThickness();
196 { border
, HTSYSMENU
},
197 { border
+ 10, HTSYSMENU
},
198 { border
+ 20, HTCAPTION
},
199 { border
+ 40, HTCLIENT
},
200 { border
+ 50, HTCLIENT
},
204 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
205 gfx::Point
point(cases
[i
].point
, cases
[i
].point
);
206 EXPECT_EQ(cases
[i
].hit
, frame
->NonClientHitTest(point
))
207 << " with border: " << border
<< ", at point " << cases
[i
].point
;
211 TEST_F(DialogTest
, BoundsAccommodateTitle
) {
212 TestDialog
* dialog2(new TestDialog());
213 dialog2
->set_title(base::ASCIIToUTF16("Title"));
214 DialogDelegate::CreateDialogWidget(dialog2
, GetContext(), NULL
);
216 // Titled dialogs have taller initial frame bounds than untitled dialogs.
217 View
* frame1
= dialog()->GetWidget()->non_client_view()->frame_view();
218 View
* frame2
= dialog2
->GetWidget()->non_client_view()->frame_view();
219 EXPECT_LT(frame1
->GetPreferredSize().height(),
220 frame2
->GetPreferredSize().height());
222 // Giving the default test dialog a title will yield the same bounds.
223 dialog()->set_title(base::ASCIIToUTF16("Title"));
224 dialog()->GetWidget()->UpdateWindowTitle();
225 EXPECT_EQ(frame1
->GetPreferredSize().height(),
226 frame2
->GetPreferredSize().height());