]> git.saurik.com Git - wxWidgets.git/blob - src/common/xtistrm.cpp
xti streaming extensions
[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 #ifdef __GNUG__
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 #include <map>
35 #include <vector>
36 #include <string>
37
38 using namespace std ;
39
40 // ----------------------------------------------------------------------------
41 // streaming xml out
42 // ----------------------------------------------------------------------------
43
44 void WriteComponent(wxObject *Object, const wxClassInfo *classInfo, wxXmlNode *parent, const wxString& nodeName , int &nextId, bool embeddedObject, map< wxObject* , int > &writtenObjects ) ;
45
46 void WriteComponentProperties( wxObject* obj , const wxClassInfo* ci , wxXmlNode *onode , int &nextId, map< wxObject* , int > &writtenObjects, map< string , int > &writtenProperties)
47 {
48 const wxPropertyInfo *pi = ci->GetFirstProperty() ;
49 while( pi )
50 {
51 if ( writtenProperties.find( pi->GetName() ) == writtenProperties.end() )
52 {
53 writtenProperties[ pi->GetName() ] = 1 ;
54 const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( pi->GetTypeInfo() ) ;
55 if ( cti )
56 {
57 const wxClassInfo* pci = cti->GetClassInfo() ;
58 wxxVariant value = pi->GetAccessor()->GetProperty(obj) ;
59 WriteComponent( pci->VariantToInstance( value ) , pci , onode , pi->GetName() , nextId ,
60 ( cti->GetKind() == wxT_OBJECT ) , writtenObjects ) ;
61 }
62 else
63 {
64 const wxDelegateTypeInfo* dti = dynamic_cast< const wxDelegateTypeInfo* > ( pi->GetTypeInfo() ) ;
65 if ( dti )
66 {
67 // in which form should we stream out these ?
68 }
69 else
70 {
71 wxXmlNode *pnode;
72 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, pi->GetName() );
73 pi->GetAccessor()->WriteValue(pnode, obj ) ;
74 onode->AddChild(pnode);
75 }
76 }
77 }
78 pi = pi->GetNext() ;
79 }
80 const wxClassInfo** parents = ci->GetParents() ;
81 for ( int i = 0 ; parents[i] ; ++ i )
82 {
83 WriteComponentProperties( obj , parents[i] , onode , nextId , writtenObjects , writtenProperties ) ;
84 }
85 }
86
87 /*
88 Writing Components does have to take inheritance into account, that's why we are iterating
89 over our parents as well
90 */
91
92 void WriteComponent(wxObject *obj, const wxClassInfo *classInfo, wxXmlNode *parent, const wxString &nodeName)
93 {
94 int nextid = 0 ; // 0 is the root element
95 map< wxObject* , int > writtenobjects ;
96 WriteComponent( obj , classInfo, parent, nodeName , nextid , false , writtenobjects ) ;
97 }
98
99 void WriteComponent(wxObject *obj, const wxClassInfo *classInfo, wxXmlNode *parent, const wxString& nodeName , int &nextId, bool embeddedObject, map< wxObject* , int > &writtenObjects )
100 {
101 map< string , int > writtenProperties ;
102 wxXmlNode *onode;
103
104 onode = new wxXmlNode(wxXML_ELEMENT_NODE, nodeName);
105
106 onode->AddProperty(wxString("class"), wxString(classInfo->GetClassName()));
107 if ( obj == NULL )
108 {
109 wxXmlNode* nullnode = new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, "null");
110 onode->AddChild(nullnode);
111 }
112 else
113 {
114 // if we have already written this object, just insert an id
115 // embedded objects have to be written out fully always, their address will be reused and is not a valid key
116 if ( !embeddedObject && (writtenObjects.find( obj ) != writtenObjects.end()) )
117 {
118 onode->AddProperty(wxString("id"), wxString::Format( "%d" , writtenObjects[obj] ) );
119 }
120 else
121 {
122 int id = nextId++ ;
123 if ( !embeddedObject )
124 writtenObjects[obj] = id ;
125 onode->AddProperty(wxString("id"), wxString::Format( "%d" , id ) );
126 WriteComponentProperties( obj , classInfo , onode , nextId , writtenObjects, writtenProperties) ;
127 }
128 }
129
130 parent->AddChild(onode);
131 }
132
133 // ----------------------------------------------------------------------------
134 // reading objects in
135 // ----------------------------------------------------------------------------
136
137 struct wxReader::wxReaderInternal
138 {
139 map<int,wxClassInfo*> m_classInfos;
140 };
141
142 wxReader::wxReader()
143 {
144 m_data = new wxReaderInternal;
145 }
146
147 wxReader::~wxReader()
148 {
149 delete m_data;
150 }
151
152 wxClassInfo* wxReader::GetObjectClassInfo(int objectID)
153 {
154 assert( m_data->m_classInfos.find(objectID) != m_data->m_classInfos.end() );
155 return m_data->m_classInfos[objectID] ;
156 }
157
158 void wxReader::SetObjectClassInfo(int objectID, wxClassInfo *classInfo )
159 {
160 assert( m_data->m_classInfos.find(objectID) == m_data->m_classInfos.end() ) ;
161 m_data->m_classInfos[objectID] = classInfo ;
162 }
163
164 bool wxReader::HasObjectClassInfo( int objectID )
165 {
166 return m_data->m_classInfos.find(objectID) != m_data->m_classInfos.end() ;
167 }
168
169
170 // ----------------------------------------------------------------------------
171 // reading xml in
172 // ----------------------------------------------------------------------------
173
174 /*
175 Reading components has not to be extended for components
176 as properties are always sought by typeinfo over all levels
177 and create params are always toplevel class only
178 */
179
180 int wxXmlReader::ReadComponent(wxXmlNode *node, wxDepersister *callbacks)
181 {
182 wxString className;
183 wxClassInfo *classInfo;
184
185 wxxVariant *createParams ;
186 int *createParamOids ;
187 const wxClassInfo** createClassInfos ;
188 wxXmlNode *children;
189 int objectID;
190
191 children = node->GetChildren();
192 if (!node->GetPropVal("class", &className))
193 {
194 // No class name. Eek. FIXME: error handling
195 return wxInvalidObjectID;
196 }
197 classInfo = wxClassInfo::FindClass(className);
198 if (children && children->GetType() == wxXML_TEXT_NODE)
199 {
200 assert( wxXmlGetContentFromNode(node) == "null" ) ;
201 // this must be a NULL component reference. We just bail out
202 return wxNullObjectID;
203 }
204
205 wxString ObjectIdString ;
206 if (!node->GetPropVal("id", &ObjectIdString))
207 {
208 // No object id. Eek. FIXME: error handling
209 return wxInvalidObjectID;
210 }
211
212 objectID = atoi( ObjectIdString.c_str() ) ;
213 // is this object already has been streamed in, return it here
214 if ( HasObjectClassInfo( objectID ) )
215 return objectID ;
216
217 // new object, start with allocation
218 // first make the object know to our internal registry
219 SetObjectClassInfo( objectID , classInfo ) ;
220
221 callbacks->AllocateObject(objectID, classInfo);
222
223 //
224 // stream back the Create parameters first
225 createParams = new wxxVariant[ classInfo->GetCreateParamCount() ] ;
226 createParamOids = new int[classInfo->GetCreateParamCount() ] ;
227 createClassInfos = new const wxClassInfo*[classInfo->GetCreateParamCount() ] ;
228
229 typedef map<string, wxXmlNode *> PropertyNodes ;
230 typedef vector<string> PropertyNames ;
231
232 PropertyNodes propertyNodes ;
233 PropertyNames propertyNames ;
234
235 while( children )
236 {
237 propertyNames.push_back( children->GetName().c_str() ) ;
238 propertyNodes[children->GetName().c_str()] = children ;
239 children = children->GetNext() ;
240 }
241
242 for ( int i = 0 ; i <classInfo->GetCreateParamCount() ; ++i )
243 {
244 const wxChar* paramName = classInfo->GetCreateParamName(i) ;
245 PropertyNodes::iterator propiter = propertyNodes.find( paramName ) ;
246 const wxPropertyInfo* pi = classInfo->FindPropertyInfo( paramName ) ;
247 // if we don't have the value of a create param set in the xml
248 // we use the default value
249 if ( propiter != propertyNodes.end() )
250 {
251 wxXmlNode* prop = propiter->second ;
252 if ( pi->GetTypeInfo()->IsObjectType() )
253 {
254 createParamOids[i] = ReadComponent( prop , callbacks ) ;
255 createClassInfos[i] = dynamic_cast<const wxClassTypeInfo*>(pi->GetTypeInfo())->GetClassInfo() ;
256 }
257 else
258 {
259 createParamOids[i] = wxInvalidObjectID ;
260 createParams[i] = ReadValue( prop , pi->GetAccessor() ) ;
261 createClassInfos[i] = NULL ;
262 }
263
264 for ( size_t j = 0 ; j < propertyNames.size() ; ++j )
265 {
266 if ( propertyNames[j] == paramName )
267 {
268 propertyNames[j] = "" ;
269 break ;
270 }
271 }
272 }
273 else
274 {
275 createParams[i] = pi->GetDefaultValue() ;
276 }
277 }
278
279 // got the parameters. Call the Create method
280 callbacks->CreateObject(objectID, classInfo,
281 classInfo->GetCreateParamCount(),
282 createParams, createParamOids, createClassInfos);
283
284 // now stream in the rest of the properties, in the sequence their properties were written in the xml
285 for ( size_t j = 0 ; j < propertyNames.size() ; ++j )
286 {
287 if ( propertyNames[j].length() )
288 {
289 PropertyNodes::iterator propiter = propertyNodes.find( propertyNames[j] ) ;
290 if ( propiter != propertyNodes.end() )
291 {
292 wxXmlNode* prop = propiter->second ;
293 const wxPropertyInfo* pi = classInfo->FindPropertyInfo( propertyNames[j].c_str() ) ;
294 if ( pi->GetTypeInfo()->IsObjectType() )
295 {
296 int valueId = ReadComponent( prop , callbacks ) ;
297 if ( callbacks )
298 {
299 if ( valueId != wxInvalidObjectID )
300 {
301 callbacks->SetPropertyAsObject( objectID , classInfo , pi , valueId ) ;
302 if ( pi->GetTypeInfo()->GetKind() == wxT_OBJECT && valueId != wxNullObjectID )
303 callbacks->DestroyObject( valueId , GetObjectClassInfo( valueId ) ) ;
304 }
305 }
306 }
307 else if ( pi->GetTypeInfo()->IsDelegateType() )
308 {
309 wxString resstring = wxXmlGetContentFromNode(prop) ;
310 wxInt32 pos = resstring.Find('.') ;
311 assert( pos != wxNOT_FOUND ) ;
312 int sinkOid = atol(resstring.Left(pos)) ;
313 wxString handlerName = resstring.Mid(pos+1) ;
314 wxClassInfo* sinkClassInfo = GetObjectClassInfo( sinkOid ) ;
315
316 if (callbacks)
317 callbacks->SetConnect( objectID , classInfo , dynamic_cast<const wxDelegateTypeInfo*>(pi->GetTypeInfo()) , sinkClassInfo ,
318 sinkClassInfo->FindHandlerInfo(handlerName) , sinkOid ) ;
319
320 }
321 else
322 {
323 if ( callbacks )
324 callbacks->SetProperty( objectID, classInfo ,pi , ReadValue( prop , pi->GetAccessor() ) ) ;
325 }
326 }
327 }
328 }
329
330 delete[] createParams ;
331 delete[] createParamOids ;
332 delete[] createClassInfos ;
333
334 return objectID;
335 }
336
337 wxxVariant wxXmlReader::ReadValue(wxXmlNode *node,
338 wxPropertyAccessor *accessor )
339 {
340 return accessor->ReadValue(node) ;
341 }
342
343 int wxXmlReader::ReadObject(wxDepersister *callbacks)
344 {
345 return ReadComponent( m_parent , callbacks ) ;
346 }
347
348 // ----------------------------------------------------------------------------
349 // depersisting to memory
350 // ----------------------------------------------------------------------------
351
352 struct wxRuntimeDepersister::wxRuntimeDepersisterInternal
353 {
354 map<int,wxObject *> m_objects;
355
356 void SetObject(int objectID, wxObject *obj )
357 {
358 assert( m_objects.find(objectID) == m_objects.end() ) ;
359 m_objects[objectID] = obj ;
360 }
361 wxObject* GetObject( int objectID )
362 {
363 if ( objectID == wxNullObjectID )
364 return NULL ;
365
366 assert( m_objects.find(objectID) != m_objects.end() ) ;
367 return m_objects[objectID] ;
368 }
369 } ;
370
371 wxRuntimeDepersister::wxRuntimeDepersister()
372 {
373 m_data = new wxRuntimeDepersisterInternal() ;
374 }
375
376 wxRuntimeDepersister::~wxRuntimeDepersister()
377 {
378 delete m_data ;
379 }
380
381 void wxRuntimeDepersister::AllocateObject(int objectID, wxClassInfo *classInfo)
382 {
383 wxObject *O;
384 O = classInfo->CreateObject();
385 m_data->SetObject(objectID, O);
386 }
387
388 void wxRuntimeDepersister::CreateObject(int objectID,
389 const wxClassInfo *classInfo,
390 int paramCount,
391 wxxVariant *params,
392 int *objectIdValues,
393 const wxClassInfo **objectClassInfos)
394 {
395 wxObject *o;
396 o = m_data->GetObject(objectID);
397 for ( int i = 0 ; i < paramCount ; ++i )
398 {
399 if ( objectIdValues[i] != wxInvalidObjectID )
400 {
401 wxObject *o;
402 o = m_data->GetObject(objectIdValues[i]);
403 params[i] = objectClassInfos[i]->InstanceToVariant(o) ;
404 }
405 }
406 classInfo->Create(o, paramCount, params);
407 }
408
409 void wxRuntimeDepersister::DestroyObject(int objectID, wxClassInfo *WXUNUSED(classInfo))
410 {
411 wxObject *o;
412 o = m_data->GetObject(objectID);
413 delete o ;
414 }
415
416 void wxRuntimeDepersister::SetProperty(int objectID,
417 const wxClassInfo *WXUNUSED(classInfo),
418 const wxPropertyInfo* propertyInfo,
419 const wxxVariant &value)
420 {
421 wxObject *o;
422 o = m_data->GetObject(objectID);
423 propertyInfo->GetAccessor()->SetProperty( o , value ) ;
424 }
425
426 void wxRuntimeDepersister::SetPropertyAsObject(int objectID,
427 const wxClassInfo *WXUNUSED(classInfo),
428 const wxPropertyInfo* propertyInfo,
429 int valueObjectId)
430 {
431 wxObject *o, *valo;
432 o = m_data->GetObject(objectID);
433 valo = m_data->GetObject(valueObjectId);
434 propertyInfo->GetAccessor()->SetProperty( o ,
435 (dynamic_cast<const wxClassTypeInfo*>(propertyInfo->GetTypeInfo()))->GetClassInfo()->InstanceToVariant(valo) ) ;
436 }
437
438 void wxRuntimeDepersister::SetConnect(int eventSourceObjectID,
439 const wxClassInfo *WXUNUSED(eventSourceClassInfo),
440 const wxDelegateTypeInfo *delegateInfo ,
441 const wxClassInfo *WXUNUSED(eventSinkClassInfo) ,
442 const wxHandlerInfo* handlerInfo ,
443 int eventSinkObjectID )
444 {
445 wxWindow *ehsource = dynamic_cast< wxWindow* >( m_data->GetObject( eventSourceObjectID ) ) ;
446 wxEvtHandler *ehsink = dynamic_cast< wxEvtHandler *>(m_data->GetObject(eventSinkObjectID) ) ;
447
448 if ( ehsource && ehsink )
449 {
450 ehsource->Connect( ehsource->GetId() , delegateInfo->GetEventType() ,
451 handlerInfo->GetEventFunction() , NULL /*user data*/ ,
452 ehsink ) ;
453 }
454 }
455
456 wxObject *wxRuntimeDepersister::GetObject(int objectID)
457 {
458 return m_data->GetObject( objectID ) ;
459 }
460
461
462 // ----------------------------------------------------------------------------
463 // depersisting to code
464 // ----------------------------------------------------------------------------
465
466 struct wxCodeDepersister::wxCodeDepersisterInternal
467 {
468 map<int,string> m_objectNames ;
469
470 void SetObjectName(int objectID, const wxString &name )
471 {
472 assert( m_objectNames.find(objectID) == m_objectNames.end() ) ;
473 m_objectNames[objectID] = (const char *)name;
474 }
475 wxString GetObjectName( int objectID )
476 {
477 if ( objectID == wxNullObjectID )
478 return "NULL" ;
479
480 assert( m_objectNames.find(objectID) != m_objectNames.end() ) ;
481 return wxString( m_objectNames[objectID].c_str() ) ;
482 }
483 } ;
484
485 wxCodeDepersister::wxCodeDepersister(wxTextOutputStream *out)
486 : m_fp(out)
487 {
488 m_data = new wxCodeDepersisterInternal ;
489 }
490
491 wxCodeDepersister::~wxCodeDepersister()
492 {
493 delete m_data ;
494 }
495
496 void wxCodeDepersister::AllocateObject(int objectID, wxClassInfo *classInfo)
497 {
498 wxString objectName = wxString::Format( "LocalObject_%d" , objectID ) ;
499 m_fp->WriteString( wxString::Format( "\t%s *%s = new %s;\n",
500 classInfo->GetClassName(),
501 objectName,
502 classInfo->GetClassName()) );
503 m_data->SetObjectName( objectID , objectName ) ;
504 }
505
506 void wxCodeDepersister::DestroyObject(int objectID, wxClassInfo *WXUNUSED(classInfo))
507 {
508 m_fp->WriteString( wxString::Format( "\tdelete %s;\n",
509 m_data->GetObjectName( objectID) ) );
510 }
511
512 wxString wxCodeDepersister::ValueAsCode( const wxxVariant &param )
513 {
514 wxString value ;
515 const wxTypeInfo* type = param.GetTypeInfo() ;
516 if ( type->GetKind() == wxT_CUSTOM )
517 {
518 const wxCustomTypeInfo* cti = dynamic_cast<const wxCustomTypeInfo*>(type) ;
519 wxASSERT_MSG( cti , wxT("Internal error, illegal wxCustomTypeInfo") ) ;
520 value.Printf( "%s(%s)",cti->GetTypeName(),param.GetAsString() );
521 }
522 else if ( type->GetKind() == wxT_STRING )
523 {
524 value.Printf( "\"%s\"",param.GetAsString() );
525 }
526 else
527 {
528 value.Printf( "%s", param.GetAsString() );
529 }
530 return value ;
531 }
532
533 void wxCodeDepersister::CreateObject(int objectID,
534 const wxClassInfo *WXUNUSED(classInfo),
535 int paramCount,
536 wxxVariant *params,
537 int *objectIDValues,
538 const wxClassInfo **WXUNUSED(objectClassInfos)
539 )
540 {
541 int i;
542 m_fp->WriteString( wxString::Format( "\t%s->Create(", m_data->GetObjectName(objectID) ) );
543 for (i = 0; i < paramCount; i++)
544 {
545 if ( objectIDValues[i] != wxInvalidObjectID )
546 m_fp->WriteString( wxString::Format( "%s", m_data->GetObjectName( objectIDValues[i] ) ) );
547 else
548 {
549 m_fp->WriteString( wxString::Format( "%s", ValueAsCode(params[i]) ) );
550 }
551 if (i < paramCount - 1)
552 m_fp->WriteString( ", ");
553 }
554 m_fp->WriteString( ");\n");
555 }
556
557 void wxCodeDepersister::SetProperty(int objectID,
558 const wxClassInfo *WXUNUSED(classInfo),
559 const wxPropertyInfo* propertyInfo,
560 const wxxVariant &value)
561 {
562 m_fp->WriteString( wxString::Format( "\t%s->%s(%s);\n",
563 m_data->GetObjectName(objectID),
564 propertyInfo->GetAccessor()->GetSetterName(),
565 ValueAsCode(value)) );
566 }
567
568 void wxCodeDepersister::SetPropertyAsObject(int objectID,
569 const wxClassInfo *WXUNUSED(classInfo),
570 const wxPropertyInfo* propertyInfo,
571 int valueObjectId)
572 {
573 if ( propertyInfo->GetTypeInfo()->GetKind() == wxT_OBJECT )
574 m_fp->WriteString( wxString::Format( "\t%s->%s(*%s);\n",
575 m_data->GetObjectName(objectID),
576 propertyInfo->GetAccessor()->GetSetterName(),
577 m_data->GetObjectName( valueObjectId) ) );
578 else
579 m_fp->WriteString( wxString::Format( "\t%s->%s(%s);\n",
580 m_data->GetObjectName(objectID),
581 propertyInfo->GetAccessor()->GetSetterName(),
582 m_data->GetObjectName( valueObjectId) ) );
583 }
584
585 void wxCodeDepersister::SetConnect(int eventSourceObjectID,
586 const wxClassInfo *WXUNUSED(eventSourceClassInfo),
587 const wxDelegateTypeInfo *delegateInfo ,
588 const wxClassInfo *eventSinkClassInfo ,
589 const wxHandlerInfo* handlerInfo ,
590 int eventSinkObjectID )
591 {
592 wxString ehsource = m_data->GetObjectName( eventSourceObjectID ) ;
593 wxString ehsink = m_data->GetObjectName(eventSinkObjectID) ;
594 wxString ehsinkClass = eventSinkClassInfo->GetClassName() ;
595 int eventType = delegateInfo->GetEventType() ;
596 wxString handlerName = handlerInfo->GetName() ;
597
598 m_fp->WriteString( wxString::Format( "\t%s->Connect( %s->GetId() , %d , (wxObjectEventFunction)(wxEventFunction) & %s::%s , NULL , %s ) ;" ,
599 ehsource , ehsource , eventType , ehsinkClass , handlerName , ehsink ) );
600 }
601
602 #endif