1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/xtistrm.cpp
3 // Purpose: streaming runtime metadata information
4 // Author: Stefan Csomor
7 // Copyright: (c) 2003 Stefan Csomor
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
18 #if wxUSE_EXTENDED_RTTI
20 #include "wx/xtistrm.h"
23 #include "wx/object.h"
28 #include "wx/tokenzr.h"
29 #include "wx/txtstrm.h"
33 #include "wx/beforestd.h"
37 #include "wx/afterstd.h"
41 // ----------------------------------------------------------------------------
43 // ----------------------------------------------------------------------------
45 struct wxObjectWriter::wxObjectWriterInternal
47 map
< const wxObject
*, int > m_writtenObjects
;
51 wxObjectWriter::wxObjectWriter()
53 m_data
= new wxObjectWriterInternal
;
57 wxObjectWriter::~wxObjectWriter()
62 struct wxObjectWriter::wxObjectWriterInternalPropertiesData
67 void wxObjectWriter::ClearObjectContext()
70 m_data
= new wxObjectWriterInternal();
74 void wxObjectWriter::WriteObject(const wxObject
*object
, const wxClassInfo
*classInfo
,
75 wxObjectWriterCallback
*writercallback
, const wxString
&name
,
76 const wxStringToAnyHashMap
&metadata
)
78 DoBeginWriteTopLevelEntry( name
);
79 WriteObject( object
, classInfo
, writercallback
, false, metadata
);
80 DoEndWriteTopLevelEntry( name
);
83 void wxObjectWriter::WriteObject(const wxObject
*object
, const wxClassInfo
*classInfo
,
84 wxObjectWriterCallback
*writercallback
, bool isEmbedded
,
85 const wxStringToAnyHashMap
&metadata
)
87 if ( !classInfo
->BeforeWriteObject( object
, this, writercallback
, metadata
) )
90 if ( writercallback
->BeforeWriteObject( this, object
, classInfo
, metadata
) )
94 else if ( IsObjectKnown( object
) )
95 DoWriteRepeatedObject( GetObjectID(object
) );
98 int oid
= m_data
->m_nextId
++;
100 m_data
->m_writtenObjects
[object
] = oid
;
102 // in case this object is a wxDynamicObject we also have to insert is superclass
103 // instance with the same id, so that object relations are streamed out correctly
104 const wxDynamicObject
* dynobj
= wx_dynamic_cast(const wxDynamicObject
*, object
);
105 if ( !isEmbedded
&& dynobj
)
106 m_data
->m_writtenObjects
[dynobj
->GetSuperClassInstance()] = oid
;
108 DoBeginWriteObject( object
, classInfo
, oid
, metadata
);
109 wxObjectWriterInternalPropertiesData data
;
110 WriteAllProperties( object
, classInfo
, writercallback
, &data
);
111 DoEndWriteObject( object
, classInfo
, oid
);
113 writercallback
->AfterWriteObject( this,object
, classInfo
);
117 void wxObjectWriter::FindConnectEntry(const wxEvtHandler
* evSource
,
118 const wxEventSourceTypeInfo
* dti
,
119 const wxObject
* &sink
,
120 const wxHandlerInfo
*&handler
)
122 wxList
*dynamicEvents
= evSource
->GetDynamicEventTable();
126 for ( wxList::const_iterator node
= dynamicEvents
->begin(); node
!= dynamicEvents
->end(); ++node
)
128 wxDynamicEventTableEntry
*entry
= (wxDynamicEventTableEntry
*)(*node
);
132 (dti
->GetEventType() == entry
->m_eventType
) &&
133 (entry
->m_id
== -1 ) &&
134 (entry
->m_fn
->GetEvtHandler() != NULL
) )
136 sink
= entry
->m_fn
->GetEvtHandler();
137 const wxClassInfo
* sinkClassInfo
= sink
->GetClassInfo();
138 const wxHandlerInfo
* sinkHandler
= sinkClassInfo
->GetFirstHandler();
139 while ( sinkHandler
)
141 if ( sinkHandler
->GetEventFunction() == entry
->m_fn
->GetEvtMethod() )
143 handler
= sinkHandler
;
146 sinkHandler
= sinkHandler
->GetNext();
153 void wxObjectWriter::WriteAllProperties( const wxObject
* obj
, const wxClassInfo
* ci
,
154 wxObjectWriterCallback
*writercallback
,
155 wxObjectWriterInternalPropertiesData
* data
)
157 wxPropertyInfoMap map
;
158 ci
->GetProperties( map
);
159 for ( int i
= 0; i
< ci
->GetCreateParamCount(); ++i
)
161 wxString name
= ci
->GetCreateParamName(i
);
162 wxPropertyInfoMap::const_iterator iter
= map
.find(name
);
163 const wxPropertyInfo
* prop
= iter
== map
.end() ? NULL
: iter
->second
;
166 WriteOneProperty( obj
, prop
->GetDeclaringClass(), prop
, writercallback
, data
);
170 wxLogError( _("Create Parameter %s not found in declared RTTI Parameters"), name
.c_str() );
174 { // Extra block for broken compilers
175 for( wxPropertyInfoMap::iterator iter
= map
.begin(); iter
!= map
.end(); ++iter
)
177 const wxPropertyInfo
* prop
= iter
->second
;
178 if ( prop
->GetFlags() & wxPROP_OBJECT_GRAPH
)
180 WriteOneProperty( obj
, prop
->GetDeclaringClass(), prop
, writercallback
, data
);
184 { // Extra block for broken compilers
185 for( wxPropertyInfoMap::iterator iter
= map
.begin(); iter
!= map
.end(); ++iter
)
187 const wxPropertyInfo
* prop
= iter
->second
;
188 if ( !(prop
->GetFlags() & wxPROP_OBJECT_GRAPH
) )
190 WriteOneProperty( obj
, prop
->GetDeclaringClass(), prop
, writercallback
, data
);
196 class WXDLLIMPEXP_BASE wxObjectPropertyWriter
: public wxObjectWriterFunctor
199 wxObjectPropertyWriter(const wxClassTypeInfo
* cti
,
200 wxObjectWriterCallback
*writercallback
,
201 wxObjectWriter
* writer
,
202 wxStringToAnyHashMap
&props
) :
203 m_cti(cti
),m_persister(writercallback
),m_writer(writer
),m_props(props
)
206 virtual void operator()(const wxObject
*vobj
)
208 m_writer
->WriteObject( vobj
, (vobj
? vobj
->GetClassInfo() : m_cti
->GetClassInfo() ),
209 m_persister
, m_cti
->GetKind()== wxT_OBJECT
, m_props
);
212 const wxClassTypeInfo
* m_cti
;
213 wxObjectWriterCallback
*m_persister
;
214 wxObjectWriter
* m_writer
;
215 wxStringToAnyHashMap
& m_props
;
218 void wxObjectWriter::WriteOneProperty( const wxObject
*obj
, const wxClassInfo
* ci
,
219 const wxPropertyInfo
* pi
, wxObjectWriterCallback
*writercallback
,
220 wxObjectWriterInternalPropertiesData
*WXUNUSED(data
) )
222 if ( pi
->GetFlags() & wxPROP_DONT_STREAM
)
225 // make sure that we are picking the correct object for accessing the property
226 const wxDynamicObject
* dynobj
= wx_dynamic_cast(const wxDynamicObject
*, obj
);
227 if ( dynobj
&& (wx_dynamic_cast(const wxDynamicClassInfo
*, ci
) == NULL
) )
228 obj
= dynobj
->GetSuperClassInstance();
230 if ( pi
->GetTypeInfo()->GetKind() == wxT_COLLECTION
)
233 pi
->GetAccessor()->GetPropertyCollection(obj
, data
);
234 const wxTypeInfo
* elementType
=
235 wx_dynamic_cast( const wxCollectionTypeInfo
*, pi
->GetTypeInfo() )->GetElementType();
238 DoBeginWriteProperty( pi
);
239 for ( wxAnyList::const_iterator iter
= data
.begin(); iter
!= data
.end(); ++iter
)
241 DoBeginWriteElement();
242 const wxAny
* valptr
= *iter
;
243 if ( writercallback
->BeforeWriteProperty( this, obj
, pi
, *valptr
) )
245 const wxClassTypeInfo
* cti
=
246 wx_dynamic_cast( const wxClassTypeInfo
*, elementType
);
249 wxStringToAnyHashMap md
;
250 wxObjectPropertyWriter
pw(cti
,writercallback
,this, md
);
252 const wxClassInfo
* pci
= cti
->GetClassInfo();
253 pci
->CallOnAny( *valptr
, &pw
);
257 DoWriteSimpleType( *valptr
);
262 DoEndWriteProperty( pi
);
267 const wxEventSourceTypeInfo
* dti
=
268 wx_dynamic_cast( const wxEventSourceTypeInfo
* , pi
->GetTypeInfo() );
271 const wxObject
* sink
= NULL
;
272 const wxHandlerInfo
*handler
= NULL
;
274 const wxEvtHandler
* evSource
= wx_dynamic_cast(const wxEvtHandler
*, obj
);
277 FindConnectEntry( evSource
, dti
, sink
, handler
);
278 if ( writercallback
->BeforeWriteDelegate( this, obj
, ci
, pi
, sink
, handler
) )
280 if ( sink
!= NULL
&& handler
!= NULL
)
282 DoBeginWriteProperty( pi
);
283 if ( IsObjectKnown( sink
) )
285 DoWriteDelegate( obj
, ci
, pi
, sink
, GetObjectID( sink
),
286 sink
->GetClassInfo(), handler
);
287 DoEndWriteProperty( pi
);
291 wxLogError( wxT("Streaming delegates for not already ")
292 wxT("streamed objects not yet supported") );
299 wxLogError(_("Illegal Object Class (Non-wxEvtHandler) as Event Source") );
305 pi
->GetAccessor()->GetProperty(obj
, value
);
307 // avoid streaming out void objects
312 if ( pi
->GetFlags() & wxPROP_ENUM_STORE_LONG
)
314 const wxEnumTypeInfo
*eti
=
315 wx_dynamic_cast(const wxEnumTypeInfo
*, pi
->GetTypeInfo() );
318 eti
->ConvertFromLong( wxANY_AS(value
, long ), value
);
322 wxLogError( _("Type must have enum - long conversion") );
326 // avoid streaming out default values
327 if ( pi
->GetTypeInfo()->HasStringConverters() &&
328 !pi
->GetDefaultValue().IsNull() ) // TODO Verify
330 if ( wxAnyGetAsString(value
) == wxAnyGetAsString(pi
->GetDefaultValue()) )
334 // avoid streaming out null objects
335 const wxClassTypeInfo
* cti
=
336 wx_dynamic_cast( const wxClassTypeInfo
* , pi
->GetTypeInfo() );
338 if ( cti
&& cti
->GetKind() == wxT_OBJECT_PTR
&& wxAnyGetAsObjectPtr(value
) == NULL
)
341 if ( writercallback
->BeforeWriteProperty( this, obj
, pi
, value
) )
343 DoBeginWriteProperty( pi
);
346 if ( cti
->HasStringConverters() )
348 wxString stringValue
;
349 cti
->ConvertToString( value
, stringValue
);
350 wxAny
convertedValue(stringValue
);
351 DoWriteSimpleType( convertedValue
);
355 wxStringToAnyHashMap md
;
356 wxObjectPropertyWriter
pw(cti
,writercallback
,this, md
);
358 const wxClassInfo
* pci
= cti
->GetClassInfo();
359 pci
->CallOnAny(value
, &pw
);
364 DoWriteSimpleType( value
);
366 DoEndWriteProperty( pi
);
372 int wxObjectWriter::GetObjectID(const wxObject
*obj
)
374 if ( !IsObjectKnown( obj
) )
375 return wxInvalidObjectID
;
377 return m_data
->m_writtenObjects
[obj
];
380 bool wxObjectWriter::IsObjectKnown( const wxObject
*obj
)
382 return m_data
->m_writtenObjects
.find( obj
) != m_data
->m_writtenObjects
.end();
386 // ----------------------------------------------------------------------------
388 // ----------------------------------------------------------------------------
390 struct wxObjectReader::wxObjectReaderInternal
392 map
<int,wxClassInfo
*> m_classInfos
;
395 wxObjectReader::wxObjectReader()
397 m_data
= new wxObjectReaderInternal
;
400 wxObjectReader::~wxObjectReader()
405 wxClassInfo
* wxObjectReader::GetObjectClassInfo(int objectID
)
407 if ( objectID
== wxNullObjectID
|| objectID
== wxInvalidObjectID
)
409 wxLogError( _("Invalid or Null Object ID passed to GetObjectClassInfo" ) );
412 if ( m_data
->m_classInfos
.find(objectID
) == m_data
->m_classInfos
.end() )
414 wxLogError( _("Unknown Object passed to GetObjectClassInfo" ) );
417 return m_data
->m_classInfos
[objectID
];
420 void wxObjectReader::SetObjectClassInfo(int objectID
, wxClassInfo
*classInfo
)
422 if ( objectID
== wxNullObjectID
|| objectID
== wxInvalidObjectID
)
424 wxLogError( _("Invalid or Null Object ID passed to GetObjectClassInfo" ) );
427 if ( m_data
->m_classInfos
.find(objectID
) != m_data
->m_classInfos
.end() )
429 wxLogError( _("Already Registered Object passed to SetObjectClassInfo" ) );
432 m_data
->m_classInfos
[objectID
] = classInfo
;
435 bool wxObjectReader::HasObjectClassInfo( int objectID
)
437 if ( objectID
== wxNullObjectID
|| objectID
== wxInvalidObjectID
)
439 wxLogError( _("Invalid or Null Object ID passed to HasObjectClassInfo" ) );
442 return m_data
->m_classInfos
.find(objectID
) != m_data
->m_classInfos
.end();
446 // ----------------------------------------------------------------------------
448 // ----------------------------------------------------------------------------
451 Reading components has not to be extended for components
452 as properties are always sought by typeinfo over all levels
453 and create params are always toplevel class only
457 // ----------------------------------------------------------------------------
458 // wxObjectRuntimeReaderCallback - depersisting to memory
459 // ----------------------------------------------------------------------------
461 struct wxObjectRuntimeReaderCallback::wxObjectRuntimeReaderCallbackInternal
463 map
<int,wxObject
*> m_objects
;
465 void SetObject(int objectID
, wxObject
*obj
)
467 if ( m_objects
.find(objectID
) != m_objects
.end() )
469 wxLogError( _("Passing a already registered object to SetObject") );
472 m_objects
[objectID
] = obj
;
474 wxObject
* GetObject( int objectID
)
476 if ( objectID
== wxNullObjectID
)
478 if ( m_objects
.find(objectID
) == m_objects
.end() )
480 wxLogError( _("Passing an unknown object to GetObject") );
484 return m_objects
[objectID
];
488 wxObjectRuntimeReaderCallback::wxObjectRuntimeReaderCallback()
490 m_data
= new wxObjectRuntimeReaderCallbackInternal();
493 wxObjectRuntimeReaderCallback::~wxObjectRuntimeReaderCallback()
498 void wxObjectRuntimeReaderCallback::AllocateObject(int objectID
, wxClassInfo
*classInfo
,
499 wxStringToAnyHashMap
&WXUNUSED(metadata
))
502 O
= classInfo
->CreateObject();
503 m_data
->SetObject(objectID
, O
);
506 void wxObjectRuntimeReaderCallback::CreateObject(int objectID
,
507 const wxClassInfo
*classInfo
,
511 const wxClassInfo
**objectClassInfos
,
512 wxStringToAnyHashMap
&WXUNUSED(metadata
))
515 o
= m_data
->GetObject(objectID
);
516 for ( int i
= 0; i
< paramCount
; ++i
)
518 if ( objectIdValues
[i
] != wxInvalidObjectID
)
521 o
= m_data
->GetObject(objectIdValues
[i
]);
522 // if this is a dynamic object and we are asked for another class
523 // than wxDynamicObject we cast it down manually.
524 wxDynamicObject
*dyno
= wx_dynamic_cast( wxDynamicObject
*, o
);
525 if ( dyno
!=NULL
&& (objectClassInfos
[i
] != dyno
->GetClassInfo()) )
527 o
= dyno
->GetSuperClassInstance();
529 params
[i
] = objectClassInfos
[i
]->ObjectPtrToAny(o
);
532 classInfo
->Create(o
, paramCount
, params
);
535 void wxObjectRuntimeReaderCallback::ConstructObject(int objectID
,
536 const wxClassInfo
*classInfo
,
540 const wxClassInfo
**objectClassInfos
,
541 wxStringToAnyHashMap
&WXUNUSED(metadata
))
544 for ( int i
= 0; i
< paramCount
; ++i
)
546 if ( objectIdValues
[i
] != wxInvalidObjectID
)
549 o
= m_data
->GetObject(objectIdValues
[i
]);
550 // if this is a dynamic object and we are asked for another class
551 // than wxDynamicObject we cast it down manually.
552 wxDynamicObject
*dyno
= wx_dynamic_cast( wxDynamicObject
*, o
);
553 if ( dyno
!=NULL
&& (objectClassInfos
[i
] != dyno
->GetClassInfo()) )
555 o
= dyno
->GetSuperClassInstance();
557 params
[i
] = objectClassInfos
[i
]->ObjectPtrToAny(o
);
560 o
= classInfo
->ConstructObject(paramCount
, params
);
561 m_data
->SetObject(objectID
, o
);
565 void wxObjectRuntimeReaderCallback::DestroyObject(int objectID
, wxClassInfo
*WXUNUSED(classInfo
))
568 o
= m_data
->GetObject(objectID
);
572 void wxObjectRuntimeReaderCallback::SetProperty(int objectID
,
573 const wxClassInfo
*classInfo
,
574 const wxPropertyInfo
* propertyInfo
,
578 o
= m_data
->GetObject(objectID
);
579 classInfo
->SetProperty( o
, propertyInfo
->GetName().c_str(), value
);
582 void wxObjectRuntimeReaderCallback::SetPropertyAsObject(int objectID
,
583 const wxClassInfo
*classInfo
,
584 const wxPropertyInfo
* propertyInfo
,
588 o
= m_data
->GetObject(objectID
);
589 valo
= m_data
->GetObject(valueObjectId
);
590 const wxClassInfo
* valClassInfo
=
591 (wx_dynamic_cast(const wxClassTypeInfo
*,propertyInfo
->GetTypeInfo()))->GetClassInfo();
593 // if this is a dynamic object and we are asked for another class
594 // than wxDynamicObject we cast it down manually.
595 wxDynamicObject
*dynvalo
= wx_dynamic_cast( wxDynamicObject
*, valo
);
596 if ( dynvalo
!=NULL
&& (valClassInfo
!= dynvalo
->GetClassInfo()) )
598 valo
= dynvalo
->GetSuperClassInstance();
601 classInfo
->SetProperty( o
, propertyInfo
->GetName().c_str(),
602 valClassInfo
->ObjectPtrToAny(valo
) );
605 void wxObjectRuntimeReaderCallback::SetConnect(int eventSourceObjectID
,
606 const wxClassInfo
*WXUNUSED(eventSourceClassInfo
),
607 const wxPropertyInfo
*delegateInfo
,
608 const wxClassInfo
*WXUNUSED(eventSinkClassInfo
),
609 const wxHandlerInfo
* handlerInfo
,
610 int eventSinkObjectID
)
612 wxEvtHandler
*ehsource
=
613 wx_dynamic_cast( wxEvtHandler
* , m_data
->GetObject( eventSourceObjectID
) );
614 wxEvtHandler
*ehsink
=
615 wx_dynamic_cast( wxEvtHandler
*,m_data
->GetObject(eventSinkObjectID
) );
617 if ( ehsource
&& ehsink
)
619 const wxEventSourceTypeInfo
*delegateTypeInfo
=
620 wx_dynamic_cast(const wxEventSourceTypeInfo
*,delegateInfo
->GetTypeInfo());
621 if( delegateTypeInfo
&& delegateTypeInfo
->GetLastEventType() == -1 )
623 ehsource
->Connect( -1, delegateTypeInfo
->GetEventType(),
624 handlerInfo
->GetEventFunction(), NULL
/*user data*/,
629 for ( wxEventType iter
= delegateTypeInfo
->GetEventType();
630 iter
<= delegateTypeInfo
->GetLastEventType(); ++iter
)
632 ehsource
->Connect( -1, iter
,
633 handlerInfo
->GetEventFunction(), NULL
/*user data*/,
640 wxObject
*wxObjectRuntimeReaderCallback::GetObject(int objectID
)
642 return m_data
->GetObject( objectID
);
645 void wxObjectRuntimeReaderCallback::AddToPropertyCollection( int objectID
,
646 const wxClassInfo
*classInfo
,
647 const wxPropertyInfo
* propertyInfo
,
651 o
= m_data
->GetObject(objectID
);
652 classInfo
->AddToPropertyCollection( o
, propertyInfo
->GetName().c_str(), value
);
655 void wxObjectRuntimeReaderCallback::AddToPropertyCollectionAsObject(int objectID
,
656 const wxClassInfo
*classInfo
,
657 const wxPropertyInfo
* propertyInfo
,
661 o
= m_data
->GetObject(objectID
);
662 valo
= m_data
->GetObject(valueObjectId
);
663 const wxCollectionTypeInfo
* collectionTypeInfo
=
664 wx_dynamic_cast( const wxCollectionTypeInfo
*, propertyInfo
->GetTypeInfo() );
665 const wxClassInfo
* valClassInfo
=
666 (wx_dynamic_cast(const wxClassTypeInfo
*,collectionTypeInfo
->GetElementType()))->GetClassInfo();
668 // if this is a dynamic object and we are asked for another class
669 // than wxDynamicObject we cast it down manually.
670 wxDynamicObject
*dynvalo
= wx_dynamic_cast( wxDynamicObject
*, valo
);
671 if ( dynvalo
!=NULL
&& (valClassInfo
!= dynvalo
->GetClassInfo()) )
673 valo
= dynvalo
->GetSuperClassInstance();
676 classInfo
->AddToPropertyCollection( o
, propertyInfo
->GetName().c_str(),
677 valClassInfo
->ObjectPtrToAny(valo
) );
680 #endif // wxUSE_EXTENDED_RTTI