]> git.saurik.com Git - wxWidgets.git/blame - src/common/xtixml.cpp
Use "Base" version of wxBell on OS/2.
[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{
54 node->AddChild(new wxXmlNode(wxXML_TEXT_NODE, "value", data ) );
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"));
100 pnode->AddProperty(wxString("name"), name);
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()));
115 pnode->AddProperty(wxT("id"), wxString::Format( "%d" , objectID ) );
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;
140 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, "element" );
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;
153 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, "prop" );
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"));
171 pnode->AddProperty(wxString("href"), wxString::Format( "%d" , objectID ) );
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
226 if (node->GetPropVal("href" , &ObjectIdString ) )
227 {
228 objectID = atoi( ObjectIdString.c_str() ) ;
229 wxASSERT_MSG( HasObjectClassInfo( objectID ) , wxT("Forward hrefs are not supported") ) ;
230 return objectID ;
231 }
232 if ( !node->GetPropVal("id" , &ObjectIdString ) )
233 {
234 return wxNullObjectID;
235 }
236 }
237 if (!node->GetPropVal("class", &className))
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") ) ;
245 if (!node->GetPropVal("id", &ObjectIdString))
246 {
247 wxASSERT_MSG(0,wxT("Objects must have an id attribute") ) ;
248 // No object id. Eek. FIXME: error handling
249 return wxInvalidObjectID;
250 }
251 objectID = atoi( ObjectIdString.c_str() ) ;
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 {
263 if ( xp->GetName() != wxString("class") && xp->GetName() != wxString("id") )
264 {
265 metadata.Add( new wxxVariant( xp->GetValue() , xp->GetName() ) ) ;
266 }
267 xp = xp->GetNext() ;
268 }
269 callbacks->AllocateObject(objectID, classInfo, metadata);
270
2abce515 271 //
9c8046dd
SC
272 // stream back the Create parameters first
273 createParams = new wxxVariant[ classInfo->GetCreateParamCount() ] ;
274 createParamOids = new int[classInfo->GetCreateParamCount() ] ;
275 createClassInfos = new const wxClassInfo*[classInfo->GetCreateParamCount() ] ;
276
277 typedef map<string, wxXmlNode *> PropertyNodes ;
278 typedef vector<string> PropertyNames ;
279
280 PropertyNodes propertyNodes ;
281 PropertyNames propertyNames ;
282
283 while( children )
284 {
285 wxString name ;
286 children->GetPropVal( wxT("name") , &name ) ;
287 propertyNames.push_back( name.c_str() ) ;
288 propertyNodes[name.c_str()] = children->GetChildren() ;
289 children = children->GetNext() ;
290 }
291
292 for ( int i = 0 ; i <classInfo->GetCreateParamCount() ; ++i )
293 {
294 const wxChar* paramName = classInfo->GetCreateParamName(i) ;
295 PropertyNodes::iterator propiter = propertyNodes.find( paramName ) ;
296 const wxPropertyInfo* pi = classInfo->FindPropertyInfo( paramName ) ;
297 wxASSERT_MSG(pi,wxString::Format("Unkown Property %s",paramName) ) ;
298 // if we don't have the value of a create param set in the xml
299 // we use the default value
300 if ( propiter != propertyNodes.end() )
301 {
302 wxXmlNode* prop = propiter->second ;
303 if ( pi->GetTypeInfo()->IsObjectType() )
304 {
305 createParamOids[i] = ReadComponent( prop , callbacks ) ;
306 createClassInfos[i] = dynamic_cast<const wxClassTypeInfo*>(pi->GetTypeInfo())->GetClassInfo() ;
307 }
308 else
309 {
310 createParamOids[i] = wxInvalidObjectID ;
311 createParams[i] = ReadValue( prop , pi->GetTypeInfo() ) ;
312 if( pi->GetFlags() & wxPROP_ENUM_STORE_LONG )
313 {
314 const wxEnumTypeInfo *eti = dynamic_cast<const wxEnumTypeInfo*>( pi->GetTypeInfo() ) ;
315 wxASSERT_MSG( eti , wxT("Type must have enum - long conversion") ) ;
316
317 long realval ;
318 eti->ConvertToLong( createParams[i] , realval ) ;
319 createParams[i] = wxxVariant( realval ) ;
320 }
321 createClassInfos[i] = NULL ;
322 }
323
324 for ( size_t j = 0 ; j < propertyNames.size() ; ++j )
325 {
326 if ( propertyNames[j] == paramName )
327 {
328 propertyNames[j] = "" ;
329 break ;
330 }
331 }
332 }
333 else
334 {
335 createParams[i] = pi->GetDefaultValue() ;
336 }
337 }
338
339 // got the parameters. Call the Create method
340 callbacks->CreateObject(objectID, classInfo,
341 classInfo->GetCreateParamCount(),
342 createParams, createParamOids, createClassInfos, metadata );
343
344 // now stream in the rest of the properties, in the sequence their properties were written in the xml
345 for ( size_t j = 0 ; j < propertyNames.size() ; ++j )
346 {
347 if ( propertyNames[j].length() )
348 {
349 PropertyNodes::iterator propiter = propertyNodes.find( propertyNames[j] ) ;
350 if ( propiter != propertyNodes.end() )
351 {
352 wxXmlNode* prop = propiter->second ;
353 const wxPropertyInfo* pi = classInfo->FindPropertyInfo( propertyNames[j].c_str() ) ;
354 if ( pi->GetTypeInfo()->GetKind() == wxT_COLLECTION )
355 {
356 const wxCollectionTypeInfo* collType = dynamic_cast< const wxCollectionTypeInfo* >( pi->GetTypeInfo() ) ;
357 const wxTypeInfo * elementType = collType->GetElementType() ;
358 while( prop )
359 {
360 wxASSERT_MSG(prop->GetName() == wxT("element") , wxT("A non empty collection must consist of 'element' nodes")) ;
361 wxXmlNode* elementContent = prop->GetChildren() ;
362 if ( elementContent )
363 {
364 // we skip empty elements
365 if ( elementType->IsObjectType() )
366 {
367 int valueId = ReadComponent( elementContent , callbacks ) ;
368 if ( valueId != wxInvalidObjectID )
369 {
370 if ( pi->GetAccessor()->HasAdder() )
371 callbacks->AddToPropertyCollectionAsObject( objectID , classInfo , pi , valueId ) ;
2abce515 372 // TODO for collections we must have a notation on taking over ownership or not
9c8046dd
SC
373 if ( elementType->GetKind() == wxT_OBJECT && valueId != wxNullObjectID )
374 callbacks->DestroyObject( valueId , GetObjectClassInfo( valueId ) ) ;
375 }
376 }
377 else
378 {
379 wxxVariant elementValue = ReadValue( elementContent , elementType ) ;
380 if ( pi->GetAccessor()->HasAdder() )
381 callbacks->AddToPropertyCollection( objectID , classInfo ,pi , elementValue ) ;
382 }
383 }
384 prop = prop->GetNext() ;
385 }
386 }
387 else if ( pi->GetTypeInfo()->IsObjectType() )
388 {
389 int valueId = ReadComponent( prop , callbacks ) ;
390 if ( valueId != wxInvalidObjectID )
391 {
392 callbacks->SetPropertyAsObject( objectID , classInfo , pi , valueId ) ;
393 if ( pi->GetTypeInfo()->GetKind() == wxT_OBJECT && valueId != wxNullObjectID )
394 callbacks->DestroyObject( valueId , GetObjectClassInfo( valueId ) ) ;
395 }
396 }
397 else if ( pi->GetTypeInfo()->IsDelegateType() )
398 {
399 if ( prop )
400 {
401 wxString resstring = prop->GetContent() ;
402 wxInt32 pos = resstring.Find('.') ;
403 assert( pos != wxNOT_FOUND ) ;
404 int sinkOid = atol(resstring.Left(pos)) ;
405 wxString handlerName = resstring.Mid(pos+1) ;
406 wxClassInfo* sinkClassInfo = GetObjectClassInfo( sinkOid ) ;
407
408 callbacks->SetConnect( objectID , classInfo , dynamic_cast<const wxDelegateTypeInfo*>(pi->GetTypeInfo()) , sinkClassInfo ,
409 sinkClassInfo->FindHandlerInfo(handlerName) , sinkOid ) ;
410 }
411
412 }
413 else
414 {
415 wxxVariant nodeval ;
416 callbacks->SetProperty( objectID, classInfo ,pi , ReadValue( prop , pi->GetTypeInfo() ) ) ;
417 }
418 }
419 }
420 }
421
422 delete[] createParams ;
423 delete[] createParamOids ;
424 delete[] createClassInfos ;
425
426 return objectID;
427}
428
429wxxVariant wxXmlReader::ReadValue(wxXmlNode *node,
430 const wxTypeInfo *type )
431{
432 wxString content ;
433 if ( node )
434 content = node->GetContent() ;
435 wxxVariant result ;
436 type->ConvertFromString( content , result ) ;
437 return result ;
438}
439
440int wxXmlReader::ReadObject( const wxString &name , wxDepersister *callbacks)
441{
442 wxXmlNode *iter = m_parent->GetChildren() ;
443 while ( iter )
444 {
445 wxString entryName ;
446 if ( iter->GetPropVal("name", &entryName) )
447 {
448 if ( entryName == name )
449 return ReadComponent( iter->GetChildren() , callbacks ) ;
450 }
451 iter = iter->GetNext() ;
452 }
453 return wxInvalidObjectID ;
454}
455
456#endif