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 wxObjectReaderCallback
*persister
, const wxString
&name
,
77 wxVariantBaseArray
&metadata
)
79 DoBeginWriteTopLevelEntry( name
);
80 WriteObject( object
, classInfo
, persister
, false, metadata
);
81 DoEndWriteTopLevelEntry( name
);
84 void wxObjectWriter::WriteObject(const wxObject
*object
, const wxClassInfo
*classInfo
,
85 wxObjectReaderCallback
*persister
, bool isEmbedded
,
86 wxVariantBaseArray
&metadata
)
88 if ( !classInfo
->BeforeWriteObject( object
, this, persister
, metadata
) )
91 if ( persister
->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
, persister
, &data
);
112 DoEndWriteObject( object
, classInfo
, oid
);
114 persister
->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 wxList::compatibility_iterator node
= dynamicEvents
->GetFirst();
130 wxDynamicEventTableEntry
*entry
= (wxDynamicEventTableEntry
*)node
->GetData();
134 (dti
->GetEventType() == entry
->m_eventType
) &&
135 (entry
->m_id
== -1 ) &&
136 (entry
->m_eventSink
!= NULL
) )
138 sink
= entry
->m_eventSink
;
139 const wxClassInfo
* sinkClassInfo
= sink
->GetClassInfo();
140 const wxHandlerInfo
* sinkHandler
= sinkClassInfo
->GetFirstHandler();
141 while ( sinkHandler
)
143 if ( sinkHandler
->GetEventFunction() == entry
->m_fn
)
145 handler
= sinkHandler
;
148 sinkHandler
= sinkHandler
->GetNext();
152 node
= node
->GetNext();
156 void wxObjectWriter::WriteAllProperties( const wxObject
* obj
, const wxClassInfo
* ci
,
157 wxObjectReaderCallback
*persister
,
158 wxObjectWriterInternalPropertiesData
* data
)
160 wxPropertyInfoMap map
;
161 ci
->GetProperties( map
);
162 for ( int i
= 0; i
< ci
->GetCreateParamCount(); ++i
)
164 wxString name
= ci
->GetCreateParamName(i
);
165 wxPropertyInfoMap::const_iterator iter
= map
.find(name
);
166 const wxPropertyInfo
* prop
= iter
== map
.end() ? NULL
: iter
->second
;
169 WriteOneProperty( obj
, prop
->GetDeclaringClass(), prop
, persister
, data
);
173 wxLogError( _("Create Parameter %s not found in declared RTTI Parameters"), name
.c_str() );
177 { // Extra block for broken compilers
178 for( wxPropertyInfoMap::iterator iter
= map
.begin(); iter
!= map
.end(); ++iter
)
180 const wxPropertyInfo
* prop
= iter
->second
;
181 if ( prop
->GetFlags() & wxPROP_OBJECT_GRAPH
)
183 WriteOneProperty( obj
, prop
->GetDeclaringClass(), prop
, persister
, data
);
187 { // Extra block for broken compilers
188 for( wxPropertyInfoMap::iterator iter
= map
.begin(); iter
!= map
.end(); ++iter
)
190 const wxPropertyInfo
* prop
= iter
->second
;
191 if ( !(prop
->GetFlags() & wxPROP_OBJECT_GRAPH
) )
193 WriteOneProperty( obj
, prop
->GetDeclaringClass(), prop
, persister
, data
);
199 void wxObjectWriter::WriteOneProperty( const wxObject
*obj
, const wxClassInfo
* ci
,
200 const wxPropertyInfo
* pi
, wxObjectReaderCallback
*persister
,
201 wxObjectWriterInternalPropertiesData
*WXUNUSED(data
) )
203 if ( pi
->GetFlags() & wxPROP_DONT_STREAM
)
206 // make sure that we are picking the correct object for accessing the property
207 const wxDynamicObject
* dynobj
= wx_dynamic_cast(const wxDynamicObject
*, obj
);
208 if ( dynobj
&& (wx_dynamic_cast(const wxDynamicClassInfo
*, ci
) == NULL
) )
209 obj
= dynobj
->GetSuperClassInstance();
211 if ( pi
->GetTypeInfo()->GetKind() == wxT_COLLECTION
)
213 wxVariantBaseArray data
;
214 pi
->GetAccessor()->GetPropertyCollection(obj
, data
);
215 const wxTypeInfo
* elementType
=
216 wx_dynamic_cast( const wxCollectionTypeInfo
*, pi
->GetTypeInfo() )->GetElementType();
217 for ( size_t i
= 0; i
< data
.GetCount(); ++i
)
220 DoBeginWriteProperty( pi
);
222 DoBeginWriteElement();
223 wxVariantBase value
= data
[i
];
224 if ( persister
->BeforeWriteProperty( this, obj
, pi
, value
) )
226 const wxClassTypeInfo
* cti
=
227 wx_dynamic_cast( const wxClassTypeInfo
*, elementType
);
230 const wxClassInfo
* pci
= cti
->GetClassInfo();
231 wxObject
*vobj
= pci
->VariantToInstance( value
);
232 wxVariantBaseArray md
;
233 WriteObject( vobj
, (vobj
? vobj
->GetClassInfo() : pci
),
234 persister
, cti
->GetKind()== wxT_OBJECT
, md
);
238 DoWriteSimpleType( value
);
242 if ( i
== data
.GetCount() - 1 )
243 DoEndWriteProperty( pi
);
248 const wxEventSourceTypeInfo
* dti
=
249 wx_dynamic_cast( const wxEventSourceTypeInfo
* , pi
->GetTypeInfo() );
252 const wxObject
* sink
= NULL
;
253 const wxHandlerInfo
*handler
= NULL
;
255 const wxEvtHandler
* evSource
= wx_dynamic_cast(const wxEvtHandler
*, obj
);
258 FindConnectEntry( evSource
, dti
, sink
, handler
);
259 if ( persister
->BeforeWriteDelegate( this, obj
, ci
, pi
, sink
, handler
) )
261 if ( sink
!= NULL
&& handler
!= NULL
)
263 DoBeginWriteProperty( pi
);
264 if ( IsObjectKnown( sink
) )
266 DoWriteDelegate( obj
, ci
, pi
, sink
, GetObjectID( sink
),
267 sink
->GetClassInfo(), handler
);
268 DoEndWriteProperty( pi
);
272 wxLogError( _T("Streaming delegates for not already ")
273 _T("streamed objects not yet supported") );
280 wxLogError(_("Illegal Object Class (Non-wxEvtHandler) as Event Source") );
286 pi
->GetAccessor()->GetProperty(obj
, value
);
288 // avoid streaming out void objects
289 if( value
.IsEmpty() )
292 if ( pi
->GetFlags() & wxPROP_ENUM_STORE_LONG
)
294 const wxEnumTypeInfo
*eti
=
295 wx_dynamic_cast(const wxEnumTypeInfo
*, pi
->GetTypeInfo() );
298 eti
->ConvertFromLong( value
.wxTEMPLATED_MEMBER_CALL(Get
, long), value
);
302 wxLogError( _("Type must have enum - long conversion") );
306 // avoid streaming out default values
307 if ( pi
->GetTypeInfo()->HasStringConverters() &&
308 !pi
->GetDefaultValue().IsEmpty() )
310 if ( value
.GetAsString() == pi
->GetDefaultValue().GetAsString() )
314 // avoid streaming out null objects
315 const wxClassTypeInfo
* cti
=
316 wx_dynamic_cast( const wxClassTypeInfo
* , pi
->GetTypeInfo() );
318 if ( cti
&& value
.GetAsObject() == NULL
)
321 if ( persister
->BeforeWriteProperty( this, obj
, pi
, value
) )
323 DoBeginWriteProperty( pi
);
326 const wxClassInfo
* pci
= cti
->GetClassInfo();
327 wxObject
*vobj
= pci
->VariantToInstance( value
);
328 if ( vobj
&& pi
->GetTypeInfo()->HasStringConverters() )
330 wxString stringValue
;
331 cti
->ConvertToString( value
, stringValue
);
332 wxVariantBase
convertedValue(stringValue
);
333 DoWriteSimpleType( convertedValue
);
337 wxVariantBaseArray md
;
338 WriteObject( vobj
, (vobj
? vobj
->GetClassInfo() : pci
),
339 persister
, cti
->GetKind()== wxT_OBJECT
, md
);
344 DoWriteSimpleType( value
);
346 DoEndWriteProperty( pi
);
352 int wxObjectWriter::GetObjectID(const wxObject
*obj
)
354 if ( !IsObjectKnown( obj
) )
355 return wxInvalidObjectID
;
357 return m_data
->m_writtenObjects
[obj
];
360 bool wxObjectWriter::IsObjectKnown( const wxObject
*obj
)
362 return m_data
->m_writtenObjects
.find( obj
) != m_data
->m_writtenObjects
.end();
366 // ----------------------------------------------------------------------------
368 // ----------------------------------------------------------------------------
370 struct wxObjectReader::wxObjectReaderInternal
372 map
<int,wxClassInfo
*> m_classInfos
;
375 wxObjectReader::wxObjectReader()
377 m_data
= new wxObjectReaderInternal
;
380 wxObjectReader::~wxObjectReader()
385 wxClassInfo
* wxObjectReader::GetObjectClassInfo(int objectID
)
387 if ( objectID
== wxNullObjectID
|| objectID
== wxInvalidObjectID
)
389 wxLogError( _("Invalid or Null Object ID passed to GetObjectClassInfo" ) );
392 if ( m_data
->m_classInfos
.find(objectID
) == m_data
->m_classInfos
.end() )
394 wxLogError( _("Unknown Object passed to GetObjectClassInfo" ) );
397 return m_data
->m_classInfos
[objectID
];
400 void wxObjectReader::SetObjectClassInfo(int objectID
, wxClassInfo
*classInfo
)
402 if ( objectID
== wxNullObjectID
|| objectID
== wxInvalidObjectID
)
404 wxLogError( _("Invalid or Null Object ID passed to GetObjectClassInfo" ) );
407 if ( m_data
->m_classInfos
.find(objectID
) != m_data
->m_classInfos
.end() )
409 wxLogError( _("Already Registered Object passed to SetObjectClassInfo" ) );
412 m_data
->m_classInfos
[objectID
] = classInfo
;
415 bool wxObjectReader::HasObjectClassInfo( int objectID
)
417 if ( objectID
== wxNullObjectID
|| objectID
== wxInvalidObjectID
)
419 wxLogError( _("Invalid or Null Object ID passed to HasObjectClassInfo" ) );
422 return m_data
->m_classInfos
.find(objectID
) != m_data
->m_classInfos
.end();
426 // ----------------------------------------------------------------------------
428 // ----------------------------------------------------------------------------
431 Reading components has not to be extended for components
432 as properties are always sought by typeinfo over all levels
433 and create params are always toplevel class only
437 // ----------------------------------------------------------------------------
438 // wxObjectRuntimeReaderCallback - depersisting to memory
439 // ----------------------------------------------------------------------------
441 struct wxObjectRuntimeReaderCallback::wxObjectRuntimeReaderCallbackInternal
443 map
<int,wxObject
*> m_objects
;
445 void SetObject(int objectID
, wxObject
*obj
)
447 if ( m_objects
.find(objectID
) != m_objects
.end() )
449 wxLogError( _("Passing a already registered object to SetObject") );
452 m_objects
[objectID
] = obj
;
454 wxObject
* GetObject( int objectID
)
456 if ( objectID
== wxNullObjectID
)
458 if ( m_objects
.find(objectID
) == m_objects
.end() )
460 wxLogError( _("Passing an unkown object to GetObject") );
464 return m_objects
[objectID
];
468 wxObjectRuntimeReaderCallback::wxObjectRuntimeReaderCallback()
470 m_data
= new wxObjectRuntimeReaderCallbackInternal();
473 wxObjectRuntimeReaderCallback::~wxObjectRuntimeReaderCallback()
478 void wxObjectRuntimeReaderCallback::AllocateObject(int objectID
, wxClassInfo
*classInfo
,
479 wxVariantBaseArray
&WXUNUSED(metadata
))
482 O
= classInfo
->CreateObject();
483 m_data
->SetObject(objectID
, O
);
486 void wxObjectRuntimeReaderCallback::CreateObject(int objectID
,
487 const wxClassInfo
*classInfo
,
489 wxVariantBase
*params
,
491 const wxClassInfo
**objectClassInfos
,
492 wxVariantBaseArray
&WXUNUSED(metadata
))
495 o
= m_data
->GetObject(objectID
);
496 for ( int i
= 0; i
< paramCount
; ++i
)
498 if ( objectIdValues
[i
] != wxInvalidObjectID
)
501 o
= m_data
->GetObject(objectIdValues
[i
]);
502 // if this is a dynamic object and we are asked for another class
503 // than wxDynamicObject we cast it down manually.
504 wxDynamicObject
*dyno
= wx_dynamic_cast( wxDynamicObject
*, o
);
505 if ( dyno
!=NULL
&& (objectClassInfos
[i
] != dyno
->GetClassInfo()) )
507 o
= dyno
->GetSuperClassInstance();
509 params
[i
] = objectClassInfos
[i
]->InstanceToVariant(o
);
512 classInfo
->Create(o
, paramCount
, params
);
515 void wxObjectRuntimeReaderCallback::ConstructObject(int objectID
,
516 const wxClassInfo
*classInfo
,
518 wxVariantBase
*params
,
520 const wxClassInfo
**objectClassInfos
,
521 wxVariantBaseArray
&WXUNUSED(metadata
))
524 for ( int i
= 0; i
< paramCount
; ++i
)
526 if ( objectIdValues
[i
] != wxInvalidObjectID
)
529 o
= m_data
->GetObject(objectIdValues
[i
]);
530 // if this is a dynamic object and we are asked for another class
531 // than wxDynamicObject we cast it down manually.
532 wxDynamicObject
*dyno
= wx_dynamic_cast( wxDynamicObject
*, o
);
533 if ( dyno
!=NULL
&& (objectClassInfos
[i
] != dyno
->GetClassInfo()) )
535 o
= dyno
->GetSuperClassInstance();
537 params
[i
] = objectClassInfos
[i
]->InstanceToVariant(o
);
540 o
= classInfo
->ConstructObject(paramCount
, params
);
541 m_data
->SetObject(objectID
, o
);
545 void wxObjectRuntimeReaderCallback::DestroyObject(int objectID
, wxClassInfo
*WXUNUSED(classInfo
))
548 o
= m_data
->GetObject(objectID
);
552 void wxObjectRuntimeReaderCallback::SetProperty(int objectID
,
553 const wxClassInfo
*classInfo
,
554 const wxPropertyInfo
* propertyInfo
,
555 const wxVariantBase
&value
)
558 o
= m_data
->GetObject(objectID
);
559 classInfo
->SetProperty( o
, propertyInfo
->GetName(), value
);
562 void wxObjectRuntimeReaderCallback::SetPropertyAsObject(int objectID
,
563 const wxClassInfo
*classInfo
,
564 const wxPropertyInfo
* propertyInfo
,
568 o
= m_data
->GetObject(objectID
);
569 valo
= m_data
->GetObject(valueObjectId
);
570 const wxClassInfo
* valClassInfo
=
571 (wx_dynamic_cast(const wxClassTypeInfo
*,propertyInfo
->GetTypeInfo()))->GetClassInfo();
573 // if this is a dynamic object and we are asked for another class
574 // than wxDynamicObject we cast it down manually.
575 wxDynamicObject
*dynvalo
= wx_dynamic_cast( wxDynamicObject
*, valo
);
576 if ( dynvalo
!=NULL
&& (valClassInfo
!= dynvalo
->GetClassInfo()) )
578 valo
= dynvalo
->GetSuperClassInstance();
581 classInfo
->SetProperty( o
, propertyInfo
->GetName(),
582 valClassInfo
->InstanceToVariant(valo
) );
585 void wxObjectRuntimeReaderCallback::SetConnect(int eventSourceObjectID
,
586 const wxClassInfo
*WXUNUSED(eventSourceClassInfo
),
587 const wxPropertyInfo
*delegateInfo
,
588 const wxClassInfo
*WXUNUSED(eventSinkClassInfo
),
589 const wxHandlerInfo
* handlerInfo
,
590 int eventSinkObjectID
)
592 wxEvtHandler
*ehsource
=
593 wx_dynamic_cast( wxEvtHandler
* , m_data
->GetObject( eventSourceObjectID
) );
594 wxEvtHandler
*ehsink
=
595 wx_dynamic_cast( wxEvtHandler
*,m_data
->GetObject(eventSinkObjectID
) );
597 if ( ehsource
&& ehsink
)
599 const wxEventSourceTypeInfo
*delegateTypeInfo
=
600 wx_dynamic_cast(const wxEventSourceTypeInfo
*,delegateInfo
->GetTypeInfo());
601 if( delegateTypeInfo
&& delegateTypeInfo
->GetLastEventType() == -1 )
603 ehsource
->Connect( -1, delegateTypeInfo
->GetEventType(),
604 handlerInfo
->GetEventFunction(), NULL
/*user data*/,
609 for ( wxEventType iter
= delegateTypeInfo
->GetEventType();
610 iter
<= delegateTypeInfo
->GetLastEventType(); ++iter
)
612 ehsource
->Connect( -1, iter
,
613 handlerInfo
->GetEventFunction(), NULL
/*user data*/,
620 wxObject
*wxObjectRuntimeReaderCallback::GetObject(int objectID
)
622 return m_data
->GetObject( objectID
);
625 void wxObjectRuntimeReaderCallback::AddToPropertyCollection( int objectID
,
626 const wxClassInfo
*classInfo
,
627 const wxPropertyInfo
* propertyInfo
,
628 const wxVariantBase
&value
)
631 o
= m_data
->GetObject(objectID
);
632 classInfo
->AddToPropertyCollection( o
, propertyInfo
->GetName(), value
);
635 void wxObjectRuntimeReaderCallback::AddToPropertyCollectionAsObject(int objectID
,
636 const wxClassInfo
*classInfo
,
637 const wxPropertyInfo
* propertyInfo
,
641 o
= m_data
->GetObject(objectID
);
642 valo
= m_data
->GetObject(valueObjectId
);
643 const wxCollectionTypeInfo
* collectionTypeInfo
=
644 wx_dynamic_cast( const wxCollectionTypeInfo
*, propertyInfo
->GetTypeInfo() );
645 const wxClassInfo
* valClassInfo
=
646 (wx_dynamic_cast(const wxClassTypeInfo
*,collectionTypeInfo
->GetElementType()))->GetClassInfo();
648 // if this is a dynamic object and we are asked for another class
649 // than wxDynamicObject we cast it down manually.
650 wxDynamicObject
*dynvalo
= wx_dynamic_cast( wxDynamicObject
*, valo
);
651 if ( dynvalo
!=NULL
&& (valClassInfo
!= dynvalo
->GetClassInfo()) )
653 valo
= dynvalo
->GetSuperClassInstance();
656 classInfo
->AddToPropertyCollection( o
, propertyInfo
->GetName(),
657 valClassInfo
->InstanceToVariant(valo
) );
661 #include "wx/arrimpl.cpp"
662 WX_DEFINE_OBJARRAY(wxVariantBaseArray
);
665 #endif // wxUSE_EXTENDED_RTTI