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