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 "ui/views/controls/combobox/combobox.h"
9 #include "base/basictypes.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "ui/base/ime/text_input_client.h"
12 #include "ui/base/models/combobox_model.h"
13 #include "ui/events/event.h"
14 #include "ui/events/event_constants.h"
15 #include "ui/events/keycodes/keyboard_codes.h"
16 #include "ui/views/controls/combobox/combobox_listener.h"
17 #include "ui/views/controls/menu/menu_runner.h"
18 #include "ui/views/controls/menu/menu_runner_handler.h"
19 #include "ui/views/ime/mock_input_method.h"
20 #include "ui/views/test/menu_runner_test_api.h"
21 #include "ui/views/test/views_test_base.h"
22 #include "ui/views/widget/widget.h"
24 using base::ASCIIToUTF16
;
30 // An dummy implementation of MenuRunnerHandler to check if the dropdown menu is
32 class TestMenuRunnerHandler
: public MenuRunnerHandler
{
34 TestMenuRunnerHandler() : executed_(false) {}
36 bool executed() const { return executed_
; }
38 virtual MenuRunner::RunResult
RunMenuAt(Widget
* parent
,
40 const gfx::Rect
& bounds
,
41 MenuAnchorPosition anchor
,
42 ui::MenuSourceType source_type
,
43 int32 types
) OVERRIDE
{
45 return MenuRunner::NORMAL_EXIT
;
51 DISALLOW_COPY_AND_ASSIGN(TestMenuRunnerHandler
);
54 // A wrapper of Combobox to intercept the result of OnKeyPressed() and
55 // OnKeyReleased() methods.
56 class TestCombobox
: public Combobox
{
58 explicit TestCombobox(ui::ComboboxModel
* model
)
61 key_received_(false) {}
63 virtual bool OnKeyPressed(const ui::KeyEvent
& e
) OVERRIDE
{
65 key_handled_
= Combobox::OnKeyPressed(e
);
69 virtual bool OnKeyReleased(const ui::KeyEvent
& e
) OVERRIDE
{
71 key_handled_
= Combobox::OnKeyReleased(e
);
75 bool key_handled() const { return key_handled_
; }
76 bool key_received() const { return key_received_
; }
79 key_received_
= key_handled_
= false;
86 DISALLOW_COPY_AND_ASSIGN(TestCombobox
);
89 // A concrete class is needed to test the combobox.
90 class TestComboboxModel
: public ui::ComboboxModel
{
92 TestComboboxModel() {}
93 virtual ~TestComboboxModel() {}
96 virtual int GetItemCount() const OVERRIDE
{
99 virtual base::string16
GetItemAt(int index
) OVERRIDE
{
100 if (IsItemSeparatorAt(index
)) {
102 return ASCIIToUTF16("SEPARATOR");
104 return ASCIIToUTF16(index
% 2 == 0 ? "PEANUT BUTTER" : "JELLY");
106 virtual bool IsItemSeparatorAt(int index
) OVERRIDE
{
107 return separators_
.find(index
) != separators_
.end();
110 void SetSeparators(const std::set
<int>& separators
) {
111 separators_
= separators
;
115 std::set
<int> separators_
;
117 DISALLOW_COPY_AND_ASSIGN(TestComboboxModel
);
120 // A combobox model which refers to a vector.
121 class VectorComboboxModel
: public ui::ComboboxModel
{
123 explicit VectorComboboxModel(std::vector
<std::string
>* values
)
125 virtual ~VectorComboboxModel() {}
127 // ui::ComboboxModel:
128 virtual int GetItemCount() const OVERRIDE
{
129 return (int)values_
->size();
131 virtual base::string16
GetItemAt(int index
) OVERRIDE
{
132 return ASCIIToUTF16(values_
->at(index
));
134 virtual bool IsItemSeparatorAt(int index
) OVERRIDE
{
139 std::vector
<std::string
>* values_
;
142 class EvilListener
: public ComboboxListener
{
144 EvilListener() : deleted_(false) {}
145 virtual ~EvilListener() {};
148 virtual void OnPerformAction(Combobox
* combobox
) OVERRIDE
{
153 bool deleted() const { return deleted_
; }
158 DISALLOW_COPY_AND_ASSIGN(EvilListener
);
161 class TestComboboxListener
: public views::ComboboxListener
{
163 TestComboboxListener() : perform_action_index_(-1), actions_performed_(0) {}
164 virtual ~TestComboboxListener() {}
166 virtual void OnPerformAction(views::Combobox
* combobox
) OVERRIDE
{
167 perform_action_index_
= combobox
->selected_index();
168 actions_performed_
++;
171 int perform_action_index() const {
172 return perform_action_index_
;
175 bool on_perform_action_called() const {
176 return actions_performed_
> 0;
179 int actions_performed() const {
180 return actions_performed_
;
184 int perform_action_index_
;
185 int actions_performed_
;
188 DISALLOW_COPY_AND_ASSIGN(TestComboboxListener
);
193 class ComboboxTest
: public ViewsTestBase
{
195 ComboboxTest() : widget_(NULL
), combobox_(NULL
) {}
197 virtual void TearDown() OVERRIDE
{
200 ViewsTestBase::TearDown();
203 void InitCombobox() {
204 model_
.reset(new TestComboboxModel());
206 ASSERT_FALSE(combobox_
);
207 combobox_
= new TestCombobox(model_
.get());
208 combobox_
->set_id(1);
210 widget_
= new Widget
;
211 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
212 params
.bounds
= gfx::Rect(200, 200, 200, 200);
213 widget_
->Init(params
);
214 View
* container
= new View();
215 widget_
->SetContentsView(container
);
216 container
->AddChildView(combobox_
);
218 widget_
->ReplaceInputMethod(new MockInputMethod
);
220 // Assumes the Widget is always focused.
221 widget_
->GetInputMethod()->OnFocus();
223 combobox_
->RequestFocus();
224 combobox_
->SizeToPreferredSize();
228 void SendKeyEvent(ui::KeyboardCode key_code
) {
229 SendKeyEventWithType(key_code
, ui::ET_KEY_PRESSED
);
232 void SendKeyEventWithType(ui::KeyboardCode key_code
, ui::EventType type
) {
233 ui::KeyEvent
event(type
, key_code
, 0, false);
234 widget_
->GetInputMethod()->DispatchKeyEvent(event
);
237 View
* GetFocusedView() {
238 return widget_
->GetFocusManager()->GetFocusedView();
241 void PerformClick(const gfx::Point
& point
) {
242 ui::MouseEvent pressed_event
= ui::MouseEvent(ui::ET_MOUSE_PRESSED
, point
,
244 ui::EF_LEFT_MOUSE_BUTTON
,
245 ui::EF_LEFT_MOUSE_BUTTON
);
246 widget_
->OnMouseEvent(&pressed_event
);
247 ui::MouseEvent released_event
= ui::MouseEvent(ui::ET_MOUSE_RELEASED
, point
,
249 ui::EF_LEFT_MOUSE_BUTTON
,
250 ui::EF_LEFT_MOUSE_BUTTON
);
251 widget_
->OnMouseEvent(&released_event
);
254 // We need widget to populate wrapper class.
257 // |combobox_| will be allocated InitCombobox() and then owned by |widget_|.
258 TestCombobox
* combobox_
;
260 // Combobox does not take ownership of the model, hence it needs to be scoped.
261 scoped_ptr
<TestComboboxModel
> model_
;
264 TEST_F(ComboboxTest
, KeyTest
) {
266 SendKeyEvent(ui::VKEY_END
);
267 EXPECT_EQ(combobox_
->selected_index() + 1, model_
->GetItemCount());
268 SendKeyEvent(ui::VKEY_HOME
);
269 EXPECT_EQ(combobox_
->selected_index(), 0);
270 SendKeyEvent(ui::VKEY_DOWN
);
271 SendKeyEvent(ui::VKEY_DOWN
);
272 EXPECT_EQ(combobox_
->selected_index(), 2);
273 SendKeyEvent(ui::VKEY_RIGHT
);
274 EXPECT_EQ(combobox_
->selected_index(), 2);
275 SendKeyEvent(ui::VKEY_LEFT
);
276 EXPECT_EQ(combobox_
->selected_index(), 2);
277 SendKeyEvent(ui::VKEY_UP
);
278 EXPECT_EQ(combobox_
->selected_index(), 1);
279 SendKeyEvent(ui::VKEY_PRIOR
);
280 EXPECT_EQ(combobox_
->selected_index(), 0);
281 SendKeyEvent(ui::VKEY_NEXT
);
282 EXPECT_EQ(combobox_
->selected_index(), model_
->GetItemCount() - 1);
285 // Check that if a combobox is disabled before it has a native wrapper, then the
286 // native wrapper inherits the disabled state when it gets created.
287 TEST_F(ComboboxTest
, DisabilityTest
) {
288 model_
.reset(new TestComboboxModel());
290 ASSERT_FALSE(combobox_
);
291 combobox_
= new TestCombobox(model_
.get());
292 combobox_
->SetEnabled(false);
294 widget_
= new Widget
;
295 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
296 params
.bounds
= gfx::Rect(100, 100, 100, 100);
297 widget_
->Init(params
);
298 View
* container
= new View();
299 widget_
->SetContentsView(container
);
300 container
->AddChildView(combobox_
);
301 EXPECT_FALSE(combobox_
->enabled());
304 // Verifies that we don't select a separator line in combobox when navigating
306 TEST_F(ComboboxTest
, SkipSeparatorSimple
) {
308 std::set
<int> separators
;
309 separators
.insert(2);
310 model_
->SetSeparators(separators
);
311 EXPECT_EQ(0, combobox_
->selected_index());
312 SendKeyEvent(ui::VKEY_DOWN
);
313 EXPECT_EQ(1, combobox_
->selected_index());
314 SendKeyEvent(ui::VKEY_DOWN
);
315 EXPECT_EQ(3, combobox_
->selected_index());
316 SendKeyEvent(ui::VKEY_UP
);
317 EXPECT_EQ(1, combobox_
->selected_index());
318 SendKeyEvent(ui::VKEY_HOME
);
319 EXPECT_EQ(0, combobox_
->selected_index());
320 SendKeyEvent(ui::VKEY_PRIOR
);
321 EXPECT_EQ(0, combobox_
->selected_index());
322 SendKeyEvent(ui::VKEY_END
);
323 EXPECT_EQ(9, combobox_
->selected_index());
326 // Verifies that we never select the separator that is in the beginning of the
327 // combobox list when navigating through keyboard.
328 TEST_F(ComboboxTest
, SkipSeparatorBeginning
) {
330 std::set
<int> separators
;
331 separators
.insert(0);
332 model_
->SetSeparators(separators
);
333 EXPECT_EQ(0, combobox_
->selected_index());
334 SendKeyEvent(ui::VKEY_DOWN
);
335 EXPECT_EQ(1, combobox_
->selected_index());
336 SendKeyEvent(ui::VKEY_DOWN
);
337 EXPECT_EQ(2, combobox_
->selected_index());
338 SendKeyEvent(ui::VKEY_UP
);
339 EXPECT_EQ(1, combobox_
->selected_index());
340 SendKeyEvent(ui::VKEY_HOME
);
341 EXPECT_EQ(1, combobox_
->selected_index());
342 SendKeyEvent(ui::VKEY_PRIOR
);
343 EXPECT_EQ(1, combobox_
->selected_index());
344 SendKeyEvent(ui::VKEY_END
);
345 EXPECT_EQ(9, combobox_
->selected_index());
348 // Verifies that we never select the separator that is in the end of the
349 // combobox list when navigating through keyboard.
350 TEST_F(ComboboxTest
, SkipSeparatorEnd
) {
352 std::set
<int> separators
;
353 separators
.insert(model_
->GetItemCount() - 1);
354 model_
->SetSeparators(separators
);
355 combobox_
->SetSelectedIndex(8);
356 SendKeyEvent(ui::VKEY_DOWN
);
357 EXPECT_EQ(8, combobox_
->selected_index());
358 SendKeyEvent(ui::VKEY_UP
);
359 EXPECT_EQ(7, combobox_
->selected_index());
360 SendKeyEvent(ui::VKEY_END
);
361 EXPECT_EQ(8, combobox_
->selected_index());
364 // Verifies that we never select any of the adjacent separators (multiple
365 // consecutive) that appear in the beginning of the combobox list when
366 // navigating through keyboard.
367 TEST_F(ComboboxTest
, SkipMultipleSeparatorsAtBeginning
) {
369 std::set
<int> separators
;
370 separators
.insert(0);
371 separators
.insert(1);
372 separators
.insert(2);
373 model_
->SetSeparators(separators
);
374 EXPECT_EQ(0, combobox_
->selected_index());
375 SendKeyEvent(ui::VKEY_DOWN
);
376 EXPECT_EQ(3, combobox_
->selected_index());
377 SendKeyEvent(ui::VKEY_UP
);
378 EXPECT_EQ(3, combobox_
->selected_index());
379 SendKeyEvent(ui::VKEY_NEXT
);
380 EXPECT_EQ(9, combobox_
->selected_index());
381 SendKeyEvent(ui::VKEY_HOME
);
382 EXPECT_EQ(3, combobox_
->selected_index());
383 SendKeyEvent(ui::VKEY_END
);
384 EXPECT_EQ(9, combobox_
->selected_index());
385 SendKeyEvent(ui::VKEY_PRIOR
);
386 EXPECT_EQ(3, combobox_
->selected_index());
389 // Verifies that we never select any of the adjacent separators (multiple
390 // consecutive) that appear in the middle of the combobox list when navigating
392 TEST_F(ComboboxTest
, SkipMultipleAdjacentSeparatorsAtMiddle
) {
394 std::set
<int> separators
;
395 separators
.insert(4);
396 separators
.insert(5);
397 separators
.insert(6);
398 model_
->SetSeparators(separators
);
399 combobox_
->SetSelectedIndex(3);
400 SendKeyEvent(ui::VKEY_DOWN
);
401 EXPECT_EQ(7, combobox_
->selected_index());
402 SendKeyEvent(ui::VKEY_UP
);
403 EXPECT_EQ(3, combobox_
->selected_index());
406 // Verifies that we never select any of the adjacent separators (multiple
407 // consecutive) that appear in the end of the combobox list when navigating
409 TEST_F(ComboboxTest
, SkipMultipleSeparatorsAtEnd
) {
411 std::set
<int> separators
;
412 separators
.insert(7);
413 separators
.insert(8);
414 separators
.insert(9);
415 model_
->SetSeparators(separators
);
416 combobox_
->SetSelectedIndex(6);
417 SendKeyEvent(ui::VKEY_DOWN
);
418 EXPECT_EQ(6, combobox_
->selected_index());
419 SendKeyEvent(ui::VKEY_UP
);
420 EXPECT_EQ(5, combobox_
->selected_index());
421 SendKeyEvent(ui::VKEY_HOME
);
422 EXPECT_EQ(0, combobox_
->selected_index());
423 SendKeyEvent(ui::VKEY_NEXT
);
424 EXPECT_EQ(6, combobox_
->selected_index());
425 SendKeyEvent(ui::VKEY_PRIOR
);
426 EXPECT_EQ(0, combobox_
->selected_index());
427 SendKeyEvent(ui::VKEY_END
);
428 EXPECT_EQ(6, combobox_
->selected_index());
431 TEST_F(ComboboxTest
, GetTextForRowTest
) {
433 std::set
<int> separators
;
434 separators
.insert(0);
435 separators
.insert(1);
436 separators
.insert(9);
437 model_
->SetSeparators(separators
);
438 for (int i
= 0; i
< combobox_
->GetRowCount(); ++i
) {
439 if (separators
.count(i
) != 0) {
440 EXPECT_TRUE(combobox_
->GetTextForRow(i
).empty()) << i
;
442 EXPECT_EQ(ASCIIToUTF16(i
% 2 == 0 ? "PEANUT BUTTER" : "JELLY"),
443 combobox_
->GetTextForRow(i
)) << i
;
448 // Verifies selecting the first matching value (and returning whether found).
449 TEST_F(ComboboxTest
, SelectValue
) {
451 ASSERT_EQ(model_
->GetDefaultIndex(), combobox_
->selected_index());
452 EXPECT_TRUE(combobox_
->SelectValue(ASCIIToUTF16("PEANUT BUTTER")));
453 EXPECT_EQ(0, combobox_
->selected_index());
454 EXPECT_TRUE(combobox_
->SelectValue(ASCIIToUTF16("JELLY")));
455 EXPECT_EQ(1, combobox_
->selected_index());
456 EXPECT_FALSE(combobox_
->SelectValue(ASCIIToUTF16("BANANAS")));
457 EXPECT_EQ(1, combobox_
->selected_index());
459 // With the action style, the selected index is always 0.
460 combobox_
->SetStyle(Combobox::STYLE_ACTION
);
461 EXPECT_FALSE(combobox_
->SelectValue(ASCIIToUTF16("PEANUT BUTTER")));
462 EXPECT_EQ(0, combobox_
->selected_index());
463 EXPECT_FALSE(combobox_
->SelectValue(ASCIIToUTF16("JELLY")));
464 EXPECT_EQ(0, combobox_
->selected_index());
465 EXPECT_FALSE(combobox_
->SelectValue(ASCIIToUTF16("BANANAS")));
466 EXPECT_EQ(0, combobox_
->selected_index());
469 TEST_F(ComboboxTest
, SelectIndexActionStyle
) {
472 // With the action style, the selected index is always 0.
473 combobox_
->SetStyle(Combobox::STYLE_ACTION
);
474 combobox_
->SetSelectedIndex(1);
475 EXPECT_EQ(0, combobox_
->selected_index());
476 combobox_
->SetSelectedIndex(2);
477 EXPECT_EQ(0, combobox_
->selected_index());
478 combobox_
->SetSelectedIndex(3);
479 EXPECT_EQ(0, combobox_
->selected_index());
482 TEST_F(ComboboxTest
, ListenerHandlesDelete
) {
483 TestComboboxModel model
;
485 // |combobox| will be deleted on change.
486 TestCombobox
* combobox
= new TestCombobox(&model
);
487 scoped_ptr
<EvilListener
> evil_listener(new EvilListener());
488 combobox
->set_listener(evil_listener
.get());
489 ASSERT_NO_FATAL_FAILURE(combobox
->ExecuteCommand(2));
490 EXPECT_TRUE(evil_listener
->deleted());
493 // |combobox| will be deleted on change.
494 combobox
= new TestCombobox(&model
);
495 evil_listener
.reset(new EvilListener());
496 combobox
->set_listener(evil_listener
.get());
497 combobox
->SetStyle(Combobox::STYLE_ACTION
);
498 ASSERT_NO_FATAL_FAILURE(combobox
->ExecuteCommand(2));
499 EXPECT_TRUE(evil_listener
->deleted());
502 TEST_F(ComboboxTest
, Click
) {
505 TestComboboxListener listener
;
506 combobox_
->set_listener(&listener
);
510 // Click the left side. The menu is shown.
511 TestMenuRunnerHandler
* test_menu_runner_handler
= new TestMenuRunnerHandler();
512 scoped_ptr
<MenuRunnerHandler
> menu_runner_handler(test_menu_runner_handler
);
513 test::MenuRunnerTestAPI
test_api(
514 combobox_
->dropdown_list_menu_runner_
.get());
515 test_api
.SetMenuRunnerHandler(menu_runner_handler
.Pass());
516 PerformClick(gfx::Point(combobox_
->x() + 1,
517 combobox_
->y() + combobox_
->height() / 2));
518 EXPECT_FALSE(listener
.on_perform_action_called());
519 EXPECT_TRUE(test_menu_runner_handler
->executed());
522 TEST_F(ComboboxTest
, ClickButDisabled
) {
525 TestComboboxListener listener
;
526 combobox_
->set_listener(&listener
);
529 combobox_
->SetEnabled(false);
531 // Click the left side, but nothing happens since the combobox is disabled.
532 TestMenuRunnerHandler
* test_menu_runner_handler
= new TestMenuRunnerHandler();
533 scoped_ptr
<MenuRunnerHandler
> menu_runner_handler(test_menu_runner_handler
);
534 test::MenuRunnerTestAPI
test_api(
535 combobox_
->dropdown_list_menu_runner_
.get());
536 test_api
.SetMenuRunnerHandler(menu_runner_handler
.Pass());
537 PerformClick(gfx::Point(combobox_
->x() + 1,
538 combobox_
->y() + combobox_
->height() / 2));
539 EXPECT_FALSE(listener
.on_perform_action_called());
540 EXPECT_FALSE(test_menu_runner_handler
->executed());
543 TEST_F(ComboboxTest
, NotifyOnClickWithReturnKey
) {
546 TestComboboxListener listener
;
547 combobox_
->set_listener(&listener
);
549 // With STYLE_NORMAL, the click event is ignored.
550 SendKeyEvent(ui::VKEY_RETURN
);
551 EXPECT_FALSE(listener
.on_perform_action_called());
553 // With STYLE_ACTION, the click event is notified.
554 combobox_
->SetStyle(Combobox::STYLE_ACTION
);
555 SendKeyEvent(ui::VKEY_RETURN
);
556 EXPECT_TRUE(listener
.on_perform_action_called());
557 EXPECT_EQ(0, listener
.perform_action_index());
560 TEST_F(ComboboxTest
, NotifyOnClickWithSpaceKey
) {
563 TestComboboxListener listener
;
564 combobox_
->set_listener(&listener
);
566 // With STYLE_NORMAL, the click event is ignored.
567 SendKeyEvent(ui::VKEY_SPACE
);
568 EXPECT_FALSE(listener
.on_perform_action_called());
569 SendKeyEventWithType(ui::VKEY_SPACE
, ui::ET_KEY_RELEASED
);
570 EXPECT_FALSE(listener
.on_perform_action_called());
572 // With STYLE_ACTION, the click event is notified after releasing.
573 combobox_
->SetStyle(Combobox::STYLE_ACTION
);
574 SendKeyEvent(ui::VKEY_SPACE
);
575 EXPECT_FALSE(listener
.on_perform_action_called());
576 SendKeyEventWithType(ui::VKEY_SPACE
, ui::ET_KEY_RELEASED
);
577 EXPECT_TRUE(listener
.on_perform_action_called());
578 EXPECT_EQ(0, listener
.perform_action_index());
581 TEST_F(ComboboxTest
, NotifyOnClickWithMouse
) {
584 TestComboboxListener listener
;
585 combobox_
->set_listener(&listener
);
587 combobox_
->SetStyle(Combobox::STYLE_ACTION
);
590 // Click the right side (arrow button). The menu is shown.
591 TestMenuRunnerHandler
* test_menu_runner_handler
= new TestMenuRunnerHandler();
592 scoped_ptr
<MenuRunnerHandler
> menu_runner_handler(test_menu_runner_handler
);
593 scoped_ptr
<test::MenuRunnerTestAPI
> test_api(
594 new test::MenuRunnerTestAPI(combobox_
->dropdown_list_menu_runner_
.get()));
595 test_api
->SetMenuRunnerHandler(menu_runner_handler
.Pass());
597 PerformClick(gfx::Point(combobox_
->x() + combobox_
->width() - 1,
598 combobox_
->y() + combobox_
->height() / 2));
599 EXPECT_FALSE(listener
.on_perform_action_called());
600 EXPECT_TRUE(test_menu_runner_handler
->executed());
602 // Click the left side (text button). The click event is notified.
603 test_menu_runner_handler
= new TestMenuRunnerHandler();
604 menu_runner_handler
.reset(test_menu_runner_handler
);
606 new test::MenuRunnerTestAPI(combobox_
->dropdown_list_menu_runner_
.get()));
607 test_api
->SetMenuRunnerHandler(menu_runner_handler
.Pass());
608 PerformClick(gfx::Point(combobox_
->x() + 1,
609 combobox_
->y() + combobox_
->height() / 2));
610 EXPECT_TRUE(listener
.on_perform_action_called());
611 EXPECT_FALSE(test_menu_runner_handler
->executed());
612 EXPECT_EQ(0, listener
.perform_action_index());
615 TEST_F(ComboboxTest
, ConsumingPressKeyEvents
) {
618 EXPECT_FALSE(combobox_
->OnKeyPressed(
619 ui::KeyEvent(ui::ET_KEY_PRESSED
, ui::VKEY_RETURN
, 0, false)));
620 EXPECT_FALSE(combobox_
->OnKeyPressed(
621 ui::KeyEvent(ui::ET_KEY_PRESSED
, ui::VKEY_SPACE
, 0, false)));
623 // When the combobox's style is STYLE_ACTION, pressing events of a space key
624 // or an enter key will be consumed.
625 combobox_
->SetStyle(Combobox::STYLE_ACTION
);
626 EXPECT_TRUE(combobox_
->OnKeyPressed(
627 ui::KeyEvent(ui::ET_KEY_PRESSED
, ui::VKEY_RETURN
, 0, false)));
628 EXPECT_TRUE(combobox_
->OnKeyPressed(
629 ui::KeyEvent(ui::ET_KEY_PRESSED
, ui::VKEY_SPACE
, 0, false)));
632 TEST_F(ComboboxTest
, ContentWidth
) {
633 std::vector
<std::string
> values
;
634 VectorComboboxModel
model(&values
);
635 TestCombobox
combobox(&model
);
637 std::string long_item
= "this is the long item";
638 std::string short_item
= "s";
641 values
[0] = long_item
;
642 combobox
.ModelChanged();
644 const int long_item_width
= combobox
.content_size_
.width();
646 values
[0] = short_item
;
647 combobox
.ModelChanged();
649 const int short_item_width
= combobox
.content_size_
.width();
652 values
[0] = short_item
;
653 values
[1] = long_item
;
654 combobox
.ModelChanged();
656 // When the style is STYLE_NORMAL, the width will fit with the longest item.
657 combobox
.SetStyle(Combobox::STYLE_NORMAL
);
658 EXPECT_EQ(long_item_width
, combobox
.content_size_
.width());
660 // When the style is STYLE_ACTION, the width will fit with the first items'
662 combobox
.SetStyle(Combobox::STYLE_ACTION
);
663 EXPECT_EQ(short_item_width
, combobox
.content_size_
.width());
666 TEST_F(ComboboxTest
, TypingPrefixNotifiesListener
) {
669 TestComboboxListener listener
;
670 combobox_
->set_listener(&listener
);
672 // Type the first character of the second menu item ("JELLY").
673 combobox_
->GetTextInputClient()->InsertChar('J', ui::EF_NONE
);
674 EXPECT_EQ(1, listener
.actions_performed());
675 EXPECT_EQ(1, listener
.perform_action_index());
677 // Type the second character of "JELLY", item shouldn't change and
678 // OnPerformAction() shouldn't be re-called.
679 combobox_
->GetTextInputClient()->InsertChar('E', ui::EF_NONE
);
680 EXPECT_EQ(1, listener
.actions_performed());
681 EXPECT_EQ(1, listener
.perform_action_index());
683 // Clears the typed text.
686 // Type the first character of "PEANUT BUTTER", which should change the
687 // selected index and perform an action.
688 combobox_
->GetTextInputClient()->InsertChar('P', ui::EF_NONE
);
689 EXPECT_EQ(2, listener
.actions_performed());
690 EXPECT_EQ(2, listener
.perform_action_index());