]> git.saurik.com Git - wxWidgets.git/blob - src/common/xtistrm.cpp
properties as collection
[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 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "xtistrm.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/hash.h"
25 #include "wx/object.h"
26 #endif
27
28 #include "wx/xml/xml.h"
29 #include "wx/tokenzr.h"
30 #include "wx/xtistrm.h"
31 #include "wx/txtstrm.h"
32
33 #if wxUSE_EXTENDED_RTTI
34
35 #include "wx/beforestd.h"
36 #include <map>
37 #include <vector>
38 #include <string>
39 #include "wx/afterstd.h"
40
41 using namespace std ;
42
43 struct wxWriter::wxWriterInternal
44 {
45 map< const wxObject* , int > m_writtenObjects ;
46 int m_nextId ;
47 } ;
48
49 wxWriter::wxWriter()
50 {
51 m_data = new wxWriterInternal ;
52 m_data->m_nextId = 0 ;
53 }
54
55 wxWriter::~wxWriter()
56 {
57 delete m_data ;
58 }
59
60 struct wxWriter::wxWriterInternalPropertiesData
61 {
62 map< string , int > m_writtenProperties ;
63 } ;
64
65 void wxWriter::ClearObjectContext()
66 {
67 delete m_data ;
68 m_data = new wxWriterInternal() ;
69 m_data->m_nextId = 0 ;
70 }
71
72 void wxWriter::WriteObject(const wxObject *object, const wxClassInfo *classInfo , wxPersister *persister , const wxString &name )
73 {
74 DoBeginWriteTopLevelEntry( name ) ;
75 WriteObject( object , classInfo , persister , false ) ;
76 DoEndWriteTopLevelEntry( name ) ;
77 }
78
79 void wxWriter::WriteObject(const wxObject *object, const wxClassInfo *classInfo , wxPersister *persister , bool isEmbedded)
80 {
81 if ( persister->BeforeWriteObject( this , object , classInfo ) )
82 {
83 if ( object == NULL )
84 DoWriteNullObject() ;
85 else if ( IsObjectKnown( object ) )
86 DoWriteRepeatedObject( GetObjectID(object) ) ;
87 else
88 {
89 int oid = m_data->m_nextId++ ;
90 if ( !isEmbedded )
91 m_data->m_writtenObjects[object] = oid ;
92
93 // in case this object is a wxDynamicObject we also have to insert is superclass
94 // instance with the same id, so that object relations are streamed out correctly
95 const wxDynamicObject* dynobj = dynamic_cast<const wxDynamicObject *>( object ) ;
96 if ( !isEmbedded && dynobj )
97 m_data->m_writtenObjects[dynobj->GetSuperClassInstance()] = oid ;
98
99 DoBeginWriteObject( object , classInfo , oid ) ;
100 wxWriterInternalPropertiesData data ;
101 WriteAllProperties( object , classInfo , persister , &data ) ;
102 DoEndWriteObject( object , classInfo , oid ) ;
103 }
104 persister->AfterWriteObject( this ,object , classInfo ) ;
105 }
106 }
107
108 void wxWriter::FindConnectEntry(const wxWindow * evSource,const wxDelegateTypeInfo* dti, const wxObject* &sink , const wxHandlerInfo *&handler)
109 {
110 wxList *dynamicEvents = evSource->GetDynamicEventTable() ;
111
112 if ( dynamicEvents )
113 {
114 wxList::compatibility_iterator node = dynamicEvents->GetFirst();
115 while (node)
116 {
117 wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData();
118
119 // find the match
120 if ( entry->m_fn && (dti->GetEventType() == entry->m_eventType) &&
121 (entry->m_id == -1 ||
122 (entry->m_lastId == -1 && evSource->GetId() == entry->m_id) ||
123 (entry->m_lastId != -1 &&
124 (evSource->GetId() >= entry->m_id && evSource->GetId() <= entry->m_lastId) ) ) &&
125 entry->m_eventSink
126 )
127 {
128 sink = entry->m_eventSink ;
129 const wxClassInfo* sinkClassInfo = sink->GetClassInfo() ;
130 const wxHandlerInfo* sinkHandler = sinkClassInfo->GetFirstHandler() ;
131 while ( sinkHandler )
132 {
133 if ( sinkHandler->GetEventFunction() == entry->m_fn )
134 {
135 handler = sinkHandler ;
136 break ;
137 }
138 sinkHandler = sinkHandler->GetNext() ;
139 }
140 break ;
141 }
142 node = node->GetNext();
143 }
144 }
145 }
146 void wxWriter::WriteAllProperties( const wxObject * obj , const wxClassInfo* ci , wxPersister *persister, wxWriterInternalPropertiesData * data )
147 {
148 // in case this object is wxDynamic object we have to hand over the streaming
149 // of the properties of the superclasses to the real super class instance
150 {
151 const wxObject *iterobj = obj ;
152 const wxDynamicObject* dynobj = dynamic_cast< const wxDynamicObject* > (iterobj ) ;
153 if ( dynobj )
154 iterobj = dynobj->GetSuperClassInstance() ;
155 const wxClassInfo** parents = ci->GetParents() ;
156 for ( int i = 0 ; parents[i] ; ++ i )
157 {
158 WriteAllProperties( iterobj , parents[i] , persister , data ) ;
159 }
160 }
161
162 const wxPropertyInfo *pi = ci->GetFirstProperty() ;
163 while( pi )
164 {
165 // this property was not written yet in this object and we don't get a veto
166 // if ( data->m_writtenProperties.find( pi->GetName() ) == data->m_writtenProperties.end() )
167 // we will have to handle property overrides differently
168 {
169 data->m_writtenProperties[ pi->GetName() ] = 1 ;
170 DoBeginWriteProperty( pi ) ;
171 if ( pi->GetTypeInfo()->GetKind() == wxT_COLLECTION )
172 {
173 wxxVariantArray data = pi->GetAccessor()->GetPropertyCollection(obj) ;
174 const wxTypeInfo * elementType = dynamic_cast< const wxCollectionTypeInfo* >( pi->GetTypeInfo() )->GetElementType() ;
175 for ( size_t i = 0 ; i < data.GetCount() ; ++i )
176 {
177 DoBeginWriteElement() ;
178 wxxVariant value = data[i] ;
179 if ( persister->BeforeWriteProperty( this , pi , value ) )
180 {
181 const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( elementType ) ;
182 if ( cti )
183 {
184 const wxClassInfo* pci = cti->GetClassInfo() ;
185 wxObject *vobj = pci->VariantToInstance( value ) ;
186 WriteObject( vobj , (vobj ? vobj->GetClassInfo() : pci ) , persister , cti->GetKind()== wxT_OBJECT ) ;
187 }
188 else
189 {
190 DoWriteSimpleType( value ) ;
191 }
192 }
193 DoEndWriteElement() ;
194 }
195 }
196 else
197 {
198 const wxDelegateTypeInfo* dti = dynamic_cast< const wxDelegateTypeInfo* > ( pi->GetTypeInfo() ) ;
199 if ( dti )
200 {
201 const wxObject* sink = NULL ;
202 const wxHandlerInfo *handler = NULL ;
203
204 const wxWindow * evSource = dynamic_cast<const wxWindow *>(obj) ;
205 wxASSERT_MSG( evSource , wxT("Illegal Object Class (Non-Window) as Event Source") ) ;
206
207 FindConnectEntry( evSource , dti , sink , handler ) ;
208 if ( persister->BeforeWriteDelegate( this , obj , ci , pi , sink , handler ) )
209 {
210 if ( sink != NULL && handler != NULL )
211 {
212 wxASSERT_MSG( IsObjectKnown( sink ) , wxT("Streaming delegates for not already streamed objects not yet supported") ) ;
213 DoWriteDelegate( obj , ci , pi , sink , GetObjectID( sink ) , sink->GetClassInfo() , handler ) ;
214 }
215 }
216 }
217 else
218 {
219 wxxVariant value = pi->GetAccessor()->GetProperty(obj) ;
220 if ( persister->BeforeWriteProperty( this , pi , value ) )
221 {
222 const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( pi->GetTypeInfo() ) ;
223 if ( cti )
224 {
225 const wxClassInfo* pci = cti->GetClassInfo() ;
226 wxObject *vobj = pci->VariantToInstance( value ) ;
227 WriteObject( vobj , (vobj ? vobj->GetClassInfo() : pci ) , persister , cti->GetKind()== wxT_OBJECT ) ;
228 }
229 else
230 {
231 DoWriteSimpleType( value ) ;
232 }
233 }
234 }
235 }
236 DoEndWriteProperty( pi ) ;
237 }
238 pi = pi->GetNext() ;
239 }
240 }
241
242 int wxWriter::GetObjectID(const wxObject *obj)
243 {
244 if ( !IsObjectKnown( obj ) )
245 return wxInvalidObjectID ;
246
247 return m_data->m_writtenObjects[obj] ;
248 }
249
250 bool wxWriter::IsObjectKnown( const wxObject *obj )
251 {
252 return m_data->m_writtenObjects.find( obj ) != m_data->m_writtenObjects.end() ;
253 }
254
255 //
256 // XML Streaming
257 //
258
259 // convenience functions
260
261 void wxXmlAddContentToNode( wxXmlNode* node , const wxString& data )
262 {
263 node->AddChild(new wxXmlNode(wxXML_TEXT_NODE, "value", data ) );
264 }
265
266 wxString wxXmlGetContentFromNode( wxXmlNode *node )
267 {
268 if ( node->GetChildren() )
269 return node->GetChildren()->GetContent() ;
270 else
271 return wxEmptyString ;
272 }
273
274 struct wxXmlWriter::wxXmlWriterInternal
275 {
276 wxXmlNode *m_root ;
277 wxXmlNode *m_current ;
278 vector< wxXmlNode * > m_objectStack ;
279
280 void Push( wxXmlNode *newCurrent )
281 {
282 m_objectStack.push_back( m_current ) ;
283 m_current = newCurrent ;
284 }
285
286 void Pop()
287 {
288 m_current = m_objectStack.back() ;
289 m_objectStack.pop_back() ;
290 }
291 } ;
292
293 wxXmlWriter::wxXmlWriter( wxXmlNode * rootnode )
294 {
295 m_data = new wxXmlWriterInternal() ;
296 m_data->m_root = rootnode ;
297 m_data->m_current = rootnode ;
298 }
299
300 wxXmlWriter::~wxXmlWriter()
301 {
302 delete m_data ;
303 }
304
305 void wxXmlWriter::DoBeginWriteTopLevelEntry( const wxString &name )
306 {
307 wxXmlNode *pnode;
308 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("entry"));
309 pnode->AddProperty(wxString("name"), name);
310 m_data->m_current->AddChild(pnode) ;
311 m_data->Push( pnode ) ;
312 }
313
314 void wxXmlWriter::DoEndWriteTopLevelEntry( const wxString &WXUNUSED(name) )
315 {
316 m_data->Pop() ;
317 }
318
319 void wxXmlWriter::DoBeginWriteObject(const wxObject *WXUNUSED(object), const wxClassInfo *classInfo, int objectID )
320 {
321 wxXmlNode *pnode;
322 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("object"));
323 pnode->AddProperty(wxT("class"), wxString(classInfo->GetClassName()));
324 pnode->AddProperty(wxT("id"), wxString::Format( "%d" , objectID ) );
325
326 m_data->m_current->AddChild(pnode) ;
327 m_data->Push( pnode ) ;
328 }
329
330 // end of writing the root object
331 void wxXmlWriter::DoEndWriteObject(const wxObject *WXUNUSED(object), const wxClassInfo *WXUNUSED(classInfo), int WXUNUSED(objectID) )
332 {
333 m_data->Pop() ;
334 }
335
336 // writes a property in the stream format
337 void wxXmlWriter::DoWriteSimpleType( wxxVariant &value )
338 {
339 wxXmlAddContentToNode( m_data->m_current ,value.GetAsString() ) ;
340 }
341
342 void wxXmlWriter::DoBeginWriteElement()
343 {
344 wxXmlNode *pnode;
345 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, "element" );
346 m_data->m_current->AddChild(pnode) ;
347 m_data->Push( pnode ) ;
348 }
349
350 void wxXmlWriter::DoEndWriteElement()
351 {
352 m_data->Pop() ;
353 }
354
355 void wxXmlWriter::DoBeginWriteProperty(const wxPropertyInfo *pi )
356 {
357 wxXmlNode *pnode;
358 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, "prop" );
359 pnode->AddProperty(wxT("name"), pi->GetName() );
360 m_data->m_current->AddChild(pnode) ;
361 m_data->Push( pnode ) ;
362 }
363
364 void wxXmlWriter::DoEndWriteProperty(const wxPropertyInfo *WXUNUSED(propInfo) )
365 {
366 m_data->Pop() ;
367 }
368
369
370
371 // insert an object reference to an already written object
372 void wxXmlWriter::DoWriteRepeatedObject( int objectID )
373 {
374 wxXmlNode *pnode;
375 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("object"));
376 pnode->AddProperty(wxString("href"), wxString::Format( "%d" , objectID ) );
377 m_data->m_current->AddChild(pnode) ;
378 }
379
380 // insert a null reference
381 void wxXmlWriter::DoWriteNullObject()
382 {
383 wxXmlNode *pnode;
384 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("object"));
385 m_data->m_current->AddChild(pnode) ;
386 }
387
388 // writes a delegate in the stream format
389 void wxXmlWriter::DoWriteDelegate( const wxObject *WXUNUSED(object), const wxClassInfo* WXUNUSED(classInfo) , const wxPropertyInfo *WXUNUSED(pi) ,
390 const wxObject *eventSink, int sinkObjectID , const wxClassInfo* WXUNUSED(eventSinkClassInfo) , const wxHandlerInfo* handlerInfo )
391 {
392 if ( eventSink != NULL && handlerInfo != NULL )
393 {
394 wxXmlAddContentToNode( m_data->m_current ,wxString::Format(wxT("%d.%s"), sinkObjectID , handlerInfo->GetName()) ) ;
395 }
396 }
397
398 // ----------------------------------------------------------------------------
399 // reading objects in
400 // ----------------------------------------------------------------------------
401
402 struct wxReader::wxReaderInternal
403 {
404 map<int,wxClassInfo*> m_classInfos;
405 };
406
407 wxReader::wxReader()
408 {
409 m_data = new wxReaderInternal;
410 }
411
412 wxReader::~wxReader()
413 {
414 delete m_data;
415 }
416
417 wxClassInfo* wxReader::GetObjectClassInfo(int objectID)
418 {
419 assert( m_data->m_classInfos.find(objectID) != m_data->m_classInfos.end() );
420 return m_data->m_classInfos[objectID] ;
421 }
422
423 void wxReader::SetObjectClassInfo(int objectID, wxClassInfo *classInfo )
424 {
425 assert( m_data->m_classInfos.find(objectID) == m_data->m_classInfos.end() ) ;
426 m_data->m_classInfos[objectID] = classInfo ;
427 }
428
429 bool wxReader::HasObjectClassInfo( int objectID )
430 {
431 return m_data->m_classInfos.find(objectID) != m_data->m_classInfos.end() ;
432 }
433
434
435 // ----------------------------------------------------------------------------
436 // reading xml in
437 // ----------------------------------------------------------------------------
438
439 /*
440 Reading components has not to be extended for components
441 as properties are always sought by typeinfo over all levels
442 and create params are always toplevel class only
443 */
444
445 int wxXmlReader::ReadComponent(wxXmlNode *node, wxDepersister *callbacks)
446 {
447 wxASSERT_MSG( callbacks , wxT("Does not support reading without a Depersistor") ) ;
448 wxString className;
449 wxClassInfo *classInfo;
450
451 wxxVariant *createParams ;
452 int *createParamOids ;
453 const wxClassInfo** createClassInfos ;
454 wxXmlNode *children;
455 int objectID;
456 wxString ObjectIdString ;
457
458 children = node->GetChildren();
459 if (!children)
460 {
461 // check for a null object or href
462 if (node->GetPropVal("href" , &ObjectIdString ) )
463 {
464 objectID = atoi( ObjectIdString.c_str() ) ;
465 wxASSERT_MSG( HasObjectClassInfo( objectID ) , wxT("Forward hrefs are not supported") ) ;
466 return objectID ;
467 }
468 if ( !node->GetPropVal("id" , &ObjectIdString ) )
469 {
470 return wxNullObjectID;
471 }
472 }
473 if (!node->GetPropVal("class", &className))
474 {
475 // No class name. Eek. FIXME: error handling
476 return wxInvalidObjectID;
477 }
478 classInfo = wxClassInfo::FindClass(className);
479 wxASSERT_MSG( classInfo , wxString::Format(wxT("unknown class %s"),className ) ) ;
480 wxASSERT_MSG( !children || children->GetType() != wxXML_TEXT_NODE , wxT("objects cannot have XML Text Nodes") ) ;
481 if (!node->GetPropVal("id", &ObjectIdString))
482 {
483 wxASSERT_MSG(0,wxT("Objects must have an id attribute") ) ;
484 // No object id. Eek. FIXME: error handling
485 return wxInvalidObjectID;
486 }
487 objectID = atoi( ObjectIdString.c_str() ) ;
488 // is this object already has been streamed in, return it here
489 wxASSERT_MSG( !HasObjectClassInfo( objectID ) , wxString::Format(wxT("Doubly used id : %d"), objectID ) ) ;
490
491 // new object, start with allocation
492 // first make the object know to our internal registry
493 SetObjectClassInfo( objectID , classInfo ) ;
494
495 callbacks->AllocateObject(objectID, classInfo);
496
497 //
498 // stream back the Create parameters first
499 createParams = new wxxVariant[ classInfo->GetCreateParamCount() ] ;
500 createParamOids = new int[classInfo->GetCreateParamCount() ] ;
501 createClassInfos = new const wxClassInfo*[classInfo->GetCreateParamCount() ] ;
502
503 typedef map<string, wxXmlNode *> PropertyNodes ;
504 typedef vector<string> PropertyNames ;
505
506 PropertyNodes propertyNodes ;
507 PropertyNames propertyNames ;
508
509 while( children )
510 {
511 wxString name ;
512 children->GetPropVal( wxT("name") , &name ) ;
513 propertyNames.push_back( name.c_str() ) ;
514 propertyNodes[name.c_str()] = children->GetChildren() ;
515 children = children->GetNext() ;
516 }
517
518 for ( int i = 0 ; i <classInfo->GetCreateParamCount() ; ++i )
519 {
520 const wxChar* paramName = classInfo->GetCreateParamName(i) ;
521 PropertyNodes::iterator propiter = propertyNodes.find( paramName ) ;
522 const wxPropertyInfo* pi = classInfo->FindPropertyInfo( paramName ) ;
523 wxASSERT_MSG(pi,wxString::Format("Unkown Property %s",paramName) ) ;
524 // if we don't have the value of a create param set in the xml
525 // we use the default value
526 if ( propiter != propertyNodes.end() )
527 {
528 wxXmlNode* prop = propiter->second ;
529 if ( pi->GetTypeInfo()->IsObjectType() )
530 {
531 createParamOids[i] = ReadComponent( prop , callbacks ) ;
532 createClassInfos[i] = dynamic_cast<const wxClassTypeInfo*>(pi->GetTypeInfo())->GetClassInfo() ;
533 }
534 else
535 {
536 createParamOids[i] = wxInvalidObjectID ;
537 createParams[i] = ReadValue( prop , pi->GetAccessor() ) ;
538 createClassInfos[i] = NULL ;
539 }
540
541 for ( size_t j = 0 ; j < propertyNames.size() ; ++j )
542 {
543 if ( propertyNames[j] == paramName )
544 {
545 propertyNames[j] = "" ;
546 break ;
547 }
548 }
549 }
550 else
551 {
552 createParams[i] = pi->GetDefaultValue() ;
553 }
554 }
555
556 // got the parameters. Call the Create method
557 callbacks->CreateObject(objectID, classInfo,
558 classInfo->GetCreateParamCount(),
559 createParams, createParamOids, createClassInfos);
560
561 // now stream in the rest of the properties, in the sequence their properties were written in the xml
562 for ( size_t j = 0 ; j < propertyNames.size() ; ++j )
563 {
564 if ( propertyNames[j].length() )
565 {
566 PropertyNodes::iterator propiter = propertyNodes.find( propertyNames[j] ) ;
567 if ( propiter != propertyNodes.end() )
568 {
569 wxXmlNode* prop = propiter->second ;
570 const wxPropertyInfo* pi = classInfo->FindPropertyInfo( propertyNames[j].c_str() ) ;
571 if ( pi->GetTypeInfo()->GetKind() == wxT_COLLECTION )
572 {
573 const wxCollectionTypeInfo* collType = dynamic_cast< const wxCollectionTypeInfo* >( pi->GetTypeInfo() ) ;
574 const wxTypeInfo * elementType = collType->GetElementType() ;
575 while( prop )
576 {
577 wxASSERT_MSG(prop->GetName() == wxT("element") , wxT("A non empty collection must consist of 'element' nodes")) ;
578 wxXmlNode* elementContent = prop->GetChildren() ;
579 wxASSERT_MSG(elementContent, wxT("An element node cannot be empty")) ;
580 if ( elementType->IsObjectType() )
581 {
582 int valueId = ReadComponent( elementContent , callbacks ) ;
583 if ( valueId != wxInvalidObjectID )
584 {
585 if ( pi->GetAccessor()->HasAdder() )
586 callbacks->AddToPropertyCollectionAsObject( objectID , classInfo , pi , valueId ) ;
587 // TODO for collections we must have a notation on taking over ownership or not
588 if ( elementType->GetKind() == wxT_OBJECT && valueId != wxNullObjectID )
589 callbacks->DestroyObject( valueId , GetObjectClassInfo( valueId ) ) ;
590 }
591 }
592 else
593 {
594 wxxVariant elementValue = ReadValue( prop , pi->GetAccessor() ) ;
595 if ( pi->GetAccessor()->HasAdder() )
596 callbacks->AddToPropertyCollection( objectID , classInfo ,pi , elementValue ) ;
597 }
598 prop = prop->GetNext() ;
599 }
600 }
601 else if ( pi->GetTypeInfo()->IsObjectType() )
602 {
603 int valueId = ReadComponent( prop , callbacks ) ;
604 if ( valueId != wxInvalidObjectID )
605 {
606 callbacks->SetPropertyAsObject( objectID , classInfo , pi , valueId ) ;
607 if ( pi->GetTypeInfo()->GetKind() == wxT_OBJECT && valueId != wxNullObjectID )
608 callbacks->DestroyObject( valueId , GetObjectClassInfo( valueId ) ) ;
609 }
610 }
611 else if ( pi->GetTypeInfo()->IsDelegateType() )
612 {
613 if ( prop )
614 {
615 wxString resstring = prop->GetContent() ;
616 wxInt32 pos = resstring.Find('.') ;
617 assert( pos != wxNOT_FOUND ) ;
618 int sinkOid = atol(resstring.Left(pos)) ;
619 wxString handlerName = resstring.Mid(pos+1) ;
620 wxClassInfo* sinkClassInfo = GetObjectClassInfo( sinkOid ) ;
621
622 callbacks->SetConnect( objectID , classInfo , dynamic_cast<const wxDelegateTypeInfo*>(pi->GetTypeInfo()) , sinkClassInfo ,
623 sinkClassInfo->FindHandlerInfo(handlerName) , sinkOid ) ;
624 }
625
626 }
627 else
628 {
629 callbacks->SetProperty( objectID, classInfo ,pi , ReadValue( prop , pi->GetAccessor() ) ) ;
630 }
631 }
632 }
633 }
634
635 delete[] createParams ;
636 delete[] createParamOids ;
637 delete[] createClassInfos ;
638
639 return objectID;
640 }
641
642 wxxVariant wxXmlReader::ReadValue(wxXmlNode *node,
643 wxPropertyAccessor *accessor )
644 {
645 wxString content ;
646 if ( node )
647 content = node->GetContent() ;
648 return accessor->ReadValue(content) ;
649 }
650
651 int wxXmlReader::ReadObject( const wxString &name , wxDepersister *callbacks)
652 {
653 wxXmlNode *iter = m_parent->GetChildren() ;
654 while ( iter )
655 {
656 wxString entryName ;
657 if ( iter->GetPropVal("name", &entryName) )
658 {
659 if ( entryName == name )
660 return ReadComponent( iter->GetChildren() , callbacks ) ;
661 }
662 iter = iter->GetNext() ;
663 }
664 return wxInvalidObjectID ;
665 }
666
667 // ----------------------------------------------------------------------------
668 // depersisting to memory
669 // ----------------------------------------------------------------------------
670
671 struct wxRuntimeDepersister::wxRuntimeDepersisterInternal
672 {
673 map<int,wxObject *> m_objects;
674
675 void SetObject(int objectID, wxObject *obj )
676 {
677 assert( m_objects.find(objectID) == m_objects.end() ) ;
678 m_objects[objectID] = obj ;
679 }
680 wxObject* GetObject( int objectID )
681 {
682 if ( objectID == wxNullObjectID )
683 return NULL ;
684
685 assert( m_objects.find(objectID) != m_objects.end() ) ;
686 return m_objects[objectID] ;
687 }
688 } ;
689
690 wxRuntimeDepersister::wxRuntimeDepersister()
691 {
692 m_data = new wxRuntimeDepersisterInternal() ;
693 }
694
695 wxRuntimeDepersister::~wxRuntimeDepersister()
696 {
697 delete m_data ;
698 }
699
700 void wxRuntimeDepersister::AllocateObject(int objectID, wxClassInfo *classInfo)
701 {
702 wxObject *O;
703 O = classInfo->CreateObject();
704 m_data->SetObject(objectID, O);
705 }
706
707 void wxRuntimeDepersister::CreateObject(int objectID,
708 const wxClassInfo *classInfo,
709 int paramCount,
710 wxxVariant *params,
711 int *objectIdValues,
712 const wxClassInfo **objectClassInfos)
713 {
714 wxObject *o;
715 o = m_data->GetObject(objectID);
716 for ( int i = 0 ; i < paramCount ; ++i )
717 {
718 if ( objectIdValues[i] != wxInvalidObjectID )
719 {
720 wxObject *o;
721 o = m_data->GetObject(objectIdValues[i]);
722 // if this is a dynamic object and we are asked for another class
723 // than wxDynamicObject we cast it down manually.
724 wxDynamicObject *dyno = dynamic_cast< wxDynamicObject * > (o) ;
725 if ( dyno!=NULL && (objectClassInfos[i] != dyno->GetClassInfo()) )
726 {
727 o = dyno->GetSuperClassInstance() ;
728 }
729 params[i] = objectClassInfos[i]->InstanceToVariant(o) ;
730 }
731 }
732 classInfo->Create(o, paramCount, params);
733 }
734
735 void wxRuntimeDepersister::DestroyObject(int objectID, wxClassInfo *WXUNUSED(classInfo))
736 {
737 wxObject *o;
738 o = m_data->GetObject(objectID);
739 delete o ;
740 }
741
742 void wxRuntimeDepersister::SetProperty(int objectID,
743 const wxClassInfo *classInfo,
744 const wxPropertyInfo* propertyInfo,
745 const wxxVariant &value)
746 {
747 wxObject *o;
748 o = m_data->GetObject(objectID);
749 classInfo->SetProperty( o , propertyInfo->GetName() , value ) ;
750 }
751
752 void wxRuntimeDepersister::SetPropertyAsObject(int objectID,
753 const wxClassInfo *classInfo,
754 const wxPropertyInfo* propertyInfo,
755 int valueObjectId)
756 {
757 wxObject *o, *valo;
758 o = m_data->GetObject(objectID);
759 valo = m_data->GetObject(valueObjectId);
760 const wxClassInfo* valClassInfo = (dynamic_cast<const wxClassTypeInfo*>(propertyInfo->GetTypeInfo()))->GetClassInfo() ;
761 // if this is a dynamic object and we are asked for another class
762 // than wxDynamicObject we cast it down manually.
763 wxDynamicObject *dynvalo = dynamic_cast< wxDynamicObject * > (valo) ;
764 if ( dynvalo!=NULL && (valClassInfo != dynvalo->GetClassInfo()) )
765 {
766 valo = dynvalo->GetSuperClassInstance() ;
767 }
768
769 classInfo->SetProperty( o , propertyInfo->GetName() , valClassInfo->InstanceToVariant(valo) ) ;
770 }
771
772 void wxRuntimeDepersister::SetConnect(int eventSourceObjectID,
773 const wxClassInfo *WXUNUSED(eventSourceClassInfo),
774 const wxDelegateTypeInfo *delegateInfo ,
775 const wxClassInfo *WXUNUSED(eventSinkClassInfo) ,
776 const wxHandlerInfo* handlerInfo ,
777 int eventSinkObjectID )
778 {
779 wxWindow *ehsource = dynamic_cast< wxWindow* >( m_data->GetObject( eventSourceObjectID ) ) ;
780 wxEvtHandler *ehsink = dynamic_cast< wxEvtHandler *>(m_data->GetObject(eventSinkObjectID) ) ;
781
782 if ( ehsource && ehsink )
783 {
784 ehsource->Connect( ehsource->GetId() , delegateInfo->GetEventType() ,
785 handlerInfo->GetEventFunction() , NULL /*user data*/ ,
786 ehsink ) ;
787 }
788 }
789
790 wxObject *wxRuntimeDepersister::GetObject(int objectID)
791 {
792 return m_data->GetObject( objectID ) ;
793 }
794
795 // adds an element to a property collection
796 void wxRuntimeDepersister::AddToPropertyCollection( int objectID ,
797 const wxClassInfo *classInfo,
798 const wxPropertyInfo* propertyInfo ,
799 const wxxVariant &value)
800 {
801 wxObject *o;
802 o = m_data->GetObject(objectID);
803 classInfo->AddToPropertyCollection( o , propertyInfo->GetName() , value ) ;
804 }
805
806 // sets the corresponding property (value is an object)
807 void wxRuntimeDepersister::AddToPropertyCollectionAsObject(int objectID,
808 const wxClassInfo *classInfo,
809 const wxPropertyInfo* propertyInfo ,
810 int valueObjectId)
811 {
812 wxObject *o, *valo;
813 o = m_data->GetObject(objectID);
814 valo = m_data->GetObject(valueObjectId);
815 const wxCollectionTypeInfo * collectionTypeInfo = dynamic_cast< const wxCollectionTypeInfo * >(propertyInfo->GetTypeInfo() ) ;
816 const wxClassInfo* valClassInfo = (dynamic_cast<const wxClassTypeInfo*>(collectionTypeInfo->GetElementType()))->GetClassInfo() ;
817 // if this is a dynamic object and we are asked for another class
818 // than wxDynamicObject we cast it down manually.
819 wxDynamicObject *dynvalo = dynamic_cast< wxDynamicObject * > (valo) ;
820 if ( dynvalo!=NULL && (valClassInfo != dynvalo->GetClassInfo()) )
821 {
822 valo = dynvalo->GetSuperClassInstance() ;
823 }
824
825 classInfo->AddToPropertyCollection( o , propertyInfo->GetName() , valClassInfo->InstanceToVariant(valo) ) ;
826 }
827
828 // ----------------------------------------------------------------------------
829 // depersisting to code
830 // ----------------------------------------------------------------------------
831
832 struct wxCodeDepersister::wxCodeDepersisterInternal
833 {
834 map<int,string> m_objectNames ;
835
836 void SetObjectName(int objectID, const wxString &name )
837 {
838 assert( m_objectNames.find(objectID) == m_objectNames.end() ) ;
839 m_objectNames[objectID] = (const char *)name;
840 }
841 wxString GetObjectName( int objectID )
842 {
843 if ( objectID == wxNullObjectID )
844 return "NULL" ;
845
846 assert( m_objectNames.find(objectID) != m_objectNames.end() ) ;
847 return wxString( m_objectNames[objectID].c_str() ) ;
848 }
849 } ;
850
851 wxCodeDepersister::wxCodeDepersister(wxTextOutputStream *out)
852 : m_fp(out)
853 {
854 m_data = new wxCodeDepersisterInternal ;
855 }
856
857 wxCodeDepersister::~wxCodeDepersister()
858 {
859 delete m_data ;
860 }
861
862 void wxCodeDepersister::AllocateObject(int objectID, wxClassInfo *classInfo)
863 {
864 wxString objectName = wxString::Format( "LocalObject_%d" , objectID ) ;
865 m_fp->WriteString( wxString::Format( "\t%s *%s = new %s;\n",
866 classInfo->GetClassName(),
867 objectName,
868 classInfo->GetClassName()) );
869 m_data->SetObjectName( objectID , objectName ) ;
870 }
871
872 void wxCodeDepersister::DestroyObject(int objectID, wxClassInfo *WXUNUSED(classInfo))
873 {
874 m_fp->WriteString( wxString::Format( "\tdelete %s;\n",
875 m_data->GetObjectName( objectID) ) );
876 }
877
878 wxString wxCodeDepersister::ValueAsCode( const wxxVariant &param )
879 {
880 wxString value ;
881 const wxTypeInfo* type = param.GetTypeInfo() ;
882 if ( type->GetKind() == wxT_CUSTOM )
883 {
884 const wxCustomTypeInfo* cti = dynamic_cast<const wxCustomTypeInfo*>(type) ;
885 wxASSERT_MSG( cti , wxT("Internal error, illegal wxCustomTypeInfo") ) ;
886 value.Printf( "%s(%s)",cti->GetTypeName(),param.GetAsString() );
887 }
888 else if ( type->GetKind() == wxT_STRING )
889 {
890 value.Printf( "\"%s\"",param.GetAsString() );
891 }
892 else
893 {
894 value.Printf( "%s", param.GetAsString() );
895 }
896 return value ;
897 }
898
899 void wxCodeDepersister::CreateObject(int objectID,
900 const wxClassInfo *WXUNUSED(classInfo),
901 int paramCount,
902 wxxVariant *params,
903 int *objectIDValues,
904 const wxClassInfo **WXUNUSED(objectClassInfos)
905 )
906 {
907 int i;
908 m_fp->WriteString( wxString::Format( "\t%s->Create(", m_data->GetObjectName(objectID) ) );
909 for (i = 0; i < paramCount; i++)
910 {
911 if ( objectIDValues[i] != wxInvalidObjectID )
912 m_fp->WriteString( wxString::Format( "%s", m_data->GetObjectName( objectIDValues[i] ) ) );
913 else
914 {
915 m_fp->WriteString( wxString::Format( "%s", ValueAsCode(params[i]) ) );
916 }
917 if (i < paramCount - 1)
918 m_fp->WriteString( ", ");
919 }
920 m_fp->WriteString( ");\n");
921 }
922
923 void wxCodeDepersister::SetProperty(int objectID,
924 const wxClassInfo *WXUNUSED(classInfo),
925 const wxPropertyInfo* propertyInfo,
926 const wxxVariant &value)
927 {
928 m_fp->WriteString( wxString::Format( "\t%s->%s(%s);\n",
929 m_data->GetObjectName(objectID),
930 propertyInfo->GetAccessor()->GetSetterName(),
931 ValueAsCode(value)) );
932 }
933
934 void wxCodeDepersister::SetPropertyAsObject(int objectID,
935 const wxClassInfo *WXUNUSED(classInfo),
936 const wxPropertyInfo* propertyInfo,
937 int valueObjectId)
938 {
939 if ( propertyInfo->GetTypeInfo()->GetKind() == wxT_OBJECT )
940 m_fp->WriteString( wxString::Format( "\t%s->%s(*%s);\n",
941 m_data->GetObjectName(objectID),
942 propertyInfo->GetAccessor()->GetSetterName(),
943 m_data->GetObjectName( valueObjectId) ) );
944 else
945 m_fp->WriteString( wxString::Format( "\t%s->%s(%s);\n",
946 m_data->GetObjectName(objectID),
947 propertyInfo->GetAccessor()->GetSetterName(),
948 m_data->GetObjectName( valueObjectId) ) );
949 }
950
951 void wxCodeDepersister::AddToPropertyCollection( int objectID ,
952 const wxClassInfo *classInfo,
953 const wxPropertyInfo* propertyInfo ,
954 const wxxVariant &value)
955 {
956 m_fp->WriteString( wxString::Format( "\t%s->%s(%s);\n",
957 m_data->GetObjectName(objectID),
958 propertyInfo->GetAccessor()->GetAdderName(),
959 ValueAsCode(value)) );
960 }
961
962 // sets the corresponding property (value is an object)
963 void wxCodeDepersister::AddToPropertyCollectionAsObject(int objectID,
964 const wxClassInfo *classInfo,
965 const wxPropertyInfo* propertyInfo ,
966 int valueObjectId)
967 {
968 // TODO
969 }
970
971 void wxCodeDepersister::SetConnect(int eventSourceObjectID,
972 const wxClassInfo *WXUNUSED(eventSourceClassInfo),
973 const wxDelegateTypeInfo *delegateInfo ,
974 const wxClassInfo *eventSinkClassInfo ,
975 const wxHandlerInfo* handlerInfo ,
976 int eventSinkObjectID )
977 {
978 wxString ehsource = m_data->GetObjectName( eventSourceObjectID ) ;
979 wxString ehsink = m_data->GetObjectName(eventSinkObjectID) ;
980 wxString ehsinkClass = eventSinkClassInfo->GetClassName() ;
981 int eventType = delegateInfo->GetEventType() ;
982 wxString handlerName = handlerInfo->GetName() ;
983
984 m_fp->WriteString( wxString::Format( "\t%s->Connect( %s->GetId() , %d , (wxObjectEventFunction)(wxEventFunction) & %s::%s , NULL , %s ) ;" ,
985 ehsource , ehsource , eventType , ehsinkClass , handlerName , ehsink ) );
986 }
987
988 #include <wx/arrimpl.cpp>
989
990 WX_DEFINE_OBJARRAY(wxxVariantArray);
991
992 #endif