]> git.saurik.com Git - wxWidgets.git/blame - src/common/xtixml.cpp
wxHashMap does not take the key type as constructor argument.
[wxWidgets.git] / src / common / xtixml.cpp
CommitLineData
9c8046dd
SC
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/common/xtistrm.cpp
2abce515 3// Purpose: streaming runtime metadata information
9c8046dd 4// Author: Stefan Csomor
2abce515 5// Modified by:
9c8046dd
SC
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"
9c8046dd
SC
30#include "wx/txtstrm.h"
31#include "wx/event.h"
32
33#if wxUSE_EXTENDED_RTTI
34
8347b97a
SC
35#include "wx/xtistrm.h"
36#include "wx/xtixml.h"
37
9c8046dd
SC
38#include "wx/beforestd.h"
39#include <map>
40#include <vector>
41#include <string>
42#include "wx/afterstd.h"
43
44using namespace std ;
45
46//
47// XML Streaming
2abce515 48//
9c8046dd
SC
49
50// convenience functions
51
52void wxXmlAddContentToNode( wxXmlNode* node , const wxString& data )
53{
63691d4f 54 node->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxT("value"), data ) );
9c8046dd
SC
55}
56
57wxString wxXmlGetContentFromNode( wxXmlNode *node )
58{
59 if ( node->GetChildren() )
60 return node->GetChildren()->GetContent() ;
61 else
62 return wxEmptyString ;
63}
64
65struct wxXmlWriter::wxXmlWriterInternal
66{
67 wxXmlNode *m_root ;
68 wxXmlNode *m_current ;
69 vector< wxXmlNode * > m_objectStack ;
70
71 void Push( wxXmlNode *newCurrent )
72 {
73 m_objectStack.push_back( m_current ) ;
74 m_current = newCurrent ;
75 }
76
77 void Pop()
78 {
79 m_current = m_objectStack.back() ;
80 m_objectStack.pop_back() ;
81 }
82} ;
83
2abce515 84wxXmlWriter::wxXmlWriter( wxXmlNode * rootnode )
9c8046dd
SC
85{
86 m_data = new wxXmlWriterInternal() ;
87 m_data->m_root = rootnode ;
88 m_data->m_current = rootnode ;
89}
90
2abce515 91wxXmlWriter::~wxXmlWriter()
9c8046dd
SC
92{
93 delete m_data ;
94}
95
2abce515 96void wxXmlWriter::DoBeginWriteTopLevelEntry( const wxString &name )
9c8046dd
SC
97{
98 wxXmlNode *pnode;
99 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("entry"));
63691d4f 100 pnode->AddProperty(wxString(wxT("name")), name);
9c8046dd
SC
101 m_data->m_current->AddChild(pnode) ;
102 m_data->Push( pnode ) ;
103}
104
105void wxXmlWriter::DoEndWriteTopLevelEntry( const wxString &WXUNUSED(name) )
106{
107 m_data->Pop() ;
108}
109
2abce515 110void wxXmlWriter::DoBeginWriteObject(const wxObject *WXUNUSED(object), const wxClassInfo *classInfo, int objectID , wxxVariantArray &metadata )
9c8046dd
SC
111{
112 wxXmlNode *pnode;
113 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("object"));
114 pnode->AddProperty(wxT("class"), wxString(classInfo->GetClassName()));
63691d4f 115 pnode->AddProperty(wxT("id"), wxString::Format( wxT("%d") , objectID ) );
9c8046dd
SC
116
117 for ( size_t i = 0 ; i < metadata.GetCount() ; ++i )
118 {
119 pnode->AddProperty( metadata[i].GetName() , metadata[i].GetAsString() ) ;
120 }
121 m_data->m_current->AddChild(pnode) ;
122 m_data->Push( pnode ) ;
123}
124
125// end of writing the root object
2abce515 126void wxXmlWriter::DoEndWriteObject(const wxObject *WXUNUSED(object), const wxClassInfo *WXUNUSED(classInfo), int WXUNUSED(objectID) )
9c8046dd
SC
127{
128 m_data->Pop() ;
129}
130
131// writes a property in the stream format
2abce515 132void wxXmlWriter::DoWriteSimpleType( wxxVariant &value )
9c8046dd
SC
133{
134 wxXmlAddContentToNode( m_data->m_current ,value.GetAsString() ) ;
135}
136
2abce515 137void wxXmlWriter::DoBeginWriteElement()
9c8046dd
SC
138{
139 wxXmlNode *pnode;
63691d4f 140 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("element") );
9c8046dd
SC
141 m_data->m_current->AddChild(pnode) ;
142 m_data->Push( pnode ) ;
143}
144
2abce515 145void wxXmlWriter::DoEndWriteElement()
9c8046dd
SC
146{
147 m_data->Pop() ;
148}
149
150void wxXmlWriter::DoBeginWriteProperty(const wxPropertyInfo *pi )
151{
152 wxXmlNode *pnode;
63691d4f 153 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("prop") );
9c8046dd
SC
154 pnode->AddProperty(wxT("name"), pi->GetName() );
155 m_data->m_current->AddChild(pnode) ;
156 m_data->Push( pnode ) ;
157}
158
159void wxXmlWriter::DoEndWriteProperty(const wxPropertyInfo *WXUNUSED(propInfo) )
160{
161 m_data->Pop() ;
162}
163
164
165
166// insert an object reference to an already written object
2abce515 167void wxXmlWriter::DoWriteRepeatedObject( int objectID )
9c8046dd
SC
168{
169 wxXmlNode *pnode;
170 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("object"));
63691d4f 171 pnode->AddProperty(wxString(wxT("href")), wxString::Format( wxT("%d") , objectID ) );
9c8046dd
SC
172 m_data->m_current->AddChild(pnode) ;
173}
174
175// insert a null reference
2abce515 176void wxXmlWriter::DoWriteNullObject()
9c8046dd
SC
177{
178 wxXmlNode *pnode;
179 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("object"));
180 m_data->m_current->AddChild(pnode) ;
181}
182
183// writes a delegate in the stream format
2abce515
SC
184void wxXmlWriter::DoWriteDelegate( const wxObject *WXUNUSED(object), const wxClassInfo* WXUNUSED(classInfo) , const wxPropertyInfo *WXUNUSED(pi) ,
185 const wxObject *eventSink, int sinkObjectID , const wxClassInfo* WXUNUSED(eventSinkClassInfo) , const wxHandlerInfo* handlerInfo )
9c8046dd
SC
186{
187 if ( eventSink != NULL && handlerInfo != NULL )
188 {
2abce515 189 wxXmlAddContentToNode( m_data->m_current ,wxString::Format(wxT("%d.%s"), sinkObjectID , handlerInfo->GetName().c_str()) ) ;
9c8046dd
SC
190 }
191}
192
193// ----------------------------------------------------------------------------
2abce515 194// reading objects in
9c8046dd
SC
195// ----------------------------------------------------------------------------
196
197
198
199// ----------------------------------------------------------------------------
2abce515 200// reading xml in
9c8046dd
SC
201// ----------------------------------------------------------------------------
202
2abce515 203/*
9c8046dd
SC
204Reading components has not to be extended for components
205as properties are always sought by typeinfo over all levels
206and create params are always toplevel class only
207*/
208
209int wxXmlReader::ReadComponent(wxXmlNode *node, wxDepersister *callbacks)
210{
211 wxASSERT_MSG( callbacks , wxT("Does not support reading without a Depersistor") ) ;
212 wxString className;
213 wxClassInfo *classInfo;
214
215 wxxVariant *createParams ;
216 int *createParamOids ;
217 const wxClassInfo** createClassInfos ;
218 wxXmlNode *children;
219 int objectID;
220 wxString ObjectIdString ;
221
222 children = node->GetChildren();
223 if (!children)
224 {
225 // check for a null object or href
63691d4f 226 if (node->GetPropVal(wxT("href") , &ObjectIdString ) )
9c8046dd 227 {
63691d4f 228 objectID = atoi( ObjectIdString.ToAscii() ) ;
9c8046dd
SC
229 wxASSERT_MSG( HasObjectClassInfo( objectID ) , wxT("Forward hrefs are not supported") ) ;
230 return objectID ;
231 }
63691d4f 232 if ( !node->GetPropVal(wxT("id") , &ObjectIdString ) )
9c8046dd
SC
233 {
234 return wxNullObjectID;
235 }
236 }
63691d4f 237 if (!node->GetPropVal(wxT("class"), &className))
9c8046dd
SC
238 {
239 // No class name. Eek. FIXME: error handling
240 return wxInvalidObjectID;
241 }
242 classInfo = wxClassInfo::FindClass(className);
243 wxASSERT_MSG( classInfo , wxString::Format(wxT("unknown class %s"),className ) ) ;
244 wxASSERT_MSG( !children || children->GetType() != wxXML_TEXT_NODE , wxT("objects cannot have XML Text Nodes") ) ;
63691d4f 245 if (!node->GetPropVal(wxT("id"), &ObjectIdString))
9c8046dd
SC
246 {
247 wxASSERT_MSG(0,wxT("Objects must have an id attribute") ) ;
248 // No object id. Eek. FIXME: error handling
249 return wxInvalidObjectID;
250 }
63691d4f 251 objectID = atoi( ObjectIdString.ToAscii() ) ;
9c8046dd
SC
252 // is this object already has been streamed in, return it here
253 wxASSERT_MSG( !HasObjectClassInfo( objectID ) , wxString::Format(wxT("Doubly used id : %d"), objectID ) ) ;
254
255 // new object, start with allocation
256 // first make the object know to our internal registry
257 SetObjectClassInfo( objectID , classInfo ) ;
258
259 wxxVariantArray metadata ;
260 wxXmlProperty *xp = node->GetProperties() ;
261 while ( xp )
262 {
63691d4f 263 if ( xp->GetName() != wxString(wxT("class")) && xp->GetName() != wxString(wxT("id")) )
9c8046dd
SC
264 {
265 metadata.Add( new wxxVariant( xp->GetValue() , xp->GetName() ) ) ;
266 }
267 xp = xp->GetNext() ;
268 }
ed45345e
SC
269 if ( !classInfo->NeedsDirectConstruction() )
270 callbacks->AllocateObject(objectID, classInfo, metadata);
9c8046dd 271
2abce515 272 //
9c8046dd
SC
273 // stream back the Create parameters first
274 createParams = new wxxVariant[ classInfo->GetCreateParamCount() ] ;
275 createParamOids = new int[classInfo->GetCreateParamCount() ] ;
276 createClassInfos = new const wxClassInfo*[classInfo->GetCreateParamCount() ] ;
277
63691d4f
SC
278#if wxUSE_UNICODE
279 typedef map<wstring, wxXmlNode *> PropertyNodes ;
280 typedef vector<wstring> PropertyNames ;
281#else
9c8046dd
SC
282 typedef map<string, wxXmlNode *> PropertyNodes ;
283 typedef vector<string> PropertyNames ;
63691d4f 284#endif
9c8046dd
SC
285 PropertyNodes propertyNodes ;
286 PropertyNames propertyNames ;
287
288 while( children )
289 {
290 wxString name ;
291 children->GetPropVal( wxT("name") , &name ) ;
292 propertyNames.push_back( name.c_str() ) ;
293 propertyNodes[name.c_str()] = children->GetChildren() ;
294 children = children->GetNext() ;
295 }
296
297 for ( int i = 0 ; i <classInfo->GetCreateParamCount() ; ++i )
298 {
299 const wxChar* paramName = classInfo->GetCreateParamName(i) ;
300 PropertyNodes::iterator propiter = propertyNodes.find( paramName ) ;
301 const wxPropertyInfo* pi = classInfo->FindPropertyInfo( paramName ) ;
63691d4f 302 wxASSERT_MSG(pi,wxString::Format(wxT("Unkown Property %s"),paramName) ) ;
9c8046dd
SC
303 // if we don't have the value of a create param set in the xml
304 // we use the default value
305 if ( propiter != propertyNodes.end() )
306 {
307 wxXmlNode* prop = propiter->second ;
308 if ( pi->GetTypeInfo()->IsObjectType() )
309 {
310 createParamOids[i] = ReadComponent( prop , callbacks ) ;
311 createClassInfos[i] = dynamic_cast<const wxClassTypeInfo*>(pi->GetTypeInfo())->GetClassInfo() ;
312 }
313 else
314 {
315 createParamOids[i] = wxInvalidObjectID ;
316 createParams[i] = ReadValue( prop , pi->GetTypeInfo() ) ;
317 if( pi->GetFlags() & wxPROP_ENUM_STORE_LONG )
318 {
319 const wxEnumTypeInfo *eti = dynamic_cast<const wxEnumTypeInfo*>( pi->GetTypeInfo() ) ;
320 wxASSERT_MSG( eti , wxT("Type must have enum - long conversion") ) ;
321
322 long realval ;
323 eti->ConvertToLong( createParams[i] , realval ) ;
324 createParams[i] = wxxVariant( realval ) ;
325 }
326 createClassInfos[i] = NULL ;
327 }
328
329 for ( size_t j = 0 ; j < propertyNames.size() ; ++j )
330 {
331 if ( propertyNames[j] == paramName )
332 {
63691d4f 333 propertyNames[j] = wxEmptyString ;
9c8046dd
SC
334 break ;
335 }
336 }
337 }
338 else
339 {
ed45345e
SC
340 if ( pi->GetTypeInfo()->IsObjectType() )
341 {
342 createParamOids[i] = wxNullObjectID ;
343 createClassInfos[i] = dynamic_cast<const wxClassTypeInfo*>(pi->GetTypeInfo())->GetClassInfo() ;
344 }
345 else
346 {
347 createParams[i] = pi->GetDefaultValue() ;
348 createParamOids[i] = wxInvalidObjectID ;
349 }
9c8046dd
SC
350 }
351 }
352
353 // got the parameters. Call the Create method
ed45345e
SC
354 if ( classInfo->NeedsDirectConstruction() )
355 callbacks->ConstructObject(objectID, classInfo,
356 classInfo->GetCreateParamCount(),
357 createParams, createParamOids, createClassInfos, metadata );
358 else
359 callbacks->CreateObject(objectID, classInfo,
360 classInfo->GetCreateParamCount(),
361 createParams, createParamOids, createClassInfos, metadata );
9c8046dd
SC
362
363 // now stream in the rest of the properties, in the sequence their properties were written in the xml
364 for ( size_t j = 0 ; j < propertyNames.size() ; ++j )
365 {
366 if ( propertyNames[j].length() )
367 {
368 PropertyNodes::iterator propiter = propertyNodes.find( propertyNames[j] ) ;
369 if ( propiter != propertyNodes.end() )
370 {
371 wxXmlNode* prop = propiter->second ;
372 const wxPropertyInfo* pi = classInfo->FindPropertyInfo( propertyNames[j].c_str() ) ;
373 if ( pi->GetTypeInfo()->GetKind() == wxT_COLLECTION )
374 {
375 const wxCollectionTypeInfo* collType = dynamic_cast< const wxCollectionTypeInfo* >( pi->GetTypeInfo() ) ;
376 const wxTypeInfo * elementType = collType->GetElementType() ;
377 while( prop )
378 {
379 wxASSERT_MSG(prop->GetName() == wxT("element") , wxT("A non empty collection must consist of 'element' nodes")) ;
380 wxXmlNode* elementContent = prop->GetChildren() ;
381 if ( elementContent )
382 {
383 // we skip empty elements
384 if ( elementType->IsObjectType() )
385 {
386 int valueId = ReadComponent( elementContent , callbacks ) ;
387 if ( valueId != wxInvalidObjectID )
388 {
389 if ( pi->GetAccessor()->HasAdder() )
390 callbacks->AddToPropertyCollectionAsObject( objectID , classInfo , pi , valueId ) ;
2abce515 391 // TODO for collections we must have a notation on taking over ownership or not
9c8046dd
SC
392 if ( elementType->GetKind() == wxT_OBJECT && valueId != wxNullObjectID )
393 callbacks->DestroyObject( valueId , GetObjectClassInfo( valueId ) ) ;
394 }
395 }
396 else
397 {
398 wxxVariant elementValue = ReadValue( elementContent , elementType ) ;
399 if ( pi->GetAccessor()->HasAdder() )
400 callbacks->AddToPropertyCollection( objectID , classInfo ,pi , elementValue ) ;
401 }
402 }
403 prop = prop->GetNext() ;
404 }
405 }
406 else if ( pi->GetTypeInfo()->IsObjectType() )
407 {
ed45345e
SC
408 // and object can either be streamed out a string or as an object
409 // in case we have no node, then the object's streaming out has been vetoed
410 if ( prop )
9c8046dd 411 {
ed45345e
SC
412 if ( prop->GetName() == wxT("object") )
413 {
414 int valueId = ReadComponent( prop , callbacks ) ;
415 if ( valueId != wxInvalidObjectID )
416 {
417 callbacks->SetPropertyAsObject( objectID , classInfo , pi , valueId ) ;
418 if ( pi->GetTypeInfo()->GetKind() == wxT_OBJECT && valueId != wxNullObjectID )
419 callbacks->DestroyObject( valueId , GetObjectClassInfo( valueId ) ) ;
420 }
421 }
422 else
423 {
424 wxASSERT( pi->GetTypeInfo()->HasStringConverters() ) ;
425 wxxVariant nodeval = ReadValue( prop , pi->GetTypeInfo() ) ;
426 callbacks->SetProperty( objectID, classInfo ,pi , nodeval ) ;
427 }
9c8046dd
SC
428 }
429 }
430 else if ( pi->GetTypeInfo()->IsDelegateType() )
431 {
432 if ( prop )
433 {
434 wxString resstring = prop->GetContent() ;
435 wxInt32 pos = resstring.Find('.') ;
436 assert( pos != wxNOT_FOUND ) ;
63691d4f 437 int sinkOid = atol(resstring.Left(pos).ToAscii()) ;
9c8046dd
SC
438 wxString handlerName = resstring.Mid(pos+1) ;
439 wxClassInfo* sinkClassInfo = GetObjectClassInfo( sinkOid ) ;
440
441 callbacks->SetConnect( objectID , classInfo , dynamic_cast<const wxDelegateTypeInfo*>(pi->GetTypeInfo()) , sinkClassInfo ,
442 sinkClassInfo->FindHandlerInfo(handlerName) , sinkOid ) ;
443 }
444
445 }
446 else
447 {
499a9a62
SC
448 wxxVariant nodeval = ReadValue( prop , pi->GetTypeInfo() ) ;
449 if( pi->GetFlags() & wxPROP_ENUM_STORE_LONG )
450 {
451 const wxEnumTypeInfo *eti = dynamic_cast<const wxEnumTypeInfo*>( pi->GetTypeInfo() ) ;
452 wxASSERT_MSG( eti , wxT("Type must have enum - long conversion") ) ;
453
454 long realval ;
455 eti->ConvertToLong( nodeval , realval ) ;
456 nodeval = wxxVariant( realval ) ;
457 }
458 callbacks->SetProperty( objectID, classInfo ,pi , nodeval ) ;
9c8046dd
SC
459 }
460 }
461 }
462 }
463
464 delete[] createParams ;
465 delete[] createParamOids ;
466 delete[] createClassInfos ;
467
468 return objectID;
469}
470
471wxxVariant wxXmlReader::ReadValue(wxXmlNode *node,
472 const wxTypeInfo *type )
473{
474 wxString content ;
475 if ( node )
476 content = node->GetContent() ;
477 wxxVariant result ;
478 type->ConvertFromString( content , result ) ;
479 return result ;
480}
481
482int wxXmlReader::ReadObject( const wxString &name , wxDepersister *callbacks)
483{
484 wxXmlNode *iter = m_parent->GetChildren() ;
485 while ( iter )
486 {
487 wxString entryName ;
63691d4f 488 if ( iter->GetPropVal(wxT("name"), &entryName) )
9c8046dd
SC
489 {
490 if ( entryName == name )
491 return ReadComponent( iter->GetChildren() , callbacks ) ;
492 }
493 iter = iter->GetNext() ;
494 }
495 return wxInvalidObjectID ;
496}
497
498#endif