]> git.saurik.com Git - wxWidgets.git/blob - src/common/xtistrm.cpp
0691af6242e6a70488d2589b92709ec7ce832377
[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 wxObjectReaderCallback *persister, const wxString &name,
77 wxVariantBaseArray &metadata )
78 {
79 DoBeginWriteTopLevelEntry( name );
80 WriteObject( object, classInfo, persister, false, metadata);
81 DoEndWriteTopLevelEntry( name );
82 }
83
84 void wxObjectWriter::WriteObject(const wxObject *object, const wxClassInfo *classInfo,
85 wxObjectReaderCallback *persister, bool isEmbedded,
86 wxVariantBaseArray &metadata )
87 {
88 if ( !classInfo->BeforeWriteObject( object, this, persister, metadata) )
89 return;
90
91 if ( persister->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, persister, &data );
112 DoEndWriteObject( object, classInfo, oid );
113 }
114 persister->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 wxList::compatibility_iterator node = dynamicEvents->GetFirst();
128 while (node)
129 {
130 wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData();
131
132 // find the match
133 if ( entry->m_fn &&
134 (dti->GetEventType() == entry->m_eventType) &&
135 (entry->m_id == -1 ) &&
136 (entry->m_eventSink != NULL ) )
137 {
138 sink = entry->m_eventSink;
139 const wxClassInfo* sinkClassInfo = sink->GetClassInfo();
140 const wxHandlerInfo* sinkHandler = sinkClassInfo->GetFirstHandler();
141 while ( sinkHandler )
142 {
143 if ( sinkHandler->GetEventFunction() == entry->m_fn )
144 {
145 handler = sinkHandler;
146 break;
147 }
148 sinkHandler = sinkHandler->GetNext();
149 }
150 break;
151 }
152 node = node->GetNext();
153 }
154 }
155 }
156 void wxObjectWriter::WriteAllProperties( const wxObject * obj, const wxClassInfo* ci,
157 wxObjectReaderCallback *persister,
158 wxObjectWriterInternalPropertiesData * data )
159 {
160 wxPropertyInfoMap map;
161 ci->GetProperties( map );
162 for ( int i = 0; i < ci->GetCreateParamCount(); ++i )
163 {
164 wxString name = ci->GetCreateParamName(i);
165 wxPropertyInfoMap::const_iterator iter = map.find(name);
166 const wxPropertyInfo* prop = iter == map.end() ? NULL : iter->second;
167 if ( prop )
168 {
169 WriteOneProperty( obj, prop->GetDeclaringClass(), prop, persister, data );
170 }
171 else
172 {
173 wxLogError( _("Create Parameter %s not found in declared RTTI Parameters"), name.c_str() );
174 }
175 map.erase( name );
176 }
177 { // Extra block for broken compilers
178 for( wxPropertyInfoMap::iterator iter = map.begin(); iter != map.end(); ++iter )
179 {
180 const wxPropertyInfo* prop = iter->second;
181 if ( prop->GetFlags() & wxPROP_OBJECT_GRAPH )
182 {
183 WriteOneProperty( obj, prop->GetDeclaringClass(), prop, persister, data );
184 }
185 }
186 }
187 { // Extra block for broken compilers
188 for( wxPropertyInfoMap::iterator iter = map.begin(); iter != map.end(); ++iter )
189 {
190 const wxPropertyInfo* prop = iter->second;
191 if ( !(prop->GetFlags() & wxPROP_OBJECT_GRAPH) )
192 {
193 WriteOneProperty( obj, prop->GetDeclaringClass(), prop, persister, data );
194 }
195 }
196 }
197 }
198
199 void wxObjectWriter::WriteOneProperty( const wxObject *obj, const wxClassInfo* ci,
200 const wxPropertyInfo* pi, wxObjectReaderCallback *persister,
201 wxObjectWriterInternalPropertiesData *WXUNUSED(data) )
202 {
203 if ( pi->GetFlags() & wxPROP_DONT_STREAM )
204 return;
205
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();
210
211 if ( pi->GetTypeInfo()->GetKind() == wxT_COLLECTION )
212 {
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 )
218 {
219 if ( i == 0 )
220 DoBeginWriteProperty( pi );
221
222 DoBeginWriteElement();
223 wxVariantBase value = data[i];
224 if ( persister->BeforeWriteProperty( this, obj, pi, value ) )
225 {
226 const wxClassTypeInfo* cti =
227 wx_dynamic_cast( const wxClassTypeInfo*, elementType );
228 if ( cti )
229 {
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 );
235 }
236 else
237 {
238 DoWriteSimpleType( value );
239 }
240 }
241 DoEndWriteElement();
242 if ( i == data.GetCount() - 1 )
243 DoEndWriteProperty( pi );
244 }
245 }
246 else
247 {
248 const wxEventSourceTypeInfo* dti =
249 wx_dynamic_cast( const wxEventSourceTypeInfo* , pi->GetTypeInfo() );
250 if ( dti )
251 {
252 const wxObject* sink = NULL;
253 const wxHandlerInfo *handler = NULL;
254
255 const wxEvtHandler * evSource = wx_dynamic_cast(const wxEvtHandler *, obj);
256 if ( evSource )
257 {
258 FindConnectEntry( evSource, dti, sink, handler );
259 if ( persister->BeforeWriteDelegate( this, obj, ci, pi, sink, handler ) )
260 {
261 if ( sink != NULL && handler != NULL )
262 {
263 DoBeginWriteProperty( pi );
264 if ( IsObjectKnown( sink ) )
265 {
266 DoWriteDelegate( obj, ci, pi, sink, GetObjectID( sink ),
267 sink->GetClassInfo(), handler );
268 DoEndWriteProperty( pi );
269 }
270 else
271 {
272 wxLogError( _T("Streaming delegates for not already ")
273 _T("streamed objects not yet supported") );
274 }
275 }
276 }
277 }
278 else
279 {
280 wxLogError(_("Illegal Object Class (Non-wxEvtHandler) as Event Source") );
281 }
282 }
283 else
284 {
285 wxVariantBase value;
286 pi->GetAccessor()->GetProperty(obj, value);
287
288 // avoid streaming out void objects
289 if( value.IsEmpty() )
290 return;
291
292 if ( pi->GetFlags() & wxPROP_ENUM_STORE_LONG )
293 {
294 const wxEnumTypeInfo *eti =
295 wx_dynamic_cast(const wxEnumTypeInfo*, pi->GetTypeInfo() );
296 if ( eti )
297 {
298 eti->ConvertFromLong( value.wxTEMPLATED_MEMBER_CALL(Get, long), value );
299 }
300 else
301 {
302 wxLogError( _("Type must have enum - long conversion") );
303 }
304 }
305
306 // avoid streaming out default values
307 if ( pi->GetTypeInfo()->HasStringConverters() &&
308 !pi->GetDefaultValue().IsEmpty() )
309 {
310 if ( value.GetAsString() == pi->GetDefaultValue().GetAsString() )
311 return;
312 }
313
314 // avoid streaming out null objects
315 const wxClassTypeInfo* cti =
316 wx_dynamic_cast( const wxClassTypeInfo* , pi->GetTypeInfo() );
317
318 if ( cti && value.GetAsObject() == NULL )
319 return;
320
321 if ( persister->BeforeWriteProperty( this, obj, pi, value ) )
322 {
323 DoBeginWriteProperty( pi );
324 if ( cti )
325 {
326 const wxClassInfo* pci = cti->GetClassInfo();
327 wxObject *vobj = pci->VariantToInstance( value );
328 if ( vobj && pi->GetTypeInfo()->HasStringConverters() )
329 {
330 wxString stringValue;
331 cti->ConvertToString( value, stringValue );
332 wxVariantBase convertedValue(stringValue);
333 DoWriteSimpleType( convertedValue );
334 }
335 else
336 {
337 wxVariantBaseArray md;
338 WriteObject( vobj, (vobj ? vobj->GetClassInfo() : pci ),
339 persister, cti->GetKind()== wxT_OBJECT, md);
340 }
341 }
342 else
343 {
344 DoWriteSimpleType( value );
345 }
346 DoEndWriteProperty( pi );
347 }
348 }
349 }
350 }
351
352 int wxObjectWriter::GetObjectID(const wxObject *obj)
353 {
354 if ( !IsObjectKnown( obj ) )
355 return wxInvalidObjectID;
356
357 return m_data->m_writtenObjects[obj];
358 }
359
360 bool wxObjectWriter::IsObjectKnown( const wxObject *obj )
361 {
362 return m_data->m_writtenObjects.find( obj ) != m_data->m_writtenObjects.end();
363 }
364
365
366 // ----------------------------------------------------------------------------
367 // wxObjectReader
368 // ----------------------------------------------------------------------------
369
370 struct wxObjectReader::wxObjectReaderInternal
371 {
372 map<int,wxClassInfo*> m_classInfos;
373 };
374
375 wxObjectReader::wxObjectReader()
376 {
377 m_data = new wxObjectReaderInternal;
378 }
379
380 wxObjectReader::~wxObjectReader()
381 {
382 delete m_data;
383 }
384
385 wxClassInfo* wxObjectReader::GetObjectClassInfo(int objectID)
386 {
387 if ( objectID == wxNullObjectID || objectID == wxInvalidObjectID )
388 {
389 wxLogError( _("Invalid or Null Object ID passed to GetObjectClassInfo" ) );
390 return NULL;
391 }
392 if ( m_data->m_classInfos.find(objectID) == m_data->m_classInfos.end() )
393 {
394 wxLogError( _("Unknown Object passed to GetObjectClassInfo" ) );
395 return NULL;
396 }
397 return m_data->m_classInfos[objectID];
398 }
399
400 void wxObjectReader::SetObjectClassInfo(int objectID, wxClassInfo *classInfo )
401 {
402 if ( objectID == wxNullObjectID || objectID == wxInvalidObjectID )
403 {
404 wxLogError( _("Invalid or Null Object ID passed to GetObjectClassInfo" ) );
405 return;
406 }
407 if ( m_data->m_classInfos.find(objectID) != m_data->m_classInfos.end() )
408 {
409 wxLogError( _("Already Registered Object passed to SetObjectClassInfo" ) );
410 return;
411 }
412 m_data->m_classInfos[objectID] = classInfo;
413 }
414
415 bool wxObjectReader::HasObjectClassInfo( int objectID )
416 {
417 if ( objectID == wxNullObjectID || objectID == wxInvalidObjectID )
418 {
419 wxLogError( _("Invalid or Null Object ID passed to HasObjectClassInfo" ) );
420 return false;
421 }
422 return m_data->m_classInfos.find(objectID) != m_data->m_classInfos.end();
423 }
424
425
426 // ----------------------------------------------------------------------------
427 // reading xml in
428 // ----------------------------------------------------------------------------
429
430 /*
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
434 */
435
436
437 // ----------------------------------------------------------------------------
438 // wxObjectRuntimeReaderCallback - depersisting to memory
439 // ----------------------------------------------------------------------------
440
441 struct wxObjectRuntimeReaderCallback::wxObjectRuntimeReaderCallbackInternal
442 {
443 map<int,wxObject *> m_objects;
444
445 void SetObject(int objectID, wxObject *obj )
446 {
447 if ( m_objects.find(objectID) != m_objects.end() )
448 {
449 wxLogError( _("Passing a already registered object to SetObject") );
450 return ;
451 }
452 m_objects[objectID] = obj;
453 }
454 wxObject* GetObject( int objectID )
455 {
456 if ( objectID == wxNullObjectID )
457 return NULL;
458 if ( m_objects.find(objectID) == m_objects.end() )
459 {
460 wxLogError( _("Passing an unkown object to GetObject") );
461 return NULL;
462 }
463
464 return m_objects[objectID];
465 }
466 };
467
468 wxObjectRuntimeReaderCallback::wxObjectRuntimeReaderCallback()
469 {
470 m_data = new wxObjectRuntimeReaderCallbackInternal();
471 }
472
473 wxObjectRuntimeReaderCallback::~wxObjectRuntimeReaderCallback()
474 {
475 delete m_data;
476 }
477
478 void wxObjectRuntimeReaderCallback::AllocateObject(int objectID, wxClassInfo *classInfo,
479 wxVariantBaseArray &WXUNUSED(metadata))
480 {
481 wxObject *O;
482 O = classInfo->CreateObject();
483 m_data->SetObject(objectID, O);
484 }
485
486 void wxObjectRuntimeReaderCallback::CreateObject(int objectID,
487 const wxClassInfo *classInfo,
488 int paramCount,
489 wxVariantBase *params,
490 int *objectIdValues,
491 const wxClassInfo **objectClassInfos,
492 wxVariantBaseArray &WXUNUSED(metadata))
493 {
494 wxObject *o;
495 o = m_data->GetObject(objectID);
496 for ( int i = 0; i < paramCount; ++i )
497 {
498 if ( objectIdValues[i] != wxInvalidObjectID )
499 {
500 wxObject *o;
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()) )
506 {
507 o = dyno->GetSuperClassInstance();
508 }
509 params[i] = objectClassInfos[i]->InstanceToVariant(o);
510 }
511 }
512 classInfo->Create(o, paramCount, params);
513 }
514
515 void wxObjectRuntimeReaderCallback::ConstructObject(int objectID,
516 const wxClassInfo *classInfo,
517 int paramCount,
518 wxVariantBase *params,
519 int *objectIdValues,
520 const wxClassInfo **objectClassInfos,
521 wxVariantBaseArray &WXUNUSED(metadata))
522 {
523 wxObject *o;
524 for ( int i = 0; i < paramCount; ++i )
525 {
526 if ( objectIdValues[i] != wxInvalidObjectID )
527 {
528 wxObject *o;
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()) )
534 {
535 o = dyno->GetSuperClassInstance();
536 }
537 params[i] = objectClassInfos[i]->InstanceToVariant(o);
538 }
539 }
540 o = classInfo->ConstructObject(paramCount, params);
541 m_data->SetObject(objectID, o);
542 }
543
544
545 void wxObjectRuntimeReaderCallback::DestroyObject(int objectID, wxClassInfo *WXUNUSED(classInfo))
546 {
547 wxObject *o;
548 o = m_data->GetObject(objectID);
549 delete o;
550 }
551
552 void wxObjectRuntimeReaderCallback::SetProperty(int objectID,
553 const wxClassInfo *classInfo,
554 const wxPropertyInfo* propertyInfo,
555 const wxVariantBase &value)
556 {
557 wxObject *o;
558 o = m_data->GetObject(objectID);
559 classInfo->SetProperty( o, propertyInfo->GetName(), value );
560 }
561
562 void wxObjectRuntimeReaderCallback::SetPropertyAsObject(int objectID,
563 const wxClassInfo *classInfo,
564 const wxPropertyInfo* propertyInfo,
565 int valueObjectId)
566 {
567 wxObject *o, *valo;
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();
572
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()) )
577 {
578 valo = dynvalo->GetSuperClassInstance();
579 }
580
581 classInfo->SetProperty( o, propertyInfo->GetName(),
582 valClassInfo->InstanceToVariant(valo) );
583 }
584
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 )
591 {
592 wxEvtHandler *ehsource =
593 wx_dynamic_cast( wxEvtHandler* , m_data->GetObject( eventSourceObjectID ) );
594 wxEvtHandler *ehsink =
595 wx_dynamic_cast( wxEvtHandler *,m_data->GetObject(eventSinkObjectID) );
596
597 if ( ehsource && ehsink )
598 {
599 const wxEventSourceTypeInfo *delegateTypeInfo =
600 wx_dynamic_cast(const wxEventSourceTypeInfo*,delegateInfo->GetTypeInfo());
601 if( delegateTypeInfo && delegateTypeInfo->GetLastEventType() == -1 )
602 {
603 ehsource->Connect( -1, delegateTypeInfo->GetEventType(),
604 handlerInfo->GetEventFunction(), NULL /*user data*/,
605 ehsink );
606 }
607 else
608 {
609 for ( wxEventType iter = delegateTypeInfo->GetEventType();
610 iter <= delegateTypeInfo->GetLastEventType(); ++iter )
611 {
612 ehsource->Connect( -1, iter,
613 handlerInfo->GetEventFunction(), NULL /*user data*/,
614 ehsink );
615 }
616 }
617 }
618 }
619
620 wxObject *wxObjectRuntimeReaderCallback::GetObject(int objectID)
621 {
622 return m_data->GetObject( objectID );
623 }
624
625 void wxObjectRuntimeReaderCallback::AddToPropertyCollection( int objectID,
626 const wxClassInfo *classInfo,
627 const wxPropertyInfo* propertyInfo,
628 const wxVariantBase &value)
629 {
630 wxObject *o;
631 o = m_data->GetObject(objectID);
632 classInfo->AddToPropertyCollection( o, propertyInfo->GetName(), value );
633 }
634
635 void wxObjectRuntimeReaderCallback::AddToPropertyCollectionAsObject(int objectID,
636 const wxClassInfo *classInfo,
637 const wxPropertyInfo* propertyInfo,
638 int valueObjectId)
639 {
640 wxObject *o, *valo;
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();
647
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()) )
652 {
653 valo = dynvalo->GetSuperClassInstance();
654 }
655
656 classInfo->AddToPropertyCollection( o, propertyInfo->GetName(),
657 valClassInfo->InstanceToVariant(valo) );
658 }
659
660 #if TEST_XVARIANT
661 #include "wx/arrimpl.cpp"
662 WX_DEFINE_OBJARRAY(wxVariantBaseArray);
663 #endif
664
665 #endif // wxUSE_EXTENDED_RTTI