From 1addaeaa750fc84b6f8b60de8676af10f147b1bc Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 10 Sep 2014 16:52:01 +0000 Subject: [PATCH] Add wxUIActionSimulator::Select(). Add a helper to select an item in a wxChoice, wxComboBox, wxListBox or similar. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@77662 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + include/wx/uiaction.h | 3 ++ interface/wx/uiaction.h | 24 ++++++++++ src/common/uiactioncmn.cpp | 69 ++++++++++++++++++++++++++++ tests/controls/itemcontainertest.cpp | 25 ++++++++++ tests/controls/itemcontainertest.h | 4 +- 6 files changed, 125 insertions(+), 1 deletion(-) diff --git a/docs/changes.txt b/docs/changes.txt index 52c8093504..70e771a3dd 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -79,6 +79,7 @@ All (GUI): - Fix drawing custom colours of wxEnumProperty items in wxPG (Artur Wieczorek). - Add wxBitmap ctor from wxCursor. - Always disable wxWizard "Back" button on the starting page (pmgrace30). +- Add wxUIActionSimulator::Select(). wxGTK: diff --git a/include/wx/uiaction.h b/include/wx/uiaction.h index fb96523544..498da69821 100644 --- a/include/wx/uiaction.h +++ b/include/wx/uiaction.h @@ -65,6 +65,9 @@ public: bool Text(const char *text); + // Select the item with the given text in the currently focused control. + bool Select(const wxString& text); + private: // This is the common part of Key{Down,Up}() methods: while we keep them // separate at public API level for consistency with Mouse{Down,Up}(), at diff --git a/interface/wx/uiaction.h b/interface/wx/uiaction.h index 51827cba06..05414003ea 100644 --- a/interface/wx/uiaction.h +++ b/interface/wx/uiaction.h @@ -144,6 +144,30 @@ public: */ bool Char(int keycode, int modifiers = wxMOD_NONE); + /** + Simulate selection of an item with the given text. + + This method selects an item in the currently focused wxChoice, + wxComboBox, wxListBox and similar controls. It does it by simulating + keyboard events, so the behaviour should be the same as if the item + was really selected by the user. + + Notice that the implementation of this method uses wxYield() and so + events can be dispatched from it. + + @param text + The text of the item to select. + + @return + @true if the item @a text was successfully selected or @false if + the currently focused window is not one of the controls allowing + item selection or if the item with the given text was not found in + it. + + @since 3.1.0 + */ + bool Select(const wxString& text); + /** Emulate typing in the keys representing the given string. diff --git a/src/common/uiactioncmn.cpp b/src/common/uiactioncmn.cpp index 32a8d2f2d4..04fb4477cf 100644 --- a/src/common/uiactioncmn.cpp +++ b/src/common/uiactioncmn.cpp @@ -16,6 +16,15 @@ #include "wx/uiaction.h" +#include "wx/ctrlsub.h" + +#ifdef wxNO_RTTI + #include "wx/choice.h" + #include "wx/combobox.h" + #include "wx/listbox.h" +#endif // wxNO_RTTI + + bool wxUIActionSimulator::MouseClick(int button) { MouseDown(button); @@ -145,4 +154,64 @@ bool wxUIActionSimulator::Text(const char *s) return true; } +bool wxUIActionSimulator::Select(const wxString& text) +{ + wxWindow* const focus = wxWindow::FindFocus(); + if ( !focus ) + return false; + + // We can only select something in controls inheriting from + // wxItemContainer, so check that we have it. +#ifdef wxNO_RTTI + wxItemContainer* container = NULL; + + if ( wxComboBox* combo = wxDynamicCast(focus, wxComboBox) ) + container = combo; + else if ( wxChoice* choice = wxDynamicCast(focus, wxChoice) ) + container = choice; + else if ( wxListBox* listbox = wxDynamicCast(focus, wxListBox) ) + container = listbox; +#else // !wxNO_RTTI + wxItemContainer* const container = dynamic_cast(focus); +#endif // wxNO_RTTI/!wxNO_RTTI + + if ( !container ) + return false; + + // We prefer to exactly emulate what a (keyboard) user would do, so prefer + // to emulate selecting the first item of the control if possible (this + // works with wxChoice, wxListBox and wxComboBox with wxCB_READONLY style + // under MSW). + if ( container->GetSelection() != 0 ) + { + Char(WXK_HOME); + wxYield(); + + // But if this didn't work, set the selection programmatically. + if ( container->GetSelection() != 0 ) + container->SetSelection(0); + } + + // And then go down in the control until we reach the item we want. + for ( ;; ) + { + if ( container->GetStringSelection() == text ) + return true; + + // We could test if the selection becomes equal to its maximal value + // (i.e. GetCount() - 1), but if, for some reason, pressing WXK_DOWN + // doesn't move it, this would still result in an infinite loop, so + // check that the selection changed for additional safety. + const int current = container->GetSelection(); + + Char(WXK_DOWN); + wxYield(); + + if ( container->GetSelection() == current ) + break; + } + + return false; +} + #endif // wxUSE_UIACTIONSIMULATOR diff --git a/tests/controls/itemcontainertest.cpp b/tests/controls/itemcontainertest.cpp index 3b5c003110..0129d6dce5 100644 --- a/tests/controls/itemcontainertest.cpp +++ b/tests/controls/itemcontainertest.cpp @@ -14,6 +14,7 @@ #endif // WX_PRECOMP #include "wx/scopeguard.h" +#include "wx/uiaction.h" #include "itemcontainertest.h" @@ -303,3 +304,27 @@ void ItemContainerTestCase::SetSelection() container->SetSelection(1); CPPUNIT_ASSERT_EQUAL( 1, container->GetSelection() ); } + +#if wxUSE_UIACTIONSIMULATOR + +void ItemContainerTestCase::SimSelect() +{ + wxItemContainer * const container = GetContainer(); + + container->Append("first"); + container->Append("second"); + container->Append("third"); + + GetContainerWindow()->SetFocus(); + + wxUIActionSimulator sim; + CPPUNIT_ASSERT( sim.Select("third") ); + CPPUNIT_ASSERT_EQUAL( 2, container->GetSelection() ); + + CPPUNIT_ASSERT( sim.Select("first") ); + CPPUNIT_ASSERT_EQUAL( 0, container->GetSelection() ); + + CPPUNIT_ASSERT( !sim.Select("tenth") ); +} + +#endif // wxUSE_UIACTIONSIMULATOR diff --git a/tests/controls/itemcontainertest.h b/tests/controls/itemcontainertest.h index 305b9089a9..5d4ea0bc37 100644 --- a/tests/controls/itemcontainertest.h +++ b/tests/controls/itemcontainertest.h @@ -39,7 +39,8 @@ protected: CPPUNIT_TEST( VoidData ); \ CPPUNIT_TEST( Set ); \ CPPUNIT_TEST( SetSelection ); \ - CPPUNIT_TEST( SetString ) + CPPUNIT_TEST( SetString ); \ + WXUISIM_TEST( SimSelect ); void Append(); void Insert(); @@ -51,6 +52,7 @@ protected: void Set(); void SetSelection(); void SetString(); + void SimSelect(); private: wxDECLARE_NO_COPY_CLASS(ItemContainerTestCase);