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 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 bool OnKeyPressed(const ui::KeyEvent
& e
) override
{
65 key_handled_
= Combobox::OnKeyPressed(e
);
69 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 ~TestComboboxModel() override
{}
95 static const int kItemCount
= 10;
98 int GetItemCount() const override
{ return kItemCount
; }
99 base::string16
GetItemAt(int index
) override
{
100 if (IsItemSeparatorAt(index
)) {
102 return ASCIIToUTF16("SEPARATOR");
104 return ASCIIToUTF16(index
% 2 == 0 ? "PEANUT BUTTER" : "JELLY");
106 bool IsItemSeparatorAt(int index
) override
{
107 return separators_
.find(index
) != separators_
.end();
110 int GetDefaultIndex() const override
{
111 // Return the first index that is not a separator.
112 for (int index
= 0; index
< kItemCount
; ++index
) {
113 if (separators_
.find(index
) == separators_
.end())
120 void SetSeparators(const std::set
<int>& separators
) {
121 separators_
= separators
;
125 std::set
<int> separators_
;
127 DISALLOW_COPY_AND_ASSIGN(TestComboboxModel
);
130 // A combobox model which refers to a vector.
131 class VectorComboboxModel
: public ui::ComboboxModel
{
133 explicit VectorComboboxModel(std::vector
<std::string
>* values
)
135 ~VectorComboboxModel() override
{}
137 // ui::ComboboxModel:
138 int GetItemCount() const override
{ return (int)values_
->size(); }
139 base::string16
GetItemAt(int index
) override
{
140 return ASCIIToUTF16(values_
->at(index
));
142 bool IsItemSeparatorAt(int index
) override
{ return false; }
145 std::vector
<std::string
>* values_
;
148 class EvilListener
: public ComboboxListener
{
150 EvilListener() : deleted_(false) {}
151 ~EvilListener() override
{};
154 void OnPerformAction(Combobox
* combobox
) override
{
159 bool deleted() const { return deleted_
; }
164 DISALLOW_COPY_AND_ASSIGN(EvilListener
);
167 class TestComboboxListener
: public views::ComboboxListener
{
169 TestComboboxListener() : perform_action_index_(-1), actions_performed_(0) {}
170 ~TestComboboxListener() override
{}
172 void OnPerformAction(views::Combobox
* combobox
) override
{
173 perform_action_index_
= combobox
->selected_index();
174 actions_performed_
++;
177 int perform_action_index() const {
178 return perform_action_index_
;
181 bool on_perform_action_called() const {
182 return actions_performed_
> 0;
185 int actions_performed() const {
186 return actions_performed_
;
190 int perform_action_index_
;
191 int actions_performed_
;
194 DISALLOW_COPY_AND_ASSIGN(TestComboboxListener
);
199 class ComboboxTest
: public ViewsTestBase
{
201 ComboboxTest() : widget_(NULL
), combobox_(NULL
) {}
203 void TearDown() override
{
206 ViewsTestBase::TearDown();
209 void InitCombobox(const std::set
<int>* separators
) {
210 model_
.reset(new TestComboboxModel());
213 model_
->SetSeparators(*separators
);
215 ASSERT_FALSE(combobox_
);
216 combobox_
= new TestCombobox(model_
.get());
217 combobox_
->set_id(1);
219 widget_
= new Widget
;
220 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
221 params
.bounds
= gfx::Rect(200, 200, 200, 200);
222 widget_
->Init(params
);
223 View
* container
= new View();
224 widget_
->SetContentsView(container
);
225 container
->AddChildView(combobox_
);
227 widget_
->ReplaceInputMethod(new MockInputMethod
);
229 // Assumes the Widget is always focused.
230 widget_
->GetInputMethod()->OnFocus();
232 combobox_
->RequestFocus();
233 combobox_
->SizeToPreferredSize();
237 void SendKeyEvent(ui::KeyboardCode key_code
) {
238 SendKeyEventWithType(key_code
, ui::ET_KEY_PRESSED
);
241 void SendKeyEventWithType(ui::KeyboardCode key_code
, ui::EventType type
) {
242 ui::KeyEvent
event(type
, key_code
, ui::EF_NONE
);
243 widget_
->GetInputMethod()->DispatchKeyEvent(event
);
246 View
* GetFocusedView() {
247 return widget_
->GetFocusManager()->GetFocusedView();
250 void PerformClick(const gfx::Point
& point
) {
251 ui::MouseEvent pressed_event
= ui::MouseEvent(ui::ET_MOUSE_PRESSED
, point
,
253 ui::EF_LEFT_MOUSE_BUTTON
,
254 ui::EF_LEFT_MOUSE_BUTTON
);
255 widget_
->OnMouseEvent(&pressed_event
);
256 ui::MouseEvent released_event
= ui::MouseEvent(ui::ET_MOUSE_RELEASED
, point
,
258 ui::EF_LEFT_MOUSE_BUTTON
,
259 ui::EF_LEFT_MOUSE_BUTTON
);
260 widget_
->OnMouseEvent(&released_event
);
263 // We need widget to populate wrapper class.
266 // |combobox_| will be allocated InitCombobox() and then owned by |widget_|.
267 TestCombobox
* combobox_
;
269 // Combobox does not take ownership of the model, hence it needs to be scoped.
270 scoped_ptr
<TestComboboxModel
> model_
;
273 TEST_F(ComboboxTest
, KeyTest
) {
275 SendKeyEvent(ui::VKEY_END
);
276 EXPECT_EQ(combobox_
->selected_index() + 1, model_
->GetItemCount());
277 SendKeyEvent(ui::VKEY_HOME
);
278 EXPECT_EQ(combobox_
->selected_index(), 0);
279 SendKeyEvent(ui::VKEY_DOWN
);
280 SendKeyEvent(ui::VKEY_DOWN
);
281 EXPECT_EQ(combobox_
->selected_index(), 2);
282 SendKeyEvent(ui::VKEY_RIGHT
);
283 EXPECT_EQ(combobox_
->selected_index(), 2);
284 SendKeyEvent(ui::VKEY_LEFT
);
285 EXPECT_EQ(combobox_
->selected_index(), 2);
286 SendKeyEvent(ui::VKEY_UP
);
287 EXPECT_EQ(combobox_
->selected_index(), 1);
288 SendKeyEvent(ui::VKEY_PRIOR
);
289 EXPECT_EQ(combobox_
->selected_index(), 0);
290 SendKeyEvent(ui::VKEY_NEXT
);
291 EXPECT_EQ(combobox_
->selected_index(), model_
->GetItemCount() - 1);
294 // Check that if a combobox is disabled before it has a native wrapper, then the
295 // native wrapper inherits the disabled state when it gets created.
296 TEST_F(ComboboxTest
, DisabilityTest
) {
297 model_
.reset(new TestComboboxModel());
299 ASSERT_FALSE(combobox_
);
300 combobox_
= new TestCombobox(model_
.get());
301 combobox_
->SetEnabled(false);
303 widget_
= new Widget
;
304 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
305 params
.bounds
= gfx::Rect(100, 100, 100, 100);
306 widget_
->Init(params
);
307 View
* container
= new View();
308 widget_
->SetContentsView(container
);
309 container
->AddChildView(combobox_
);
310 EXPECT_FALSE(combobox_
->enabled());
313 // Verifies that we don't select a separator line in combobox when navigating
315 TEST_F(ComboboxTest
, SkipSeparatorSimple
) {
316 std::set
<int> separators
;
317 separators
.insert(2);
318 InitCombobox(&separators
);
319 EXPECT_EQ(0, combobox_
->selected_index());
320 SendKeyEvent(ui::VKEY_DOWN
);
321 EXPECT_EQ(1, combobox_
->selected_index());
322 SendKeyEvent(ui::VKEY_DOWN
);
323 EXPECT_EQ(3, combobox_
->selected_index());
324 SendKeyEvent(ui::VKEY_UP
);
325 EXPECT_EQ(1, combobox_
->selected_index());
326 SendKeyEvent(ui::VKEY_HOME
);
327 EXPECT_EQ(0, combobox_
->selected_index());
328 SendKeyEvent(ui::VKEY_PRIOR
);
329 EXPECT_EQ(0, combobox_
->selected_index());
330 SendKeyEvent(ui::VKEY_END
);
331 EXPECT_EQ(9, combobox_
->selected_index());
334 // Verifies that we never select the separator that is in the beginning of the
335 // combobox list when navigating through keyboard.
336 TEST_F(ComboboxTest
, SkipSeparatorBeginning
) {
337 std::set
<int> separators
;
338 separators
.insert(0);
339 InitCombobox(&separators
);
340 EXPECT_EQ(1, combobox_
->selected_index());
341 SendKeyEvent(ui::VKEY_DOWN
);
342 EXPECT_EQ(2, combobox_
->selected_index());
343 SendKeyEvent(ui::VKEY_DOWN
);
344 EXPECT_EQ(3, combobox_
->selected_index());
345 SendKeyEvent(ui::VKEY_UP
);
346 EXPECT_EQ(2, combobox_
->selected_index());
347 SendKeyEvent(ui::VKEY_HOME
);
348 EXPECT_EQ(1, combobox_
->selected_index());
349 SendKeyEvent(ui::VKEY_PRIOR
);
350 EXPECT_EQ(1, combobox_
->selected_index());
351 SendKeyEvent(ui::VKEY_END
);
352 EXPECT_EQ(9, combobox_
->selected_index());
355 // Verifies that we never select the separator that is in the end of the
356 // combobox list when navigating through keyboard.
357 TEST_F(ComboboxTest
, SkipSeparatorEnd
) {
358 std::set
<int> separators
;
359 separators
.insert(TestComboboxModel::kItemCount
- 1);
360 InitCombobox(&separators
);
361 combobox_
->SetSelectedIndex(8);
362 SendKeyEvent(ui::VKEY_DOWN
);
363 EXPECT_EQ(8, combobox_
->selected_index());
364 SendKeyEvent(ui::VKEY_UP
);
365 EXPECT_EQ(7, combobox_
->selected_index());
366 SendKeyEvent(ui::VKEY_END
);
367 EXPECT_EQ(8, combobox_
->selected_index());
370 // Verifies that we never select any of the adjacent separators (multiple
371 // consecutive) that appear in the beginning of the combobox list when
372 // navigating through keyboard.
373 TEST_F(ComboboxTest
, SkipMultipleSeparatorsAtBeginning
) {
374 std::set
<int> separators
;
375 separators
.insert(0);
376 separators
.insert(1);
377 separators
.insert(2);
378 InitCombobox(&separators
);
379 EXPECT_EQ(3, combobox_
->selected_index());
380 SendKeyEvent(ui::VKEY_DOWN
);
381 EXPECT_EQ(4, combobox_
->selected_index());
382 SendKeyEvent(ui::VKEY_UP
);
383 EXPECT_EQ(3, combobox_
->selected_index());
384 SendKeyEvent(ui::VKEY_NEXT
);
385 EXPECT_EQ(9, combobox_
->selected_index());
386 SendKeyEvent(ui::VKEY_HOME
);
387 EXPECT_EQ(3, combobox_
->selected_index());
388 SendKeyEvent(ui::VKEY_END
);
389 EXPECT_EQ(9, combobox_
->selected_index());
390 SendKeyEvent(ui::VKEY_PRIOR
);
391 EXPECT_EQ(3, combobox_
->selected_index());
394 // Verifies that we never select any of the adjacent separators (multiple
395 // consecutive) that appear in the middle of the combobox list when navigating
397 TEST_F(ComboboxTest
, SkipMultipleAdjacentSeparatorsAtMiddle
) {
398 std::set
<int> separators
;
399 separators
.insert(4);
400 separators
.insert(5);
401 separators
.insert(6);
402 InitCombobox(&separators
);
403 combobox_
->SetSelectedIndex(3);
404 SendKeyEvent(ui::VKEY_DOWN
);
405 EXPECT_EQ(7, combobox_
->selected_index());
406 SendKeyEvent(ui::VKEY_UP
);
407 EXPECT_EQ(3, combobox_
->selected_index());
410 // Verifies that we never select any of the adjacent separators (multiple
411 // consecutive) that appear in the end of the combobox list when navigating
413 TEST_F(ComboboxTest
, SkipMultipleSeparatorsAtEnd
) {
414 std::set
<int> separators
;
415 separators
.insert(7);
416 separators
.insert(8);
417 separators
.insert(9);
418 InitCombobox(&separators
);
419 combobox_
->SetSelectedIndex(6);
420 SendKeyEvent(ui::VKEY_DOWN
);
421 EXPECT_EQ(6, combobox_
->selected_index());
422 SendKeyEvent(ui::VKEY_UP
);
423 EXPECT_EQ(5, combobox_
->selected_index());
424 SendKeyEvent(ui::VKEY_HOME
);
425 EXPECT_EQ(0, combobox_
->selected_index());
426 SendKeyEvent(ui::VKEY_NEXT
);
427 EXPECT_EQ(6, combobox_
->selected_index());
428 SendKeyEvent(ui::VKEY_PRIOR
);
429 EXPECT_EQ(0, combobox_
->selected_index());
430 SendKeyEvent(ui::VKEY_END
);
431 EXPECT_EQ(6, combobox_
->selected_index());
434 TEST_F(ComboboxTest
, GetTextForRowTest
) {
435 std::set
<int> separators
;
436 separators
.insert(0);
437 separators
.insert(1);
438 separators
.insert(9);
439 InitCombobox(&separators
);
440 for (int i
= 0; i
< combobox_
->GetRowCount(); ++i
) {
441 if (separators
.count(i
) != 0) {
442 EXPECT_TRUE(combobox_
->GetTextForRow(i
).empty()) << i
;
444 EXPECT_EQ(ASCIIToUTF16(i
% 2 == 0 ? "PEANUT BUTTER" : "JELLY"),
445 combobox_
->GetTextForRow(i
)) << i
;
450 // Verifies selecting the first matching value (and returning whether found).
451 TEST_F(ComboboxTest
, SelectValue
) {
453 ASSERT_EQ(model_
->GetDefaultIndex(), combobox_
->selected_index());
454 EXPECT_TRUE(combobox_
->SelectValue(ASCIIToUTF16("PEANUT BUTTER")));
455 EXPECT_EQ(0, combobox_
->selected_index());
456 EXPECT_TRUE(combobox_
->SelectValue(ASCIIToUTF16("JELLY")));
457 EXPECT_EQ(1, combobox_
->selected_index());
458 EXPECT_FALSE(combobox_
->SelectValue(ASCIIToUTF16("BANANAS")));
459 EXPECT_EQ(1, combobox_
->selected_index());
461 // With the action style, the selected index is always 0.
462 combobox_
->SetStyle(Combobox::STYLE_ACTION
);
463 EXPECT_FALSE(combobox_
->SelectValue(ASCIIToUTF16("PEANUT BUTTER")));
464 EXPECT_EQ(0, combobox_
->selected_index());
465 EXPECT_FALSE(combobox_
->SelectValue(ASCIIToUTF16("JELLY")));
466 EXPECT_EQ(0, combobox_
->selected_index());
467 EXPECT_FALSE(combobox_
->SelectValue(ASCIIToUTF16("BANANAS")));
468 EXPECT_EQ(0, combobox_
->selected_index());
471 TEST_F(ComboboxTest
, SelectIndexActionStyle
) {
474 // With the action style, the selected index is always 0.
475 combobox_
->SetStyle(Combobox::STYLE_ACTION
);
476 combobox_
->SetSelectedIndex(1);
477 EXPECT_EQ(0, combobox_
->selected_index());
478 combobox_
->SetSelectedIndex(2);
479 EXPECT_EQ(0, combobox_
->selected_index());
480 combobox_
->SetSelectedIndex(3);
481 EXPECT_EQ(0, combobox_
->selected_index());
484 TEST_F(ComboboxTest
, ListenerHandlesDelete
) {
485 TestComboboxModel model
;
487 // |combobox| will be deleted on change.
488 TestCombobox
* combobox
= new TestCombobox(&model
);
489 scoped_ptr
<EvilListener
> evil_listener(new EvilListener());
490 combobox
->set_listener(evil_listener
.get());
491 ASSERT_NO_FATAL_FAILURE(combobox
->ExecuteCommand(2));
492 EXPECT_TRUE(evil_listener
->deleted());
495 // |combobox| will be deleted on change.
496 combobox
= new TestCombobox(&model
);
497 evil_listener
.reset(new EvilListener());
498 combobox
->set_listener(evil_listener
.get());
499 combobox
->SetStyle(Combobox::STYLE_ACTION
);
500 ASSERT_NO_FATAL_FAILURE(combobox
->ExecuteCommand(2));
501 EXPECT_TRUE(evil_listener
->deleted());
504 TEST_F(ComboboxTest
, Click
) {
507 TestComboboxListener listener
;
508 combobox_
->set_listener(&listener
);
512 // Click the left side. The menu is shown.
513 TestMenuRunnerHandler
* test_menu_runner_handler
= new TestMenuRunnerHandler();
514 scoped_ptr
<MenuRunnerHandler
> menu_runner_handler(test_menu_runner_handler
);
515 test::MenuRunnerTestAPI
test_api(
516 combobox_
->dropdown_list_menu_runner_
.get());
517 test_api
.SetMenuRunnerHandler(menu_runner_handler
.Pass());
518 PerformClick(gfx::Point(combobox_
->x() + 1,
519 combobox_
->y() + combobox_
->height() / 2));
520 EXPECT_FALSE(listener
.on_perform_action_called());
521 EXPECT_TRUE(test_menu_runner_handler
->executed());
524 TEST_F(ComboboxTest
, ClickButDisabled
) {
527 TestComboboxListener listener
;
528 combobox_
->set_listener(&listener
);
531 combobox_
->SetEnabled(false);
533 // Click the left side, but nothing happens since the combobox is disabled.
534 TestMenuRunnerHandler
* test_menu_runner_handler
= new TestMenuRunnerHandler();
535 scoped_ptr
<MenuRunnerHandler
> menu_runner_handler(test_menu_runner_handler
);
536 test::MenuRunnerTestAPI
test_api(
537 combobox_
->dropdown_list_menu_runner_
.get());
538 test_api
.SetMenuRunnerHandler(menu_runner_handler
.Pass());
539 PerformClick(gfx::Point(combobox_
->x() + 1,
540 combobox_
->y() + combobox_
->height() / 2));
541 EXPECT_FALSE(listener
.on_perform_action_called());
542 EXPECT_FALSE(test_menu_runner_handler
->executed());
545 TEST_F(ComboboxTest
, NotifyOnClickWithReturnKey
) {
548 TestComboboxListener listener
;
549 combobox_
->set_listener(&listener
);
551 // With STYLE_NORMAL, the click event is ignored.
552 SendKeyEvent(ui::VKEY_RETURN
);
553 EXPECT_FALSE(listener
.on_perform_action_called());
555 // With STYLE_ACTION, the click event is notified.
556 combobox_
->SetStyle(Combobox::STYLE_ACTION
);
557 SendKeyEvent(ui::VKEY_RETURN
);
558 EXPECT_TRUE(listener
.on_perform_action_called());
559 EXPECT_EQ(0, listener
.perform_action_index());
562 TEST_F(ComboboxTest
, NotifyOnClickWithSpaceKey
) {
565 TestComboboxListener listener
;
566 combobox_
->set_listener(&listener
);
568 // With STYLE_NORMAL, the click event is ignored.
569 SendKeyEvent(ui::VKEY_SPACE
);
570 EXPECT_FALSE(listener
.on_perform_action_called());
571 SendKeyEventWithType(ui::VKEY_SPACE
, ui::ET_KEY_RELEASED
);
572 EXPECT_FALSE(listener
.on_perform_action_called());
574 // With STYLE_ACTION, the click event is notified after releasing.
575 combobox_
->SetStyle(Combobox::STYLE_ACTION
);
576 SendKeyEvent(ui::VKEY_SPACE
);
577 EXPECT_FALSE(listener
.on_perform_action_called());
578 SendKeyEventWithType(ui::VKEY_SPACE
, ui::ET_KEY_RELEASED
);
579 EXPECT_TRUE(listener
.on_perform_action_called());
580 EXPECT_EQ(0, listener
.perform_action_index());
583 TEST_F(ComboboxTest
, NotifyOnClickWithMouse
) {
586 TestComboboxListener listener
;
587 combobox_
->set_listener(&listener
);
589 combobox_
->SetStyle(Combobox::STYLE_ACTION
);
592 // Click the right side (arrow button). The menu is shown.
593 TestMenuRunnerHandler
* test_menu_runner_handler
= new TestMenuRunnerHandler();
594 scoped_ptr
<MenuRunnerHandler
> menu_runner_handler(test_menu_runner_handler
);
595 scoped_ptr
<test::MenuRunnerTestAPI
> test_api(
596 new test::MenuRunnerTestAPI(combobox_
->dropdown_list_menu_runner_
.get()));
597 test_api
->SetMenuRunnerHandler(menu_runner_handler
.Pass());
599 PerformClick(gfx::Point(combobox_
->x() + combobox_
->width() - 1,
600 combobox_
->y() + combobox_
->height() / 2));
601 EXPECT_FALSE(listener
.on_perform_action_called());
602 EXPECT_TRUE(test_menu_runner_handler
->executed());
604 // Click the left side (text button). The click event is notified.
605 test_menu_runner_handler
= new TestMenuRunnerHandler();
606 menu_runner_handler
.reset(test_menu_runner_handler
);
608 new test::MenuRunnerTestAPI(combobox_
->dropdown_list_menu_runner_
.get()));
609 test_api
->SetMenuRunnerHandler(menu_runner_handler
.Pass());
610 PerformClick(gfx::Point(combobox_
->x() + 1,
611 combobox_
->y() + combobox_
->height() / 2));
612 EXPECT_TRUE(listener
.on_perform_action_called());
613 EXPECT_FALSE(test_menu_runner_handler
->executed());
614 EXPECT_EQ(0, listener
.perform_action_index());
617 TEST_F(ComboboxTest
, ConsumingPressKeyEvents
) {
620 EXPECT_FALSE(combobox_
->OnKeyPressed(
621 ui::KeyEvent(ui::ET_KEY_PRESSED
, ui::VKEY_RETURN
, ui::EF_NONE
)));
622 EXPECT_FALSE(combobox_
->OnKeyPressed(
623 ui::KeyEvent(ui::ET_KEY_PRESSED
, ui::VKEY_SPACE
, ui::EF_NONE
)));
625 // When the combobox's style is STYLE_ACTION, pressing events of a space key
626 // or an enter key will be consumed.
627 combobox_
->SetStyle(Combobox::STYLE_ACTION
);
628 EXPECT_TRUE(combobox_
->OnKeyPressed(
629 ui::KeyEvent(ui::ET_KEY_PRESSED
, ui::VKEY_RETURN
, ui::EF_NONE
)));
630 EXPECT_TRUE(combobox_
->OnKeyPressed(
631 ui::KeyEvent(ui::ET_KEY_PRESSED
, ui::VKEY_SPACE
, ui::EF_NONE
)));
634 TEST_F(ComboboxTest
, ContentWidth
) {
635 std::vector
<std::string
> values
;
636 VectorComboboxModel
model(&values
);
637 TestCombobox
combobox(&model
);
639 std::string long_item
= "this is the long item";
640 std::string short_item
= "s";
643 values
[0] = long_item
;
644 combobox
.ModelChanged();
646 const int long_item_width
= combobox
.content_size_
.width();
648 values
[0] = short_item
;
649 combobox
.ModelChanged();
651 const int short_item_width
= combobox
.content_size_
.width();
654 values
[0] = short_item
;
655 values
[1] = long_item
;
656 combobox
.ModelChanged();
658 // When the style is STYLE_NORMAL, the width will fit with the longest item.
659 combobox
.SetStyle(Combobox::STYLE_NORMAL
);
660 EXPECT_EQ(long_item_width
, combobox
.content_size_
.width());
662 // When the style is STYLE_ACTION, the width will fit with the first items'
664 combobox
.SetStyle(Combobox::STYLE_ACTION
);
665 EXPECT_EQ(short_item_width
, combobox
.content_size_
.width());
668 TEST_F(ComboboxTest
, TypingPrefixNotifiesListener
) {
671 TestComboboxListener listener
;
672 combobox_
->set_listener(&listener
);
674 // Type the first character of the second menu item ("JELLY").
675 combobox_
->GetTextInputClient()->InsertChar('J', ui::EF_NONE
);
676 EXPECT_EQ(1, listener
.actions_performed());
677 EXPECT_EQ(1, listener
.perform_action_index());
679 // Type the second character of "JELLY", item shouldn't change and
680 // OnPerformAction() shouldn't be re-called.
681 combobox_
->GetTextInputClient()->InsertChar('E', ui::EF_NONE
);
682 EXPECT_EQ(1, listener
.actions_performed());
683 EXPECT_EQ(1, listener
.perform_action_index());
685 // Clears the typed text.
688 // Type the first character of "PEANUT BUTTER", which should change the
689 // selected index and perform an action.
690 combobox_
->GetTextInputClient()->InsertChar('P', ui::EF_NONE
);
691 EXPECT_EQ(2, listener
.actions_performed());
692 EXPECT_EQ(2, listener
.perform_action_index());