From f254e2424a5220e559e48205ace1114ea3e87f3f Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 16 Oct 2010 18:10:42 +0000 Subject: [PATCH] Improve validation of wxCheckBox styles. Detect when incompatible styles are used (this required changing the value of wxCHK_2STATE to be non-null) and sanitize the styles (after asserting) in this case. Put the validation code in wxCheckBoxBase instead of having slightly different versions of it in port-specific wxCheckBox implementations. Add a unit test checking that the expected asserts are indeed generated. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@65824 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/checkbox.h | 47 ++++++++++++++++++++++++++++++++- src/gtk/checkbox.cpp | 6 +---- src/gtk1/checkbox.cpp | 6 +---- src/msw/checkbox.cpp | 8 +----- src/osx/checkbox_osx.cpp | 1 + src/univ/checkbox.cpp | 1 + tests/controls/checkboxtest.cpp | 45 +++++++++++++++++++++++++++---- 7 files changed, 91 insertions(+), 23 deletions(-) diff --git a/include/wx/checkbox.h b/include/wx/checkbox.h index 60a8189f24..342db830cf 100644 --- a/include/wx/checkbox.h +++ b/include/wx/checkbox.h @@ -25,8 +25,12 @@ * Determine whether to use a 3-state or 2-state * checkbox. 3-state enables to differentiate * between 'unchecked', 'checked' and 'undetermined'. + * + * In addition to the styles here it is also possible to specify just 0 which + * is treated the same as wxCHK_2STATE for compatibility (but using explicit + * flag is preferred). */ -#define wxCHK_2STATE 0x0000 +#define wxCHK_2STATE 0x4000 #define wxCHK_3STATE 0x1000 /* @@ -129,6 +133,47 @@ protected: return wxCHK_UNCHECKED; } + // Helper function to be called from derived classes Create() + // implementations: it checks that the style doesn't contain any + // incompatible bits and modifies it to be sane if it does. + static void WXValidateStyle(long *stylePtr) + { + long& style = *stylePtr; + + if ( style == 0 ) + { + // For compatibility we use absence of style flags as wxCHK_2STATE + // because wxCHK_2STATE used to have the value of 0 and some + // existing code may use 0 instead of it. + style = wxCHK_2STATE; + } + else if ( style & wxCHK_3STATE ) + { + if ( style & wxCHK_2STATE ) + { + wxFAIL_MSG( "wxCHK_2STATE and wxCHK_3STATE can't be used " + "together" ); + style &= ~wxCHK_3STATE; + } + } + else // No wxCHK_3STATE + { + if ( !(style & wxCHK_2STATE) ) + { + wxFAIL_MSG( "Either wxCHK_2STATE or wxCHK_3STATE must be " + "specified" ); + style |= wxCHK_2STATE; + } + + if ( style & wxCHK_ALLOW_3RD_STATE_FOR_USER ) + { + wxFAIL_MSG( "wxCHK_ALLOW_3RD_STATE_FOR_USER doesn't make sense " + "without wxCHK_3STATE" ); + style &= ~wxCHK_ALLOW_3RD_STATE_FOR_USER; + } + } + } + private: wxDECLARE_NO_COPY_CLASS(wxCheckBoxBase); }; diff --git a/src/gtk/checkbox.cpp b/src/gtk/checkbox.cpp index 52d99fe569..5faa27c19b 100644 --- a/src/gtk/checkbox.cpp +++ b/src/gtk/checkbox.cpp @@ -105,6 +105,7 @@ bool wxCheckBox::Create(wxWindow *parent, const wxValidator& validator, const wxString &name ) { + WXValidateStyle( &style ); if (!PreCreation( parent, pos, size ) || !CreateBase( parent, id, pos, size, style, validator, name )) { @@ -112,11 +113,6 @@ bool wxCheckBox::Create(wxWindow *parent, return false; } - wxASSERT_MSG( (style & wxCHK_ALLOW_3RD_STATE_FOR_USER) == 0 || - (style & wxCHK_3STATE) != 0, - wxT("Using wxCHK_ALLOW_3RD_STATE_FOR_USER") - wxT(" style flag for a 2-state checkbox is useless") ); - if ( style & wxALIGN_RIGHT ) { // VZ: as I don't know a way to create a right aligned checkbox with diff --git a/src/gtk1/checkbox.cpp b/src/gtk1/checkbox.cpp index 4bd1fd35af..c895b7c82c 100644 --- a/src/gtk1/checkbox.cpp +++ b/src/gtk1/checkbox.cpp @@ -77,6 +77,7 @@ bool wxCheckBox::Create(wxWindow *parent, m_acceptsFocus = true; m_blockEvent = false; + WXValidateStyle(&style); if (!PreCreation( parent, pos, size ) || !CreateBase( parent, id, pos, size, style, validator, name )) { @@ -84,11 +85,6 @@ bool wxCheckBox::Create(wxWindow *parent, return false; } - wxASSERT_MSG( (style & wxCHK_ALLOW_3RD_STATE_FOR_USER) == 0 || - (style & wxCHK_3STATE) != 0, - wxT("Using wxCHK_ALLOW_3RD_STATE_FOR_USER") - wxT(" style flag for a 2-state checkbox is useless") ); - if ( style & wxALIGN_RIGHT ) { // VZ: as I don't know a way to create a right aligned checkbox with diff --git a/src/msw/checkbox.cpp b/src/msw/checkbox.cpp index 3d2e8d80a9..2a9e8643ef 100644 --- a/src/msw/checkbox.cpp +++ b/src/msw/checkbox.cpp @@ -153,22 +153,16 @@ bool wxCheckBox::Create(wxWindow *parent, { Init(); + WXValidateStyle(&style); if ( !CreateControl(parent, id, pos, size, style, validator, name) ) return false; long msStyle = WS_TABSTOP; if ( style & wxCHK_3STATE ) - { msStyle |= BS_3STATE; - } else - { - wxASSERT_MSG( !Is3rdStateAllowedForUser(), - wxT("Using wxCH_ALLOW_3RD_STATE_FOR_USER") - wxT(" style flag for a 2-state checkbox is useless") ); msStyle |= BS_CHECKBOX; - } if ( style & wxALIGN_RIGHT ) { diff --git a/src/osx/checkbox_osx.cpp b/src/osx/checkbox_osx.cpp index f248aff651..93cbf2c7bb 100644 --- a/src/osx/checkbox_osx.cpp +++ b/src/osx/checkbox_osx.cpp @@ -36,6 +36,7 @@ bool wxCheckBox::Create(wxWindow *parent, m_labelOrig = m_label = label ; + WXValidateStyle( &style ); m_peer = wxWidgetImpl::CreateCheckBox( this, parent, id, label, pos, size, style, GetExtraStyle() ) ; MacPostControlCreate(pos, size) ; diff --git a/src/univ/checkbox.cpp b/src/univ/checkbox.cpp index b1f443903f..d92d93808e 100644 --- a/src/univ/checkbox.cpp +++ b/src/univ/checkbox.cpp @@ -80,6 +80,7 @@ bool wxCheckBox::Create(wxWindow *parent, const wxValidator& validator, const wxString &name) { + WXValidateStyle( &style ); if ( !wxControl::Create(parent, id, pos, size, style, validator, name) ) return false; diff --git a/tests/controls/checkboxtest.cpp b/tests/controls/checkboxtest.cpp index 1e1ba92cc7..359d544d18 100644 --- a/tests/controls/checkboxtest.cpp +++ b/tests/controls/checkboxtest.cpp @@ -35,11 +35,26 @@ private: CPPUNIT_TEST( Check ); CPPUNIT_TEST( ThirdState ); CPPUNIT_TEST( ThirdStateUser ); + CPPUNIT_TEST( InvalidStyles ); CPPUNIT_TEST_SUITE_END(); void Check(); void ThirdState(); void ThirdStateUser(); + void InvalidStyles(); + + // Initialize m_check with a new checkbox with the specified style + // + // This function always returns false just to make it more convenient to + // use inside WX_ASSERT_FAILS_WITH_ASSERT(), its return value doesn't have + // any meaning otherwise. + bool CreateCheckBox(long style) + { + m_check = new wxCheckBox(wxTheApp->GetTopWindow(), wxID_ANY, "Check box", + wxDefaultPosition, wxDefaultSize, style); + return false; + } + wxCheckBox* m_check; @@ -96,8 +111,7 @@ void CheckBoxTestCase::ThirdState() { #if !defined(__WXMGL__) && !defined(__WXPM__) && !defined(__WXGTK12__) wxDELETE(m_check); - m_check = new wxCheckBox(wxTheApp->GetTopWindow(), wxID_ANY, "Check box", - wxDefaultPosition, wxDefaultSize, wxCHK_3STATE); + CreateCheckBox(wxCHK_3STATE); CPPUNIT_ASSERT_EQUAL(wxCHK_UNCHECKED, m_check->Get3StateValue()); CPPUNIT_ASSERT(m_check->Is3State()); @@ -117,9 +131,7 @@ void CheckBoxTestCase::ThirdStateUser() { #if !defined(__WXMGL__) && !defined(__WXPM__) && !defined(__WXGTK12__) wxDELETE(m_check); - m_check = new wxCheckBox(wxTheApp->GetTopWindow(), wxID_ANY, "Check box", - wxDefaultPosition, wxDefaultSize, - wxCHK_3STATE | wxCHK_ALLOW_3RD_STATE_FOR_USER); + CreateCheckBox(wxCHK_3STATE | wxCHK_ALLOW_3RD_STATE_FOR_USER); CPPUNIT_ASSERT_EQUAL(wxCHK_UNCHECKED, m_check->Get3StateValue()); CPPUNIT_ASSERT(m_check->Is3State()); @@ -135,4 +147,27 @@ void CheckBoxTestCase::ThirdStateUser() #endif } +void CheckBoxTestCase::InvalidStyles() +{ + // Check that using incompatible styles doesn't work. + wxDELETE( m_check ); + WX_ASSERT_FAILS_WITH_ASSERT( CreateCheckBox(wxCHK_2STATE | wxCHK_3STATE) ); +#if !wxDEBUG_LEVEL + CPPUNIT_ASSERT( !m_check->Is3State() ); + CPPUNIT_ASSERT( !m_check->Is3rdStateAllowedForUser() ); +#endif + + wxDELETE( m_check ); + WX_ASSERT_FAILS_WITH_ASSERT( + CreateCheckBox(wxCHK_2STATE | wxCHK_ALLOW_3RD_STATE_FOR_USER) ); +#if !wxDEBUG_LEVEL + CPPUNIT_ASSERT( !m_check->Is3State() ); + CPPUNIT_ASSERT( !m_check->Is3rdStateAllowedForUser() ); +#endif + + // wxCHK_ALLOW_3RD_STATE_FOR_USER without wxCHK_3STATE doesn't work. + wxDELETE( m_check ); + WX_ASSERT_FAILS_WITH_ASSERT( CreateCheckBox(wxCHK_ALLOW_3RD_STATE_FOR_USER) ); +} + #endif //wxUSE_CHECKBOX -- 2.45.2