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

@@ -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