e3f1423632
No real changes. Closes https://github.com/wxWidgets/wxWidgets/pull/268
533 lines
18 KiB
C++
533 lines
18 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: wx/xtitypes.h
|
|
// Purpose: enum, set, basic types support
|
|
// Author: Stefan Csomor
|
|
// Modified by: Francesco Montorsi
|
|
// Created: 27/07/03
|
|
// Copyright: (c) 1997 Julian Smart
|
|
// (c) 2003 Stefan Csomor
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef _XTITYPES_H_
|
|
#define _XTITYPES_H_
|
|
|
|
#include "wx/defs.h"
|
|
|
|
#if wxUSE_EXTENDED_RTTI
|
|
|
|
#include "wx/string.h"
|
|
#include "wx/hashmap.h"
|
|
#include "wx/arrstr.h"
|
|
#include "wx/flags.h"
|
|
#include "wx/intl.h"
|
|
#include "wx/log.h"
|
|
#include <typeinfo>
|
|
|
|
class WXDLLIMPEXP_BASE wxClassInfo;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Enum Support
|
|
//
|
|
// In the header files XTI requires no change from pure c++ code, however in the
|
|
// implementation, an enum needs to be enumerated e.g.:
|
|
//
|
|
// wxBEGIN_ENUM( wxFlavor )
|
|
// wxENUM_MEMBER( Vanilla )
|
|
// wxENUM_MEMBER( Chocolate )
|
|
// wxENUM_MEMBER( Strawberry )
|
|
// wxEND_ENUM( wxFlavor )
|
|
// ----------------------------------------------------------------------------
|
|
|
|
struct WXDLLIMPEXP_BASE wxEnumMemberData
|
|
{
|
|
const wxChar* m_name;
|
|
int m_value;
|
|
};
|
|
|
|
class WXDLLIMPEXP_BASE wxEnumData
|
|
{
|
|
public:
|
|
wxEnumData( wxEnumMemberData* data );
|
|
|
|
// returns true if the member has been found and sets the int value
|
|
// pointed to accordingly (if ptr != null )
|
|
// if not found returns false, value left unchanged
|
|
bool HasEnumMemberValue( const wxChar *name, int *value = NULL ) const;
|
|
|
|
// returns the value of the member, if not found in debug mode an
|
|
// assert is issued, in release 0 is returned
|
|
int GetEnumMemberValue(const wxChar *name ) const;
|
|
|
|
// returns the name of the enum member having the passed in value
|
|
// returns an empty string if not found
|
|
const wxChar *GetEnumMemberName(int value) const;
|
|
|
|
// returns the number of members in this enum
|
|
int GetEnumCount() const { return m_count; }
|
|
|
|
// returns the value of the nth member
|
|
int GetEnumMemberValueByIndex( int n ) const;
|
|
|
|
// returns the value of the nth member
|
|
const wxChar *GetEnumMemberNameByIndex( int n ) const;
|
|
|
|
private:
|
|
wxEnumMemberData *m_members;
|
|
int m_count;
|
|
};
|
|
|
|
#define wxBEGIN_ENUM( e ) \
|
|
wxEnumMemberData s_enumDataMembers##e[] = {
|
|
|
|
#define wxENUM_MEMBER( v ) { wxT(#v), v },
|
|
|
|
#define wxEND_ENUM( e ) \
|
|
{ NULL, 0 } }; \
|
|
wxEnumData s_enumData##e( s_enumDataMembers##e ); \
|
|
wxEnumData *wxGetEnumData(e) { return &s_enumData##e; } \
|
|
template<> void wxStringReadValue(const wxString& s, e &data ) \
|
|
{ data = (e) s_enumData##e.GetEnumMemberValue(s.c_str()); } \
|
|
template<> void wxStringWriteValue(wxString &s, const e &data ) \
|
|
{ s = s_enumData##e.GetEnumMemberName((int)data); } \
|
|
void FromLong##e( long data, wxAny& result ) \
|
|
{ result = wxAny((e)data); } \
|
|
void ToLong##e( const wxAny& data, long &result ) \
|
|
{ result = (long) (data).As(static_cast<e*>(NULL)); } \
|
|
\
|
|
wxTO_STRING_IMP( e ) \
|
|
wxFROM_STRING_IMP( e ) \
|
|
wxEnumTypeInfo s_typeInfo##e(wxT_ENUM, &s_enumData##e, \
|
|
&wxTO_STRING( e ), &wxFROM_STRING( e ), &ToLong##e, \
|
|
&FromLong##e, typeid(e).name() );
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Set Support
|
|
//
|
|
// in the header :
|
|
//
|
|
// enum wxFlavor
|
|
// {
|
|
// Vanilla,
|
|
// Chocolate,
|
|
// Strawberry,
|
|
// };
|
|
//
|
|
// typedef wxBitset<wxFlavor> wxCoupe;
|
|
//
|
|
// in the implementation file :
|
|
//
|
|
// wxBEGIN_ENUM( wxFlavor )
|
|
// wxENUM_MEMBER( Vanilla )
|
|
// wxENUM_MEMBER( Chocolate )
|
|
// wxENUM_MEMBER( Strawberry )
|
|
// wxEND_ENUM( wxFlavor )
|
|
//
|
|
// wxIMPLEMENT_SET_STREAMING( wxCoupe, wxFlavor )
|
|
//
|
|
// implementation note: no partial specialization for streaming, but a delegation
|
|
// to a different class
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void WXDLLIMPEXP_BASE wxSetStringToArray( const wxString &s, wxArrayString &array );
|
|
|
|
template<typename e>
|
|
void wxSetFromString(const wxString &s, wxBitset<e> &data )
|
|
{
|
|
wxEnumData* edata = wxGetEnumData((e) 0);
|
|
data.reset();
|
|
|
|
wxArrayString array;
|
|
wxSetStringToArray( s, array );
|
|
wxString flag;
|
|
for ( int i = 0; i < array.Count(); ++i )
|
|
{
|
|
flag = array[i];
|
|
int ivalue;
|
|
if ( edata->HasEnumMemberValue( flag.c_str(), &ivalue ) )
|
|
{
|
|
data.set( (e) ivalue );
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename e>
|
|
void wxSetToString( wxString &s, const wxBitset<e> &data )
|
|
{
|
|
wxEnumData* edata = wxGetEnumData((e) 0);
|
|
int count = edata->GetEnumCount();
|
|
int i;
|
|
s.Clear();
|
|
for ( i = 0; i < count; i++ )
|
|
{
|
|
e value = (e) edata->GetEnumMemberValueByIndex(i);
|
|
if ( data.test( value ) )
|
|
{
|
|
// this could also be done by the templated calls
|
|
if ( !s.empty() )
|
|
s += wxT("|");
|
|
s += edata->GetEnumMemberNameByIndex(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
#define wxIMPLEMENT_SET_STREAMING(SetName,e) \
|
|
template<> void wxStringReadValue(const wxString &s, wxBitset<e> &data ) \
|
|
{ wxSetFromString( s, data ); } \
|
|
template<> void wxStringWriteValue( wxString &s, const wxBitset<e> &data ) \
|
|
{ wxSetToString( s, data ); } \
|
|
void FromLong##SetName( long data, wxAny& result ) \
|
|
{ result = wxAny(SetName((unsigned long)data)); } \
|
|
void ToLong##SetName( const wxAny& data, long &result ) \
|
|
{ result = (long) (data).As(static_cast<SetName*>(NULL)).to_ulong(); } \
|
|
wxTO_STRING_IMP( SetName ) \
|
|
wxFROM_STRING_IMP( SetName ) \
|
|
wxEnumTypeInfo s_typeInfo##SetName(wxT_SET, &s_enumData##e, \
|
|
&wxTO_STRING( SetName ), &wxFROM_STRING( SetName ), \
|
|
&ToLong##SetName, &FromLong##SetName, typeid(SetName).name() );
|
|
|
|
template<typename e>
|
|
void wxFlagsFromString(const wxString &s, e &data )
|
|
{
|
|
wxEnumData* edata = wxGetEnumData((e*) 0);
|
|
data.m_data = 0;
|
|
|
|
wxArrayString array;
|
|
wxSetStringToArray( s, array );
|
|
wxString flag;
|
|
for ( size_t i = 0; i < array.Count(); ++i )
|
|
{
|
|
flag = array[i];
|
|
int ivalue;
|
|
if ( edata->HasEnumMemberValue( flag.c_str(), &ivalue ) )
|
|
{
|
|
data.m_data |= ivalue;
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename e>
|
|
void wxFlagsToString( wxString &s, const e& data )
|
|
{
|
|
wxEnumData* edata = wxGetEnumData((e*) 0);
|
|
int count = edata->GetEnumCount();
|
|
int i;
|
|
s.Clear();
|
|
long dataValue = data.m_data;
|
|
for ( i = 0; i < count; i++ )
|
|
{
|
|
int value = edata->GetEnumMemberValueByIndex(i);
|
|
// make this to allow for multi-bit constants to work
|
|
if ( value && ( dataValue & value ) == value )
|
|
{
|
|
// clear the flags we just set
|
|
dataValue &= ~value;
|
|
// this could also be done by the templated calls
|
|
if ( !s.empty() )
|
|
s +=wxT("|");
|
|
s += edata->GetEnumMemberNameByIndex(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
#define wxBEGIN_FLAGS( e ) \
|
|
wxEnumMemberData s_enumDataMembers##e[] = {
|
|
|
|
#define wxFLAGS_MEMBER( v ) { wxT(#v), static_cast<int>(v) },
|
|
|
|
#define wxEND_FLAGS( e ) \
|
|
{ NULL, 0 } }; \
|
|
wxEnumData s_enumData##e( s_enumDataMembers##e ); \
|
|
wxEnumData *wxGetEnumData(e*) { return &s_enumData##e; } \
|
|
template<> void wxStringReadValue(const wxString &s, e &data ) \
|
|
{ wxFlagsFromString<e>( s, data ); } \
|
|
template<> void wxStringWriteValue( wxString &s, const e& data ) \
|
|
{ wxFlagsToString<e>( s, data ); } \
|
|
void FromLong##e( long data, wxAny& result ) \
|
|
{ result = wxAny(e(data)); } \
|
|
void ToLong##e( const wxAny& data, long &result ) \
|
|
{ result = (long) (data).As(static_cast<e*>(NULL)).m_data; } \
|
|
wxTO_STRING_IMP( e ) \
|
|
wxFROM_STRING_IMP( e ) \
|
|
wxEnumTypeInfo s_typeInfo##e(wxT_SET, &s_enumData##e, \
|
|
&wxTO_STRING( e ), &wxFROM_STRING( e ), &ToLong##e, \
|
|
&FromLong##e, typeid(e).name() );
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Type Information
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// All data exposed by the RTTI is characterized using the following classes.
|
|
// The first characterization is done by wxTypeKind. All enums up to and including
|
|
// wxT_CUSTOM represent so called simple types. These cannot be divided any further.
|
|
// They can be converted to and from wxStrings, that's all.
|
|
// Other wxTypeKinds can instead be splitted recursively into smaller parts until
|
|
// the simple types are reached.
|
|
|
|
enum wxTypeKind
|
|
{
|
|
wxT_VOID = 0, // unknown type
|
|
wxT_BOOL,
|
|
wxT_CHAR,
|
|
wxT_UCHAR,
|
|
wxT_INT,
|
|
wxT_UINT,
|
|
wxT_LONG,
|
|
wxT_ULONG,
|
|
wxT_LONGLONG,
|
|
wxT_ULONGLONG,
|
|
wxT_FLOAT,
|
|
wxT_DOUBLE,
|
|
wxT_STRING, // must be wxString
|
|
wxT_SET, // must be wxBitset<> template
|
|
wxT_ENUM,
|
|
wxT_CUSTOM, // user defined type (e.g. wxPoint)
|
|
|
|
wxT_LAST_SIMPLE_TYPE_KIND = wxT_CUSTOM,
|
|
|
|
wxT_OBJECT_PTR, // object reference
|
|
wxT_OBJECT, // embedded object
|
|
wxT_COLLECTION, // collection
|
|
|
|
wxT_DELEGATE, // for connecting against an event source
|
|
|
|
wxT_LAST_TYPE_KIND = wxT_DELEGATE // sentinel for bad data, asserts, debugging
|
|
};
|
|
|
|
class WXDLLIMPEXP_BASE wxAny;
|
|
class WXDLLIMPEXP_BASE wxTypeInfo;
|
|
|
|
WX_DECLARE_STRING_HASH_MAP_WITH_DECL( wxTypeInfo*, wxTypeInfoMap, class WXDLLIMPEXP_BASE );
|
|
|
|
class WXDLLIMPEXP_BASE wxTypeInfo
|
|
{
|
|
public:
|
|
typedef void (*wxVariant2StringFnc)( const wxAny& data, wxString &result );
|
|
typedef void (*wxString2VariantFnc)( const wxString& data, wxAny &result );
|
|
|
|
wxTypeInfo(wxTypeKind kind,
|
|
wxVariant2StringFnc to = NULL, wxString2VariantFnc from = NULL,
|
|
const wxString &name = wxEmptyString):
|
|
m_toString(to), m_fromString(from), m_kind(kind), m_name(name)
|
|
{
|
|
Register();
|
|
}
|
|
#if 0 // wxUSE_UNICODE
|
|
wxTypeInfo(wxTypeKind kind,
|
|
wxVariant2StringFnc to, wxString2VariantFnc from,
|
|
const char *name):
|
|
m_toString(to), m_fromString(from), m_kind(kind),
|
|
m_name(wxString::FromAscii(name))
|
|
{
|
|
Register();
|
|
}
|
|
#endif
|
|
|
|
virtual ~wxTypeInfo()
|
|
{
|
|
Unregister();
|
|
}
|
|
|
|
// return the kind of this type (wxT_... constants)
|
|
wxTypeKind GetKind() const { return m_kind; }
|
|
|
|
// returns the unique name of this type
|
|
const wxString& GetTypeName() const { return m_name; }
|
|
|
|
// is this type a delegate type
|
|
bool IsDelegateType() const { return m_kind == wxT_DELEGATE; }
|
|
|
|
// is this type a custom type
|
|
bool IsCustomType() const { return m_kind == wxT_CUSTOM; }
|
|
|
|
// is this type an object type
|
|
bool IsObjectType() const { return m_kind == wxT_OBJECT || m_kind == wxT_OBJECT_PTR; }
|
|
|
|
// can the content of this type be converted to and from strings ?
|
|
bool HasStringConverters() const { return m_toString != NULL && m_fromString != NULL; }
|
|
|
|
// convert a wxAny holding data of this type into a string
|
|
void ConvertToString( const wxAny& data, wxString &result ) const
|
|
{
|
|
if ( m_toString )
|
|
(*m_toString)( data, result );
|
|
else
|
|
wxLogError( wxGetTranslation(wxT("String conversions not supported")) );
|
|
}
|
|
|
|
// convert a string into a wxAny holding the corresponding data in this type
|
|
void ConvertFromString( const wxString& data, wxAny &result ) const
|
|
{
|
|
if( m_fromString )
|
|
(*m_fromString)( data, result );
|
|
else
|
|
wxLogError( wxGetTranslation(wxT("String conversions not supported")) );
|
|
}
|
|
|
|
// statics:
|
|
|
|
// looks for the corresponding type, will return NULL if not found
|
|
static wxTypeInfo *FindType( const wxString& typeName );
|
|
private:
|
|
void Register();
|
|
void Unregister();
|
|
|
|
wxVariant2StringFnc m_toString;
|
|
wxString2VariantFnc m_fromString;
|
|
|
|
wxTypeKind m_kind;
|
|
wxString m_name;
|
|
|
|
// the static list of all types we know about
|
|
static wxTypeInfoMap* ms_typeTable;
|
|
};
|
|
|
|
class WXDLLIMPEXP_BASE wxBuiltInTypeInfo : public wxTypeInfo
|
|
{
|
|
public:
|
|
wxBuiltInTypeInfo( wxTypeKind kind, wxVariant2StringFnc to = NULL,
|
|
wxString2VariantFnc from = NULL,
|
|
const wxString &name = wxEmptyString ) :
|
|
wxTypeInfo( kind, to, from, name )
|
|
{ wxASSERT_MSG( GetKind() < wxT_SET, wxT("Illegal Kind for Base Type") ); }
|
|
};
|
|
|
|
class WXDLLIMPEXP_BASE wxCustomTypeInfo : public wxTypeInfo
|
|
{
|
|
public:
|
|
wxCustomTypeInfo( const wxString &name, wxVariant2StringFnc to,
|
|
wxString2VariantFnc from ) :
|
|
wxTypeInfo( wxT_CUSTOM, to, from, name )
|
|
{}
|
|
};
|
|
|
|
class WXDLLIMPEXP_BASE wxEnumTypeInfo : public wxTypeInfo
|
|
{
|
|
public:
|
|
typedef void (*converterToLong_t)( const wxAny& data, long &result );
|
|
typedef void (*converterFromLong_t)( long data, wxAny &result );
|
|
|
|
wxEnumTypeInfo( wxTypeKind kind, wxEnumData* enumInfo, wxVariant2StringFnc to,
|
|
wxString2VariantFnc from, converterToLong_t toLong,
|
|
converterFromLong_t fromLong, const wxString &name ) :
|
|
wxTypeInfo( kind, to, from, name ), m_toLong( toLong ), m_fromLong( fromLong )
|
|
{
|
|
wxASSERT_MSG( kind == wxT_ENUM || kind == wxT_SET,
|
|
wxT("Illegal Kind for Enum Type"));
|
|
m_enumInfo = enumInfo;
|
|
}
|
|
|
|
const wxEnumData* GetEnumData() const { return m_enumInfo; }
|
|
|
|
// convert a wxAny holding data of this type into a long
|
|
void ConvertToLong( const wxAny& data, long &result ) const
|
|
{
|
|
if( m_toLong )
|
|
(*m_toLong)( data, result );
|
|
else
|
|
wxLogError( wxGetTranslation(wxT("Long Conversions not supported")) );
|
|
}
|
|
|
|
// convert a long into a wxAny holding the corresponding data in this type
|
|
void ConvertFromLong( long data, wxAny &result ) const
|
|
{
|
|
if( m_fromLong )
|
|
(*m_fromLong)( data, result );
|
|
else
|
|
wxLogError( wxGetTranslation(wxT("Long Conversions not supported")) );
|
|
}
|
|
|
|
private:
|
|
converterToLong_t m_toLong;
|
|
converterFromLong_t m_fromLong;
|
|
|
|
wxEnumData *m_enumInfo; // Kind == wxT_ENUM or Kind == wxT_SET
|
|
};
|
|
|
|
class WXDLLIMPEXP_BASE wxClassTypeInfo : public wxTypeInfo
|
|
{
|
|
public:
|
|
wxClassTypeInfo( wxTypeKind kind, wxClassInfo* classInfo,
|
|
wxVariant2StringFnc to = NULL, wxString2VariantFnc from = NULL,
|
|
const wxString &name = wxEmptyString);
|
|
|
|
const wxClassInfo *GetClassInfo() const { return m_classInfo; }
|
|
|
|
private:
|
|
wxClassInfo *m_classInfo; // Kind == wxT_OBJECT - could be NULL
|
|
};
|
|
|
|
class WXDLLIMPEXP_BASE wxCollectionTypeInfo : public wxTypeInfo
|
|
{
|
|
public:
|
|
wxCollectionTypeInfo( const wxString &elementName, wxVariant2StringFnc to,
|
|
wxString2VariantFnc from , const wxString &name) :
|
|
wxTypeInfo( wxT_COLLECTION, to, from, name )
|
|
{ m_elementTypeName = elementName; m_elementType = NULL; }
|
|
|
|
const wxTypeInfo* GetElementType() const
|
|
{
|
|
if ( m_elementType == NULL )
|
|
m_elementType = wxTypeInfo::FindType( m_elementTypeName );
|
|
return m_elementType;
|
|
}
|
|
|
|
private:
|
|
mutable wxTypeInfo * m_elementType;
|
|
wxString m_elementTypeName;
|
|
};
|
|
|
|
class WXDLLIMPEXP_BASE wxEventSourceTypeInfo : public wxTypeInfo
|
|
{
|
|
public:
|
|
wxEventSourceTypeInfo( int eventType, wxClassInfo* eventClass,
|
|
wxVariant2StringFnc to = NULL,
|
|
wxString2VariantFnc from = NULL );
|
|
wxEventSourceTypeInfo( int eventType, int lastEventType, wxClassInfo* eventClass,
|
|
wxVariant2StringFnc to = NULL, wxString2VariantFnc from = NULL );
|
|
|
|
int GetEventType() const { return m_eventType; }
|
|
int GetLastEventType() const { return m_lastEventType; }
|
|
const wxClassInfo* GetEventClass() const { return m_eventClass; }
|
|
|
|
private:
|
|
const wxClassInfo *m_eventClass; // (extended will merge into classinfo)
|
|
int m_eventType;
|
|
int m_lastEventType;
|
|
};
|
|
|
|
template<typename T> const wxTypeInfo* wxGetTypeInfo( T * )
|
|
{ return wxTypeInfo::FindType(typeid(T).name()); }
|
|
|
|
// this macro is for usage with custom, non-object derived classes and structs,
|
|
// wxPoint is such a custom type
|
|
|
|
#if wxUSE_FUNC_TEMPLATE_POINTER
|
|
#define wxCUSTOM_TYPE_INFO( e, toString, fromString ) \
|
|
wxCustomTypeInfo s_typeInfo##e(typeid(e).name(), &toString, &fromString);
|
|
#else
|
|
#define wxCUSTOM_TYPE_INFO( e, toString, fromString ) \
|
|
void ToString##e( const wxAny& data, wxString &result ) \
|
|
{ toString(data, result); } \
|
|
void FromString##e( const wxString& data, wxAny &result ) \
|
|
{ fromString(data, result); } \
|
|
wxCustomTypeInfo s_typeInfo##e(typeid(e).name(), \
|
|
&ToString##e, &FromString##e);
|
|
#endif
|
|
|
|
#define wxCOLLECTION_TYPE_INFO( element, collection ) \
|
|
wxCollectionTypeInfo s_typeInfo##collection( typeid(element).name(), \
|
|
NULL, NULL, typeid(collection).name() );
|
|
|
|
// sometimes a compiler invents specializations that are nowhere called,
|
|
// use this macro to satisfy the refs, currently we don't have to play
|
|
// tricks, but if we will have to according to the compiler, we will use
|
|
// that macro for that
|
|
|
|
#define wxILLEGAL_TYPE_SPECIALIZATION( a )
|
|
|
|
#endif // wxUSE_EXTENDED_RTTI
|
|
#endif // _XTITYPES_H_
|