Allow wxAny to contain 'const char*' or 'const wchar_t*'. This was previously not possible since these pointers were converted to wxString, as convenient means to work with string literals. Now pointers (to string literals) are stored instead, and As<wxString>(), comparison operators do the type conversion.
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@64106 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
a96160b58f
commit
153107b402
130
include/wx/any.h
130
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<T> \
|
||||
{ \
|
||||
WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImpl##TYPENAME) \
|
||||
public: \
|
||||
wxAnyValueTypeImpl##TYPENAME() : \
|
||||
wxAnyValueTypeImplBase<T>() { } \
|
||||
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<T> : 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<wxString>
|
||||
{
|
||||
WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImplString)
|
||||
public:
|
||||
wxAnyValueTypeImplString() :
|
||||
wxAnyValueTypeImplBase<wxString>() { }
|
||||
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<wxString> : 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<T>::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<const char*>::sm_instance;
|
||||
wxAnyValueTypeImpl<const char*>::SetValue(value, m_buffer);
|
||||
}
|
||||
|
||||
wxAny(const wchar_t* value)
|
||||
{
|
||||
m_type = wxAnyNullValueType;
|
||||
Assign(wxString(value));
|
||||
m_type = wxAnyValueTypeImpl<const wchar_t*>::sm_instance;
|
||||
wxAnyValueTypeImpl<const wchar_t*>::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<wxString>::IsSameClass(m_type) )
|
||||
wxString value2;
|
||||
if ( !GetAs(&value2) )
|
||||
return false;
|
||||
|
||||
return value ==
|
||||
static_cast<wxString>
|
||||
(wxAnyValueTypeImpl<wxString>::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<typename T>
|
||||
@ -886,6 +913,19 @@ public:
|
||||
return static_cast<T>(wxAnyValueTypeImpl<T>::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.
|
||||
|
@ -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<T> \
|
||||
gs_##CLASSNAME##AnyToVariantRegistration = \
|
||||
wxAnyToVariantRegistrationImpl<T>(&CLASSNAME::VariantDataFactory);
|
||||
wxAnyToVariantRegistrationImpl<T>(&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 \
|
||||
|
@ -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<typename T>
|
||||
T As() const;
|
||||
|
@ -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<wxString>::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<bool>)
|
||||
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<wxDateTime>)
|
||||
//WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl<wxObject*>)
|
||||
//WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl<wxArrayString>)
|
||||
|
@ -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") );
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user