]> git.saurik.com Git - wxWidgets.git/blame - src/common/xtixml.cpp
Fix for the undocumented holes in spiner sizes.
[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
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() ) ;
8f2b1cfd
SC
229 if ( HasObjectClassInfo( objectID ) )
230 {
231 return objectID ;
232 }
233 else
234 {
235 wxLogError( _("Forward hrefs are not supported") ) ;
236 return wxInvalidObjectID ;
237 }
9c8046dd 238 }
63691d4f 239 if ( !node->GetPropVal(wxT("id") , &ObjectIdString ) )
9c8046dd
SC
240 {
241 return wxNullObjectID;
242 }
243 }
63691d4f 244 if (!node->GetPropVal(wxT("class"), &className))
9c8046dd
SC
245 {
246 // No class name. Eek. FIXME: error handling
247 return wxInvalidObjectID;
248 }
249 classInfo = wxClassInfo::FindClass(className);
8f2b1cfd
SC
250 if ( classInfo == NULL )
251 {
252 wxLogError( wxString::Format(_("unknown class %s"),className ) ) ;
253 return wxInvalidObjectID ;
254 }
255
256 if ( children != NULL && children->GetType() == wxXML_TEXT_NODE )
257 {
258 wxLogError(_("objects cannot have XML Text Nodes") ) ;
259 return wxInvalidObjectID;
260 }
63691d4f 261 if (!node->GetPropVal(wxT("id"), &ObjectIdString))
9c8046dd 262 {
8f2b1cfd 263 wxLogError(_("Objects must have an id attribute") ) ;
9c8046dd
SC
264 // No object id. Eek. FIXME: error handling
265 return wxInvalidObjectID;
266 }
63691d4f 267 objectID = atoi( ObjectIdString.ToAscii() ) ;
9c8046dd 268 // is this object already has been streamed in, return it here
8f2b1cfd
SC
269 if ( HasObjectClassInfo( objectID ) )
270 {
271 wxLogError ( wxString::Format(_("Doubly used id : %d"), objectID ) ) ;
272 return wxInvalidObjectID ;
273 }
9c8046dd
SC
274
275 // new object, start with allocation
276 // first make the object know to our internal registry
277 SetObjectClassInfo( objectID , classInfo ) ;
278
279 wxxVariantArray metadata ;
280 wxXmlProperty *xp = node->GetProperties() ;
281 while ( xp )
282 {
63691d4f 283 if ( xp->GetName() != wxString(wxT("class")) && xp->GetName() != wxString(wxT("id")) )
9c8046dd
SC
284 {
285 metadata.Add( new wxxVariant( xp->GetValue() , xp->GetName() ) ) ;
286 }
287 xp = xp->GetNext() ;
288 }
ed45345e
SC
289 if ( !classInfo->NeedsDirectConstruction() )
290 callbacks->AllocateObject(objectID, classInfo, metadata);
9c8046dd 291
2abce515 292 //
9c8046dd
SC
293 // stream back the Create parameters first
294 createParams = new wxxVariant[ classInfo->GetCreateParamCount() ] ;
295 createParamOids = new int[classInfo->GetCreateParamCount() ] ;
296 createClassInfos = new const wxClassInfo*[classInfo->GetCreateParamCount() ] ;
297
63691d4f
SC
298#if wxUSE_UNICODE
299 typedef map<wstring, wxXmlNode *> PropertyNodes ;
300 typedef vector<wstring> PropertyNames ;
301#else
9c8046dd
SC
302 typedef map<string, wxXmlNode *> PropertyNodes ;
303 typedef vector<string> PropertyNames ;
63691d4f 304#endif
9c8046dd
SC
305 PropertyNodes propertyNodes ;
306 PropertyNames propertyNames ;
307
308 while( children )
309 {
310 wxString name ;
311 children->GetPropVal( wxT("name") , &name ) ;
312 propertyNames.push_back( name.c_str() ) ;
313 propertyNodes[name.c_str()] = children->GetChildren() ;
314 children = children->GetNext() ;
315 }
316
317 for ( int i = 0 ; i <classInfo->GetCreateParamCount() ; ++i )
318 {
319 const wxChar* paramName = classInfo->GetCreateParamName(i) ;
320 PropertyNodes::iterator propiter = propertyNodes.find( paramName ) ;
321 const wxPropertyInfo* pi = classInfo->FindPropertyInfo( paramName ) ;
8f2b1cfd
SC
322 if ( pi == 0 )
323 {
324 wxLogError( wxString::Format(_("Unkown Property %s"),paramName) ) ;
325 }
9c8046dd
SC
326 // if we don't have the value of a create param set in the xml
327 // we use the default value
328 if ( propiter != propertyNodes.end() )
329 {
330 wxXmlNode* prop = propiter->second ;
331 if ( pi->GetTypeInfo()->IsObjectType() )
332 {
333 createParamOids[i] = ReadComponent( prop , callbacks ) ;
334 createClassInfos[i] = dynamic_cast<const wxClassTypeInfo*>(pi->GetTypeInfo())->GetClassInfo() ;
335 }
336 else
337 {
338 createParamOids[i] = wxInvalidObjectID ;
339 createParams[i] = ReadValue( prop , pi->GetTypeInfo() ) ;
340 if( pi->GetFlags() & wxPROP_ENUM_STORE_LONG )
341 {
342 const wxEnumTypeInfo *eti = dynamic_cast<const wxEnumTypeInfo*>( pi->GetTypeInfo() ) ;
8f2b1cfd
SC
343 if ( eti )
344 {
345 long realval ;
346 eti->ConvertToLong( createParams[i] , realval ) ;
347 createParams[i] = wxxVariant( realval ) ;
348 }
349 else
350 {
351 wxLogError( _("Type must have enum - long conversion") ) ;
352 }
9c8046dd
SC
353 }
354 createClassInfos[i] = NULL ;
355 }
356
357 for ( size_t j = 0 ; j < propertyNames.size() ; ++j )
358 {
359 if ( propertyNames[j] == paramName )
360 {
63691d4f 361 propertyNames[j] = wxEmptyString ;
9c8046dd
SC
362 break ;
363 }
364 }
365 }
366 else
367 {
ed45345e
SC
368 if ( pi->GetTypeInfo()->IsObjectType() )
369 {
370 createParamOids[i] = wxNullObjectID ;
371 createClassInfos[i] = dynamic_cast<const wxClassTypeInfo*>(pi->GetTypeInfo())->GetClassInfo() ;
372 }
373 else
374 {
375 createParams[i] = pi->GetDefaultValue() ;
376 createParamOids[i] = wxInvalidObjectID ;
377 }
9c8046dd
SC
378 }
379 }
380
381 // got the parameters. Call the Create method
ed45345e
SC
382 if ( classInfo->NeedsDirectConstruction() )
383 callbacks->ConstructObject(objectID, classInfo,
384 classInfo->GetCreateParamCount(),
385 createParams, createParamOids, createClassInfos, metadata );
386 else
387 callbacks->CreateObject(objectID, classInfo,
388 classInfo->GetCreateParamCount(),
389 createParams, createParamOids, createClassInfos, metadata );
9c8046dd
SC
390
391 // now stream in the rest of the properties, in the sequence their properties were written in the xml
392 for ( size_t j = 0 ; j < propertyNames.size() ; ++j )
393 {
394 if ( propertyNames[j].length() )
395 {
396 PropertyNodes::iterator propiter = propertyNodes.find( propertyNames[j] ) ;
397 if ( propiter != propertyNodes.end() )
398 {
399 wxXmlNode* prop = propiter->second ;
400 const wxPropertyInfo* pi = classInfo->FindPropertyInfo( propertyNames[j].c_str() ) ;
401 if ( pi->GetTypeInfo()->GetKind() == wxT_COLLECTION )
402 {
403 const wxCollectionTypeInfo* collType = dynamic_cast< const wxCollectionTypeInfo* >( pi->GetTypeInfo() ) ;
404 const wxTypeInfo * elementType = collType->GetElementType() ;
405 while( prop )
406 {
8f2b1cfd
SC
407 if ( prop->GetName() != wxT("element") )
408 {
409 wxLogError( _("A non empty collection must consist of 'element' nodes" ) ) ;
410 break ;
411 }
9c8046dd
SC
412 wxXmlNode* elementContent = prop->GetChildren() ;
413 if ( elementContent )
414 {
415 // we skip empty elements
416 if ( elementType->IsObjectType() )
417 {
418 int valueId = ReadComponent( elementContent , callbacks ) ;
419 if ( valueId != wxInvalidObjectID )
420 {
421 if ( pi->GetAccessor()->HasAdder() )
422 callbacks->AddToPropertyCollectionAsObject( objectID , classInfo , pi , valueId ) ;
2abce515 423 // TODO for collections we must have a notation on taking over ownership or not
9c8046dd
SC
424 if ( elementType->GetKind() == wxT_OBJECT && valueId != wxNullObjectID )
425 callbacks->DestroyObject( valueId , GetObjectClassInfo( valueId ) ) ;
426 }
427 }
428 else
429 {
430 wxxVariant elementValue = ReadValue( elementContent , elementType ) ;
431 if ( pi->GetAccessor()->HasAdder() )
432 callbacks->AddToPropertyCollection( objectID , classInfo ,pi , elementValue ) ;
433 }
434 }
435 prop = prop->GetNext() ;
436 }
437 }
438 else if ( pi->GetTypeInfo()->IsObjectType() )
439 {
ed45345e
SC
440 // and object can either be streamed out a string or as an object
441 // in case we have no node, then the object's streaming out has been vetoed
442 if ( prop )
9c8046dd 443 {
ed45345e
SC
444 if ( prop->GetName() == wxT("object") )
445 {
446 int valueId = ReadComponent( prop , callbacks ) ;
447 if ( valueId != wxInvalidObjectID )
448 {
449 callbacks->SetPropertyAsObject( objectID , classInfo , pi , valueId ) ;
450 if ( pi->GetTypeInfo()->GetKind() == wxT_OBJECT && valueId != wxNullObjectID )
451 callbacks->DestroyObject( valueId , GetObjectClassInfo( valueId ) ) ;
452 }
453 }
454 else
455 {
456 wxASSERT( pi->GetTypeInfo()->HasStringConverters() ) ;
457 wxxVariant nodeval = ReadValue( prop , pi->GetTypeInfo() ) ;
458 callbacks->SetProperty( objectID, classInfo ,pi , nodeval ) ;
459 }
9c8046dd
SC
460 }
461 }
462 else if ( pi->GetTypeInfo()->IsDelegateType() )
463 {
464 if ( prop )
465 {
466 wxString resstring = prop->GetContent() ;
467 wxInt32 pos = resstring.Find('.') ;
8f2b1cfd
SC
468 if ( pos != wxNOT_FOUND )
469 {
470 int sinkOid = atol(resstring.Left(pos).ToAscii()) ;
471 wxString handlerName = resstring.Mid(pos+1) ;
472 wxClassInfo* sinkClassInfo = GetObjectClassInfo( sinkOid ) ;
9c8046dd 473
8f2b1cfd
SC
474 callbacks->SetConnect( objectID , classInfo , pi , sinkClassInfo ,
475 sinkClassInfo->FindHandlerInfo(handlerName) , sinkOid ) ;
476 }
477 else
478 {
479 wxLogError( _("incorrect event handler string, missing dot") ) ;
480 }
9c8046dd
SC
481 }
482
483 }
484 else
485 {
499a9a62
SC
486 wxxVariant nodeval = ReadValue( prop , pi->GetTypeInfo() ) ;
487 if( pi->GetFlags() & wxPROP_ENUM_STORE_LONG )
488 {
489 const wxEnumTypeInfo *eti = dynamic_cast<const wxEnumTypeInfo*>( pi->GetTypeInfo() ) ;
8f2b1cfd
SC
490 if ( eti )
491 {
492 long realval ;
493 eti->ConvertToLong( nodeval , realval ) ;
494 nodeval = wxxVariant( realval ) ;
495 }
496 else
497 {
498 wxLogError( _("Type must have enum - long conversion") ) ;
499 }
499a9a62
SC
500 }
501 callbacks->SetProperty( objectID, classInfo ,pi , nodeval ) ;
9c8046dd
SC
502 }
503 }
504 }
505 }
506
507 delete[] createParams ;
508 delete[] createParamOids ;
509 delete[] createClassInfos ;
510
511 return objectID;
512}
513
514wxxVariant wxXmlReader::ReadValue(wxXmlNode *node,
515 const wxTypeInfo *type )
516{
517 wxString content ;
518 if ( node )
519 content = node->GetContent() ;
520 wxxVariant result ;
521 type->ConvertFromString( content , result ) ;
522 return result ;
523}
524
525int wxXmlReader::ReadObject( const wxString &name , wxDepersister *callbacks)
526{
527 wxXmlNode *iter = m_parent->GetChildren() ;
528 while ( iter )
529 {
530 wxString entryName ;
63691d4f 531 if ( iter->GetPropVal(wxT("name"), &entryName) )
9c8046dd
SC
532 {
533 if ( entryName == name )
534 return ReadComponent( iter->GetChildren() , callbacks ) ;
535 }
536 iter = iter->GetNext() ;
537 }
538 return wxInvalidObjectID ;
539}
540
541#endif