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