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
, 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 WriteComponent( pci
->VariantToInstance( pi
->GetAccessor()->GetProperty(obj
) ) , pci
, onode
, pi
->GetName() , nextId
, writtenObjects
) ;
62 const wxDelegateTypeInfo
* dti
= dynamic_cast< const wxDelegateTypeInfo
* > ( pi
->GetTypeInfo() ) ;
65 // in which form should we stream out these ?
70 pnode
= new wxXmlNode(wxXML_ELEMENT_NODE
, pi
->GetName() );
71 pi
->GetAccessor()->WriteValue(pnode
, obj
) ;
72 onode
->AddChild(pnode
);
78 const wxClassInfo
** parents
= ci
->GetParents() ;
79 for ( int i
= 0 ; parents
[i
] ; ++ i
)
81 WriteComponentProperties( obj
, parents
[i
] , onode
, nextId
, writtenObjects
, writtenProperties
) ;
86 Writing Components does have to take inheritance into account, that's why we are iterating
87 over our parents as well
90 void WriteComponent(wxObject
*obj
, const wxClassInfo
*classInfo
, wxXmlNode
*parent
, const wxString
&nodeName
)
92 int nextid
= 0 ; // 0 is the root element
93 map
< wxObject
* , int > writtenobjects
;
94 WriteComponent( obj
, classInfo
, parent
, nodeName
, nextid
, writtenobjects
) ;
97 void WriteComponent(wxObject
*obj
, const wxClassInfo
*classInfo
, wxXmlNode
*parent
, const wxString
& nodeName
, int &nextId
, map
< wxObject
* , int > &writtenObjects
)
99 map
< string
, int > writtenProperties
;
102 onode
= new wxXmlNode(wxXML_ELEMENT_NODE
, nodeName
);
104 onode
->AddProperty(wxString("class"), wxString(classInfo
->GetClassName()));
107 wxXmlNode
* nullnode
= new wxXmlNode(wxXML_TEXT_NODE
, wxEmptyString
, "null");
108 onode
->AddChild(nullnode
);
112 // if we have already written this object, just insert an id
113 if ( writtenObjects
.find( obj
) != writtenObjects
.end() )
115 onode
->AddProperty(wxString("id"), wxString::Format( "%d" , writtenObjects
[obj
] ) );
120 writtenObjects
[obj
] = id
;
121 onode
->AddProperty(wxString("id"), wxString::Format( "%d" , id
) );
122 WriteComponentProperties( obj
, classInfo
, onode
, nextId
, writtenObjects
, writtenProperties
) ;
126 parent
->AddChild(onode
);
129 // ----------------------------------------------------------------------------
131 // ----------------------------------------------------------------------------
133 wxxVariant
wxReader::ReadPropertyValueNoAssign(wxXmlNode
*Node
,
134 wxClassInfo
*ClassInfo
,
135 const wxPropertyInfo
* &pi
,
136 wxIDepersist
*Callbacks
)
142 // <propname type=foo>value</propname>
144 //ISSUE: NULL component references are streamed out as "null" text
145 // node. This is not in keeping with the XML mindset.
147 pi
= ClassInfo
->FindPropertyInfo(Node
->GetName());
150 // error handling, please
151 assert(!"Property not found in extended class info");
154 const wxClassTypeInfo
* cti
= dynamic_cast< const wxClassTypeInfo
* > ( pi
->GetTypeInfo() ) ;
157 const wxClassInfo
* eci
= cti
->GetClassInfo() ;
159 ChildID
= ReadComponent(Node
, Callbacks
);
163 res
= wxxVariant(GetObjectName(ChildID
));
165 res
= eci
->InstanceToVariant(GetObject(ChildID
));
170 res
= wxxVariant(wxString("NULL"));
172 res
= eci
->InstanceToVariant(NULL
);
177 const wxDelegateTypeInfo
* dti
= dynamic_cast< const wxDelegateTypeInfo
* > ( pi
->GetTypeInfo() ) ;
182 // in which form should we code these ?
183 res
= wxxVariant( wxXmlGetContentFromNode(Node
) ) ;
187 res
= wxxVariant( wxXmlGetContentFromNode(Node
) ) ;
194 if ( pi
->GetTypeInfo()->GetKind() == wxT_STRING
)
195 res
= wxxVariant( wxString::Format("wxString(\"%s\")",wxXmlGetContentFromNode(Node
)));
197 res
= wxxVariant( wxString::Format("%s(%s)",pi
->GetTypeName(),wxXmlGetContentFromNode(Node
) ) );
200 res
= pi
->GetAccessor()->ReadValue(Node
) ;
206 void wxReader::ReadPropertyValue(wxXmlNode
*Node
,
207 wxClassInfo
*ClassInfo
,
209 wxIDepersist
*Callbacks
)
211 const wxPropertyInfo
*pi
;
212 wxxVariant res
= ReadPropertyValueNoAssign( Node
, ClassInfo
, pi
, Callbacks
) ;
214 const wxDelegateTypeInfo
* dti
= dynamic_cast< const wxDelegateTypeInfo
* > ( pi
->GetTypeInfo() ) ;
218 wxString resstring
= res
.Get
<wxString
>() ;
219 wxInt32 pos
= resstring
.Find('.') ;
220 assert( pos
!= wxNOT_FOUND
) ;
221 int handlerOid
= atol(resstring
.Left(pos
)) ;
222 wxString handlerName
= resstring
.Mid(pos
+1) ;
225 Callbacks
->SetConnect( ObjectID
, ClassInfo
, dti
->GetEventType() , handlerName
, handlerOid
) ;
230 Callbacks
->SetProperty(ObjectID
, ClassInfo
, pi
, res
);
234 struct wxReader::wxReaderInternal
237 Code streamer will be storing names here. Runtime object streamer
238 will be storing actual pointers to objects here. The two are never
239 mixed. So the Objects array either has data, or the ObjectNames
240 array has data. Never both. Keyed by ObjectID (int)
242 map
<int,wxObject
*> Objects
;
244 map
<int,string
> ObjectNames
;
245 // only used when generating code, since the names loose the type info
246 map
<int,wxClassInfo
*> ObjectClasses
;
249 wxReader::wxReader(bool GenerateCode
) : genCode(GenerateCode
)
251 Data
= new wxReaderInternal
;
254 wxReader::~wxReader()
259 wxObject
*wxReader::GetObject(int id
)
261 assert( Data
->Objects
.find(id
) != Data
->Objects
.end() );
262 return Data
->Objects
[id
];
265 wxString
wxReader::GetObjectName(int id
)
267 assert( Data
->ObjectNames
.find(id
) != Data
->ObjectNames
.end() );
268 return wxString(Data
->ObjectNames
[id
].c_str());
271 wxClassInfo
* wxReader::GetObjectClassInfo(int id
)
273 assert( Data
->ObjectClasses
.find(id
) != Data
->ObjectClasses
.end() );
274 return Data
->ObjectClasses
[id
] ;
277 void wxReader::SetObject(int id
, wxObject
*Object
)
279 assert( Data
->Objects
.find(id
) == Data
->Objects
.end() ) ;
280 Data
->Objects
[id
] = Object
;
283 void wxReader::SetObjectName(int id
, const wxString
&Name
, wxClassInfo
*ClassInfo
)
285 assert( Data
->ObjectNames
.find(id
) == Data
->ObjectNames
.end() ) ;
286 Data
->ObjectNames
[id
] = (const char *)Name
;
287 Data
->ObjectClasses
[id
] = ClassInfo
;
291 Reading components has not to be extended for components
292 as properties are always sought by typeinfo over all levels
293 and create params are always toplevel class only
296 int wxReader::ReadComponent(wxXmlNode
*Node
, wxIDepersist
*Callbacks
)
299 wxClassInfo
*ClassInfo
;
301 wxxVariant
*CreateParams
;
305 Callbacks
->NotifyReader(this);
307 Children
= Node
->GetChildren();
308 if (!Node
->GetPropVal("class", &ClassName
))
310 // No class name. Eek. FIXME: error handling
313 ClassInfo
= wxClassInfo::FindClass(ClassName
);
314 if (Node
->GetType() == wxXML_TEXT_NODE
)
316 assert( wxXmlGetContentFromNode(Node
) == "null" ) ;
317 // this must be a NULL component reference. We just bail out
321 wxString ObjectIdString
;
322 if (!Node
->GetPropVal("id", &ObjectIdString
))
324 // No object id. Eek. FIXME: error handling
328 ObjectID
= atoi( ObjectIdString
.c_str() ) ;
329 // is this object already has been streamed in, return it here
332 if ( Data
->ObjectNames
.find( ObjectID
) != Data
->ObjectNames
.end() )
337 if ( Data
->Objects
.find( ObjectID
) != Data
->Objects
.end() )
341 // new object, start with allocation
342 Callbacks
->AllocateObject(ObjectID
, ClassInfo
);
345 // stream back the Create parameters first
346 CreateParams
= new wxxVariant
[ ClassInfo
->GetCreateParamCount() ] ;
348 typedef map
<string
, wxXmlNode
*> PropertyNodes
;
349 typedef vector
<string
> PropertyNames
;
351 PropertyNodes propertyNodes
;
352 PropertyNames propertyNames
;
356 propertyNames
.push_back( Children
->GetName().c_str() ) ;
357 propertyNodes
[Children
->GetName().c_str()] = Children
;
358 Children
= Children
->GetNext() ;
361 for ( int i
= 0 ; i
<ClassInfo
->GetCreateParamCount() ; ++i
)
363 const wxChar
* paramName
= ClassInfo
->GetCreateParamName(i
) ;
364 PropertyNodes::iterator propiter
= propertyNodes
.find( paramName
) ;
365 // if we don't have the value of a create param set in the xml
366 // we use the default value
367 if ( propiter
!= propertyNodes
.end() )
369 wxXmlNode
* prop
= propiter
->second
;
371 CreateParams
[i
] = ReadPropertyValueNoAssign( prop
, ClassInfo
, pi
, Callbacks
) ;
372 // CreateParams[i] = ClassInfo->FindPropertyInfo( ClassInfo->GetCreateParamName(i) ->GetAccessor()->ReadValue( prop ) ;
373 for ( size_t j
= 0 ; j
< propertyNames
.size() ; ++j
)
375 if ( propertyNames
[j
] == paramName
)
377 propertyNames
[j
] = "" ;
384 CreateParams
[i
] = ClassInfo
->FindPropertyInfo( paramName
)->GetDefaultValue() ;
388 // got the parameters. Call the Create method
389 Callbacks
->CreateObject(ObjectID
,
391 ClassInfo
->GetCreateParamCount(),
394 // now stream in the rest of the properties, in the sequence their properties were written in the xml
395 for ( size_t j
= 0 ; j
< propertyNames
.size() ; ++j
)
397 if ( propertyNames
[j
].length() )
399 PropertyNodes::iterator propiter
= propertyNodes
.find( propertyNames
[j
] ) ;
400 if ( propiter
!= propertyNodes
.end() )
402 wxXmlNode
* prop
= propiter
->second
;
403 string name
= propiter
->first
;
404 ReadPropertyValue( prop
, ClassInfo
, ObjectID
, Callbacks
) ;
409 for( PropertyNodes::iterator propiter = propertyNodes.begin() ; propiter != propertyNodes.end() ; propiter++ )
411 wxXmlNode* prop = propiter->second ;
412 string name = propiter->first ;
413 ReadPropertyValue( prop , ClassInfo , ObjectID , Callbacks ) ;
417 // FIXME: if the list of children is not NULL now, then that means that
418 // there were properties in the XML not represented in the meta data
419 // this just needs error handling.
422 delete[] CreateParams
;
427 // ----------------------------------------------------------------------------
428 // depersisting to memory
429 // ----------------------------------------------------------------------------
431 void wxIDepersistRuntime::AllocateObject(int ObjectID
, wxClassInfo
*ClassInfo
)
434 O
= ClassInfo
->CreateObject();
435 Reader
->SetObject(ObjectID
, O
);
438 void wxIDepersistRuntime::CreateObject(int ObjectID
,
439 wxClassInfo
*ClassInfo
,
444 O
= Reader
->GetObject(ObjectID
);
445 ClassInfo
->Create(O
, ParamCount
, Params
);
448 void wxIDepersistRuntime::SetProperty(int ObjectID
,
449 wxClassInfo
*WXUNUSED(ClassInfo
),
450 const wxPropertyInfo
* PropertyInfo
,
451 const wxxVariant
&Value
)
454 O
= Reader
->GetObject(ObjectID
);
455 PropertyInfo
->GetAccessor()->SetProperty( O
, Value
) ;
458 void wxIDepersistRuntime::SetConnect(int EventSourceObjectID
,
459 wxClassInfo
*WXUNUSED(EventSourceClassInfo
),
461 const wxString
&handlerName
,
462 int EventSinkObjectID
)
464 wxWindow
*ehsource
= dynamic_cast< wxWindow
* >( Reader
->GetObject( EventSourceObjectID
) ) ;
465 wxEvtHandler
*ehsink
= dynamic_cast< wxEvtHandler
*>(Reader
->GetObject(EventSinkObjectID
) ) ;
467 if ( ehsource
&& ehsink
)
469 ehsource
->Connect( ehsource
->GetId() , eventType
,
470 ehsink
->GetClassInfo()->FindHandlerInfo(handlerName
)->GetEventFunction() , NULL
/*user data*/ ,
475 // ----------------------------------------------------------------------------
476 // depersisting to code
477 // ----------------------------------------------------------------------------
480 void wxIDepersistCode::AllocateObject(int ObjectID
, wxClassInfo
*ClassInfo
)
482 wxString objectName
= wxString::Format( "LocalObject_%d" , ObjectID
) ;
483 fp
->WriteString( wxString::Format( "\t%s *%s = new %s;\n",
484 ClassInfo
->GetClassName(),
486 ClassInfo
->GetClassName()) );
487 Reader
->SetObjectName(ObjectID
, objectName
, ClassInfo
);
490 void wxIDepersistCode::CreateObject(int ObjectID
,
491 wxClassInfo
*WXUNUSED(ClassInfo
),
496 fp
->WriteString( wxString::Format( "\t%s->Create(", Reader
->GetObjectName(ObjectID
) ) );
497 for (i
= 0; i
< ParamCount
; i
++)
499 fp
->WriteString( wxString::Format( "%s", (const char *)Params
[i
].Get
<wxString
>() ) );
500 if (i
< ParamCount
- 1)
501 fp
->WriteString( ", ");
503 fp
->WriteString( ");\n");
506 void wxIDepersistCode::SetProperty(int ObjectID
,
507 wxClassInfo
*WXUNUSED(ClassInfo
),
508 const wxPropertyInfo
* PropertyInfo
,
509 const wxxVariant
&Value
)
511 wxString d
= Value
.Get
<wxString
>() ;
512 fp
->WriteString( wxString::Format( "\t%s->%s(%s);\n",
513 Reader
->GetObjectName(ObjectID
),
514 PropertyInfo
->GetAccessor()->GetSetterName(),
518 void wxIDepersistCode::SetConnect(int EventSourceObjectID
,
519 wxClassInfo
*WXUNUSED(EventSourceClassInfo
),
521 const wxString
&handlerName
,
522 int EventSinkObjectID
)
524 wxString ehsource
= Reader
->GetObjectName( EventSourceObjectID
) ;
525 wxString ehsink
= Reader
->GetObjectName(EventSinkObjectID
) ;
526 wxString ehsinkClass
= Reader
->GetObjectClassInfo(EventSinkObjectID
)->GetClassName() ;
528 fp
->WriteString( wxString::Format( "\t%s->Connect( %s->GetId() , %d , (wxObjectEventFunction)(wxEventFunction) & %s::%s , NULL , %s ) ;" ,
529 ehsource
, ehsource
, eventType
, ehsinkClass
, handlerName
, ehsink
) );