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:
134
include/wx/any.h
134
include/wx/any.h
@@ -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)
|
||||||
{
|
{
|
||||||
|
@@ -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"
|
||||||
|
@@ -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);
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
//@{
|
//@{
|
||||||
|
@@ -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.
|
||||||
*/
|
*/
|
||||||
|
@@ -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
|
||||||
|
@@ -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);
|
||||||
|
@@ -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>
|
||||||
|
Reference in New Issue
Block a user