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