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/input_method.h"
12 #include "ui/base/ime/text_input_client.h"
13 #include "ui/base/models/combobox_model.h"
14 #include "ui/events/event.h"
15 #include "ui/events/event_constants.h"
16 #include "ui/events/event_utils.h"
17 #include "ui/events/keycodes/keyboard_codes.h"
18 #include "ui/views/controls/combobox/combobox_listener.h"
19 #include "ui/views/controls/menu/menu_runner.h"
20 #include "ui/views/controls/menu/menu_runner_handler.h"
21 #include "ui/views/test/menu_runner_test_api.h"
22 #include "ui/views/test/views_test_base.h"
23 #include "ui/views/widget/widget.h"
25 using base::ASCIIToUTF16
;
31 // An dummy implementation of MenuRunnerHandler to check if the dropdown menu is
33 class TestMenuRunnerHandler
: public MenuRunnerHandler
{
35 TestMenuRunnerHandler() : executed_(false) {}
37 bool executed() const { return executed_
; }
39 MenuRunner::RunResult
RunMenuAt(Widget
* parent
,
41 const gfx::Rect
& bounds
,
42 MenuAnchorPosition anchor
,
43 ui::MenuSourceType source_type
,
44 int32 types
) override
{
46 return MenuRunner::NORMAL_EXIT
;
52 DISALLOW_COPY_AND_ASSIGN(TestMenuRunnerHandler
);
55 // A wrapper of Combobox to intercept the result of OnKeyPressed() and
56 // OnKeyReleased() methods.
57 class TestCombobox
: public Combobox
{
59 explicit TestCombobox(ui::ComboboxModel
* model
)
62 key_received_(false) {}
64 bool OnKeyPressed(const ui::KeyEvent
& e
) override
{
66 key_handled_
= Combobox::OnKeyPressed(e
);
70 bool OnKeyReleased(const ui::KeyEvent
& e
) override
{
72 key_handled_
= Combobox::OnKeyReleased(e
);
76 bool key_handled() const { return key_handled_
; }
77 bool key_received() const { return key_received_
; }
80 key_received_
= key_handled_
= false;
87 DISALLOW_COPY_AND_ASSIGN(TestCombobox
);
90 // A concrete class is needed to test the combobox.
91 class TestComboboxModel
: public ui::ComboboxModel
{
93 TestComboboxModel() {}
94 ~TestComboboxModel() override
{}
96 static const int kItemCount
= 10;
99 int GetItemCount() const override
{ return kItemCount
; }
100 base::string16
GetItemAt(int index
) override
{
101 if (IsItemSeparatorAt(index
)) {
103 return ASCIIToUTF16("SEPARATOR");
105 return ASCIIToUTF16(index
% 2 == 0 ? "PEANUT BUTTER" : "JELLY");
107 bool IsItemSeparatorAt(int index
) override
{
108 return separators_
.find(index
) != separators_
.end();
111 int GetDefaultIndex() const override
{
112 // Return the first index that is not a separator.
113 for (int index
= 0; index
< kItemCount
; ++index
) {
114 if (separators_
.find(index
) == separators_
.end())
121 void SetSeparators(const std::set
<int>& separators
) {
122 separators_
= separators
;
126 std::set
<int> separators_
;
128 DISALLOW_COPY_AND_ASSIGN(TestComboboxModel
);
131 // A combobox model which refers to a vector.
132 class VectorComboboxModel
: public ui::ComboboxModel
{
134 explicit VectorComboboxModel(std::vector
<std::string
>* values
)
136 ~VectorComboboxModel() override
{}
138 // ui::ComboboxModel:
139 int GetItemCount() const override
{ return (int)values_
->size(); }
140 base::string16
GetItemAt(int index
) override
{
141 return ASCIIToUTF16(values_
->at(index
));
143 bool IsItemSeparatorAt(int index
) override
{ return false; }
146 std::vector
<std::string
>* values_
;
149 class EvilListener
: public ComboboxListener
{
151 EvilListener() : deleted_(false) {}
152 ~EvilListener() override
{};
155 void OnPerformAction(Combobox
* combobox
) override
{
160 bool deleted() const { return deleted_
; }
165 DISALLOW_COPY_AND_ASSIGN(EvilListener
);
168 class TestComboboxListener
: public views::ComboboxListener
{
170 TestComboboxListener() : perform_action_index_(-1), actions_performed_(0) {}
171 ~TestComboboxListener() override
{}
173 void OnPerformAction(views::Combobox
* combobox
) override
{
174 perform_action_index_
= combobox
->selected_index();
175 actions_performed_
++;
178 int perform_action_index() const {
179 return perform_action_index_
;
182 bool on_perform_action_called() const {
183 return actions_performed_
> 0;
186 int actions_performed() const {
187 return actions_performed_
;
191 int perform_action_index_
;
192 int actions_performed_
;
195 DISALLOW_COPY_AND_ASSIGN(TestComboboxListener
);
200 class ComboboxTest
: public ViewsTestBase
{
202 ComboboxTest() : widget_(NULL
), combobox_(NULL
) {}
204 void TearDown() override
{
207 ViewsTestBase::TearDown();
210 void InitCombobox(const std::set
<int>* separators
) {
211 model_
.reset(new TestComboboxModel());
214 model_
->SetSeparators(*separators
);
216 ASSERT_FALSE(combobox_
);
217 combobox_
= new TestCombobox(model_
.get());
218 combobox_
->set_id(1);
220 widget_
= new Widget
;
221 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
222 params
.bounds
= gfx::Rect(200, 200, 200, 200);
223 widget_
->Init(params
);
224 View
* container
= new View();
225 widget_
->SetContentsView(container
);
226 container
->AddChildView(combobox_
);
228 combobox_
->RequestFocus();
229 combobox_
->SizeToPreferredSize();
233 void SendKeyEvent(ui::KeyboardCode key_code
) {
234 SendKeyEventWithType(key_code
, ui::ET_KEY_PRESSED
);
237 void SendKeyEventWithType(ui::KeyboardCode key_code
, ui::EventType type
) {
238 ui::KeyEvent
event(type
, key_code
, ui::EF_NONE
);
239 FocusManager
* focus_manager
= widget_
->GetFocusManager();
240 widget_
->OnKeyEvent(&event
);
241 if (!event
.handled() && focus_manager
)
242 focus_manager
->OnKeyEvent(event
);
245 View
* GetFocusedView() {
246 return widget_
->GetFocusManager()->GetFocusedView();
249 void PerformClick(const gfx::Point
& point
) {
250 ui::MouseEvent pressed_event
= ui::MouseEvent(
251 ui::ET_MOUSE_PRESSED
, point
, point
, ui::EventTimeForNow(),
252 ui::EF_LEFT_MOUSE_BUTTON
, ui::EF_LEFT_MOUSE_BUTTON
);
253 widget_
->OnMouseEvent(&pressed_event
);
254 ui::MouseEvent released_event
= ui::MouseEvent(
255 ui::ET_MOUSE_RELEASED
, point
, point
, ui::EventTimeForNow(),
256 ui::EF_LEFT_MOUSE_BUTTON
, ui::EF_LEFT_MOUSE_BUTTON
);
257 widget_
->OnMouseEvent(&released_event
);
260 // We need widget to populate wrapper class.
263 // |combobox_| will be allocated InitCombobox() and then owned by |widget_|.
264 TestCombobox
* combobox_
;
266 // Combobox does not take ownership of the model, hence it needs to be scoped.
267 scoped_ptr
<TestComboboxModel
> model_
;
270 TEST_F(ComboboxTest
, KeyTest
) {
272 SendKeyEvent(ui::VKEY_END
);
273 EXPECT_EQ(combobox_
->selected_index() + 1, model_
->GetItemCount());
274 SendKeyEvent(ui::VKEY_HOME
);
275 EXPECT_EQ(combobox_
->selected_index(), 0);
276 SendKeyEvent(ui::VKEY_DOWN
);
277 SendKeyEvent(ui::VKEY_DOWN
);
278 EXPECT_EQ(combobox_
->selected_index(), 2);
279 SendKeyEvent(ui::VKEY_RIGHT
);
280 EXPECT_EQ(combobox_
->selected_index(), 2);
281 SendKeyEvent(ui::VKEY_LEFT
);
282 EXPECT_EQ(combobox_
->selected_index(), 2);
283 SendKeyEvent(ui::VKEY_UP
);
284 EXPECT_EQ(combobox_
->selected_index(), 1);
285 SendKeyEvent(ui::VKEY_PRIOR
);
286 EXPECT_EQ(combobox_
->selected_index(), 0);
287 SendKeyEvent(ui::VKEY_NEXT
);
288 EXPECT_EQ(combobox_
->selected_index(), model_
->GetItemCount() - 1);
291 // Check that if a combobox is disabled before it has a native wrapper, then the
292 // native wrapper inherits the disabled state when it gets created.
293 TEST_F(ComboboxTest
, DisabilityTest
) {
294 model_
.reset(new TestComboboxModel());
296 ASSERT_FALSE(combobox_
);
297 combobox_
= new TestCombobox(model_
.get());
298 combobox_
->SetEnabled(false);
300 widget_
= new Widget
;
301 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_POPUP
);
302 params
.bounds
= gfx::Rect(100, 100, 100, 100);
303 widget_
->Init(params
);
304 View
* container
= new View();
305 widget_
->SetContentsView(container
);
306 container
->AddChildView(combobox_
);
307 EXPECT_FALSE(combobox_
->enabled());
310 // Verifies that we don't select a separator line in combobox when navigating
312 TEST_F(ComboboxTest
, SkipSeparatorSimple
) {
313 std::set
<int> separators
;
314 separators
.insert(2);
315 InitCombobox(&separators
);
316 EXPECT_EQ(0, combobox_
->selected_index());
317 SendKeyEvent(ui::VKEY_DOWN
);
318 EXPECT_EQ(1, combobox_
->selected_index());
319 SendKeyEvent(ui::VKEY_DOWN
);
320 EXPECT_EQ(3, combobox_
->selected_index());
321 SendKeyEvent(ui::VKEY_UP
);
322 EXPECT_EQ(1, combobox_
->selected_index());
323 SendKeyEvent(ui::VKEY_HOME
);
324 EXPECT_EQ(0, combobox_
->selected_index());
325 SendKeyEvent(ui::VKEY_PRIOR
);
326 EXPECT_EQ(0, combobox_
->selected_index());
327 SendKeyEvent(ui::VKEY_END
);
328 EXPECT_EQ(9, combobox_
->selected_index());
331 // Verifies that we never select the separator that is in the beginning of the
332 // combobox list when navigating through keyboard.
333 TEST_F(ComboboxTest
, SkipSeparatorBeginning
) {
334 std::set
<int> separators
;
335 separators
.insert(0);
336 InitCombobox(&separators
);
337 EXPECT_EQ(1, combobox_
->selected_index());
338 SendKeyEvent(ui::VKEY_DOWN
);
339 EXPECT_EQ(2, combobox_
->selected_index());
340 SendKeyEvent(ui::VKEY_DOWN
);
341 EXPECT_EQ(3, combobox_
->selected_index());
342 SendKeyEvent(ui::VKEY_UP
);
343 EXPECT_EQ(2, combobox_
->selected_index());
344 SendKeyEvent(ui::VKEY_HOME
);
345 EXPECT_EQ(1, combobox_
->selected_index());
346 SendKeyEvent(ui::VKEY_PRIOR
);
347 EXPECT_EQ(1, combobox_
->selected_index());
348 SendKeyEvent(ui::VKEY_END
);
349 EXPECT_EQ(9, combobox_
->selected_index());
352 // Verifies that we never select the separator that is in the end of the
353 // combobox list when navigating through keyboard.
354 TEST_F(ComboboxTest
, SkipSeparatorEnd
) {
355 std::set
<int> separators
;
356 separators
.insert(TestComboboxModel::kItemCount
- 1);
357 InitCombobox(&separators
);
358 combobox_
->SetSelectedIndex(8);
359 SendKeyEvent(ui::VKEY_DOWN
);
360 EXPECT_EQ(8, combobox_
->selected_index());
361 SendKeyEvent(ui::VKEY_UP
);
362 EXPECT_EQ(7, combobox_
->selected_index());
363 SendKeyEvent(ui::VKEY_END
);
364 EXPECT_EQ(8, combobox_
->selected_index());
367 // Verifies that we never select any of the adjacent separators (multiple
368 // consecutive) that appear in the beginning of the combobox list when
369 // navigating through keyboard.
370 TEST_F(ComboboxTest
, SkipMultipleSeparatorsAtBeginning
) {
371 std::set
<int> separators
;
372 separators
.insert(0);
373 separators
.insert(1);
374 separators
.insert(2);
375 InitCombobox(&separators
);
376 EXPECT_EQ(3, combobox_
->selected_index());
377 SendKeyEvent(ui::VKEY_DOWN
);
378 EXPECT_EQ(4, combobox_
->selected_index());
379 SendKeyEvent(ui::VKEY_UP
);
380 EXPECT_EQ(3, combobox_
->selected_index());
381 SendKeyEvent(ui::VKEY_NEXT
);
382 EXPECT_EQ(9, combobox_
->selected_index());
383 SendKeyEvent(ui::VKEY_HOME
);
384 EXPECT_EQ(3, combobox_
->selected_index());
385 SendKeyEvent(ui::VKEY_END
);
386 EXPECT_EQ(9, combobox_
->selected_index());
387 SendKeyEvent(ui::VKEY_PRIOR
);
388 EXPECT_EQ(3, combobox_
->selected_index());
391 // Verifies that we never select any of the adjacent separators (multiple
392 // consecutive) that appear in the middle of the combobox list when navigating
394 TEST_F(ComboboxTest
, SkipMultipleAdjacentSeparatorsAtMiddle
) {
395 std::set
<int> separators
;
396 separators
.insert(4);
397 separators
.insert(5);
398 separators
.insert(6);
399 InitCombobox(&separators
);
400 combobox_
->SetSelectedIndex(3);
401 SendKeyEvent(ui::VKEY_DOWN
);
402 EXPECT_EQ(7, combobox_
->selected_index());
403 SendKeyEvent(ui::VKEY_UP
);
404 EXPECT_EQ(3, combobox_
->selected_index());
407 // Verifies that we never select any of the adjacent separators (multiple
408 // consecutive) that appear in the end of the combobox list when navigating
410 TEST_F(ComboboxTest
, SkipMultipleSeparatorsAtEnd
) {
411 std::set
<int> separators
;
412 separators
.insert(7);
413 separators
.insert(8);
414 separators
.insert(9);
415 InitCombobox(&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
) {
432 std::set
<int> separators
;
433 separators
.insert(0);
434 separators
.insert(1);
435 separators
.insert(9);
436 InitCombobox(&separators
);
437 for (int i
= 0; i
< combobox_
->GetRowCount(); ++i
) {
438 if (separators
.count(i
) != 0) {
439 EXPECT_TRUE(combobox_
->GetTextForRow(i
).empty()) << i
;
441 EXPECT_EQ(ASCIIToUTF16(i
% 2 == 0 ? "PEANUT BUTTER" : "JELLY"),
442 combobox_
->GetTextForRow(i
)) << i
;
447 // Verifies selecting the first matching value (and returning whether found).
448 TEST_F(ComboboxTest
, SelectValue
) {
450 ASSERT_EQ(model_
->GetDefaultIndex(), combobox_
->selected_index());
451 EXPECT_TRUE(combobox_
->SelectValue(ASCIIToUTF16("PEANUT BUTTER")));
452 EXPECT_EQ(0, combobox_
->selected_index());
453 EXPECT_TRUE(combobox_
->SelectValue(ASCIIToUTF16("JELLY")));
454 EXPECT_EQ(1, combobox_
->selected_index());
455 EXPECT_FALSE(combobox_
->SelectValue(ASCIIToUTF16("BANANAS")));
456 EXPECT_EQ(1, combobox_
->selected_index());
458 // With the action style, the selected index is always 0.
459 combobox_
->SetStyle(Combobox::STYLE_ACTION
);
460 EXPECT_FALSE(combobox_
->SelectValue(ASCIIToUTF16("PEANUT BUTTER")));
461 EXPECT_EQ(0, combobox_
->selected_index());
462 EXPECT_FALSE(combobox_
->SelectValue(ASCIIToUTF16("JELLY")));
463 EXPECT_EQ(0, combobox_
->selected_index());
464 EXPECT_FALSE(combobox_
->SelectValue(ASCIIToUTF16("BANANAS")));
465 EXPECT_EQ(0, combobox_
->selected_index());
468 TEST_F(ComboboxTest
, SelectIndexActionStyle
) {
471 // With the action style, the selected index is always 0.
472 combobox_
->SetStyle(Combobox::STYLE_ACTION
);
473 combobox_
->SetSelectedIndex(1);
474 EXPECT_EQ(0, combobox_
->selected_index());
475 combobox_
->SetSelectedIndex(2);
476 EXPECT_EQ(0, combobox_
->selected_index());
477 combobox_
->SetSelectedIndex(3);
478 EXPECT_EQ(0, combobox_
->selected_index());
481 TEST_F(ComboboxTest
, ListenerHandlesDelete
) {
482 TestComboboxModel model
;
484 // |combobox| will be deleted on change.
485 TestCombobox
* combobox
= new TestCombobox(&model
);
486 scoped_ptr
<EvilListener
> evil_listener(new EvilListener());
487 combobox
->set_listener(evil_listener
.get());
488 ASSERT_NO_FATAL_FAILURE(combobox
->ExecuteCommand(2));
489 EXPECT_TRUE(evil_listener
->deleted());
492 // |combobox| will be deleted on change.
493 combobox
= new TestCombobox(&model
);
494 evil_listener
.reset(new EvilListener());
495 combobox
->set_listener(evil_listener
.get());
496 combobox
->SetStyle(Combobox::STYLE_ACTION
);
497 ASSERT_NO_FATAL_FAILURE(combobox
->ExecuteCommand(2));
498 EXPECT_TRUE(evil_listener
->deleted());
501 TEST_F(ComboboxTest
, Click
) {
504 TestComboboxListener listener
;
505 combobox_
->set_listener(&listener
);
509 // Click the left side. The menu is shown.
510 TestMenuRunnerHandler
* test_menu_runner_handler
= new TestMenuRunnerHandler();
511 scoped_ptr
<MenuRunnerHandler
> menu_runner_handler(test_menu_runner_handler
);
512 test::MenuRunnerTestAPI
test_api(
513 combobox_
->dropdown_list_menu_runner_
.get());
514 test_api
.SetMenuRunnerHandler(menu_runner_handler
.Pass());
515 PerformClick(gfx::Point(combobox_
->x() + 1,
516 combobox_
->y() + combobox_
->height() / 2));
517 EXPECT_FALSE(listener
.on_perform_action_called());
518 EXPECT_TRUE(test_menu_runner_handler
->executed());
521 TEST_F(ComboboxTest
, ClickButDisabled
) {
524 TestComboboxListener listener
;
525 combobox_
->set_listener(&listener
);
528 combobox_
->SetEnabled(false);
530 // Click the left side, but nothing happens since the combobox is disabled.
531 TestMenuRunnerHandler
* test_menu_runner_handler
= new TestMenuRunnerHandler();
532 scoped_ptr
<MenuRunnerHandler
> menu_runner_handler(test_menu_runner_handler
);
533 test::MenuRunnerTestAPI
test_api(
534 combobox_
->dropdown_list_menu_runner_
.get());
535 test_api
.SetMenuRunnerHandler(menu_runner_handler
.Pass());
536 PerformClick(gfx::Point(combobox_
->x() + 1,
537 combobox_
->y() + combobox_
->height() / 2));
538 EXPECT_FALSE(listener
.on_perform_action_called());
539 EXPECT_FALSE(test_menu_runner_handler
->executed());
542 TEST_F(ComboboxTest
, NotifyOnClickWithReturnKey
) {
545 TestComboboxListener listener
;
546 combobox_
->set_listener(&listener
);
548 // With STYLE_NORMAL, the click event is ignored.
549 SendKeyEvent(ui::VKEY_RETURN
);
550 EXPECT_FALSE(listener
.on_perform_action_called());
552 // With STYLE_ACTION, the click event is notified.
553 combobox_
->SetStyle(Combobox::STYLE_ACTION
);
554 SendKeyEvent(ui::VKEY_RETURN
);
555 EXPECT_TRUE(listener
.on_perform_action_called());
556 EXPECT_EQ(0, listener
.perform_action_index());
559 TEST_F(ComboboxTest
, NotifyOnClickWithSpaceKey
) {
562 TestComboboxListener listener
;
563 combobox_
->set_listener(&listener
);
565 // With STYLE_NORMAL, the click event is ignored.
566 SendKeyEvent(ui::VKEY_SPACE
);
567 EXPECT_FALSE(listener
.on_perform_action_called());
568 SendKeyEventWithType(ui::VKEY_SPACE
, ui::ET_KEY_RELEASED
);
569 EXPECT_FALSE(listener
.on_perform_action_called());
571 // With STYLE_ACTION, the click event is notified after releasing.
572 combobox_
->SetStyle(Combobox::STYLE_ACTION
);
573 SendKeyEvent(ui::VKEY_SPACE
);
574 EXPECT_FALSE(listener
.on_perform_action_called());
575 SendKeyEventWithType(ui::VKEY_SPACE
, ui::ET_KEY_RELEASED
);
576 EXPECT_TRUE(listener
.on_perform_action_called());
577 EXPECT_EQ(0, listener
.perform_action_index());
580 TEST_F(ComboboxTest
, NotifyOnClickWithMouse
) {
583 TestComboboxListener listener
;
584 combobox_
->set_listener(&listener
);
586 combobox_
->SetStyle(Combobox::STYLE_ACTION
);
589 // Click the right side (arrow button). The menu is shown.
590 TestMenuRunnerHandler
* test_menu_runner_handler
= new TestMenuRunnerHandler();
591 scoped_ptr
<MenuRunnerHandler
> menu_runner_handler(test_menu_runner_handler
);
592 scoped_ptr
<test::MenuRunnerTestAPI
> test_api(
593 new test::MenuRunnerTestAPI(combobox_
->dropdown_list_menu_runner_
.get()));
594 test_api
->SetMenuRunnerHandler(menu_runner_handler
.Pass());
596 PerformClick(gfx::Point(combobox_
->x() + combobox_
->width() - 1,
597 combobox_
->y() + combobox_
->height() / 2));
598 EXPECT_FALSE(listener
.on_perform_action_called());
599 EXPECT_TRUE(test_menu_runner_handler
->executed());
601 // Click the left side (text button). The click event is notified.
602 test_menu_runner_handler
= new TestMenuRunnerHandler();
603 menu_runner_handler
.reset(test_menu_runner_handler
);
605 new test::MenuRunnerTestAPI(combobox_
->dropdown_list_menu_runner_
.get()));
606 test_api
->SetMenuRunnerHandler(menu_runner_handler
.Pass());
607 PerformClick(gfx::Point(combobox_
->x() + 1,
608 combobox_
->y() + combobox_
->height() / 2));
609 EXPECT_TRUE(listener
.on_perform_action_called());
610 EXPECT_FALSE(test_menu_runner_handler
->executed());
611 EXPECT_EQ(0, listener
.perform_action_index());
614 TEST_F(ComboboxTest
, ConsumingPressKeyEvents
) {
617 EXPECT_FALSE(combobox_
->OnKeyPressed(
618 ui::KeyEvent(ui::ET_KEY_PRESSED
, ui::VKEY_RETURN
, ui::EF_NONE
)));
619 EXPECT_FALSE(combobox_
->OnKeyPressed(
620 ui::KeyEvent(ui::ET_KEY_PRESSED
, ui::VKEY_SPACE
, ui::EF_NONE
)));
622 // When the combobox's style is STYLE_ACTION, pressing events of a space key
623 // or an enter key will be consumed.
624 combobox_
->SetStyle(Combobox::STYLE_ACTION
);
625 EXPECT_TRUE(combobox_
->OnKeyPressed(
626 ui::KeyEvent(ui::ET_KEY_PRESSED
, ui::VKEY_RETURN
, ui::EF_NONE
)));
627 EXPECT_TRUE(combobox_
->OnKeyPressed(
628 ui::KeyEvent(ui::ET_KEY_PRESSED
, ui::VKEY_SPACE
, ui::EF_NONE
)));
631 TEST_F(ComboboxTest
, ContentWidth
) {
632 std::vector
<std::string
> values
;
633 VectorComboboxModel
model(&values
);
634 TestCombobox
combobox(&model
);
636 std::string long_item
= "this is the long item";
637 std::string short_item
= "s";
640 values
[0] = long_item
;
641 combobox
.ModelChanged();
643 const int long_item_width
= combobox
.content_size_
.width();
645 values
[0] = short_item
;
646 combobox
.ModelChanged();
648 const int short_item_width
= combobox
.content_size_
.width();
651 values
[0] = short_item
;
652 values
[1] = long_item
;
653 combobox
.ModelChanged();
655 // When the style is STYLE_NORMAL, the width will fit with the longest item.
656 combobox
.SetStyle(Combobox::STYLE_NORMAL
);
657 EXPECT_EQ(long_item_width
, combobox
.content_size_
.width());
659 // When the style is STYLE_ACTION, the width will fit with the first items'
661 combobox
.SetStyle(Combobox::STYLE_ACTION
);
662 EXPECT_EQ(short_item_width
, combobox
.content_size_
.width());
665 TEST_F(ComboboxTest
, TypingPrefixNotifiesListener
) {
668 TestComboboxListener listener
;
669 combobox_
->set_listener(&listener
);
670 ui::TextInputClient
* input_client
=
671 widget_
->GetInputMethod()->GetTextInputClient();
673 // Type the first character of the second menu item ("JELLY").
674 input_client
->InsertChar('J', ui::EF_NONE
);
675 EXPECT_EQ(1, listener
.actions_performed());
676 EXPECT_EQ(1, listener
.perform_action_index());
678 // Type the second character of "JELLY", item shouldn't change and
679 // OnPerformAction() shouldn't be re-called.
680 input_client
->InsertChar('E', ui::EF_NONE
);
681 EXPECT_EQ(1, listener
.actions_performed());
682 EXPECT_EQ(1, listener
.perform_action_index());
684 // Clears the typed text.
686 combobox_
->RequestFocus();
688 // Type the first character of "PEANUT BUTTER", which should change the
689 // selected index and perform an action.
690 input_client
->InsertChar('P', ui::EF_NONE
);
691 EXPECT_EQ(2, listener
.actions_performed());
692 EXPECT_EQ(2, listener
.perform_action_index());