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:
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "wx/vector.h"
|
||||
#include "wx/module.h"
|
||||
#include "wx/hashmap.h"
|
||||
|
||||
using namespace wxPrivate;
|
||||
|
||||
@@ -34,9 +35,19 @@ using namespace wxPrivate;
|
||||
// wxAnyValueTypeGlobals
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
#if wxUSE_VARIANT
|
||||
|
||||
WX_DECLARE_HASH_MAP(wxAnyValueType*,
|
||||
wxVariantDataFactory,
|
||||
wxPointerHash,
|
||||
wxPointerEqual,
|
||||
wxAnyTypeToVariantDataFactoryMap);
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// Helper class to manage wxAnyValueType instances and other
|
||||
// related global variables.
|
||||
// Helper class to manage wxAnyValueType instances and and other
|
||||
// related global variables (such as wxAny<->wxVariant type association).
|
||||
//
|
||||
// NB: We really need to have wxAnyValueType instances allocated
|
||||
// in heap. They are stored as static template member variables,
|
||||
@@ -51,6 +62,9 @@ public:
|
||||
}
|
||||
~wxAnyValueTypeGlobals()
|
||||
{
|
||||
#if wxUSE_VARIANT
|
||||
m_anyToVariant.clear();
|
||||
#endif
|
||||
for ( size_t i=0; i<m_valueTypes.size(); i++ )
|
||||
delete m_valueTypes[i];
|
||||
}
|
||||
@@ -60,12 +74,147 @@ public:
|
||||
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:
|
||||
wxVector<wxAnyValueType*> m_valueTypes;
|
||||
wxVector<wxAnyValueType*> m_valueTypes;
|
||||
#if wxUSE_VARIANT
|
||||
wxAnyTypeToVariantDataFactoryMap m_anyToVariant;
|
||||
wxVector<wxAnyToVariantRegistration*> m_anyToVariantRegs;
|
||||
#endif
|
||||
};
|
||||
|
||||
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
|
||||
// etc. get freed correctly. We must use a separate wxAnyValueTypeGlobals
|
||||
|
Reference in New Issue
Block a user