]> git.saurik.com Git - wxWidgets.git/blob - src/common/xtistrm.cpp
fix crash in wxWindowGTK::GTKHandleUnrealize(), closes #14752
[wxWidgets.git] / src / common / xtistrm.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/xtistrm.cpp
3 // Purpose: streaming runtime metadata information
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 27/07/03
7 // RCS-ID: $Id$
8 // Copyright: (c) 2003 Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_EXTENDED_RTTI
20
21 #include "wx/xtistrm.h"
22
23 #ifndef WX_PRECOMP
24 #include "wx/object.h"
25 #include "wx/hash.h"
26 #include "wx/event.h"
27 #endif
28
29 #include "wx/tokenzr.h"
30 #include "wx/txtstrm.h"
31
32 // STL headers:
33
34 #include "wx/beforestd.h"
35 #include <map>
36 #include <vector>
37 #include <string>
38 #include "wx/afterstd.h"
39 using namespace std;
40
41
42 // ----------------------------------------------------------------------------
43 // wxObjectWriter
44 // ----------------------------------------------------------------------------
45
46 struct wxObjectWriter::wxObjectWriterInternal
47 {
48 map< const wxObject*, int > m_writtenObjects;
49 int m_nextId;
50 };
51
52 wxObjectWriter::wxObjectWriter()
53 {
54 m_data = new wxObjectWriterInternal;
55 m_data->m_nextId = 0;
56 }
57
58 wxObjectWriter::~wxObjectWriter()
59 {
60 delete m_data;
61 }
62
63 struct wxObjectWriter::wxObjectWriterInternalPropertiesData
64 {
65 char nothing;
66 };
67
68 void wxObjectWriter::ClearObjectContext()
69 {
70 delete m_data;
71 m_data = new wxObjectWriterInternal();
72 m_data->m_nextId = 0;
73 }
74
75 void wxObjectWriter::WriteObject(const wxObject *object, const wxClassInfo *classInfo,
76 wxObjectWriterCallback *writercallback, const wxString &name,
77 const wxStringToAnyHashMap &metadata )
78 {
79 DoBeginWriteTopLevelEntry( name );
80 WriteObject( object, classInfo, writercallback, false, metadata);
81 DoEndWriteTopLevelEntry( name );
82 }
83
84 void wxObjectWriter::WriteObject(const wxObject *object, const wxClassInfo *classInfo,
85 wxObjectWriterCallback *writercallback, bool isEmbedded,
86 const wxStringToAnyHashMap &metadata )
87 {
88 if ( !classInfo->BeforeWriteObject( object, this, writercallback, metadata) )
89 return;
90
91 if ( writercallback->BeforeWriteObject( this, object, classInfo, metadata) )
92 {
93 if ( object == NULL )
94 DoWriteNullObject();
95 else if ( IsObjectKnown( object ) )
96 DoWriteRepeatedObject( GetObjectID(object) );
97 else
98 {
99 int oid = m_data->m_nextId++;
100 if ( !isEmbedded )
101 m_data->m_writtenObjects[object] = oid;
102
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;
108
109 DoBeginWriteObject( object, classInfo, oid, metadata );
110 wxObjectWriterInternalPropertiesData data;
111 WriteAllProperties( object, classInfo, writercallback, &data );
112 DoEndWriteObject( object, classInfo, oid );
113 }
114 writercallback->AfterWriteObject( this,object, classInfo );
115 }
116 }
117
118 void wxObjectWriter::FindConnectEntry(const wxEvtHandler * evSource,
119 const wxEventSourceTypeInfo* dti,
120 const wxObject* &sink,
121 const wxHandlerInfo *&handler)
122 {
123 wxList *dynamicEvents = evSource->GetDynamicEventTable();
124
125 if ( dynamicEvents )
126 {
127 for ( wxList::const_iterator node = dynamicEvents->begin(); node != dynamicEvents->end(); ++node )
128 {
129 wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)(*node);
130
131 // find the match
132 if ( entry->m_fn &&
133 (dti->GetEventType() == entry->m_eventType) &&
134 (entry->m_id == -1 ) &&
135 (entry->m_fn->GetEvtHandler() != NULL ) )
136 {
137 sink = entry->m_fn->GetEvtHandler();
138 const wxClassInfo* sinkClassInfo = sink->GetClassInfo();
139 const wxHandlerInfo* sinkHandler = sinkClassInfo->GetFirstHandler();
140 while ( sinkHandler )
141 {
142 if ( sinkHandler->GetEventFunction() == entry->m_fn->GetEvtMethod() )
143 {
144 handler = sinkHandler;
145 break;
146 }
147 sinkHandler = sinkHandler->GetNext();
148 }
149 break;
150 }
151 }
152 }
153 }
154 void wxObjectWriter::WriteAllProperties( const wxObject * obj, const wxClassInfo* ci,
155 wxObjectWriterCallback *writercallback,
156 wxObjectWriterInternalPropertiesData * data )
157 {
158 wxPropertyInfoMap map;
159 ci->GetProperties( map );
160 for ( int i = 0; i < ci->GetCreateParamCount(); ++i )
161 {
162 wxString name = ci->GetCreateParamName(i);
163 wxPropertyInfoMap::const_iterator iter = map.find(name);
164 const wxPropertyInfo* prop = iter == map.end() ? NULL : iter->second;
165 if ( prop )
166 {
167 WriteOneProperty( obj, prop->GetDeclaringClass(), prop, writercallback, data );
168 }
169 else
170 {
171 wxLogError( _("Create Parameter %s not found in declared RTTI Parameters"), name.c_str() );
172 }
173 map.erase( name );
174 }
175 { // Extra block for broken compilers
176 for( wxPropertyInfoMap::iterator iter = map.begin(); iter != map.end(); ++iter )
177 {
178 const wxPropertyInfo* prop = iter->second;
179 if ( prop->GetFlags() & wxPROP_OBJECT_GRAPH )
180 {
181 WriteOneProperty( obj, prop->GetDeclaringClass(), prop, writercallback, data );
182 }
183 }
184 }
185 { // Extra block for broken compilers
186 for( wxPropertyInfoMap::iterator iter = map.begin(); iter != map.end(); ++iter )
187 {
188 const wxPropertyInfo* prop = iter->second;
189 if ( !(prop->GetFlags() & wxPROP_OBJECT_GRAPH) )
190 {
191 WriteOneProperty( obj, prop->GetDeclaringClass(), prop, writercallback, data );
192 }
193 }
194 }
195 }
196
197 class WXDLLIMPEXP_BASE wxObjectPropertyWriter: public wxObjectWriterFunctor
198 {
199 public:
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)
205 {}
206
207 virtual void operator()(const wxObject *vobj)
208 {
209 m_writer->WriteObject( vobj, (vobj ? vobj->GetClassInfo() : m_cti->GetClassInfo() ),
210 m_persister, m_cti->GetKind()== wxT_OBJECT, m_props );
211 }
212 private:
213 const wxClassTypeInfo* m_cti;
214 wxObjectWriterCallback *m_persister;
215 wxObjectWriter* m_writer;
216 wxStringToAnyHashMap& m_props;
217 };
218
219 void wxObjectWriter::WriteOneProperty( const wxObject *obj, const wxClassInfo* ci,
220 const wxPropertyInfo* pi, wxObjectWriterCallback *writercallback,
221 wxObjectWriterInternalPropertiesData *WXUNUSED(data) )
222 {
223 if ( pi->GetFlags() & wxPROP_DONT_STREAM )
224 return;
225
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();
230
231 if ( pi->GetTypeInfo()->GetKind() == wxT_COLLECTION )
232 {
233 wxAnyList data;
234 pi->GetAccessor()->GetPropertyCollection(obj, data);
235 const wxTypeInfo * elementType =
236 wx_dynamic_cast( const wxCollectionTypeInfo*, pi->GetTypeInfo() )->GetElementType();
237 if ( !data.empty() )
238 {
239 DoBeginWriteProperty( pi );
240 for ( wxAnyList::const_iterator iter = data.begin(); iter != data.end(); ++iter )
241 {
242 DoBeginWriteElement();
243 const wxAny* valptr = *iter;
244 if ( writercallback->BeforeWriteProperty( this, obj, pi, *valptr ) )
245 {
246 const wxClassTypeInfo* cti =
247 wx_dynamic_cast( const wxClassTypeInfo*, elementType );
248 if ( cti )
249 {
250 wxStringToAnyHashMap md;
251 wxObjectPropertyWriter pw(cti,writercallback,this, md);
252
253 const wxClassInfo* pci = cti->GetClassInfo();
254 pci->CallOnAny( *valptr, &pw);
255 }
256 else
257 {
258 DoWriteSimpleType( *valptr );
259 }
260 }
261 DoEndWriteElement();
262 }
263 DoEndWriteProperty( pi );
264 }
265 }
266 else
267 {
268 const wxEventSourceTypeInfo* dti =
269 wx_dynamic_cast( const wxEventSourceTypeInfo* , pi->GetTypeInfo() );
270 if ( dti )
271 {
272 const wxObject* sink = NULL;
273 const wxHandlerInfo *handler = NULL;
274
275 const wxEvtHandler * evSource = wx_dynamic_cast(const wxEvtHandler *, obj);
276 if ( evSource )
277 {
278 FindConnectEntry( evSource, dti, sink, handler );
279 if ( writercallback->BeforeWriteDelegate( this, obj, ci, pi, sink, handler ) )
280 {
281 if ( sink != NULL && handler != NULL )
282 {
283 DoBeginWriteProperty( pi );
284 if ( IsObjectKnown( sink ) )
285 {
286 DoWriteDelegate( obj, ci, pi, sink, GetObjectID( sink ),
287 sink->GetClassInfo(), handler );
288 DoEndWriteProperty( pi );
289 }
290 else
291 {
292 wxLogError( wxT("Streaming delegates for not already ")
293 wxT("streamed objects not yet supported") );
294 }
295 }
296 }
297 }
298 else
299 {
300 wxLogError(_("Illegal Object Class (Non-wxEvtHandler) as Event Source") );
301 }
302 }
303 else
304 {
305 wxAny value;
306 pi->GetAccessor()->GetProperty(obj, value);
307
308 // avoid streaming out void objects
309 // TODO Verify
310 if( value.IsNull() )
311 return;
312
313 if ( pi->GetFlags() & wxPROP_ENUM_STORE_LONG )
314 {
315 const wxEnumTypeInfo *eti =
316 wx_dynamic_cast(const wxEnumTypeInfo*, pi->GetTypeInfo() );
317 if ( eti )
318 {
319 eti->ConvertFromLong( wxANY_AS(value, long ), value );
320 }
321 else
322 {
323 wxLogError( _("Type must have enum - long conversion") );
324 }
325 }
326
327 // avoid streaming out default values
328 if ( pi->GetTypeInfo()->HasStringConverters() &&
329 !pi->GetDefaultValue().IsNull() ) // TODO Verify
330 {
331 if ( wxAnyGetAsString(value) == wxAnyGetAsString(pi->GetDefaultValue()) )
332 return;
333 }
334
335 // avoid streaming out null objects
336 const wxClassTypeInfo* cti =
337 wx_dynamic_cast( const wxClassTypeInfo* , pi->GetTypeInfo() );
338
339 if ( cti && cti->GetKind() == wxT_OBJECT_PTR && wxAnyGetAsObjectPtr(value) == NULL )
340 return;
341
342 if ( writercallback->BeforeWriteProperty( this, obj, pi, value ) )
343 {
344 DoBeginWriteProperty( pi );
345 if ( cti )
346 {
347 if ( cti->HasStringConverters() )
348 {
349 wxString stringValue;
350 cti->ConvertToString( value, stringValue );
351 wxAny convertedValue(stringValue);
352 DoWriteSimpleType( convertedValue );
353 }
354 else
355 {
356 wxStringToAnyHashMap md;
357 wxObjectPropertyWriter pw(cti,writercallback,this, md);
358
359 const wxClassInfo* pci = cti->GetClassInfo();
360 pci->CallOnAny(value, &pw);
361 }
362 }
363 else
364 {
365 DoWriteSimpleType( value );
366 }
367 DoEndWriteProperty( pi );
368 }
369 }
370 }
371 }
372
373 int wxObjectWriter::GetObjectID(const wxObject *obj)
374 {
375 if ( !IsObjectKnown( obj ) )
376 return wxInvalidObjectID;
377
378 return m_data->m_writtenObjects[obj];
379 }
380
381 bool wxObjectWriter::IsObjectKnown( const wxObject *obj )
382 {
383 return m_data->m_writtenObjects.find( obj ) != m_data->m_writtenObjects.end();
384 }
385
386
387 // ----------------------------------------------------------------------------
388 // wxObjectReader
389 // ----------------------------------------------------------------------------
390
391 struct wxObjectReader::wxObjectReaderInternal
392 {
393 map<int,wxClassInfo*> m_classInfos;
394 };
395
396 wxObjectReader::wxObjectReader()
397 {
398 m_data = new wxObjectReaderInternal;
399 }
400
401 wxObjectReader::~wxObjectReader()
402 {
403 delete m_data;
404 }
405
406 wxClassInfo* wxObjectReader::GetObjectClassInfo(int objectID)
407 {
408 if ( objectID == wxNullObjectID || objectID == wxInvalidObjectID )
409 {
410 wxLogError( _("Invalid or Null Object ID passed to GetObjectClassInfo" ) );
411 return NULL;
412 }
413 if ( m_data->m_classInfos.find(objectID) == m_data->m_classInfos.end() )
414 {
415 wxLogError( _("Unknown Object passed to GetObjectClassInfo" ) );
416 return NULL;
417 }
418 return m_data->m_classInfos[objectID];
419 }
420
421 void wxObjectReader::SetObjectClassInfo(int objectID, wxClassInfo *classInfo )
422 {
423 if ( objectID == wxNullObjectID || objectID == wxInvalidObjectID )
424 {
425 wxLogError( _("Invalid or Null Object ID passed to GetObjectClassInfo" ) );
426 return;
427 }
428 if ( m_data->m_classInfos.find(objectID) != m_data->m_classInfos.end() )
429 {
430 wxLogError( _("Already Registered Object passed to SetObjectClassInfo" ) );
431 return;
432 }
433 m_data->m_classInfos[objectID] = classInfo;
434 }
435
436 bool wxObjectReader::HasObjectClassInfo( int objectID )
437 {
438 if ( objectID == wxNullObjectID || objectID == wxInvalidObjectID )
439 {
440 wxLogError( _("Invalid or Null Object ID passed to HasObjectClassInfo" ) );
441 return false;
442 }
443 return m_data->m_classInfos.find(objectID) != m_data->m_classInfos.end();
444 }
445
446
447 // ----------------------------------------------------------------------------
448 // reading xml in
449 // ----------------------------------------------------------------------------
450
451 /*
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
455 */
456
457
458 // ----------------------------------------------------------------------------
459 // wxObjectRuntimeReaderCallback - depersisting to memory
460 // ----------------------------------------------------------------------------
461
462 struct wxObjectRuntimeReaderCallback::wxObjectRuntimeReaderCallbackInternal
463 {
464 map<int,wxObject *> m_objects;
465
466 void SetObject(int objectID, wxObject *obj )
467 {
468 if ( m_objects.find(objectID) != m_objects.end() )
469 {
470 wxLogError( _("Passing a already registered object to SetObject") );
471 return ;
472 }
473 m_objects[objectID] = obj;
474 }
475 wxObject* GetObject( int objectID )
476 {
477 if ( objectID == wxNullObjectID )
478 return NULL;
479 if ( m_objects.find(objectID) == m_objects.end() )
480 {
481 wxLogError( _("Passing an unknown object to GetObject") );
482 return NULL;
483 }
484
485 return m_objects[objectID];
486 }
487 };
488
489 wxObjectRuntimeReaderCallback::wxObjectRuntimeReaderCallback()
490 {
491 m_data = new wxObjectRuntimeReaderCallbackInternal();
492 }
493
494 wxObjectRuntimeReaderCallback::~wxObjectRuntimeReaderCallback()
495 {
496 delete m_data;
497 }
498
499 void wxObjectRuntimeReaderCallback::AllocateObject(int objectID, wxClassInfo *classInfo,
500 wxStringToAnyHashMap &WXUNUSED(metadata))
501 {
502 wxObject *O;
503 O = classInfo->CreateObject();
504 m_data->SetObject(objectID, O);
505 }
506
507 void wxObjectRuntimeReaderCallback::CreateObject(int objectID,
508 const wxClassInfo *classInfo,
509 int paramCount,
510 wxAny *params,
511 int *objectIdValues,
512 const wxClassInfo **objectClassInfos,
513 wxStringToAnyHashMap &WXUNUSED(metadata))
514 {
515 wxObject *o;
516 o = m_data->GetObject(objectID);
517 for ( int i = 0; i < paramCount; ++i )
518 {
519 if ( objectIdValues[i] != wxInvalidObjectID )
520 {
521 wxObject *o;
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()) )
527 {
528 o = dyno->GetSuperClassInstance();
529 }
530 params[i] = objectClassInfos[i]->ObjectPtrToAny(o);
531 }
532 }
533 classInfo->Create(o, paramCount, params);
534 }
535
536 void wxObjectRuntimeReaderCallback::ConstructObject(int objectID,
537 const wxClassInfo *classInfo,
538 int paramCount,
539 wxAny *params,
540 int *objectIdValues,
541 const wxClassInfo **objectClassInfos,
542 wxStringToAnyHashMap &WXUNUSED(metadata))
543 {
544 wxObject *o;
545 for ( int i = 0; i < paramCount; ++i )
546 {
547 if ( objectIdValues[i] != wxInvalidObjectID )
548 {
549 wxObject *o;
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()) )
555 {
556 o = dyno->GetSuperClassInstance();
557 }
558 params[i] = objectClassInfos[i]->ObjectPtrToAny(o);
559 }
560 }
561 o = classInfo->ConstructObject(paramCount, params);
562 m_data->SetObject(objectID, o);
563 }
564
565
566 void wxObjectRuntimeReaderCallback::DestroyObject(int objectID, wxClassInfo *WXUNUSED(classInfo))
567 {
568 wxObject *o;
569 o = m_data->GetObject(objectID);
570 delete o;
571 }
572
573 void wxObjectRuntimeReaderCallback::SetProperty(int objectID,
574 const wxClassInfo *classInfo,
575 const wxPropertyInfo* propertyInfo,
576 const wxAny &value)
577 {
578 wxObject *o;
579 o = m_data->GetObject(objectID);
580 classInfo->SetProperty( o, propertyInfo->GetName().c_str(), value );
581 }
582
583 void wxObjectRuntimeReaderCallback::SetPropertyAsObject(int objectID,
584 const wxClassInfo *classInfo,
585 const wxPropertyInfo* propertyInfo,
586 int valueObjectId)
587 {
588 wxObject *o, *valo;
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();
593
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()) )
598 {
599 valo = dynvalo->GetSuperClassInstance();
600 }
601
602 classInfo->SetProperty( o, propertyInfo->GetName().c_str(),
603 valClassInfo->ObjectPtrToAny(valo) );
604 }
605
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 )
612 {
613 wxEvtHandler *ehsource =
614 wx_dynamic_cast( wxEvtHandler* , m_data->GetObject( eventSourceObjectID ) );
615 wxEvtHandler *ehsink =
616 wx_dynamic_cast( wxEvtHandler *,m_data->GetObject(eventSinkObjectID) );
617
618 if ( ehsource && ehsink )
619 {
620 const wxEventSourceTypeInfo *delegateTypeInfo =
621 wx_dynamic_cast(const wxEventSourceTypeInfo*,delegateInfo->GetTypeInfo());
622 if( delegateTypeInfo && delegateTypeInfo->GetLastEventType() == -1 )
623 {
624 ehsource->Connect( -1, delegateTypeInfo->GetEventType(),
625 handlerInfo->GetEventFunction(), NULL /*user data*/,
626 ehsink );
627 }
628 else
629 {
630 for ( wxEventType iter = delegateTypeInfo->GetEventType();
631 iter <= delegateTypeInfo->GetLastEventType(); ++iter )
632 {
633 ehsource->Connect( -1, iter,
634 handlerInfo->GetEventFunction(), NULL /*user data*/,
635 ehsink );
636 }
637 }
638 }
639 }
640
641 wxObject *wxObjectRuntimeReaderCallback::GetObject(int objectID)
642 {
643 return m_data->GetObject( objectID );
644 }
645
646 void wxObjectRuntimeReaderCallback::AddToPropertyCollection( int objectID,
647 const wxClassInfo *classInfo,
648 const wxPropertyInfo* propertyInfo,
649 const wxAny &value)
650 {
651 wxObject *o;
652 o = m_data->GetObject(objectID);
653 classInfo->AddToPropertyCollection( o, propertyInfo->GetName().c_str(), value );
654 }
655
656 void wxObjectRuntimeReaderCallback::AddToPropertyCollectionAsObject(int objectID,
657 const wxClassInfo *classInfo,
658 const wxPropertyInfo* propertyInfo,
659 int valueObjectId)
660 {
661 wxObject *o, *valo;
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();
668
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()) )
673 {
674 valo = dynvalo->GetSuperClassInstance();
675 }
676
677 classInfo->AddToPropertyCollection( o, propertyInfo->GetName().c_str(),
678 valClassInfo->ObjectPtrToAny(valo) );
679 }
680
681 #endif // wxUSE_EXTENDED_RTTI