Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Side by Side Diff: ui/views/window/dialog_delegate_unittest.cc

Issue 2604303002: (Mac)Views: Widgets focus first View in traversal order if initial focus fails. (Closed)
Patch Set: Fix compile error. Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/views/widget/widget.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <stddef.h> 5 #include <stddef.h>
6 6
7 #include "base/macros.h" 7 #include "base/macros.h"
8 #include "base/strings/utf_string_conversions.h" 8 #include "base/strings/utf_string_conversions.h"
9 #include "ui/base/hit_test.h" 9 #include "ui/base/hit_test.h"
10 #include "ui/events/event_processor.h" 10 #include "ui/events/event_processor.h"
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
42 // not dependent on the order of AddAccelerator calls. 42 // not dependent on the order of AddAccelerator calls.
43 EXPECT_FALSE(GetWidget()); 43 EXPECT_FALSE(GetWidget());
44 AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); 44 AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
45 } 45 }
46 46
47 // WidgetDelegate overrides: 47 // WidgetDelegate overrides:
48 bool ShouldShowWindowTitle() const override { 48 bool ShouldShowWindowTitle() const override {
49 return !title_.empty(); 49 return !title_.empty();
50 } 50 }
51 51
52 bool ShouldShowCloseButton() const override { return false; }
53
52 // DialogDelegateView overrides: 54 // DialogDelegateView overrides:
53 bool Cancel() override { 55 bool Cancel() override {
54 canceled_ = true; 56 canceled_ = true;
55 return closeable_; 57 return closeable_;
56 } 58 }
57 bool Accept() override { 59 bool Accept() override {
58 accepted_ = true; 60 accepted_ = true;
59 return closeable_; 61 return closeable_;
60 } 62 }
61 bool Close() override { 63 bool Close() override {
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 123
122 class DialogTest : public ViewsTestBase { 124 class DialogTest : public ViewsTestBase {
123 public: 125 public:
124 DialogTest() : dialog_(nullptr) {} 126 DialogTest() : dialog_(nullptr) {}
125 ~DialogTest() override {} 127 ~DialogTest() override {}
126 128
127 void SetUp() override { 129 void SetUp() override {
128 ViewsTestBase::SetUp(); 130 ViewsTestBase::SetUp();
129 dialog_ = new TestDialog(); 131 dialog_ = new TestDialog();
130 dialog_->Init(); 132 dialog_->Init();
131 DialogDelegate::CreateDialogWidget(dialog_, GetContext(), nullptr)->Show(); 133 DialogDelegate::CreateDialogWidget(dialog_, GetContext(), nullptr);
132 } 134 }
133 135
134 void TearDown() override { 136 void TearDown() override {
135 dialog_->TearDown(); 137 dialog_->TearDown();
136 ViewsTestBase::TearDown(); 138 ViewsTestBase::TearDown();
137 } 139 }
138 140
139 void SimulateKeyEvent(const ui::KeyEvent& event) { 141 void SimulateKeyEvent(const ui::KeyEvent& event) {
140 ui::KeyEvent event_copy = event; 142 ui::KeyEvent event_copy = event;
141 if (dialog()->GetFocusManager()->OnKeyEvent(event_copy)) 143 if (dialog()->GetFocusManager()->OnKeyEvent(event_copy))
142 dialog()->GetWidget()->OnKeyEvent(&event_copy); 144 dialog()->GetWidget()->OnKeyEvent(&event_copy);
143 } 145 }
144 146
147 void ShowDialog() { dialog()->GetWidget()->Show(); }
148
145 TestDialog* dialog() const { return dialog_; } 149 TestDialog* dialog() const { return dialog_; }
146 150
147 private: 151 private:
148 TestDialog* dialog_; 152 TestDialog* dialog_;
149 153
150 DISALLOW_COPY_AND_ASSIGN(DialogTest); 154 DISALLOW_COPY_AND_ASSIGN(DialogTest);
151 }; 155 };
152 156
153 } // namespace 157 } // namespace
154 158
155 TEST_F(DialogTest, AcceptAndCancel) { 159 TEST_F(DialogTest, AcceptAndCancel) {
160 ShowDialog();
156 DialogClientView* client_view = dialog()->GetDialogClientView(); 161 DialogClientView* client_view = dialog()->GetDialogClientView();
157 LabelButton* ok_button = client_view->ok_button(); 162 LabelButton* ok_button = client_view->ok_button();
158 LabelButton* cancel_button = client_view->cancel_button(); 163 LabelButton* cancel_button = client_view->cancel_button();
159 164
160 // Check that return/escape accelerators accept/close dialogs. 165 // Check that return/escape accelerators accept/close dialogs.
161 EXPECT_EQ(dialog()->input(), dialog()->GetFocusManager()->GetFocusedView()); 166 EXPECT_EQ(dialog()->input(), dialog()->GetFocusManager()->GetFocusedView());
162 const ui::KeyEvent return_event( 167 const ui::KeyEvent return_event(
163 ui::ET_KEY_PRESSED, ui::VKEY_RETURN, ui::EF_NONE); 168 ui::ET_KEY_PRESSED, ui::VKEY_RETURN, ui::EF_NONE);
164 SimulateKeyEvent(return_event); 169 SimulateKeyEvent(return_event);
165 dialog()->CheckAndResetStates(false, true, false, nullptr); 170 dialog()->CheckAndResetStates(false, true, false, nullptr);
(...skipping 14 matching lines...) Expand all
180 SimulateKeyEvent(return_event); 185 SimulateKeyEvent(return_event);
181 dialog()->CheckAndResetStates(true, false, false, nullptr); 186 dialog()->CheckAndResetStates(true, false, false, nullptr);
182 187
183 // Check that escape can be overridden. 188 // Check that escape can be overridden.
184 dialog()->set_should_handle_escape(true); 189 dialog()->set_should_handle_escape(true);
185 SimulateKeyEvent(escape_event); 190 SimulateKeyEvent(escape_event);
186 dialog()->CheckAndResetStates(false, false, false, nullptr); 191 dialog()->CheckAndResetStates(false, false, false, nullptr);
187 } 192 }
188 193
189 TEST_F(DialogTest, RemoveDefaultButton) { 194 TEST_F(DialogTest, RemoveDefaultButton) {
195 ShowDialog();
190 // Removing buttons from the dialog here should not cause a crash on close. 196 // Removing buttons from the dialog here should not cause a crash on close.
191 delete dialog()->GetDialogClientView()->ok_button(); 197 delete dialog()->GetDialogClientView()->ok_button();
192 delete dialog()->GetDialogClientView()->cancel_button(); 198 delete dialog()->GetDialogClientView()->cancel_button();
193 } 199 }
194 200
195 TEST_F(DialogTest, HitTest_HiddenTitle) { 201 TEST_F(DialogTest, HitTest_HiddenTitle) {
202 ShowDialog();
196 // Ensure that BubbleFrameView hit-tests as expected when the title is hidden. 203 // Ensure that BubbleFrameView hit-tests as expected when the title is hidden.
197 const NonClientView* view = dialog()->GetWidget()->non_client_view(); 204 const NonClientView* view = dialog()->GetWidget()->non_client_view();
198 BubbleFrameView* frame = static_cast<BubbleFrameView*>(view->frame_view()); 205 BubbleFrameView* frame = static_cast<BubbleFrameView*>(view->frame_view());
199 const int border = frame->bubble_border()->GetBorderThickness(); 206 const int border = frame->bubble_border()->GetBorderThickness();
200 207
201 struct { 208 struct {
202 const int point; 209 const int point;
203 const int hit; 210 const int hit;
204 } cases[] = { 211 } cases[] = {
205 { border, HTSYSMENU }, 212 { border, HTSYSMENU },
206 { border + 10, HTSYSMENU }, 213 { border + 10, HTSYSMENU },
207 { border + 20, HTCLIENT }, 214 { border + 20, HTCLIENT },
208 { border + 50, HTCLIENT }, 215 { border + 50, HTCLIENT },
209 { border + 60, HTCLIENT }, 216 { border + 60, HTCLIENT },
210 { 1000, HTNOWHERE }, 217 { 1000, HTNOWHERE },
211 }; 218 };
212 219
213 for (size_t i = 0; i < arraysize(cases); ++i) { 220 for (size_t i = 0; i < arraysize(cases); ++i) {
214 gfx::Point point(cases[i].point, cases[i].point); 221 gfx::Point point(cases[i].point, cases[i].point);
215 EXPECT_EQ(cases[i].hit, frame->NonClientHitTest(point)) 222 EXPECT_EQ(cases[i].hit, frame->NonClientHitTest(point))
216 << " case " << i << " with border: " << border << ", at point " 223 << " case " << i << " with border: " << border << ", at point "
217 << cases[i].point; 224 << cases[i].point;
218 } 225 }
219 } 226 }
220 227
221 TEST_F(DialogTest, HitTest_WithTitle) { 228 TEST_F(DialogTest, HitTest_WithTitle) {
229 ShowDialog();
222 // Ensure that BubbleFrameView hit-tests as expected when the title is shown. 230 // Ensure that BubbleFrameView hit-tests as expected when the title is shown.
223 const NonClientView* view = dialog()->GetWidget()->non_client_view(); 231 const NonClientView* view = dialog()->GetWidget()->non_client_view();
224 dialog()->set_title(base::ASCIIToUTF16("Title")); 232 dialog()->set_title(base::ASCIIToUTF16("Title"));
225 dialog()->GetWidget()->UpdateWindowTitle(); 233 dialog()->GetWidget()->UpdateWindowTitle();
226 BubbleFrameView* frame = static_cast<BubbleFrameView*>(view->frame_view()); 234 BubbleFrameView* frame = static_cast<BubbleFrameView*>(view->frame_view());
227 const int border = frame->bubble_border()->GetBorderThickness(); 235 const int border = frame->bubble_border()->GetBorderThickness();
228 236
229 struct { 237 struct {
230 const int point; 238 const int point;
231 const int hit; 239 const int hit;
232 } cases[] = { 240 } cases[] = {
233 { border, HTSYSMENU }, 241 { border, HTSYSMENU },
234 { border + 10, HTSYSMENU }, 242 { border + 10, HTSYSMENU },
235 { border + 20, HTCAPTION }, 243 { border + 20, HTCAPTION },
236 { border + 50, HTCLIENT }, 244 { border + 50, HTCLIENT },
237 { border + 60, HTCLIENT }, 245 { border + 60, HTCLIENT },
238 { 1000, HTNOWHERE }, 246 { 1000, HTNOWHERE },
239 }; 247 };
240 248
241 for (size_t i = 0; i < arraysize(cases); ++i) { 249 for (size_t i = 0; i < arraysize(cases); ++i) {
242 gfx::Point point(cases[i].point, cases[i].point); 250 gfx::Point point(cases[i].point, cases[i].point);
243 EXPECT_EQ(cases[i].hit, frame->NonClientHitTest(point)) 251 EXPECT_EQ(cases[i].hit, frame->NonClientHitTest(point))
244 << " with border: " << border << ", at point " << cases[i].point; 252 << " with border: " << border << ", at point " << cases[i].point;
245 } 253 }
246 } 254 }
247 255
248 TEST_F(DialogTest, BoundsAccommodateTitle) { 256 TEST_F(DialogTest, BoundsAccommodateTitle) {
257 ShowDialog();
249 TestDialog* dialog2(new TestDialog()); 258 TestDialog* dialog2(new TestDialog());
250 dialog2->set_title(base::ASCIIToUTF16("Title")); 259 dialog2->set_title(base::ASCIIToUTF16("Title"));
251 DialogDelegate::CreateDialogWidget(dialog2, GetContext(), nullptr); 260 DialogDelegate::CreateDialogWidget(dialog2, GetContext(), nullptr);
252 261
253 // Titled dialogs have taller initial frame bounds than untitled dialogs. 262 // Titled dialogs have taller initial frame bounds than untitled dialogs.
254 View* frame1 = dialog()->GetWidget()->non_client_view()->frame_view(); 263 View* frame1 = dialog()->GetWidget()->non_client_view()->frame_view();
255 View* frame2 = dialog2->GetWidget()->non_client_view()->frame_view(); 264 View* frame2 = dialog2->GetWidget()->non_client_view()->frame_view();
256 EXPECT_LT(frame1->GetPreferredSize().height(), 265 EXPECT_LT(frame1->GetPreferredSize().height(),
257 frame2->GetPreferredSize().height()); 266 frame2->GetPreferredSize().height());
258 267
259 // Giving the default test dialog a title will yield the same bounds. 268 // Giving the default test dialog a title will yield the same bounds.
260 dialog()->set_title(base::ASCIIToUTF16("Title")); 269 dialog()->set_title(base::ASCIIToUTF16("Title"));
261 dialog()->GetWidget()->UpdateWindowTitle(); 270 dialog()->GetWidget()->UpdateWindowTitle();
262 EXPECT_EQ(frame1->GetPreferredSize().height(), 271 EXPECT_EQ(frame1->GetPreferredSize().height(),
263 frame2->GetPreferredSize().height()); 272 frame2->GetPreferredSize().height());
264 273
265 dialog2->TearDown(); 274 dialog2->TearDown();
266 } 275 }
267 276
268 // Tests default focus is assigned correctly when showing a new dialog. 277 // Tests default focus is assigned correctly when showing a new dialog.
269 TEST_F(DialogTest, InitialFocus) { 278 TEST_F(DialogTest, InitialFocus) {
279 ShowDialog();
270 EXPECT_TRUE(dialog()->input()->HasFocus()); 280 EXPECT_TRUE(dialog()->input()->HasFocus());
271 EXPECT_EQ(dialog()->input(), dialog()->GetFocusManager()->GetFocusedView()); 281 EXPECT_EQ(dialog()->input(), dialog()->GetFocusManager()->GetFocusedView());
272 } 282 }
273 283
284 // If the initially focused View provided is unfocusable, check the next
285 // available focusable View is focused.
286 TEST_F(DialogTest, UnfocusableInitialFocus) {
287 DialogDelegateView* dialog = new DialogDelegateView();
288 Textfield* textfield = new Textfield();
289 dialog->AddChildView(textfield);
290 Widget* dialog_widget =
291 DialogDelegate::CreateDialogWidget(dialog, GetContext(), nullptr);
292
293 // Turn off focusability on all the dialog's buttons. On Mac, we can just do
294 // this by turning off full keyboard access. On non-Mac, this will have no
295 // effect - turn off focusability for Views there manually.
296 SetFullKeyboardAccessState(dialog_widget, false);
tapted 2017/01/12 02:25:43 if you do this before creating the widget, I think
Patti Lor 2017/01/12 06:12:37 Oh, that works! Thanks, reverted stuff back.
297 #if !defined(OS_MACOSX)
298 DialogClientView* dcv = dialog->GetDialogClientView();
299 dcv->ok_button()->SetFocusBehavior(View::FocusBehavior::NEVER);
300 dcv->cancel_button()->SetFocusBehavior(View::FocusBehavior::NEVER);
301 #endif
302
303 // On showing the dialog, the initially focused View will be the OK button.
304 // Since it is no longer focusable, focus should advance to the next focusable
305 // View, which is |textfield|.
306 dialog_widget->Show();
307 EXPECT_TRUE(textfield->HasFocus());
308 EXPECT_EQ(textfield, dialog->GetFocusManager()->GetFocusedView());
309 dialog_widget->Close();
310 }
311
274 } // namespace views 312 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/widget/widget.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698