1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/xtistrm.cpp
3 // Purpose: streaming runtime metadata information
4 // Author: Stefan Csomor
8 // Copyright: (c) 2003 Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
19 #if wxUSE_EXTENDED_RTTI
21 #include "wx/xtistrm.h"
24 #include "wx/object.h"
29 #include "wx/tokenzr.h"
30 #include "wx/txtstrm.h"
34 #include "wx/beforestd.h"
38 #include "wx/afterstd.h"
42 // ----------------------------------------------------------------------------
44 // ----------------------------------------------------------------------------
46 struct wxObjectWriter::wxObjectWriterInternal
48 map
< const wxObject
*, int > m_writtenObjects
;
52 wxObjectWriter::wxObjectWriter()
54 m_data
= new wxObjectWriterInternal
;
58 wxObjectWriter::~wxObjectWriter()
63 struct wxObjectWriter::wxObjectWriterInternalPropertiesData
68 void wxObjectWriter::ClearObjectContext()
71 m_data
= new wxObjectWriterInternal();
75 void wxObjectWriter::WriteObject(const wxObject
*object
, const wxClassInfo
*classInfo
,
76 wxObjectWriterCallback
*writercallback
, const wxString
&name
,
77 const wxStringToAnyHashMap
&metadata
)
79 DoBeginWriteTopLevelEntry( name
);
80 WriteObject( object
, classInfo
, writercallback
, false, metadata
);
81 DoEndWriteTopLevelEntry( name
);
84 void wxObjectWriter::WriteObject(const wxObject
*object
, const wxClassInfo
*classInfo
,
85 wxObjectWriterCallback
*writercallback
, bool isEmbedded
,
86 const wxStringToAnyHashMap
&metadata
)
88 if ( !classInfo
->BeforeWriteObject( object
, this, writercallback
, metadata
) )
91 if ( writercallback
->BeforeWriteObject( this, object
, classInfo
, metadata
) )
95 else if ( IsObjectKnown( object
) )
96 DoWriteRepeatedObject( GetObjectID(object
) );
99 int oid
= m_data
->m_nextId
++;
101 m_data
->m_writtenObjects
[object
] = oid
;
103 // in case this object is a wxDynamicObject we also have to insert is superclass
104 // instance with the same id, so that object relations are streamed out correctly
105 const wxDynamicObject
* dynobj
= wx_dynamic_cast(const wxDynamicObject
*, object
);
106 if ( !isEmbedded
&& dynobj
)
107 m_data
->m_writtenObjects
[dynobj
->GetSuperClassInstance()] = oid
;
109 DoBeginWriteObject( object
, classInfo
, oid
, metadata
);
110 wxObjectWriterInternalPropertiesData data
;
111 WriteAllProperties( object
, classInfo
, writercallback
, &data
);
112 DoEndWriteObject( object
, classInfo
, oid
);
114 writercallback
->AfterWriteObject( this,object
, classInfo
);
118 void wxObjectWriter::FindConnectEntry(const wxEvtHandler
* evSource
,
119 const wxEventSourceTypeInfo
* dti
,
120 const wxObject
* &sink
,
121 const wxHandlerInfo
*&handler
)
123 wxList
*dynamicEvents
= evSource
->GetDynamicEventTable();
127 for ( wxList::const_iterator node
= dynamicEvents
->begin(); node
!= dynamicEvents
->end(); ++node
)
129 wxDynamicEventTableEntry
*entry
= (wxDynamicEventTableEntry
*)(*node
);
133 (dti
->GetEventType() == entry
->m_eventType
) &&
134 (entry
->m_id
== -1 ) &&
135 (entry
->m_fn
->GetEvtHandler() != NULL
) )
137 sink
= entry
->m_fn
->GetEvtHandler();
138 const wxClassInfo
* sinkClassInfo
= sink
->GetClassInfo();
139 const wxHandlerInfo
* sinkHandler
= sinkClassInfo
->GetFirstHandler();
140 while ( sinkHandler
)
142 if ( sinkHandler
->GetEventFunction() == entry
->m_fn
->GetEvtMethod() )
144 handler
= sinkHandler
;
147 sinkHandler
= sinkHandler
->GetNext();
154 void wxObjectWriter::WriteAllProperties( const wxObject
* obj
, const wxClassInfo
* ci
,
155 wxObjectWriterCallback
*writercallback
,
156 wxObjectWriterInternalPropertiesData
* data
)
158 wxPropertyInfoMap map
;
159 ci
->GetProperties( map
);
160 for ( int i
= 0; i
< ci
->GetCreateParamCount(); ++i
)
162 wxString name
= ci
->GetCreateParamName(i
);
163 wxPropertyInfoMap::const_iterator iter
= map
.find(name
);
164 const wxPropertyInfo
* prop
= iter
== map
.end() ? NULL
: iter
->second
;
167 WriteOneProperty( obj
, prop
->GetDeclaringClass(), prop
, writercallback
, data
);
171 wxLogError( _("Create Parameter %s not found in declared RTTI Parameters"), name
.c_str() );
175 { // Extra block for broken compilers
176 for( wxPropertyInfoMap::iterator iter
= map
.begin(); iter
!= map
.end(); ++iter
)
178 const wxPropertyInfo
* prop
= iter
->second
;
179 if ( prop
->GetFlags() & wxPROP_OBJECT_GRAPH
)
181 WriteOneProperty( obj
, prop
->GetDeclaringClass(), prop
, writercallback
, data
);
185 { // Extra block for broken compilers
186 for( wxPropertyInfoMap::iterator iter
= map
.begin(); iter
!= map
.end(); ++iter
)
188 const wxPropertyInfo
* prop
= iter
->second
;
189 if ( !(prop
->GetFlags() & wxPROP_OBJECT_GRAPH
) )
191 WriteOneProperty( obj
, prop
->GetDeclaringClass(), prop
, writercallback
, data
);
197 class WXDLLIMPEXP_BASE wxObjectPropertyWriter
: public wxObjectWriterFunctor
200 wxObjectPropertyWriter(const wxClassTypeInfo
* cti
,
201 wxObjectWriterCallback
*writercallback
,
202 wxObjectWriter
* writer
,
203 wxStringToAnyHashMap
&props
) :
204 m_cti(cti
),m_persister(writercallback
),m_writer(writer
),m_props(props
)
207 virtual void operator()(const wxObject
*vobj
)
209 m_writer
->WriteObject( vobj
, (vobj
? vobj
->GetClassInfo() : m_cti
->GetClassInfo() ),
210 m_persister
, m_cti
->GetKind()== wxT_OBJECT
, m_props
);
213 const wxClassTypeInfo
* m_cti
;
214 wxObjectWriterCallback
*m_persister
;
215 wxObjectWriter
* m_writer
;
216 wxStringToAnyHashMap
& m_props
;
219 void wxObjectWriter::WriteOneProperty( const wxObject
*obj
, const wxClassInfo
* ci
,
220 const wxPropertyInfo
* pi
, wxObjectWriterCallback
*writercallback
,
221 wxObjectWriterInternalPropertiesData
*WXUNUSED(data
) )
223 if ( pi
->GetFlags() & wxPROP_DONT_STREAM
)
226 // make sure that we are picking the correct object for accessing the property
227 const wxDynamicObject
* dynobj
= wx_dynamic_cast(const wxDynamicObject
*, obj
);
228 if ( dynobj
&& (wx_dynamic_cast(const wxDynamicClassInfo
*, ci
) == NULL
) )
229 obj
= dynobj
->GetSuperClassInstance();
231 if ( pi
->GetTypeInfo()->GetKind() == wxT_COLLECTION
)
234 pi
->GetAccessor()->GetPropertyCollection(obj
, data
);
235 const wxTypeInfo
* elementType
=
236 wx_dynamic_cast( const wxCollectionTypeInfo
*, pi
->GetTypeInfo() )->GetElementType();
239 DoBeginWriteProperty( pi
);
240 for ( wxAnyList::const_iterator iter
= data
.begin(); iter
!= data
.end(); ++iter
)
242 DoBeginWriteElement();
243 const wxAny
* valptr
= *iter
;
244 if ( writercallback
->BeforeWriteProperty( this, obj
, pi
, *valptr
) )
246 const wxClassTypeInfo
* cti
=
247 wx_dynamic_cast( const wxClassTypeInfo
*, elementType
);
250 wxStringToAnyHashMap md
;
251 wxObjectPropertyWriter
pw(cti
,writercallback
,this, md
);
253 const wxClassInfo
* pci
= cti
->GetClassInfo();
254 pci
->CallOnAny( *valptr
, &pw
);
258 DoWriteSimpleType( *valptr
);
263 DoEndWriteProperty( pi
);
268 const wxEventSourceTypeInfo
* dti
=
269 wx_dynamic_cast( const wxEventSourceTypeInfo
* , pi
->GetTypeInfo() );
272 const wxObject
* sink
= NULL
;
273 const wxHandlerInfo
*handler
= NULL
;
275 const wxEvtHandler
* evSource
= wx_dynamic_cast(const wxEvtHandler
*, obj
);
278 FindConnectEntry( evSource
, dti
, sink
, handler
);
279 if ( writercallback
->BeforeWriteDelegate( this, obj
, ci
, pi
, sink
, handler
) )
281 if ( sink
!= NULL
&& handler
!= NULL
)
283 DoBeginWriteProperty( pi
);
284 if ( IsObjectKnown( sink
) )
286 DoWriteDelegate( obj
, ci
, pi
, sink
, GetObjectID( sink
),
287 sink
->GetClassInfo(), handler
);
288 DoEndWriteProperty( pi
);
292 wxLogError( wxT("Streaming delegates for not already ")
293 wxT("streamed objects not yet supported") );
300 wxLogError(_("Illegal Object Class (Non-wxEvtHandler) as Event Source") );
306 pi
->GetAccessor()->GetProperty(obj
, value
);
308 // avoid streaming out void objects
313 if ( pi
->GetFlags() & wxPROP_ENUM_STORE_LONG
)
315 const wxEnumTypeInfo
*eti
=
316 wx_dynamic_cast(const wxEnumTypeInfo
*, pi
->GetTypeInfo() );
319 eti
->ConvertFromLong( wxANY_AS(value
, long ), value
);
323 wxLogError( _("Type must have enum - long conversion") );
327 // avoid streaming out default values
328 if ( pi
->GetTypeInfo()->HasStringConverters() &&
329 !pi
->GetDefaultValue().IsNull() ) // TODO Verify
331 if ( wxAnyGetAsString(value
) == wxAnyGetAsString(pi
->GetDefaultValue()) )
335 // avoid streaming out null objects
336 const wxClassTypeInfo
* cti
=
337 wx_dynamic_cast( const wxClassTypeInfo
* , pi
->GetTypeInfo() );
339 if ( cti
&& cti
->GetKind() == wxT_OBJECT_PTR
&& wxAnyGetAsObjectPtr(value
) == NULL
)
342 if ( writercallback
->BeforeWriteProperty( this, obj
, pi
, value
) )
344 DoBeginWriteProperty( pi
);
347 if ( cti
->HasStringConverters() )
349 wxString stringValue
;
350 cti
->ConvertToString( value
, stringValue
);
351 wxAny
convertedValue(stringValue
);
352 DoWriteSimpleType( convertedValue
);
356 wxStringToAnyHashMap md
;
357 wxObjectPropertyWriter
pw(cti
,writercallback
,this, md
);
359 const wxClassInfo
* pci
= cti
->GetClassInfo();
360 pci
->CallOnAny(value
, &pw
);
365 DoWriteSimpleType( value
);
367 DoEndWriteProperty( pi
);
373 int wxObjectWriter::GetObjectID(const wxObject
*obj
)
375 if ( !IsObjectKnown( obj
) )
376 return wxInvalidObjectID
;
378 return m_data
->m_writtenObjects
[obj
];
381 bool wxObjectWriter::IsObjectKnown( const wxObject
*obj
)
383 return m_data
->m_writtenObjects
.find( obj
) != m_data
->m_writtenObjects
.end();
387 // ----------------------------------------------------------------------------
389 // ----------------------------------------------------------------------------
391 struct wxObjectReader::wxObjectReaderInternal
393 map
<int,wxClassInfo
*> m_classInfos
;
396 wxObjectReader::wxObjectReader()
398 m_data
= new wxObjectReaderInternal
;
401 wxObjectReader::~wxObjectReader()
406 wxClassInfo
* wxObjectReader::GetObjectClassInfo(int objectID
)
408 if ( objectID
== wxNullObjectID
|| objectID
== wxInvalidObjectID
)
410 wxLogError( _("Invalid or Null Object ID passed to GetObjectClassInfo" ) );
413 if ( m_data
->m_classInfos
.find(objectID
) == m_data
->m_classInfos
.end() )
415 wxLogError( _("Unknown Object passed to GetObjectClassInfo" ) );
418 return m_data
->m_classInfos
[objectID
];
421 void wxObjectReader::SetObjectClassInfo(int objectID
, wxClassInfo
*classInfo
)
423 if ( objectID
== wxNullObjectID
|| objectID
== wxInvalidObjectID
)
425 wxLogError( _("Invalid or Null Object ID passed to GetObjectClassInfo" ) );
428 if ( m_data
->m_classInfos
.find(objectID
) != m_data
->m_classInfos
.end() )
430 wxLogError( _("Already Registered Object passed to SetObjectClassInfo" ) );
433 m_data
->m_classInfos
[objectID
] = classInfo
;
436 bool wxObjectReader::HasObjectClassInfo( int objectID
)
438 if ( objectID
== wxNullObjectID
|| objectID
== wxInvalidObjectID
)
440 wxLogError( _("Invalid or Null Object ID passed to HasObjectClassInfo" ) );
443 return m_data
->m_classInfos
.find(objectID
) != m_data
->m_classInfos
.end();
447 // ----------------------------------------------------------------------------
449 // ----------------------------------------------------------------------------
452 Reading components has not to be extended for components
453 as properties are always sought by typeinfo over all levels
454 and create params are always toplevel class only
458 // ----------------------------------------------------------------------------
459 // wxObjectRuntimeReaderCallback - depersisting to memory
460 // ----------------------------------------------------------------------------
462 struct wxObjectRuntimeReaderCallback::wxObjectRuntimeReaderCallbackInternal
464 map
<int,wxObject
*> m_objects
;
466 void SetObject(int objectID
, wxObject
*obj
)
468 if ( m_objects
.find(objectID
) != m_objects
.end() )
470 wxLogError( _("Passing a already registered object to SetObject") );
473 m_objects
[objectID
] = obj
;
475 wxObject
* GetObject( int objectID
)
477 if ( objectID
== wxNullObjectID
)
479 if ( m_objects
.find(objectID
) == m_objects
.end() )
481 wxLogError( _("Passing an unknown object to GetObject") );
485 return m_objects
[objectID
];
489 wxObjectRuntimeReaderCallback::wxObjectRuntimeReaderCallback()
491 m_data
= new wxObjectRuntimeReaderCallbackInternal();
494 wxObjectRuntimeReaderCallback::~wxObjectRuntimeReaderCallback()
499 void wxObjectRuntimeReaderCallback::AllocateObject(int objectID
, wxClassInfo
*classInfo
,
500 wxStringToAnyHashMap
&WXUNUSED(metadata
))
503 O
= classInfo
->CreateObject();
504 m_data
->SetObject(objectID
, O
);
507 void wxObjectRuntimeReaderCallback::CreateObject(int objectID
,
508 const wxClassInfo
*classInfo
,
512 const wxClassInfo
**objectClassInfos
,
513 wxStringToAnyHashMap
&WXUNUSED(metadata
))
516 o
= m_data
->GetObject(objectID
);
517 for ( int i
= 0; i
< paramCount
; ++i
)
519 if ( objectIdValues
[i
] != wxInvalidObjectID
)
522 o
= m_data
->GetObject(objectIdValues
[i
]);
523 // if this is a dynamic object and we are asked for another class
524 // than wxDynamicObject we cast it down manually.
525 wxDynamicObject
*dyno
= wx_dynamic_cast( wxDynamicObject
*, o
);
526 if ( dyno
!=NULL
&& (objectClassInfos
[i
] != dyno
->GetClassInfo()) )
528 o
= dyno
->GetSuperClassInstance();
530 params
[i
] = objectClassInfos
[i
]->ObjectPtrToAny(o
);
533 classInfo
->Create(o
, paramCount
, params
);
536 void wxObjectRuntimeReaderCallback::ConstructObject(int objectID
,
537 const wxClassInfo
*classInfo
,
541 const wxClassInfo
**objectClassInfos
,
542 wxStringToAnyHashMap
&WXUNUSED(metadata
))
545 for ( int i
= 0; i
< paramCount
; ++i
)
547 if ( objectIdValues
[i
] != wxInvalidObjectID
)
550 o
= m_data
->GetObject(objectIdValues
[i
]);
551 // if this is a dynamic object and we are asked for another class
552 // than wxDynamicObject we cast it down manually.
553 wxDynamicObject
*dyno
= wx_dynamic_cast( wxDynamicObject
*, o
);
554 if ( dyno
!=NULL
&& (objectClassInfos
[i
] != dyno
->GetClassInfo()) )
556 o
= dyno
->GetSuperClassInstance();
558 params
[i
] = objectClassInfos
[i
]->ObjectPtrToAny(o
);
561 o
= classInfo
->ConstructObject(paramCount
, params
);
562 m_data
->SetObject(objectID
, o
);
566 void wxObjectRuntimeReaderCallback::DestroyObject(int objectID
, wxClassInfo
*WXUNUSED(classInfo
))
569 o
= m_data
->GetObject(objectID
);
573 void wxObjectRuntimeReaderCallback::SetProperty(int objectID
,
574 const wxClassInfo
*classInfo
,
575 const wxPropertyInfo
* propertyInfo
,
579 o
= m_data
->GetObject(objectID
);
580 classInfo
->SetProperty( o
, propertyInfo
->GetName().c_str(), value
);
583 void wxObjectRuntimeReaderCallback::SetPropertyAsObject(int objectID
,
584 const wxClassInfo
*classInfo
,
585 const wxPropertyInfo
* propertyInfo
,
589 o
= m_data
->GetObject(objectID
);
590 valo
= m_data
->GetObject(valueObjectId
);
591 const wxClassInfo
* valClassInfo
=
592 (wx_dynamic_cast(const wxClassTypeInfo
*,propertyInfo
->GetTypeInfo()))->GetClassInfo();
594 // if this is a dynamic object and we are asked for another class
595 // than wxDynamicObject we cast it down manually.
596 wxDynamicObject
*dynvalo
= wx_dynamic_cast( wxDynamicObject
*, valo
);
597 if ( dynvalo
!=NULL
&& (valClassInfo
!= dynvalo
->GetClassInfo()) )
599 valo
= dynvalo
->GetSuperClassInstance();
602 classInfo
->SetProperty( o
, propertyInfo
->GetName().c_str(),
603 valClassInfo
->ObjectPtrToAny(valo
) );
606 void wxObjectRuntimeReaderCallback::SetConnect(int eventSourceObjectID
,
607 const wxClassInfo
*WXUNUSED(eventSourceClassInfo
),
608 const wxPropertyInfo
*delegateInfo
,
609 const wxClassInfo
*WXUNUSED(eventSinkClassInfo
),
610 const wxHandlerInfo
* handlerInfo
,
611 int eventSinkObjectID
)
613 wxEvtHandler
*ehsource
=
614 wx_dynamic_cast( wxEvtHandler
* , m_data
->GetObject( eventSourceObjectID
) );
615 wxEvtHandler
*ehsink
=
616 wx_dynamic_cast( wxEvtHandler
*,m_data
->GetObject(eventSinkObjectID
) );
618 if ( ehsource
&& ehsink
)
620 const wxEventSourceTypeInfo
*delegateTypeInfo
=
621 wx_dynamic_cast(const wxEventSourceTypeInfo
*,delegateInfo
->GetTypeInfo());
622 if( delegateTypeInfo
&& delegateTypeInfo
->GetLastEventType() == -1 )
624 ehsource
->Connect( -1, delegateTypeInfo
->GetEventType(),
625 handlerInfo
->GetEventFunction(), NULL
/*user data*/,
630 for ( wxEventType iter
= delegateTypeInfo
->GetEventType();
631 iter
<= delegateTypeInfo
->GetLastEventType(); ++iter
)
633 ehsource
->Connect( -1, iter
,
634 handlerInfo
->GetEventFunction(), NULL
/*user data*/,
641 wxObject
*wxObjectRuntimeReaderCallback::GetObject(int objectID
)
643 return m_data
->GetObject( objectID
);
646 void wxObjectRuntimeReaderCallback::AddToPropertyCollection( int objectID
,
647 const wxClassInfo
*classInfo
,
648 const wxPropertyInfo
* propertyInfo
,
652 o
= m_data
->GetObject(objectID
);
653 classInfo
->AddToPropertyCollection( o
, propertyInfo
->GetName().c_str(), value
);
656 void wxObjectRuntimeReaderCallback::AddToPropertyCollectionAsObject(int objectID
,
657 const wxClassInfo
*classInfo
,
658 const wxPropertyInfo
* propertyInfo
,
662 o
= m_data
->GetObject(objectID
);
663 valo
= m_data
->GetObject(valueObjectId
);
664 const wxCollectionTypeInfo
* collectionTypeInfo
=
665 wx_dynamic_cast( const wxCollectionTypeInfo
*, propertyInfo
->GetTypeInfo() );
666 const wxClassInfo
* valClassInfo
=
667 (wx_dynamic_cast(const wxClassTypeInfo
*,collectionTypeInfo
->GetElementType()))->GetClassInfo();
669 // if this is a dynamic object and we are asked for another class
670 // than wxDynamicObject we cast it down manually.
671 wxDynamicObject
*dynvalo
= wx_dynamic_cast( wxDynamicObject
*, valo
);
672 if ( dynvalo
!=NULL
&& (valClassInfo
!= dynvalo
->GetClassInfo()) )
674 valo
= dynvalo
->GetSuperClassInstance();
677 classInfo
->AddToPropertyCollection( o
, propertyInfo
->GetName().c_str(),
678 valClassInfo
->ObjectPtrToAny(valo
) );
681 #endif // wxUSE_EXTENDED_RTTI