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 virtual ~TestDialog() {}
29 // DialogDelegateView overrides:
30 virtual bool Cancel() OVERRIDE
{
34 virtual bool Accept() OVERRIDE
{
39 // DialogDelegateView overrides:
40 virtual gfx::Size
GetPreferredSize() const OVERRIDE
{
41 return gfx::Size(200, 200);
43 virtual base::string16
GetWindowTitle() const OVERRIDE
{ return title_
; }
44 virtual bool UseNewStyleForThisDialog() const OVERRIDE
{ return true; }
46 // ButtonListener override:
47 virtual void ButtonPressed(Button
* sender
, const ui::Event
& event
) OVERRIDE
{
48 last_pressed_button_
= sender
;
51 Button
* last_pressed_button() const { return last_pressed_button_
; }
53 void PressEnterAndCheckStates(Button
* button
) {
54 ui::KeyEvent
key_event(ui::ET_KEY_PRESSED
, ui::VKEY_RETURN
, ui::EF_NONE
);
55 GetFocusManager()->OnKeyEvent(key_event
);
56 const DialogClientView
* client_view
= GetDialogClientView();
57 EXPECT_EQ(canceled_
, client_view
->cancel_button()->is_default());
58 EXPECT_EQ(accepted_
, client_view
->ok_button()->is_default());
59 // This view does not listen for ok or cancel clicks, DialogClientView does.
60 CheckAndResetStates(button
== client_view
->cancel_button(),
61 button
== client_view
->ok_button(),
62 (canceled_
|| accepted_
) ? NULL
: button
);
65 void CheckAndResetStates(bool canceled
, bool accepted
, Button
* last_pressed
) {
66 EXPECT_EQ(canceled
, canceled_
);
68 EXPECT_EQ(accepted
, accepted_
);
70 EXPECT_EQ(last_pressed
, last_pressed_button_
);
71 last_pressed_button_
= NULL
;
79 void set_title(const base::string16
& title
) { title_
= title
; }
84 // Prevent the dialog from closing, for repeated ok and cancel button clicks.
86 Button
* last_pressed_button_
;
87 base::string16 title_
;
89 DISALLOW_COPY_AND_ASSIGN(TestDialog
);
92 class DialogTest
: public ViewsTestBase
{
94 DialogTest() : dialog_(NULL
) {}
95 virtual ~DialogTest() {}
97 virtual void SetUp() OVERRIDE
{
98 ViewsTestBase::SetUp();
99 dialog_
= new TestDialog();
100 DialogDelegate::CreateDialogWidget(dialog_
, GetContext(), NULL
)->Show();
103 virtual void TearDown() OVERRIDE
{
105 ViewsTestBase::TearDown();
108 TestDialog
* dialog() const { return dialog_
; }
113 DISALLOW_COPY_AND_ASSIGN(DialogTest
);
118 TEST_F(DialogTest
, DefaultButtons
) {
119 DialogClientView
* client_view
= dialog()->GetDialogClientView();
120 LabelButton
* ok_button
= client_view
->ok_button();
122 // DialogDelegate's default button (ok) should be default (and handle enter).
123 EXPECT_EQ(ui::DIALOG_BUTTON_OK
, dialog()->GetDefaultDialogButton());
124 dialog()->PressEnterAndCheckStates(ok_button
);
126 // Focus another button in the dialog, it should become the default.
127 LabelButton
* button_1
= new LabelButton(dialog(), base::string16());
128 client_view
->AddChildView(button_1
);
129 client_view
->OnWillChangeFocus(ok_button
, button_1
);
130 EXPECT_TRUE(button_1
->is_default());
131 dialog()->PressEnterAndCheckStates(button_1
);
133 // Focus a Checkbox (not a push button), OK should become the default again.
134 Checkbox
* checkbox
= new Checkbox(base::string16());
135 client_view
->AddChildView(checkbox
);
136 client_view
->OnWillChangeFocus(button_1
, checkbox
);
137 EXPECT_FALSE(button_1
->is_default());
138 dialog()->PressEnterAndCheckStates(ok_button
);
140 // Focus yet another button in the dialog, it should become the default.
141 LabelButton
* button_2
= new LabelButton(dialog(), base::string16());
142 client_view
->AddChildView(button_2
);
143 client_view
->OnWillChangeFocus(checkbox
, button_2
);
144 EXPECT_FALSE(button_1
->is_default());
145 EXPECT_TRUE(button_2
->is_default());
146 dialog()->PressEnterAndCheckStates(button_2
);
148 // Focus nothing, OK should become the default again.
149 client_view
->OnWillChangeFocus(button_2
, NULL
);
150 EXPECT_FALSE(button_1
->is_default());
151 EXPECT_FALSE(button_2
->is_default());
152 dialog()->PressEnterAndCheckStates(ok_button
);
155 TEST_F(DialogTest
, AcceptAndCancel
) {
156 DialogClientView
* client_view
= dialog()->GetDialogClientView();
157 LabelButton
* ok_button
= client_view
->ok_button();
158 LabelButton
* cancel_button
= client_view
->cancel_button();
160 // Check that return/escape accelerators accept/cancel dialogs.
161 const ui::KeyEvent
return_key(
162 ui::ET_KEY_PRESSED
, ui::VKEY_RETURN
, ui::EF_NONE
);
163 dialog()->GetFocusManager()->OnKeyEvent(return_key
);
164 dialog()->CheckAndResetStates(false, true, NULL
);
165 const ui::KeyEvent
escape_key(
166 ui::ET_KEY_PRESSED
, ui::VKEY_ESCAPE
, ui::EF_NONE
);
167 dialog()->GetFocusManager()->OnKeyEvent(escape_key
);
168 dialog()->CheckAndResetStates(true, false, NULL
);
170 // Check ok and cancel button behavior on a directed return key events.
171 ok_button
->OnKeyPressed(return_key
);
172 dialog()->CheckAndResetStates(false, true, NULL
);
173 cancel_button
->OnKeyPressed(return_key
);
174 dialog()->CheckAndResetStates(true, false, NULL
);
176 // Check that return accelerators cancel dialogs if cancel is focused.
177 cancel_button
->RequestFocus();
178 dialog()->GetFocusManager()->OnKeyEvent(return_key
);
179 dialog()->CheckAndResetStates(true, false, NULL
);
182 TEST_F(DialogTest
, RemoveDefaultButton
) {
183 // Removing buttons from the dialog here should not cause a crash on close.
184 delete dialog()->GetDialogClientView()->ok_button();
185 delete dialog()->GetDialogClientView()->cancel_button();
188 TEST_F(DialogTest
, HitTest
) {
189 // Ensure that the new style's BubbleFrameView hit-tests as expected.
190 const NonClientView
* view
= dialog()->GetWidget()->non_client_view();
191 BubbleFrameView
* frame
= static_cast<BubbleFrameView
*>(view
->frame_view());
192 const int border
= frame
->bubble_border()->GetBorderThickness();
198 { border
, HTSYSMENU
},
199 { border
+ 10, HTSYSMENU
},
200 { border
+ 20, HTCAPTION
},
201 { border
+ 40, HTCLIENT
},
202 { border
+ 50, HTCLIENT
},
206 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(cases
); ++i
) {
207 gfx::Point
point(cases
[i
].point
, cases
[i
].point
);
208 EXPECT_EQ(cases
[i
].hit
, frame
->NonClientHitTest(point
))
209 << " with border: " << border
<< ", at point " << cases
[i
].point
;
213 TEST_F(DialogTest
, BoundsAccommodateTitle
) {
214 TestDialog
* dialog2(new TestDialog());
215 dialog2
->set_title(base::ASCIIToUTF16("Title"));
216 DialogDelegate::CreateDialogWidget(dialog2
, GetContext(), NULL
);
218 // Titled dialogs have taller initial frame bounds than untitled dialogs.
219 View
* frame1
= dialog()->GetWidget()->non_client_view()->frame_view();
220 View
* frame2
= dialog2
->GetWidget()->non_client_view()->frame_view();
221 EXPECT_LT(frame1
->GetPreferredSize().height(),
222 frame2
->GetPreferredSize().height());
224 // Giving the default test dialog a title will yield the same bounds.
225 dialog()->set_title(base::ASCIIToUTF16("Title"));
226 dialog()->GetWidget()->UpdateWindowTitle();
227 EXPECT_EQ(frame1
->GetPreferredSize().height(),
228 frame2
->GetPreferredSize().height());