wxVariant <-> wxAny conversion functionality. Includes implicit construction of wxAny from wxVariant, and vice versa. wxVariant->wxAny conversion is implemented by adding new virtual member function into wxVariantData. wxAny->wxVariant conversion is implemented by associating wxAnyValueTypes with functions that generate wxVariantData instances (using a hash map).

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@64000 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Jaakko Salli
2010-04-16 14:33:52 +00:00
parent 75504144d2
commit 0bf14ab8b1
7 changed files with 868 additions and 9 deletions

View File

@@ -521,6 +521,76 @@ public: \
//wxDECLARE_ANY_TYPE(wxArrayString, WXDLLIMPEXP_BASE) //wxDECLARE_ANY_TYPE(wxArrayString, WXDLLIMPEXP_BASE)
#if wxUSE_VARIANT
class WXDLLIMPEXP_FWD_BASE wxAnyToVariantRegistration;
// Because of header inter-dependencies, cannot include this earlier
#include "wx/variant.h"
//
// wxVariantData* data type implementation. For cases when appropriate
// wxAny<->wxVariant conversion code is missing.
//
class WXDLLIMPEXP_BASE wxAnyValueTypeImplVariantData :
public wxAnyValueTypeImplBase<wxVariantData*>
{
WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImplVariantData)
public:
wxAnyValueTypeImplVariantData() :
wxAnyValueTypeImplBase<wxVariantData*>() { }
virtual ~wxAnyValueTypeImplVariantData() { }
virtual void DeleteValue(wxAnyValueBuffer& buf) const
{
wxVariantData* data = static_cast<wxVariantData*>(buf.m_ptr);
if ( data )
data->DecRef();
}
virtual void CopyBuffer(const wxAnyValueBuffer& src,
wxAnyValueBuffer& dst) const
{
wxVariantData* data = static_cast<wxVariantData*>(src.m_ptr);
if ( data )
data->IncRef();
dst.m_ptr = data;
}
static void SetValue(wxVariantData* value,
wxAnyValueBuffer& buf)
{
value->IncRef();
buf.m_ptr = value;
}
static wxVariantData* GetValue(const wxAnyValueBuffer& buf)
{
return static_cast<wxVariantData*>(buf.m_ptr);
}
virtual bool ConvertValue(const wxAnyValueBuffer& src,
wxAnyValueType* dstType,
wxAnyValueBuffer& dst) const
{
wxUnusedVar(src);
wxUnusedVar(dstType);
wxUnusedVar(dst);
return false;
}
};
template<>
class wxAnyValueTypeImpl<wxVariantData*> :
public wxAnyValueTypeImplVariantData
{
public:
wxAnyValueTypeImpl() : wxAnyValueTypeImplVariantData() { }
virtual ~wxAnyValueTypeImpl() { }
};
#endif // wxUSE_VARIANT
#ifdef __VISUALC6__ #ifdef __VISUALC6__
// Re-enable useless VC6 warnings // Re-enable useless VC6 warnings
@@ -563,6 +633,22 @@ bool operator==(TUS value) const \
} }
#if wxUSE_VARIANT
// Note that the following functions are implemented outside wxAny class
// so that it can reside entirely in header and lack the export declaration.
// Helper function used to associate wxAnyValueType with a wxVariantData.
extern WXDLLIMPEXP_BASE void
wxPreRegisterAnyToVariant(wxAnyToVariantRegistration* reg);
// This function performs main wxAny to wxVariant conversion duties.
extern WXDLLIMPEXP_BASE bool
wxConvertAnyToVariant(const wxAny& any, wxVariant* variant);
#endif // wxUSE_VARIANT
// //
// The wxAny class represents a container for any type. A variant's value // The wxAny class represents a container for any type. A variant's value
// can be changed at run time, possibly to a different type of value. // can be changed at run time, possibly to a different type of value.
@@ -610,6 +696,14 @@ public:
AssignAny(any); AssignAny(any);
} }
#if wxUSE_VARIANT
wxAny(const wxVariant& variant)
{
m_type = wxAnyNullValueType;
AssignVariant(variant);
}
#endif
template<typename T> template<typename T>
wxAny(const T& value) wxAny(const T& value)
{ {
@@ -676,6 +770,14 @@ public:
return *this; return *this;
} }
#if wxUSE_VARIANT
wxAny& operator=(const wxVariant &variant)
{
AssignVariant(variant);
return *this;
}
#endif
template<typename T> template<typename T>
wxAny& operator=(const T &value) wxAny& operator=(const T &value)
{ {
@@ -810,6 +912,14 @@ public:
return true; return true;
} }
#if wxUSE_VARIANT
// GetAs() wxVariant specialization
bool GetAs(wxVariant* value) const
{
return wxConvertAnyToVariant(*this, value);
}
#endif
private: private:
// Assignment functions // Assignment functions
void AssignAny(const wxAny& any) void AssignAny(const wxAny& any)
@@ -825,6 +935,30 @@ private:
newType->CopyBuffer(any.m_buffer, m_buffer); newType->CopyBuffer(any.m_buffer, m_buffer);
} }
#if wxUSE_VARIANT
void AssignVariant(const wxVariant& variant)
{
wxVariantData* data = variant.GetData();
if ( data && data->GetAsAny(this) )
return;
m_type->DeleteValue(m_buffer);
if ( variant.IsNull() )
{
// Init as Null
m_type = wxAnyNullValueType;
}
else
{
// If everything else fails, wrap the whole wxVariantData
m_type = wxAnyValueTypeImpl<wxVariantData*>::sm_instance;
wxAnyValueTypeImpl<wxVariantData*>::SetValue(data, m_buffer);
}
}
#endif
template<typename T> template<typename T>
void Assign(const T &value) void Assign(const T &value)
{ {

View File

@@ -29,6 +29,8 @@
#include "wx/iosfwrap.h" #include "wx/iosfwrap.h"
class wxAny;
/* /*
* wxVariantData stores the actual data in a wxVariant object, * wxVariantData stores the actual data in a wxVariant object,
* to allow it to store any type of data. * to allow it to store any type of data.
@@ -78,6 +80,11 @@ public:
// a copy of the data. // a copy of the data.
virtual wxVariantData* Clone() const { return NULL; } virtual wxVariantData* Clone() const { return NULL; }
#if wxUSE_ANY
// Converts value to wxAny, if possible. Return true if successful.
virtual bool GetAsAny(wxAny* WXUNUSED(any)) const { return false; }
#endif
protected: protected:
// Protected dtor should make some incompatible code // Protected dtor should make some incompatible code
// break more louder. That is, they should do data->DecRef() // break more louder. That is, they should do data->DecRef()
@@ -101,6 +108,9 @@ public:
wxVariant(const wxVariant& variant); wxVariant(const wxVariant& variant);
wxVariant(wxVariantData* data, const wxString& name = wxEmptyString); wxVariant(wxVariantData* data, const wxString& name = wxEmptyString);
#if wxUSE_ANY
wxVariant(const wxAny& any);
#endif
virtual ~wxVariant(); virtual ~wxVariant();
// generic assignment // generic assignment
@@ -150,6 +160,10 @@ public:
// write contents to a string (e.g. for debugging) // write contents to a string (e.g. for debugging)
wxString MakeString() const; wxString MakeString() const;
#if wxUSE_ANY
wxAny GetAny() const;
#endif
// double // double
wxVariant(double val, const wxString& name = wxEmptyString); wxVariant(double val, const wxString& name = wxEmptyString);
bool operator== (double value) const; bool operator== (double value) const;
@@ -341,6 +355,83 @@ private:
DECLARE_DYNAMIC_CLASS(wxVariant) DECLARE_DYNAMIC_CLASS(wxVariant)
}; };
//
// wxVariant <-> wxAny conversion code
//
#if wxUSE_ANY
#include "wx/any.h"
// In order to convert wxAny to wxVariant, we need to be able to associate
// wxAnyValueType with a wxVariantData factory function.
typedef wxVariantData* (*wxVariantDataFactory)(const wxAny& any);
// Actual Any-to-Variant registration must be postponed to a time when all
// global variables have been initialized. Hence this arrangement.
// wxAnyToVariantRegistration instances are kept in global scope and
// wxAnyValueTypeGlobals in any.cpp will use their data when the time is
// right.
class WXDLLIMPEXP_BASE wxAnyToVariantRegistration
{
public:
wxAnyToVariantRegistration(wxVariantDataFactory factory);
virtual wxAnyValueType* GetAssociatedType() = 0;
wxVariantDataFactory GetFactory() const { return m_factory; }
private:
wxVariantDataFactory m_factory;
};
template<typename T>
class wxAnyToVariantRegistrationImpl : public wxAnyToVariantRegistration
{
public:
wxAnyToVariantRegistrationImpl(wxVariantDataFactory factory)
: wxAnyToVariantRegistration(factory)
{
}
virtual wxAnyValueType* GetAssociatedType()
{
return wxAnyValueTypeImpl<T>::GetInstance();
}
private:
};
#define DECLARE_WXANY_CONVERSION() \
virtual bool GetAsAny(wxAny* any) const; \
static wxVariantData* VariantDataFactory(const wxAny& any);
#define REGISTER_WXANY_CONVERSION(T, CLASSNAME) \
static wxAnyToVariantRegistrationImpl<T> \
gs_##CLASSNAME##AnyToVariantRegistration = \
wxAnyToVariantRegistrationImpl<T>(&CLASSNAME::VariantDataFactory);
#define IMPLEMENT_TRIVIAL_WXANY_CONVERSION(T, CLASSNAME) \
bool CLASSNAME::GetAsAny(wxAny* any) const \
{ \
*any = m_value; \
return true; \
} \
wxVariantData* CLASSNAME::VariantDataFactory(const wxAny& any) \
{ \
return new CLASSNAME(wxANY_AS(any, T)); \
} \
REGISTER_WXANY_CONVERSION(T, CLASSNAME)
// This is needed for wxVariantList conversion
WX_DECLARE_LIST_WITH_DECL(wxAny, wxAnyList, class WXDLLIMPEXP_BASE);
#else // if !wxUSE_ANY
#define DECLARE_WXANY_CONVERSION()
#define REGISTER_WXANY_CONVERSION(T, CLASSNAME)
#define IMPLEMENT_TRIVIAL_WXANY_CONVERSION(T, CLASSNAME)
#endif // wxUSE_ANY/!wxUSE_ANY
#define DECLARE_VARIANT_OBJECT(classname) \ #define DECLARE_VARIANT_OBJECT(classname) \
DECLARE_VARIANT_OBJECT_EXPORTED(classname, wxEMPTY_PARAMETER_VALUE) DECLARE_VARIANT_OBJECT_EXPORTED(classname, wxEMPTY_PARAMETER_VALUE)
@@ -367,6 +458,7 @@ public:\
\ \
virtual wxVariantData* Clone() const { return new classname##VariantData(m_value); } \ virtual wxVariantData* Clone() const { return new classname##VariantData(m_value); } \
\ \
DECLARE_WXANY_CONVERSION() \
protected:\ protected:\
classname m_value; \ classname m_value; \
};\ };\
@@ -395,7 +487,8 @@ expdecl wxVariant& operator << ( wxVariant &variant, const classname &value )\
classname##VariantData *data = new classname##VariantData( value );\ classname##VariantData *data = new classname##VariantData( value );\
variant.SetData( data );\ variant.SetData( data );\
return variant;\ return variant;\
} } \
IMPLEMENT_TRIVIAL_WXANY_CONVERSION(classname, classname##VariantData)
// implements a wxVariantData-derived class using for the Eq() method the // implements a wxVariantData-derived class using for the Eq() method the
// operator== which must have been provided by "classname" // operator== which must have been provided by "classname"

View File

@@ -13,9 +13,9 @@
The wxAny class represents a container for any type. Its value The wxAny class represents a container for any type. Its value
can be changed at run time, possibly to a different type of value. can be changed at run time, possibly to a different type of value.
wxAny is a backwards incompatible successor class for wxVariant, wxAny is a backwards-incompatible (but convertible) successor class for
essentially doing the same thing in a more modern, template-based manner wxVariant, essentially doing the same thing in a more modern, template-
and with transparent support for any user data type. based manner and with transparent support for any user data type.
Some pseudo-code'ish example of use with arbitrary user data: Some pseudo-code'ish example of use with arbitrary user data:
@@ -87,6 +87,17 @@ public:
*/ */
wxAny(const wxAny& any); wxAny(const wxAny& any);
/**
Constructs wxAny, converting value from wxVariant.
@remarks Because of this conversion, it is not usually possible to
have wxAny that actually holds a wxVariant. If wxVariant
cannot be converted to a specific data type, wxAny will then
hold and manage reference to wxVariantData* similar to how
wxVariant does.
*/
wxAny(const wxVariant& variant);
/** /**
Destructor. Destructor.
*/ */
@@ -127,6 +138,16 @@ public:
template<typename T> template<typename T>
bool GetAs(T* value) const; bool GetAs(T* value) const;
/**
Specialization of GetAs() that allows conversion of wxAny into
wxVariant.
@return Returns @true if conversion was successful. Conversion usually
only fails if variant used custom wxVariantData that did not
implement the wxAny to wxVariant conversion functions.
*/
bool GetAs(wxVariant* value) const;
/** /**
Returns the value type as wxAnyValueType instance. Returns the value type as wxAnyValueType instance.
@@ -154,6 +175,7 @@ public:
template<typename T> template<typename T>
wxAny& operator=(const T &value); wxAny& operator=(const T &value);
wxAny& operator=(const wxAny &any); wxAny& operator=(const wxAny &any);
wxAny& operator=(const wxVariant &variant);
//@} //@}
//@{ //@{

View File

@@ -12,6 +12,11 @@
The wxVariant class represents a container for any type. A variant's value The wxVariant class represents a container for any type. A variant's value
can be changed at run time, possibly to a different type of value. can be changed at run time, possibly to a different type of value.
@note As of wxWidgets 2.9.1, wxAny has become the preferred variant class.
While most controls still use wxVariant in their interface, you
can start using wxAny in your code because of an implicit conversion
layer. See below for more information.
As standard, wxVariant can store values of type bool, wxChar, double, long, As standard, wxVariant can store values of type bool, wxChar, double, long,
string, string list, time, date, void pointer, list of strings, and list of string, string list, time, date, void pointer, list of strings, and list of
variants. However, an application can extend wxVariant's capabilities by variants. However, an application can extend wxVariant's capabilities by
@@ -85,10 +90,71 @@
wxDynamicCast(), to use C++ RTTI type information instead of wxWidgets wxDynamicCast(), to use C++ RTTI type information instead of wxWidgets
RTTI. RTTI.
@section variant_wxanyconversion wxVariant to wxAny Conversion Layer
wxAny is a more modern, template-based variant class. It is not
directly compatible with wxVariant, but there is a transparent conversion
layer.
Following is an example how to use these conversions with wxPropertyGrid's
property class wxPGProperty (which currently uses wxVariants both
internally and in the public API):
@code
// Get property value as wxAny instead of wxVariant
wxAny value = property->GetValue();
// Do something with it
DoSomethingWithString(value.As<wxString>());
// Write back new value to property
value = "New Value";
property->SetValue(value);
@endcode
Some caveats:
@li In wxAny, there are no separate types for handling integers of
different sizes, so converting wxAny with 'long long' value
will yield wxVariant of "long" type when the value is small
enough to fit in without overflow. Otherwise, variant type
"longlong" is used. Also note that wxAny holding unsigned integer
will always be converted to "ulonglong" wxVariant type.
@li Unlike wxVariant, wxAny does not store a (rarely needed) name string.
@li Because of implicit conversion of wxVariant to wxAny, wxAny cannot
usually contain value of type wxVariant. In other words,
any.CheckType<wxVariant>() can never return @true.
Supplied conversion functions will automatically work with all
built-in wxVariant types, and also with all user-specified types generated
using IMPLEMENT_VARIANT_OBJECT(). For hand-built wxVariantData classes,
you will need to use supplied macros in a following manner:
@code
// Declare wxVariantData for data type Foo
class wxVariantDataFoo: public wxVariantData
{
public:
// interface
// ...
DECLARE_WXANY_CONVERSION()
protected:
// data storage etc
// ...
};
IMPLEMENT_TRIVIAL_WXANY_CONVERSION(Foo, wxVariantDataFoo)
@endcode
@library{wxbase} @library{wxbase}
@category{data} @category{data}
@see wxVariantData @see wxVariantData, wxAny
*/ */
class wxVariant : public wxObject class wxVariant : public wxObject
{ {
@@ -111,6 +177,11 @@ public:
*/ */
wxVariant(const wxVariant& variant); wxVariant(const wxVariant& variant);
/**
Constructs a variant by converting it from wxAny.
*/
wxVariant(const wxAny& any);
/** /**
Constructs a variant from a wide string literal. Constructs a variant from a wide string literal.
*/ */
@@ -265,6 +336,11 @@ public:
bool Convert(wxDateTime* value) const; bool Convert(wxDateTime* value) const;
//@} //@}
/**
Converts wxVariant into wxAny.
*/
wxAny GetAny() const;
/** /**
Returns the string array value. Returns the string array value.
*/ */
@@ -552,6 +628,11 @@ public:
*/ */
virtual bool Eq(wxVariantData& data) const = 0; virtual bool Eq(wxVariantData& data) const = 0;
/**
Converts value to wxAny, if possible. Return @true if successful.
*/
virtual bool GetAny(wxAny* any) const;
/** /**
Returns the string type of the data. Returns the string type of the data.
*/ */

View File

@@ -27,6 +27,7 @@
#include "wx/vector.h" #include "wx/vector.h"
#include "wx/module.h" #include "wx/module.h"
#include "wx/hashmap.h"
using namespace wxPrivate; using namespace wxPrivate;
@@ -34,9 +35,19 @@ using namespace wxPrivate;
// wxAnyValueTypeGlobals // wxAnyValueTypeGlobals
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
#if wxUSE_VARIANT
WX_DECLARE_HASH_MAP(wxAnyValueType*,
wxVariantDataFactory,
wxPointerHash,
wxPointerEqual,
wxAnyTypeToVariantDataFactoryMap);
#endif
// //
// Helper class to manage wxAnyValueType instances and other // Helper class to manage wxAnyValueType instances and and other
// related global variables. // related global variables (such as wxAny<->wxVariant type association).
// //
// NB: We really need to have wxAnyValueType instances allocated // NB: We really need to have wxAnyValueType instances allocated
// in heap. They are stored as static template member variables, // in heap. They are stored as static template member variables,
@@ -51,6 +62,9 @@ public:
} }
~wxAnyValueTypeGlobals() ~wxAnyValueTypeGlobals()
{ {
#if wxUSE_VARIANT
m_anyToVariant.clear();
#endif
for ( size_t i=0; i<m_valueTypes.size(); i++ ) for ( size_t i=0; i<m_valueTypes.size(); i++ )
delete m_valueTypes[i]; delete m_valueTypes[i];
} }
@@ -60,12 +74,147 @@ public:
m_valueTypes.push_back(valueType); m_valueTypes.push_back(valueType);
} }
#if wxUSE_VARIANT
void PreRegisterAnyToVariant(wxAnyToVariantRegistration* reg)
{
m_anyToVariantRegs.push_back(reg);
}
// Find wxVariantData factory function for given value type,
// (or compatible, if possible)
wxVariantDataFactory FindVariantDataFactory(const wxAnyValueType* type)
{
wxAnyTypeToVariantDataFactoryMap& anyToVariant = m_anyToVariant;
wxAnyTypeToVariantDataFactoryMap::const_iterator it;
it = anyToVariant.find(type);
if ( it != anyToVariant.end() )
return it->second;
// Not found, handle pre-registrations
size_t i = m_anyToVariantRegs.size();
while ( i > 0 )
{
i--;
wxAnyToVariantRegistration* reg = m_anyToVariantRegs[i];
wxAnyValueType* assocType = reg->GetAssociatedType();
if ( assocType )
{
// Both variant data and wxAnyValueType have been
// now been properly initialized, so remove the
// pre-registration entry and move data to anyToVarian
// map.
anyToVariant[assocType] = reg->GetFactory();
m_anyToVariantRegs.erase( m_anyToVariantRegs.begin() + i );
}
}
// Then try again
it = anyToVariant.find(type);
if ( it != anyToVariant.end() )
return it->second;
// Finally, attempt to find a compatible type
for ( it = anyToVariant.begin(); it != anyToVariant.end(); it++ )
{
if ( type->IsSameType(it->first) )
{
wxVariantDataFactory f = it->second;
anyToVariant[type] = f;
return f;
}
}
// Nothing found
return NULL;
}
#endif
private: private:
wxVector<wxAnyValueType*> m_valueTypes; wxVector<wxAnyValueType*> m_valueTypes;
#if wxUSE_VARIANT
wxAnyTypeToVariantDataFactoryMap m_anyToVariant;
wxVector<wxAnyToVariantRegistration*> m_anyToVariantRegs;
#endif
}; };
static wxAnyValueTypeGlobals* g_wxAnyValueTypeGlobals = NULL; static wxAnyValueTypeGlobals* g_wxAnyValueTypeGlobals = NULL;
#if wxUSE_VARIANT
WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImplVariantData)
void wxPreRegisterAnyToVariant(wxAnyToVariantRegistration* reg)
{
if ( !g_wxAnyValueTypeGlobals )
g_wxAnyValueTypeGlobals = new wxAnyValueTypeGlobals();
g_wxAnyValueTypeGlobals->PreRegisterAnyToVariant(reg);
}
bool wxConvertAnyToVariant(const wxAny& any, wxVariant* variant)
{
if ( any.IsNull() )
{
variant->MakeNull();
return true;
}
// (signed) integer is a special case, because there is only one type
// in wxAny, and two ("long" and "longlong") in wxVariant. For better
// backwards compatibility, convert all values that fit in "long",
// and others to "longlong".
if ( wxANY_CHECK_TYPE(any, signed int) )
{
#ifdef wxLongLong_t
wxLongLong_t ll;
if ( any.GetAs(&ll) )
{
if ( ll > LONG_MAX )
*variant = wxLongLong(ll);
else
*variant = (long) wxLongLong(ll).GetLo();
}
else
{
return false;
}
#else
long l;
if ( any.GetAs(&l) )
*variant = l;
else
return false;
#endif
return true;
}
// Find matching factory function
wxVariantDataFactory f =
g_wxAnyValueTypeGlobals->FindVariantDataFactory(any.GetType());
wxVariantData* data;
if ( f )
{
data = f(any);
}
else
{
// Check if wxAny wrapped wxVariantData*
if ( !any.GetAs(&data) )
return false;
// Wrapper's GetValue() does not increase reference
// count, se have to do it before the data gets passed
// to a new variant.
data->IncRef();
}
variant->SetData(data);
return true;
}
#endif // wxUSE_VARIANT
// //
// This class is to make sure that wxAnyValueType instances // This class is to make sure that wxAnyValueType instances
// etc. get freed correctly. We must use a separate wxAnyValueTypeGlobals // etc. get freed correctly. We must use a separate wxAnyValueTypeGlobals

