diff --git a/include/wx/any.h b/include/wx/any.h index 2e9a9af4e5..64930ef66b 100644 --- a/include/wx/any.h +++ b/include/wx/any.h @@ -402,36 +402,56 @@ WX_ANY_DEFINE_SUB_TYPE(wxULongLong_t, Uint) #endif +// +// This macro is used in header, but then in source file we must have: +// WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl##TYPENAME) +// +#define _WX_ANY_DEFINE_CONVERTIBLE_TYPE(T, TYPENAME, CONVFUNC, GV) \ +class WXDLLIMPEXP_BASE wxAnyValueTypeImpl##TYPENAME : \ + public wxAnyValueTypeImplBase \ +{ \ + WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImpl##TYPENAME) \ +public: \ + wxAnyValueTypeImpl##TYPENAME() : \ + wxAnyValueTypeImplBase() { } \ + virtual ~wxAnyValueTypeImpl##TYPENAME() { } \ + virtual bool ConvertValue(const wxAnyValueBuffer& src, \ + wxAnyValueType* dstType, \ + wxAnyValueBuffer& dst) const \ + { \ + GV value = GetValue(src); \ + return CONVFUNC(value, dstType, dst); \ + } \ +}; \ +template<> \ +class wxAnyValueTypeImpl : public wxAnyValueTypeImpl##TYPENAME \ +{ \ +public: \ + wxAnyValueTypeImpl() : wxAnyValueTypeImpl##TYPENAME() { } \ + virtual ~wxAnyValueTypeImpl() { } \ +}; + +#define WX_ANY_DEFINE_CONVERTIBLE_TYPE(T, TYPENAME, CONVFUNC, BT) \ +_WX_ANY_DEFINE_CONVERTIBLE_TYPE(T, TYPENAME, CONVFUNC, BT) \ + +#define WX_ANY_DEFINE_CONVERTIBLE_TYPE_BASE(T, TYPENAME, CONVFUNC) \ +_WX_ANY_DEFINE_CONVERTIBLE_TYPE(T, TYPENAME, \ + CONVFUNC, const T&) \ + // // String value type // -class WXDLLIMPEXP_BASE wxAnyValueTypeImplString : - public wxAnyValueTypeImplBase -{ - WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImplString) -public: - wxAnyValueTypeImplString() : - wxAnyValueTypeImplBase() { } - virtual ~wxAnyValueTypeImplString() { } - /** - Convert value into buffer of different type. Return false if - not possible. - */ - virtual bool ConvertValue(const wxAnyValueBuffer& src, - wxAnyValueType* dstType, - wxAnyValueBuffer& dst) const; - -}; - -template<> -class wxAnyValueTypeImpl : public wxAnyValueTypeImplString -{ -public: - wxAnyValueTypeImpl() : wxAnyValueTypeImplString() { } - virtual ~wxAnyValueTypeImpl() { } -}; +// Convert wxString to destination wxAny value type +extern WXDLLIMPEXP_BASE bool wxAnyConvertString(const wxString& value, + wxAnyValueType* dstType, + wxAnyValueBuffer& dst); +WX_ANY_DEFINE_CONVERTIBLE_TYPE_BASE(wxString, wxString, wxAnyConvertString) +WX_ANY_DEFINE_CONVERTIBLE_TYPE(const char*, ConstCharPtr, + wxAnyConvertString, wxString) +WX_ANY_DEFINE_CONVERTIBLE_TYPE(const wchar_t*, ConstWchar_tPtr, + wxAnyConvertString, wxString) // // Bool value type @@ -686,16 +706,16 @@ public: wxAnyValueTypeImpl::SetValue(value, m_buffer); } + // These two constructors are needed to deal with string literals wxAny(const char* value) { - m_type = wxAnyNullValueType; - Assign(wxString(value)); + m_type = wxAnyValueTypeImpl::sm_instance; + wxAnyValueTypeImpl::SetValue(value, m_buffer); } - wxAny(const wchar_t* value) { - m_type = wxAnyNullValueType; - Assign(wxString(value)); + m_type = wxAnyValueTypeImpl::sm_instance; + wxAnyValueTypeImpl::SetValue(value, m_buffer); } wxAny(const wxAny& any) @@ -789,11 +809,17 @@ public: } #endif + // These two operators are needed to deal with string literals wxAny& operator=(const char* value) - { Assign(wxString(value)); return *this; } + { + Assign(value); + return *this; + } wxAny& operator=(const wchar_t* value) - { Assign(wxString(value)); return *this; } - //@} + { + Assign(value); + return *this; + } //@{ /** @@ -801,12 +827,10 @@ public: */ bool operator==(const wxString& value) const { - if ( !wxAnyValueTypeImpl::IsSameClass(m_type) ) + wxString value2; + if ( !GetAs(&value2) ) return false; - - return value == - static_cast - (wxAnyValueTypeImpl::GetValue(m_buffer)); + return value == value2; } bool operator==(const char* value) const @@ -865,14 +889,17 @@ public: //@} /** - This template function converts wxAny into given type. No dynamic - conversion is performed, so if the type is incorrect an assertion - failure will occur in debug builds, and a bogus value is returned - in release ones. + This template function converts wxAny into given type. In most cases + no type conversion is performed, so if the type is incorrect an + assertion failure will occur. - @remarks This template function does not work on some older compilers - (such as Visual C++ 6.0). For full compiler compatibility - please use wxANY_AS(any, T) macro instead. + @remarks For conveniency, conversion is done when T is wxString. This + is useful when a string literal (which are treated as + const char* and const wchar_t*) has been assigned to wxAny. + + This template function may not work properly with Visual C++ + 6. For full compiler compatibility, please use + wxANY_AS(any, T) macro instead. */ // FIXME-VC6: remove this hack when VC6 is no longer supported template @@ -886,6 +913,19 @@ public: return static_cast(wxAnyValueTypeImpl::GetValue(m_buffer)); } + // Allow easy conversion from 'const char *' etc. to wxString + // FIXME-VC6: remove this hack when VC6 is no longer supported + //template<> + wxString As(wxString*) const + { + wxString value; + if ( !GetAs(&value) ) + { + wxFAIL_MSG("Incorrect or non-convertible data type"); + } + return value; + } + /** Template function that etrieves and converts the value of this variant to the type that T* value is. diff --git a/include/wx/variant.h b/include/wx/variant.h index 852be3bb6b..671db18c65 100644 --- a/include/wx/variant.h +++ b/include/wx/variant.h @@ -404,10 +404,13 @@ private: virtual bool GetAsAny(wxAny* any) const; \ static wxVariantData* VariantDataFactory(const wxAny& any); -#define REGISTER_WXANY_CONVERSION(T, CLASSNAME) \ +#define _REGISTER_WXANY_CONVERSION(T, CLASSNAME, FUNC) \ static wxAnyToVariantRegistrationImpl \ gs_##CLASSNAME##AnyToVariantRegistration = \ - wxAnyToVariantRegistrationImpl(&CLASSNAME::VariantDataFactory); + wxAnyToVariantRegistrationImpl(&FUNC); + +#define REGISTER_WXANY_CONVERSION(T, CLASSNAME) \ +_REGISTER_WXANY_CONVERSION(T, CLASSNAME, CLASSNAME::VariantDataFactory) #define IMPLEMENT_TRIVIAL_WXANY_CONVERSION(T, CLASSNAME) \ bool CLASSNAME::GetAsAny(wxAny* any) const \ diff --git a/interface/wx/any.h b/interface/wx/any.h index 826d2b7a14..2a8a22c3e6 100644 --- a/interface/wx/any.h +++ b/interface/wx/any.h @@ -104,14 +104,17 @@ public: ~wxAny(); /** - This template function converts wxAny into given type. No dynamic - conversion is performed, so if the type is incorrect an assertion - failure will occur in debug builds, and a bogus value is returned - in release ones. + This template function converts wxAny into given type. In most cases + no type conversion is performed, so if the type is incorrect an + assertion failure will occur. - @remarks This template function may not work properly with Visual C++ - 6. For full compiler compatibility, please use - wxANY_AS(any, T) macro instead. + @remarks For conveniency, conversion is done when T is wxString. This + is useful when a string literal (which are treated as + const char* and const wchar_t*) has been assigned to wxAny. + + This template function may not work properly with Visual C++ + 6. For full compiler compatibility, please use + wxANY_AS(any, T) macro instead. */ template T As() const; diff --git a/src/common/any.cpp b/src/common/any.cpp index 56e315eb95..ac960455b3 100644 --- a/src/common/any.cpp +++ b/src/common/any.cpp @@ -374,12 +374,16 @@ bool wxAnyValueTypeImplUint::ConvertValue(const wxAnyValueBuffer& src, return true; } -bool wxAnyValueTypeImplString::ConvertValue(const wxAnyValueBuffer& src, - wxAnyValueType* dstType, - wxAnyValueBuffer& dst) const +// Convert wxString to destination wxAny value type +bool wxAnyConvertString(const wxString& value, + wxAnyValueType* dstType, + wxAnyValueBuffer& dst) { - wxString value = GetValue(src); - if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseIntType) ) + if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxString) ) + { + wxAnyValueTypeImpl::SetValue(value, dst); + } + else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxAnyBaseIntType) ) { wxAnyBaseIntType value2; #ifdef wxLongLong_t @@ -411,14 +415,15 @@ bool wxAnyValueTypeImplString::ConvertValue(const wxAnyValueBuffer& src, else if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, bool) ) { bool value2; - value.MakeLower(); - if ( value == wxS("true") || - value == wxS("yes") || - value == wxS('1') ) + wxString s(value); + s.MakeLower(); + if ( s == wxS("true") || + s == wxS("yes") || + s == wxS('1') ) value2 = true; - else if ( value == wxS("false") || - value == wxS("no") || - value == wxS('0') ) + else if ( s == wxS("false") || + s == wxS("no") || + s == wxS('0') ) value2 = false; else return false; @@ -493,10 +498,13 @@ bool wxAnyValueTypeImplDouble::ConvertValue(const wxAnyValueBuffer& src, WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplInt) WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplUint) -WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplString) WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl) WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplDouble) +WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplwxString) +WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplConstCharPtr) +WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplConstWchar_tPtr) + WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl) //WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl) //WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl) diff --git a/src/common/variant.cpp b/src/common/variant.cpp index 0470d2d4b3..1820f4b8d5 100644 --- a/src/common/variant.cpp +++ b/src/common/variant.cpp @@ -879,6 +879,26 @@ protected: IMPLEMENT_TRIVIAL_WXANY_CONVERSION(wxString, wxVariantDataString) +#if wxUSE_ANY +// This allows converting string literal wxAnys to string variants +wxVariantData* wxVariantDataFromConstCharPAny(const wxAny& any) +{ + return new wxVariantDataString(wxANY_AS(any, const char*)); +} + +wxVariantData* wxVariantDataFromConstWchar_tPAny(const wxAny& any) +{ + return new wxVariantDataString(wxANY_AS(any, const wchar_t*)); +} + +_REGISTER_WXANY_CONVERSION(const char*, + ConstCharP, + wxVariantDataFromConstCharPAny) +_REGISTER_WXANY_CONVERSION(const wchar_t*, + ConstWchar_tP, + wxVariantDataFromConstWchar_tPAny) +#endif + bool wxVariantDataString::Eq(wxVariantData& data) const { wxASSERT_MSG( (data.GetType() == wxT("string")), wxT("wxVariantDataString::Eq: argument mismatch") ); diff --git a/tests/any/anytest.cpp b/tests/any/anytest.cpp index e215f48905..8bdd8a2369 100644 --- a/tests/any/anytest.cpp +++ b/tests/any/anytest.cpp @@ -32,6 +32,7 @@ public: private: CPPUNIT_TEST_SUITE( wxAnyTestCase ); + CPPUNIT_TEST( CheckType ); CPPUNIT_TEST( Equality ); CPPUNIT_TEST( As ); CPPUNIT_TEST( GetAs ); @@ -40,6 +41,7 @@ private: CPPUNIT_TEST( CustomTemplateSpecialization ); CPPUNIT_TEST_SUITE_END(); + void CheckType(); void Equality(); void As(); void GetAs(); @@ -164,6 +166,19 @@ wxAnyTestCase::wxAnyTestCase() m_anyVoidPtr2 = dummyVoidPointer; } +void wxAnyTestCase::CheckType() +{ + wxAny nullAny; + CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(nullAny, wxString)); + + CPPUNIT_ASSERT(wxANY_CHECK_TYPE(m_anyCharString2, const char*)); + CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(m_anyCharString2, wxString)); + CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(m_anyCharString2, const wchar_t*)); + CPPUNIT_ASSERT(wxANY_CHECK_TYPE(m_anyWcharString2, const wchar_t*)); + CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(m_anyWcharString2, wxString)); + CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(m_anyWcharString2, const char*)); +} + void wxAnyTestCase::Equality() { // @@ -243,8 +258,12 @@ void wxAnyTestCase::As() wxString k = wxANY_AS(m_anyStringString1, wxString); CPPUNIT_ASSERT(k == "abc"); wxString l = wxANY_AS(m_anyCharString1, wxString); + const char* cptr = wxANY_AS(m_anyCharString1, const char*); CPPUNIT_ASSERT(l == "abc"); + CPPUNIT_ASSERT(cptr); wxString m = wxANY_AS(m_anyWcharString1, wxString); + const wchar_t* wcptr = wxANY_AS(m_anyWcharString1, const wchar_t*); + CPPUNIT_ASSERT(wcptr); CPPUNIT_ASSERT(m == "abc"); bool n = wxANY_AS(m_anyBool1, bool); CPPUNIT_ASSERT(n); @@ -488,6 +507,19 @@ void wxAnyTestCase::wxVariantConversions() CPPUNIT_ASSERT(res); CPPUNIT_ASSERT(variant.GetString() == "ABC"); + // Must be able to build string wxVariant from wxAny built from + // string literal + any = "ABC"; + res = any.GetAs(&variant); + CPPUNIT_ASSERT(res); + CPPUNIT_ASSERT(variant.GetType() == "string"); + CPPUNIT_ASSERT(variant.GetString() == "ABC"); + any = L"ABC"; + res = any.GetAs(&variant); + CPPUNIT_ASSERT(res); + CPPUNIT_ASSERT(variant.GetType() == "string"); + CPPUNIT_ASSERT(variant.GetString() == L"ABC"); + any = vDouble; double d = wxANY_AS(any, double); CPPUNIT_ASSERT_DOUBLES_EQUAL(d, TEST_FLOAT_CONST, FEQ_DELTA);