1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/xtistrm.cpp
3 // Purpose: streaming runtime metadata information
4 // Author: Stefan Csomor
8 // Copyright: (c) 2003 Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "xtistrm.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
25 #include "wx/object.h"
28 #include "wx/xml/xml.h"
29 #include "wx/tokenzr.h"
30 #include "wx/xtistrm.h"
31 #include "wx/txtstrm.h"
33 #if wxUSE_EXTENDED_RTTI
40 // ----------------------------------------------------------------------------
42 // ----------------------------------------------------------------------------
44 void WriteComponent(wxObject
*Object
, const wxClassInfo
*classInfo
, wxXmlNode
*parent
, const wxString
& nodeName
, int &nextId
, bool embeddedObject
, map
< wxObject
* , int > &writtenObjects
) ;
46 void WriteComponentProperties( wxObject
* obj
, const wxClassInfo
* ci
, wxXmlNode
*onode
, int &nextId
, map
< wxObject
* , int > &writtenObjects
, map
< string
, int > &writtenProperties
)
48 const wxPropertyInfo
*pi
= ci
->GetFirstProperty() ;
51 if ( writtenProperties
.find( pi
->GetName() ) == writtenProperties
.end() )
53 writtenProperties
[ pi
->GetName() ] = 1 ;
54 const wxClassTypeInfo
* cti
= dynamic_cast< const wxClassTypeInfo
* > ( pi
->GetTypeInfo() ) ;
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
) ;
64 const wxDelegateTypeInfo
* dti
= dynamic_cast< const wxDelegateTypeInfo
* > ( pi
->GetTypeInfo() ) ;
67 // in which form should we stream out these ?
72 pnode
= new wxXmlNode(wxXML_ELEMENT_NODE
, pi
->GetName() );
73 pi
->GetAccessor()->WriteValue(pnode
, obj
) ;
74 onode
->AddChild(pnode
);
80 const wxClassInfo
** parents
= ci
->GetParents() ;
81 for ( int i
= 0 ; parents
[i
] ; ++ i
)
83 WriteComponentProperties( obj
, parents
[i
] , onode
, nextId
, writtenObjects
, writtenProperties
) ;
88 Writing Components does have to take inheritance into account, that's why we are iterating
89 over our parents as well
92 void WriteComponent(wxObject
*obj
, const wxClassInfo
*classInfo
, wxXmlNode
*parent
, const wxString
&nodeName
)
94 int nextid
= 0 ; // 0 is the root element
95 map
< wxObject
* , int > writtenobjects
;
96 WriteComponent( obj
, classInfo
, parent
, nodeName
, nextid
, false , writtenobjects
) ;
99 void WriteComponent(wxObject
*obj
, const wxClassInfo
*classInfo
, wxXmlNode
*parent
, const wxString
& nodeName
, int &nextId
, bool embeddedObject
, map
< wxObject
* , int > &writtenObjects
)
101 map
< string
, int > writtenProperties
;
104 onode
= new wxXmlNode(wxXML_ELEMENT_NODE
, nodeName
);
106 onode
->AddProperty(wxString("class"), wxString(classInfo
->GetClassName()));
109 wxXmlNode
* nullnode
= new wxXmlNode(wxXML_TEXT_NODE
, wxEmptyString
, "null");
110 onode
->AddChild(nullnode
);
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()) )
118 onode
->AddProperty(wxString("id"), wxString::Format( "%d" , writtenObjects
[obj
] ) );
123 if ( !embeddedObject
)
124 writtenObjects
[obj
] = id
;
125 onode
->AddProperty(wxString("id"), wxString::Format( "%d" , id
) );
126 WriteComponentProperties( obj
, classInfo
, onode
, nextId
, writtenObjects
, writtenProperties
) ;
130 parent
->AddChild(onode
);
133 // ----------------------------------------------------------------------------
134 // reading objects in
135 // ----------------------------------------------------------------------------
137 struct wxReader::wxReaderInternal
139 map
<int,wxClassInfo
*> m_classInfos
;
144 m_data
= new wxReaderInternal
;
147 wxReader::~wxReader()
152 wxClassInfo
* wxReader::GetObjectClassInfo(int objectID
)
154 assert( m_data
->m_classInfos
.find(objectID
) != m_data
->m_classInfos
.end() );
155 return m_data
->m_classInfos
[objectID
] ;
158 void wxReader::SetObjectClassInfo(int objectID
, wxClassInfo
*classInfo
)
160 assert( m_data
->m_classInfos
.find(objectID
) == m_data
->m_classInfos
.end() ) ;
161 m_data
->m_classInfos
[objectID
] = classInfo
;
164 bool wxReader::HasObjectClassInfo( int objectID
)
166 return m_data
->m_classInfos
.find(objectID
) != m_data
->m_classInfos
.end() ;
170 // ----------------------------------------------------------------------------
172 // ----------------------------------------------------------------------------
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
180 int wxXmlReader::ReadComponent(wxXmlNode
*node
, wxDepersister
*callbacks
)
183 wxClassInfo
*classInfo
;
185 wxxVariant
*createParams
;
186 int *createParamOids
;
187 const wxClassInfo
** createClassInfos
;
191 children
= node
->GetChildren();
192 if (!node
->GetPropVal("class", &className
))
194 // No class name. Eek. FIXME: error handling
195 return wxInvalidObjectID
;
197 classInfo
= wxClassInfo::FindClass(className
);
198 if (children
&& children
->GetType() == wxXML_TEXT_NODE
)
200 assert( wxXmlGetContentFromNode(node
) == "null" ) ;
201 // this must be a NULL component reference. We just bail out
202 return wxNullObjectID
;
205 wxString ObjectIdString
;
206 if (!node
->GetPropVal("id", &ObjectIdString
))
208 // No object id. Eek. FIXME: error handling
209 return wxInvalidObjectID
;
212 objectID
= atoi( ObjectIdString
.c_str() ) ;
213 // is this object already has been streamed in, return it here
214 if ( HasObjectClassInfo( objectID
) )
217 // new object, start with allocation
218 // first make the object know to our internal registry
219 SetObjectClassInfo( objectID
, classInfo
) ;
221 callbacks
->AllocateObject(objectID
, classInfo
);
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() ] ;
229 typedef map
<string
, wxXmlNode
*> PropertyNodes
;
230 typedef vector
<string
> PropertyNames
;
232 PropertyNodes propertyNodes
;
233 PropertyNames propertyNames
;
237 propertyNames
.push_back( children
->GetName().c_str() ) ;
238 propertyNodes
[children
->GetName().c_str()] = children
;
239 children
= children
->GetNext() ;
242 for ( int i
= 0 ; i
<classInfo
->GetCreateParamCount() ; ++i
)
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() )
251 wxXmlNode
* prop
= propiter
->second
;
252 if ( pi
->GetTypeInfo()->IsObjectType() )
254 createParamOids
[i
] = ReadComponent( prop
, callbacks
) ;
255 createClassInfos
[i
] = dynamic_cast<const wxClassTypeInfo
*>(pi
->GetTypeInfo())->GetClassInfo() ;
259 createParamOids
[i
] = wxInvalidObjectID
;
260 createParams
[i
] = ReadValue( prop
, pi
->GetAccessor() ) ;
261 createClassInfos
[i
] = NULL
;
264 for ( size_t j
= 0 ; j
< propertyNames
.size() ; ++j
)
266 if ( propertyNames
[j
] == paramName
)
268 propertyNames
[j
] = "" ;
275 createParams
[i
] = pi
->GetDefaultValue() ;
279 // got the parameters. Call the Create method
280 callbacks
->CreateObject(objectID
, classInfo
,
281 classInfo
->GetCreateParamCount(),
282 createParams
, createParamOids
, createClassInfos
);
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
)
287 if ( propertyNames
[j
].length() )
289 PropertyNodes::iterator propiter
= propertyNodes
.find( propertyNames
[j
] ) ;
290 if ( propiter
!= propertyNodes
.end() )
292 wxXmlNode
* prop
= propiter
->second
;
293 const wxPropertyInfo
* pi
= classInfo
->FindPropertyInfo( propertyNames
[j
].c_str() ) ;
294 if ( pi
->GetTypeInfo()->IsObjectType() )
296 int valueId
= ReadComponent( prop
, callbacks
) ;
299 if ( valueId
!= wxInvalidObjectID
)
301 callbacks
->SetPropertyAsObject( objectID
, classInfo
, pi
, valueId
) ;
302 if ( pi
->GetTypeInfo()->GetKind() == wxT_OBJECT
&& valueId
!= wxNullObjectID
)
303 callbacks
->DestroyObject( valueId
, GetObjectClassInfo( valueId
) ) ;
307 else if ( pi
->GetTypeInfo()->IsDelegateType() )
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
) ;
317 callbacks
->SetConnect( objectID
, classInfo
, dynamic_cast<const wxDelegateTypeInfo
*>(pi
->GetTypeInfo()) , sinkClassInfo
,
318 sinkClassInfo
->FindHandlerInfo(handlerName
) , sinkOid
) ;
324 callbacks
->SetProperty( objectID
, classInfo
,pi
, ReadValue( prop
, pi
->GetAccessor() ) ) ;
330 delete[] createParams
;
331 delete[] createParamOids
;
332 delete[] createClassInfos
;
337 wxxVariant
wxXmlReader::ReadValue(wxXmlNode
*node
,
338 wxPropertyAccessor
*accessor
)
340 return accessor
->ReadValue(node
) ;
343 int wxXmlReader::ReadObject(wxDepersister
*callbacks
)
345 return ReadComponent( m_parent
, callbacks
) ;
348 // ----------------------------------------------------------------------------
349 // depersisting to memory
350 // ----------------------------------------------------------------------------
352 struct wxRuntimeDepersister::wxRuntimeDepersisterInternal
354 map
<int,wxObject
*> m_objects
;
356 void SetObject(int objectID
, wxObject
*obj
)
358 assert( m_objects
.find(objectID
) == m_objects
.end() ) ;
359 m_objects
[objectID
] = obj
;
361 wxObject
* GetObject( int objectID
)
363 if ( objectID
== wxNullObjectID
)
366 assert( m_objects
.find(objectID
) != m_objects
.end() ) ;
367 return m_objects
[objectID
] ;
371 wxRuntimeDepersister::wxRuntimeDepersister()
373 m_data
= new wxRuntimeDepersisterInternal() ;
376 wxRuntimeDepersister::~wxRuntimeDepersister()
381 void wxRuntimeDepersister::AllocateObject(int objectID
, wxClassInfo
*classInfo
)
384 O
= classInfo
->CreateObject();
385 m_data
->SetObject(objectID
, O
);
388 void wxRuntimeDepersister::CreateObject(int objectID
,
389 const wxClassInfo
*classInfo
,
393 const wxClassInfo
**objectClassInfos
)
396 o
= m_data
->GetObject(objectID
);
397 for ( int i
= 0 ; i
< paramCount
; ++i
)
399 if ( objectIdValues
[i
] != wxInvalidObjectID
)
402 o
= m_data
->GetObject(objectIdValues
[i
]);
403 params
[i
] = objectClassInfos
[i
]->InstanceToVariant(o
) ;
406 classInfo
->Create(o
, paramCount
, params
);
409 void wxRuntimeDepersister::DestroyObject(int objectID
, wxClassInfo
*WXUNUSED(classInfo
))
412 o
= m_data
->GetObject(objectID
);
416 void wxRuntimeDepersister::SetProperty(int objectID
,
417 const wxClassInfo
*WXUNUSED(classInfo
),
418 const wxPropertyInfo
* propertyInfo
,
419 const wxxVariant
&value
)
422 o
= m_data
->GetObject(objectID
);
423 propertyInfo
->GetAccessor()->SetProperty( o
, value
) ;
426 void wxRuntimeDepersister::SetPropertyAsObject(int objectID
,
427 const wxClassInfo
*WXUNUSED(classInfo
),
428 const wxPropertyInfo
* propertyInfo
,
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
) ) ;
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
)
445 wxWindow
*ehsource
= dynamic_cast< wxWindow
* >( m_data
->GetObject( eventSourceObjectID
) ) ;
446 wxEvtHandler
*ehsink
= dynamic_cast< wxEvtHandler
*>(m_data
->GetObject(eventSinkObjectID
) ) ;
448 if ( ehsource
&& ehsink
)
450 ehsource
->Connect( ehsource
->GetId() , delegateInfo
->GetEventType() ,
451 handlerInfo
->GetEventFunction() , NULL
/*user data*/ ,
456 wxObject
*wxRuntimeDepersister::GetObject(int objectID
)
458 return m_data
->GetObject( objectID
) ;
462 // ----------------------------------------------------------------------------
463 // depersisting to code
464 // ----------------------------------------------------------------------------
466 struct wxCodeDepersister::wxCodeDepersisterInternal
468 map
<int,string
> m_objectNames
;
470 void SetObjectName(int objectID
, const wxString
&name
)
472 assert( m_objectNames
.find(objectID
) == m_objectNames
.end() ) ;
473 m_objectNames
[objectID
] = (const char *)name
;
475 wxString
GetObjectName( int objectID
)
477 if ( objectID
== wxNullObjectID
)
480 assert( m_objectNames
.find(objectID
) != m_objectNames
.end() ) ;
481 return wxString( m_objectNames
[objectID
].c_str() ) ;
485 wxCodeDepersister::wxCodeDepersister(wxTextOutputStream
*out
)
488 m_data
= new wxCodeDepersisterInternal
;
491 wxCodeDepersister::~wxCodeDepersister()
496 void wxCodeDepersister::AllocateObject(int objectID
, wxClassInfo
*classInfo
)
498 wxString objectName
= wxString::Format( "LocalObject_%d" , objectID
) ;
499 m_fp
->WriteString( wxString::Format( "\t%s *%s = new %s;\n",
500 classInfo
->GetClassName(),
502 classInfo
->GetClassName()) );
503 m_data
->SetObjectName( objectID
, objectName
) ;
506 void wxCodeDepersister::DestroyObject(int objectID
, wxClassInfo
*WXUNUSED(classInfo
))
508 m_fp
->WriteString( wxString::Format( "\tdelete %s;\n",
509 m_data
->GetObjectName( objectID
) ) );
512 wxString
wxCodeDepersister::ValueAsCode( const wxxVariant
¶m
)
515 const wxTypeInfo
* type
= param
.GetTypeInfo() ;
516 if ( type
->GetKind() == wxT_CUSTOM
)
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() );
522 else if ( type
->GetKind() == wxT_STRING
)
524 value
.Printf( "\"%s\"",param
.GetAsString() );
528 value
.Printf( "%s", param
.GetAsString() );
533 void wxCodeDepersister::CreateObject(int objectID
,
534 const wxClassInfo
*WXUNUSED(classInfo
),
538 const wxClassInfo
**WXUNUSED(objectClassInfos
)
542 m_fp
->WriteString( wxString::Format( "\t%s->Create(", m_data
->GetObjectName(objectID
) ) );
543 for (i
= 0; i
< paramCount
; i
++)
545 if ( objectIDValues
[i
] != wxInvalidObjectID
)
546 m_fp
->WriteString( wxString::Format( "%s", m_data
->GetObjectName( objectIDValues
[i
] ) ) );
549 m_fp
->WriteString( wxString::Format( "%s", ValueAsCode(params
[i
]) ) );
551 if (i
< paramCount
- 1)
552 m_fp
->WriteString( ", ");
554 m_fp
->WriteString( ");\n");
557 void wxCodeDepersister::SetProperty(int objectID
,
558 const wxClassInfo
*WXUNUSED(classInfo
),
559 const wxPropertyInfo
* propertyInfo
,
560 const wxxVariant
&value
)
562 m_fp
->WriteString( wxString::Format( "\t%s->%s(%s);\n",
563 m_data
->GetObjectName(objectID
),
564 propertyInfo
->GetAccessor()->GetSetterName(),
565 ValueAsCode(value
)) );
568 void wxCodeDepersister::SetPropertyAsObject(int objectID
,
569 const wxClassInfo
*WXUNUSED(classInfo
),
570 const wxPropertyInfo
* propertyInfo
,
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
) ) );
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
) ) );
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
)
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() ;
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
) );