View File

@@ -193,6 +193,48 @@ bool wxVariant::IsValueKindOf(const wxClassInfo* type) const
return info ? info->IsKindOf(type) : false ; return info ? info->IsKindOf(type) : false ;
} }
// -----------------------------------------------------------------
// wxVariant <-> wxAny conversion code
// -----------------------------------------------------------------
#if wxUSE_ANY
wxAnyToVariantRegistration::
wxAnyToVariantRegistration(wxVariantDataFactory factory)
: m_factory(factory)
{
wxPreRegisterAnyToVariant(this);
}
wxVariant::wxVariant(const wxAny& any)
: wxObject()
{
wxVariant variant;
if ( !any.GetAs(&variant) )
{
wxFAIL_MSG("wxAny of this type cannot be converted to wxVariant");
return;
}
*this = variant;
}
wxAny wxVariant::GetAny() const
{
if ( IsNull() )
return wxAny();
wxVariantData* data = GetData();
wxAny any;
if ( data->GetAsAny(&any) )
return any;
// If everything else fails, wrap the whole wxVariantData
return wxAny(data);
}
#endif // wxUSE_ANY
// ----------------------------------------------------------------- // -----------------------------------------------------------------
// wxVariantDataLong // wxVariantDataLong
@@ -224,10 +266,27 @@ public:
virtual wxString GetType() const { return wxT("long"); } virtual wxString GetType() const { return wxT("long"); }
// Since wxAny does not have separate type for integers shorter than
// longlong, we do not usually implement wxVariant->wxAny conversion
// here (but in wxVariantDataLongLong instead).
#ifndef wxLongLong_t
DECLARE_WXANY_CONVERSION()
#else
bool GetAsAny(wxAny* any) const
{
*any = m_value;
return true;
}
#endif
protected: protected:
long m_value; long m_value;
}; };
#ifndef wxLongLong_t
IMPLEMENT_TRIVIAL_WXANY_CONVERSION(long, wxVariantDataLong)
#endif
bool wxVariantDataLong::Eq(wxVariantData& data) const bool wxVariantDataLong::Eq(wxVariantData& data) const
{ {
wxASSERT_MSG( (data.GetType() == wxT("long")), wxT("wxVariantDataLong::Eq: argument mismatch") ); wxASSERT_MSG( (data.GetType() == wxT("long")), wxT("wxVariantDataLong::Eq: argument mismatch") );
@@ -373,10 +432,14 @@ public:
virtual wxString GetType() const { return wxT("double"); } virtual wxString GetType() const { return wxT("double"); }
wxVariantData* Clone() const { return new wxVariantDoubleData(m_value); } wxVariantData* Clone() const { return new wxVariantDoubleData(m_value); }
DECLARE_WXANY_CONVERSION()
protected: protected:
double m_value; double m_value;
}; };
IMPLEMENT_TRIVIAL_WXANY_CONVERSION(double, wxVariantDoubleData)
bool wxVariantDoubleData::Eq(wxVariantData& data) const bool wxVariantDoubleData::Eq(wxVariantData& data) const
{ {
wxASSERT_MSG( (data.GetType() == wxT("double")), wxT("wxVariantDoubleData::Eq: argument mismatch") ); wxASSERT_MSG( (data.GetType() == wxT("double")), wxT("wxVariantDoubleData::Eq: argument mismatch") );
@@ -509,10 +572,14 @@ public:
virtual wxString GetType() const { return wxT("bool"); } virtual wxString GetType() const { return wxT("bool"); }
wxVariantData* Clone() const { return new wxVariantDataBool(m_value); } wxVariantData* Clone() const { return new wxVariantDataBool(m_value); }
DECLARE_WXANY_CONVERSION()
protected: protected:
bool m_value; bool m_value;
}; };
IMPLEMENT_TRIVIAL_WXANY_CONVERSION(bool, wxVariantDataBool)
bool wxVariantDataBool::Eq(wxVariantData& data) const bool wxVariantDataBool::Eq(wxVariantData& data) const
{ {
wxASSERT_MSG( (data.GetType() == wxT("bool")), wxT("wxVariantDataBool::Eq: argument mismatch") ); wxASSERT_MSG( (data.GetType() == wxT("bool")), wxT("wxVariantDataBool::Eq: argument mismatch") );
@@ -646,10 +713,13 @@ public:
virtual wxString GetType() const { return wxT("char"); } virtual wxString GetType() const { return wxT("char"); }
wxVariantData* Clone() const { return new wxVariantDataChar(m_value); } wxVariantData* Clone() const { return new wxVariantDataChar(m_value); }
DECLARE_WXANY_CONVERSION()
protected: protected:
wxUniChar m_value; wxUniChar m_value;
}; };
IMPLEMENT_TRIVIAL_WXANY_CONVERSION(wxUniChar, wxVariantDataChar)
bool wxVariantDataChar::Eq(wxVariantData& data) const bool wxVariantDataChar::Eq(wxVariantData& data) const
{ {
wxASSERT_MSG( (data.GetType() == wxT("char")), wxT("wxVariantDataChar::Eq: argument mismatch") ); wxASSERT_MSG( (data.GetType() == wxT("char")), wxT("wxVariantDataChar::Eq: argument mismatch") );
@@ -798,10 +868,13 @@ public:
virtual wxString GetType() const { return wxT("string"); } virtual wxString GetType() const { return wxT("string"); }
wxVariantData* Clone() const { return new wxVariantDataString(m_value); } wxVariantData* Clone() const { return new wxVariantDataString(m_value); }
DECLARE_WXANY_CONVERSION()
protected: protected:
wxString m_value; wxString m_value;
}; };
IMPLEMENT_TRIVIAL_WXANY_CONVERSION(wxString, wxVariantDataString)
bool wxVariantDataString::Eq(wxVariantData& data) const bool wxVariantDataString::Eq(wxVariantData& data) const
{ {
wxASSERT_MSG( (data.GetType() == wxT("string")), wxT("wxVariantDataString::Eq: argument mismatch") ); wxASSERT_MSG( (data.GetType() == wxT("string")), wxT("wxVariantDataString::Eq: argument mismatch") );
@@ -954,10 +1027,13 @@ public:
virtual wxClassInfo* GetValueClassInfo(); virtual wxClassInfo* GetValueClassInfo();
DECLARE_WXANY_CONVERSION()
protected: protected:
wxObject* m_value; wxObject* m_value;
}; };
IMPLEMENT_TRIVIAL_WXANY_CONVERSION(wxObject*, wxVariantDataWxObjectPtr)
bool wxVariantDataWxObjectPtr::Eq(wxVariantData& data) const bool wxVariantDataWxObjectPtr::Eq(wxVariantData& data) const
{ {
wxASSERT_MSG( data.GetType() == GetType(), wxT("wxVariantDataWxObjectPtr::Eq: argument mismatch") ); wxASSERT_MSG( data.GetType() == GetType(), wxT("wxVariantDataWxObjectPtr::Eq: argument mismatch") );
@@ -1073,10 +1149,13 @@ public:
virtual wxString GetType() const { return wxT("void*"); } virtual wxString GetType() const { return wxT("void*"); }
virtual wxVariantData* Clone() const { return new wxVariantDataVoidPtr(m_value); } virtual wxVariantData* Clone() const { return new wxVariantDataVoidPtr(m_value); }
DECLARE_WXANY_CONVERSION()
protected: protected:
void* m_value; void* m_value;
}; };
IMPLEMENT_TRIVIAL_WXANY_CONVERSION(void*, wxVariantDataVoidPtr)
bool wxVariantDataVoidPtr::Eq(wxVariantData& data) const bool wxVariantDataVoidPtr::Eq(wxVariantData& data) const
{ {
wxASSERT_MSG( data.GetType() == wxT("void*"), wxT("wxVariantDataVoidPtr::Eq: argument mismatch") ); wxASSERT_MSG( data.GetType() == wxT("void*"), wxT("wxVariantDataVoidPtr::Eq: argument mismatch") );
@@ -1185,10 +1264,12 @@ public:
virtual wxString GetType() const { return wxT("datetime"); } virtual wxString GetType() const { return wxT("datetime"); }
virtual wxVariantData* Clone() const { return new wxVariantDataDateTime(m_value); } virtual wxVariantData* Clone() const { return new wxVariantDataDateTime(m_value); }
DECLARE_WXANY_CONVERSION()
protected: protected:
wxDateTime m_value; wxDateTime m_value;
}; };
IMPLEMENT_TRIVIAL_WXANY_CONVERSION(wxDateTime, wxVariantDataDateTime)
bool wxVariantDataDateTime::Eq(wxVariantData& data) const bool wxVariantDataDateTime::Eq(wxVariantData& data) const
{ {
@@ -1316,10 +1397,13 @@ public:
virtual wxString GetType() const { return wxT("arrstring"); } virtual wxString GetType() const { return wxT("arrstring"); }
virtual wxVariantData* Clone() const { return new wxVariantDataArrayString(m_value); } virtual wxVariantData* Clone() const { return new wxVariantDataArrayString(m_value); }
DECLARE_WXANY_CONVERSION()
protected: protected:
wxArrayString m_value; wxArrayString m_value;
}; };
IMPLEMENT_TRIVIAL_WXANY_CONVERSION(wxArrayString, wxVariantDataArrayString)
bool wxVariantDataArrayString::Eq(wxVariantData& data) const bool wxVariantDataArrayString::Eq(wxVariantData& data) const
{ {
wxASSERT_MSG( data.GetType() == GetType(), wxT("wxVariantDataArrayString::Eq: argument mismatch") ); wxASSERT_MSG( data.GetType() == GetType(), wxT("wxVariantDataArrayString::Eq: argument mismatch") );
@@ -1449,10 +1533,48 @@ public:
virtual wxString GetType() const { return wxS("longlong"); } virtual wxString GetType() const { return wxS("longlong"); }
DECLARE_WXANY_CONVERSION()
protected: protected:
wxLongLong m_value; wxLongLong m_value;
}; };
//
// wxLongLong type requires customized wxAny conversion code
//
#if wxUSE_ANY
#ifdef wxLongLong_t
bool wxVariantDataLongLong::GetAsAny(wxAny* any) const
{
*any = m_value.GetValue();
return true;
}
wxVariantData* wxVariantDataLongLong::VariantDataFactory(const wxAny& any)
{
return new wxVariantDataLongLong(wxANY_AS(any, wxLongLong_t));
}
REGISTER_WXANY_CONVERSION(wxLongLong_t, wxVariantDataLongLong)
#else // if !defined(wxLongLong_t)
bool wxVariantDataLongLong::GetAsAny(wxAny* any) const
{
*any = m_value;
return true;
}
wxVariantData* wxVariantDataLongLong::VariantDataFactory(const wxAny& any)
{
return new wxVariantDataLongLong(wxANY_AS(any, wxLongLong));
}
REGISTER_WXANY_CONVERSION(wxLongLong, wxVariantDataLongLong)
#endif // defined(wxLongLong_t)/!defined(wxLongLong_t)
#endif // wxUSE_ANY
bool wxVariantDataLongLong::Eq(wxVariantData& data) const bool wxVariantDataLongLong::Eq(wxVariantData& data) const
{ {
wxASSERT_MSG( (data.GetType() == wxS("longlong")), wxASSERT_MSG( (data.GetType() == wxS("longlong")),
@@ -1610,10 +1732,49 @@ public:
virtual wxString GetType() const { return wxS("ulonglong"); } virtual wxString GetType() const { return wxS("ulonglong"); }
DECLARE_WXANY_CONVERSION()
protected: protected:
wxULongLong m_value; wxULongLong m_value;
}; };
//
// wxULongLong type requires customized wxAny conversion code
//
#if wxUSE_ANY
#ifdef wxLongLong_t
bool wxVariantDataULongLong::GetAsAny(wxAny* any) const
{
*any = m_value.GetValue();
return true;
}
wxVariantData* wxVariantDataULongLong::VariantDataFactory(const wxAny& any)
{
return new wxVariantDataULongLong(wxANY_AS(any, wxULongLong_t));
}
REGISTER_WXANY_CONVERSION(wxULongLong_t, wxVariantDataULongLong)
#else // if !defined(wxLongLong_t)
bool wxVariantDataULongLong::GetAsAny(wxAny* any) const
{
*any = m_value;
return true;
}
wxVariantData* wxVariantDataULongLong::VariantDataFactory(const wxAny& any)
{
return new wxVariantDataULongLong(wxANY_AS(any, wxULongLong));
}
REGISTER_WXANY_CONVERSION(wxULongLong, wxVariantDataULongLong)
#endif // defined(wxLongLong_t)/!defined(wxLongLong_t)
#endif // wxUSE_ANY
bool wxVariantDataULongLong::Eq(wxVariantData& data) const bool wxVariantDataULongLong::Eq(wxVariantData& data) const
{ {
wxASSERT_MSG( (data.GetType() == wxS("ulonglong")), wxASSERT_MSG( (data.GetType() == wxS("ulonglong")),
@@ -1764,10 +1925,54 @@ public:
void Clear(); void Clear();
wxVariantData* Clone() const { return new wxVariantDataList(m_value); } wxVariantData* Clone() const { return new wxVariantDataList(m_value); }
DECLARE_WXANY_CONVERSION()
protected: protected:
wxVariantList m_value; wxVariantList m_value;
}; };
#if wxUSE_ANY
//
// Convert to/from list of wxAnys
//
WX_DEFINE_LIST(wxAnyList)
bool wxVariantDataList::GetAsAny(wxAny* any) const
{
wxAnyList dst;
wxVariantList::compatibility_iterator node = m_value.GetFirst();
while (node)
{
wxVariant* pVar = node->GetData();
dst.push_back(new wxAny(*pVar));
node = node->GetNext();
}
*any = dst;
return true;
}
wxVariantData* wxVariantDataList::VariantDataFactory(const wxAny& any)
{
wxAnyList src = wxANY_AS(any, wxAnyList);
wxVariantList dst;
wxAnyList::compatibility_iterator node = src.GetFirst();
while (node)
{
wxAny* pAny = node->GetData();
dst.push_back(new wxVariant(*pAny));
node = node->GetNext();
}
return new wxVariantDataList(dst);
}
REGISTER_WXANY_CONVERSION(wxAnyList, wxVariantDataList)
#endif // wxUSE_ANY
wxVariantDataList::wxVariantDataList(const wxVariantList& list) wxVariantDataList::wxVariantDataList(const wxVariantList& list)
{ {
SetValue(list); SetValue(list);

View File

@@ -36,6 +36,7 @@ private:
CPPUNIT_TEST( As ); CPPUNIT_TEST( As );
CPPUNIT_TEST( GetAs ); CPPUNIT_TEST( GetAs );
CPPUNIT_TEST( Null ); CPPUNIT_TEST( Null );
CPPUNIT_TEST( wxVariantConversions );
CPPUNIT_TEST( CustomTemplateSpecialization ); CPPUNIT_TEST( CustomTemplateSpecialization );
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
@@ -43,6 +44,7 @@ private:
void As(); void As();
void GetAs(); void GetAs();
void Null(); void Null();
void wxVariantConversions();
void CustomTemplateSpecialization(); void CustomTemplateSpecialization();
wxDateTime m_testDateTime; wxDateTime m_testDateTime;
@@ -66,6 +68,7 @@ private:
wxAny m_anyWxObjectPtr1; wxAny m_anyWxObjectPtr1;
wxAny m_anyVoidPtr1; wxAny m_anyVoidPtr1;
wxAny m_anyDateTime1; wxAny m_anyDateTime1;
wxAny m_anyUniChar1;
wxAny m_anySignedChar2; wxAny m_anySignedChar2;
wxAny m_anySignedShort2; wxAny m_anySignedShort2;
@@ -156,6 +159,7 @@ wxAnyTestCase::wxAnyTestCase()
m_anyFloatDouble2 = (float)TEST_FLOAT_CONST; m_anyFloatDouble2 = (float)TEST_FLOAT_CONST;
m_anyDoubleDouble2 = (double)TEST_FLOAT_CONST; m_anyDoubleDouble2 = (double)TEST_FLOAT_CONST;
m_anyDateTime2 = m_testDateTime; m_anyDateTime2 = m_testDateTime;
m_anyUniChar1 = wxUniChar('A');
m_anyWxObjectPtr2 = dummyWxObjectPointer; m_anyWxObjectPtr2 = dummyWxObjectPointer;
m_anyVoidPtr2 = dummyVoidPointer; m_anyVoidPtr2 = dummyVoidPointer;
} }
@@ -248,6 +252,8 @@ void wxAnyTestCase::As()
CPPUNIT_ASSERT_DOUBLES_EQUAL(o, TEST_FLOAT_CONST, FEQ_DELTA); CPPUNIT_ASSERT_DOUBLES_EQUAL(o, TEST_FLOAT_CONST, FEQ_DELTA);
double p = wxANY_AS(m_anyDoubleDouble1, double); double p = wxANY_AS(m_anyDoubleDouble1, double);
CPPUNIT_ASSERT_DOUBLES_EQUAL(p, TEST_FLOAT_CONST, FEQ_DELTA); CPPUNIT_ASSERT_DOUBLES_EQUAL(p, TEST_FLOAT_CONST, FEQ_DELTA);
wxUniChar chr = wxANY_AS(m_anyUniChar1, wxUniChar);
CPPUNIT_ASSERT(chr == 'A');
wxDateTime q = wxANY_AS(m_anyDateTime1, wxDateTime); wxDateTime q = wxANY_AS(m_anyDateTime1, wxDateTime);
CPPUNIT_ASSERT(q == m_testDateTime); CPPUNIT_ASSERT(q == m_testDateTime);
wxObject* r = wxANY_AS(m_anyWxObjectPtr1, wxObject*); wxObject* r = wxANY_AS(m_anyWxObjectPtr1, wxObject*);
@@ -370,8 +376,10 @@ void wxAnyTestCase::GetAs()
CPPUNIT_ASSERT_DOUBLES_EQUAL(d2, TEST_FLOAT_CONST, FEQ_DELTA); CPPUNIT_ASSERT_DOUBLES_EQUAL(d2, TEST_FLOAT_CONST, FEQ_DELTA);
} }
// //
// Test user data type specialization of wxAnyValueTypeImpl // Test user data type for wxAnyValueTypeImpl specialization
// any hand-built wxVariantData
// //
class MyClass class MyClass
@@ -392,6 +400,173 @@ private:
}; };
#if wxUSE_VARIANT
// For testing purposes, create dummy variant data implementation
// that does not have wxAny conversion code
class wxMyVariantData : public wxVariantData
{
public:
wxMyVariantData(const MyClass& value)
{
m_value = value;
}
virtual bool Eq(wxVariantData& WXUNUSED(data)) const
{
return false;
}
// What type is it? Return a string name.
virtual wxString GetType() const { return "MyClass"; }
virtual wxVariantData* Clone() const
{
return new wxMyVariantData(m_value);
}
protected:
MyClass m_value;
};
#endif // wxUSE_VARIANT
void wxAnyTestCase::wxVariantConversions()
{
#if wxUSE_VARIANT
//
// Test various conversions to and from wxVariant
//
bool res;
// Prepare wxVariants
wxVariant vLong(123L);
wxVariant vString("ABC");
wxVariant vDouble(TEST_FLOAT_CONST);
wxVariant vBool((bool)true);
wxVariant vChar('A');
#ifdef wxLongLong_t
wxVariant vLongLong(wxLongLong(wxLL(0xFFFFFFFFFF)));
wxVariant vULongLong(wxULongLong(wxULL(123456)));
#endif
wxArrayString arrstr;
arrstr.push_back("test string");
wxVariant vArrayString(arrstr);
wxVariant vDateTime(m_testDateTime);
wxVariant vVoidPtr(dummyVoidPointer);
wxVariant vCustomType(new wxMyVariantData(MyClass(101)));
wxVariant vList;
vList.NullList();
vList.Append(15);
vList.Append("abc");
// Convert to wxAnys, and then back to wxVariants
wxVariant variant;
wxAny any(vLong);
CPPUNIT_ASSERT(any == 123L);
res = any.GetAs(&variant);
CPPUNIT_ASSERT(res);
CPPUNIT_ASSERT(variant == 123L);
// Make sure integer variant has correct type information
CPPUNIT_ASSERT(variant.GetLong() == 123);
CPPUNIT_ASSERT(variant.GetType() == "long");
// Unsigned long wxAny should convert to "ulonglong" wxVariant
any = 1000UL;
res = any.GetAs(&variant);
CPPUNIT_ASSERT(res);
CPPUNIT_ASSERT(variant.GetType() == "ulonglong");
CPPUNIT_ASSERT(variant.GetLong() == 1000);
any = vString;
CPPUNIT_ASSERT(any == "ABC");
res = any.GetAs(&variant);
CPPUNIT_ASSERT(res);
CPPUNIT_ASSERT(variant.GetString() == "ABC");
any = vDouble;
double d = wxANY_AS(any, double);
CPPUNIT_ASSERT_DOUBLES_EQUAL(d, TEST_FLOAT_CONST, FEQ_DELTA);
res = any.GetAs(&variant);
CPPUNIT_ASSERT(res);
CPPUNIT_ASSERT_DOUBLES_EQUAL(variant.GetDouble(),
TEST_FLOAT_CONST,
FEQ_DELTA);
any = vBool;
CPPUNIT_ASSERT(wxANY_AS(any, bool) == true);
res = any.GetAs(&variant);
CPPUNIT_ASSERT(res);
CPPUNIT_ASSERT(variant.GetBool() == true);
any = vChar;
//CPPUNIT_ASSERT(wxANY_AS(any, wxUniChar) == 'A');
res = any.GetAs(&variant);
CPPUNIT_ASSERT(res);
CPPUNIT_ASSERT(variant.GetChar() == 'A');
#ifdef wxLongLong_t
any = vLongLong;
CPPUNIT_ASSERT(any == wxLL(0xFFFFFFFFFF));
res = any.GetAs(&variant);
CPPUNIT_ASSERT(res);
CPPUNIT_ASSERT(variant.GetLongLong() == wxLongLong(wxLL(0xFFFFFFFFFF)));
CPPUNIT_ASSERT(variant.GetType() == "longlong");
any = vULongLong;
CPPUNIT_ASSERT(any == wxLL(123456));
res = any.GetAs(&variant);
CPPUNIT_ASSERT(res);
CPPUNIT_ASSERT(variant.GetULongLong() == wxULongLong(wxULL(123456)));
#endif
// Cannot test equality for the rest, just test that they convert
// back correctly.
any = vArrayString;
res = any.GetAs(&variant);
CPPUNIT_ASSERT(res);
wxArrayString arrstr2 = variant.GetArrayString();
CPPUNIT_ASSERT(arrstr2 == arrstr);
any = m_testDateTime;
CPPUNIT_ASSERT(wxANY_AS(any, wxDateTime) == m_testDateTime);
any = vDateTime;
CPPUNIT_ASSERT(wxANY_AS(any, wxDateTime) == m_testDateTime);
res = any.GetAs(&variant);
CPPUNIT_ASSERT(res);
CPPUNIT_ASSERT(variant == m_testDateTime);
any = vVoidPtr;
res = any.GetAs(&variant);
CPPUNIT_ASSERT(res);
CPPUNIT_ASSERT(variant.GetVoidPtr() == dummyVoidPointer);
any = vList;
CPPUNIT_ASSERT(wxANY_CHECK_TYPE(any, wxAnyList));
wxAnyList anyList = wxANY_AS(any, wxAnyList);
CPPUNIT_ASSERT(anyList.GetCount() == 2);
CPPUNIT_ASSERT(wxANY_AS((*anyList[0]), int) == 15);
CPPUNIT_ASSERT(wxANY_AS((*anyList[1]), wxString) == "abc");
res = any.GetAs(&variant);
CPPUNIT_ASSERT(res);
CPPUNIT_ASSERT(variant.GetType() == "list");
CPPUNIT_ASSERT(variant.GetCount() == 2);
CPPUNIT_ASSERT(variant[0].GetLong() == 15);
CPPUNIT_ASSERT(variant[1].GetString() == "abc");
any = vCustomType;
CPPUNIT_ASSERT(wxANY_CHECK_TYPE(any, wxVariantData*));
res = any.GetAs(&variant);
CPPUNIT_ASSERT(res);
CPPUNIT_ASSERT(variant.GetType() == "MyClass");
#endif // wxUSE_VARIANT
}
template<> template<>
class wxAnyValueTypeImpl<MyClass> : class wxAnyValueTypeImpl<MyClass> :
public wxAnyValueTypeImplBase<MyClass> public wxAnyValueTypeImplBase<MyClass>