metadata streaming
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@22359 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
183
include/wx/xtistrm.h
Normal file
183
include/wx/xtistrm.h
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Name: wx/xtistrm.h
|
||||||
|
// Purpose: streaming runtime metadata information (extended class info)
|
||||||
|
// Author: Stefan Csomor
|
||||||
|
// Modified by:
|
||||||
|
// Created: 27/07/03
|
||||||
|
// RCS-ID: $Id$
|
||||||
|
// Copyright: (c) 2003 Stefan Csomor
|
||||||
|
// Licence: wxWindows licence
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef _WX_XTISTRMH__
|
||||||
|
#define _WX_XTISTRMH__
|
||||||
|
|
||||||
|
#if defined(__GNUG__) && !defined(__APPLE__)
|
||||||
|
#pragma interface "xtistrm.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "wx/wx.h"
|
||||||
|
|
||||||
|
#if wxUSE_EXTENDED_RTTI
|
||||||
|
|
||||||
|
// Filer contains the interfaces for streaming objects in and out of XML,
|
||||||
|
// rendering them either to objects in memory, or to code. Note: We
|
||||||
|
// consider the process of generating code to be one of *depersisting* the
|
||||||
|
// object from xml, *not* of persisting the object to code from an object
|
||||||
|
// in memory. This distincation can be confusing, and should be kept
|
||||||
|
// in mind when looking at the property streamers and callback interfaces
|
||||||
|
// listed below.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Main interface for streaming out an object to XML.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void WriteComponent(wxObject *Object, const wxClassInfo *ClassInfo, wxXmlNode *parent, const wxString& nodeName );
|
||||||
|
|
||||||
|
class wxReader;
|
||||||
|
/*
|
||||||
|
Streaming callbacks for depersisting XML to code, or running objects
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct wxIDepersist ;
|
||||||
|
|
||||||
|
/*
|
||||||
|
wxReader handles streaming in a class from XML. Maintains a list of
|
||||||
|
objects, and names, and issues calls out to interfaces to depersist the
|
||||||
|
guts from the XML tree.
|
||||||
|
*/
|
||||||
|
class wxReader : wxObject
|
||||||
|
{
|
||||||
|
struct wxReaderInternal;
|
||||||
|
wxReaderInternal *Data;
|
||||||
|
|
||||||
|
wxxVariant ReadPropertyValueNoAssign(wxXmlNode *Node,
|
||||||
|
wxClassInfo *ClassInfo,
|
||||||
|
const wxPropertyInfo *& propertyInfo ,
|
||||||
|
wxIDepersist *Callbacks = NULL);
|
||||||
|
|
||||||
|
void ReadPropertyValue(wxXmlNode *Node,
|
||||||
|
wxClassInfo *ClassInfo,
|
||||||
|
int ObjectId ,
|
||||||
|
wxIDepersist *Callbacks = NULL );
|
||||||
|
|
||||||
|
bool genCode; // true if the reader should generate code.
|
||||||
|
// ISSUE: ick!
|
||||||
|
// this interface is getting crufty. Why the
|
||||||
|
// different depersist callbacks in here, if there
|
||||||
|
// is another place that knows that we're generating
|
||||||
|
// code? Needs some repair work.
|
||||||
|
public:
|
||||||
|
wxReader(bool GenerateCode = false);
|
||||||
|
~wxReader();
|
||||||
|
|
||||||
|
// Reads a component from XML. The return is the object ID, which can
|
||||||
|
// be used in calls to GetObject or GetObjectName.
|
||||||
|
//
|
||||||
|
// ISSUE: Still needs to implement references to objects.
|
||||||
|
// requires a bit of additional design in the XML (minor).
|
||||||
|
int ReadComponent(wxXmlNode *parent, wxIDepersist *Callbacks);
|
||||||
|
|
||||||
|
// When streaming in, we may we depersisting to code, or to objects
|
||||||
|
// in memory. The depersist callbacks for generating code will
|
||||||
|
// not create the objects, but will create names for them instead.
|
||||||
|
// So internally, we keep track of IDs, not pointers. Depending
|
||||||
|
// on who you are in your callbacks, you can query the names or
|
||||||
|
// pointers of the objects as need be. You should not mix both,
|
||||||
|
// because you will die if you do.
|
||||||
|
|
||||||
|
wxObject *GetObject(int id);
|
||||||
|
wxString GetObjectName(int id);
|
||||||
|
wxClassInfo *GetObjectClassInfo(int id) ;
|
||||||
|
|
||||||
|
void SetObject(int id, wxObject *Object);
|
||||||
|
void SetObjectName(int id, const wxString &Name, wxClassInfo* ClassInfo);
|
||||||
|
|
||||||
|
// Returns the result of a top level ReadComponent call. Used
|
||||||
|
// typically after you have instructed the reader to stream in an
|
||||||
|
// object, and you want the object back now. Only really valid if
|
||||||
|
// you are reading back in to an object in memory, as opposed to code.
|
||||||
|
wxObject *GetRoot() { return GetObject( 0 ) ; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wxIDepersist
|
||||||
|
{
|
||||||
|
// NotifyReader is called by wxReader so that we can have access to the
|
||||||
|
// object store functions in the reader when we are called back. Hmm.
|
||||||
|
// probably should have just made the callback functions each take a
|
||||||
|
// wxReader.
|
||||||
|
virtual void NotifyReader(wxReader *Reader) = 0;
|
||||||
|
|
||||||
|
// The next three callbacks match the ACS model of creation of objects.
|
||||||
|
// At runtime, these will create actual instances, and manipulate them.
|
||||||
|
// When generating code, these will just create statements of C++
|
||||||
|
// code to create the objects.
|
||||||
|
virtual void AllocateObject(int ObjectID, wxClassInfo *ClassInfo) = 0;
|
||||||
|
virtual void CreateObject(int ObjectID,
|
||||||
|
wxClassInfo *ClassInfo,
|
||||||
|
int ParamCount,
|
||||||
|
wxxVariant *VariantValues) = 0;
|
||||||
|
virtual void SetProperty(int ObjectID,
|
||||||
|
wxClassInfo *ClassInfo,
|
||||||
|
const wxPropertyInfo* PropertyInfo ,
|
||||||
|
const wxxVariant &VariantValue) = 0;
|
||||||
|
virtual void SetConnect(int EventSourceObjectID,
|
||||||
|
wxClassInfo *EventSourceClassInfo,
|
||||||
|
int eventType ,
|
||||||
|
const wxString &handlerName ,
|
||||||
|
int EventSinkObjectID ) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
wxIDepersistRuntime implements the callbacks that will depersist
|
||||||
|
an object into a running memory image, as opposed to writing
|
||||||
|
C++ initialization code to bring the object to life.
|
||||||
|
*/
|
||||||
|
class wxIDepersistRuntime : public wxIDepersist
|
||||||
|
{
|
||||||
|
wxReader *Reader;
|
||||||
|
public:
|
||||||
|
virtual void NotifyReader(wxReader *_Reader)
|
||||||
|
{
|
||||||
|
Reader = _Reader;
|
||||||
|
}
|
||||||
|
virtual void AllocateObject(int ObjectID, wxClassInfo *ClassInfo);
|
||||||
|
virtual void CreateObject(int ObjectID, wxClassInfo *ClassInfo, int ParamCount, wxxVariant *VariantValues);
|
||||||
|
virtual void SetProperty(int ObjectID, wxClassInfo *ClassInfo, const wxPropertyInfo* PropertyInfo, const wxxVariant &VariantValue);
|
||||||
|
virtual void SetConnect(int EventSourceObjectID,
|
||||||
|
wxClassInfo *EventSourceClassInfo,
|
||||||
|
int eventType ,
|
||||||
|
const wxString &handlerName ,
|
||||||
|
int EventSinkObjectID ) ;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
wxIDepersistCode implements the callbacks that will depersist
|
||||||
|
an object into a C++ initialization function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class wxTextOutputStream ;
|
||||||
|
|
||||||
|
class wxIDepersistCode : public wxIDepersist
|
||||||
|
{
|
||||||
|
wxReader *Reader;
|
||||||
|
wxTextOutputStream *fp;
|
||||||
|
public:
|
||||||
|
wxIDepersistCode(wxTextOutputStream *out) : fp(out) { }
|
||||||
|
virtual void NotifyReader(wxReader *_Reader)
|
||||||
|
{
|
||||||
|
Reader = _Reader;
|
||||||
|
}
|
||||||
|
virtual void AllocateObject(int ObjectID, wxClassInfo *ClassInfo);
|
||||||
|
virtual void CreateObject(int ObjectID, wxClassInfo *ClassInfo, int ParamCount, wxxVariant *VariantValues);
|
||||||
|
virtual void SetProperty(int ObjectID, wxClassInfo *ClassInfo, const wxPropertyInfo* PropertyInfo, const wxxVariant &VariantValue);
|
||||||
|
virtual void SetConnect(int EventSourceObjectID,
|
||||||
|
wxClassInfo *EventSourceClassInfo,
|
||||||
|
int eventType ,
|
||||||
|
const wxString &handlerName ,
|
||||||
|
int EventSinkObjectID ) ;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // wxUSE_EXTENDED_RTTI
|
||||||
|
|
||||||
|
#endif
|
532
src/common/xtistrm.cpp
Normal file
532
src/common/xtistrm.cpp
Normal file
@@ -0,0 +1,532 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Name: src/common/xtistrm.cpp
|
||||||
|
// Purpose: streaming runtime metadata information
|
||||||
|
// Author: Stefan Csomor
|
||||||
|
// Modified by:
|
||||||
|
// Created: 27/07/03
|
||||||
|
// RCS-ID: $Id$
|
||||||
|
// Copyright: (c) 2003 Stefan Csomor
|
||||||
|
// Licence: wxWindows licence
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "xtistrm.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// For compilers that support precompilation, includes "wx.h".
|
||||||
|
#include "wx/wxprec.h"
|
||||||
|
|
||||||
|
#ifdef __BORLANDC__
|
||||||
|
#pragma hdrstop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WX_PRECOMP
|
||||||
|
#include "wx/hash.h"
|
||||||
|
#include "wx/object.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "wx/xml/xml.h"
|
||||||
|
#include "wx/tokenzr.h"
|
||||||
|
#include "wx/xtistrm.h"
|
||||||
|
#include "wx/txtstrm.h"
|
||||||
|
|
||||||
|
#if wxUSE_EXTENDED_RTTI
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using namespace std ;
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// streaming xml out
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void WriteComponent(wxObject *Object, const wxClassInfo *ClassInfo, wxXmlNode *parent, const wxString& nodeName , int &nextId , map< wxObject* , int > &writtenObjects ) ;
|
||||||
|
|
||||||
|
void WriteComponentProperties( wxObject* obj , const wxClassInfo* ci , wxXmlNode *onode , int &nextId, map< wxObject* , int > &writtenObjects, map< string , int > &writtenProperties)
|
||||||
|
{
|
||||||
|
const wxPropertyInfo *pi = ci->GetFirstProperty() ;
|
||||||
|
while( pi )
|
||||||
|
{
|
||||||
|
if ( writtenProperties.find( pi->GetName() ) == writtenProperties.end() )
|
||||||
|
{
|
||||||
|
writtenProperties[ pi->GetName() ] = 1 ;
|
||||||
|
const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( pi->GetTypeInfo() ) ;
|
||||||
|
if ( cti )
|
||||||
|
{
|
||||||
|
const wxClassInfo* pci = cti->GetClassInfo() ;
|
||||||
|
WriteComponent( pci->VariantToInstance( pi->GetAccessor()->GetProperty(obj) ) , pci , onode , pi->GetName() , nextId , writtenObjects ) ;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const wxDelegateTypeInfo* dti = dynamic_cast< const wxDelegateTypeInfo* > ( pi->GetTypeInfo() ) ;
|
||||||
|
if ( dti )
|
||||||
|
{
|
||||||
|
// in which form should we stream out these ?
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wxXmlNode *pnode;
|
||||||
|
pnode = new wxXmlNode(wxXML_ELEMENT_NODE, pi->GetName() );
|
||||||
|
pi->GetAccessor()->WriteValue(pnode, obj ) ;
|
||||||
|
onode->AddChild(pnode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pi = pi->GetNext() ;
|
||||||
|
}
|
||||||
|
const wxClassInfo** parents = ci->GetParents() ;
|
||||||
|
for ( int i = 0 ; parents[i] ; ++ i )
|
||||||
|
{
|
||||||
|
WriteComponentProperties( obj , parents[i] , onode , nextId , writtenObjects , writtenProperties ) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Writing Components does have to take inheritance into account, that's why we are iterating
|
||||||
|
over our parents as well
|
||||||
|
*/
|
||||||
|
|
||||||
|
void WriteComponent(wxObject *obj, const wxClassInfo *classInfo, wxXmlNode *parent, const wxString &nodeName)
|
||||||
|
{
|
||||||
|
int nextid = 0 ; // 0 is the root element
|
||||||
|
map< wxObject* , int > writtenobjects ;
|
||||||
|
WriteComponent( obj , classInfo, parent, nodeName , nextid , writtenobjects ) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteComponent(wxObject *obj, const wxClassInfo *classInfo, wxXmlNode *parent, const wxString& nodeName , int &nextId, map< wxObject* , int > &writtenObjects )
|
||||||
|
{
|
||||||
|
map< string , int > writtenProperties ;
|
||||||
|
wxXmlNode *onode;
|
||||||
|
|
||||||
|
onode = new wxXmlNode(wxXML_ELEMENT_NODE, nodeName);
|
||||||
|
|
||||||
|
onode->AddProperty(wxString("class"), wxString(classInfo->GetClassName()));
|
||||||
|
if ( obj == NULL )
|
||||||
|
{
|
||||||
|
wxXmlNode* nullnode = new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, "null");
|
||||||
|
onode->AddChild(nullnode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if we have already written this object, just insert an id
|
||||||
|
if ( writtenObjects.find( obj ) != writtenObjects.end() )
|
||||||
|
{
|
||||||
|
onode->AddProperty(wxString("id"), wxString::Format( "%d" , writtenObjects[obj] ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int id = nextId++ ;
|
||||||
|
writtenObjects[obj] = id ;
|
||||||
|
onode->AddProperty(wxString("id"), wxString::Format( "%d" , id ) );
|
||||||
|
WriteComponentProperties( obj , classInfo , onode , nextId , writtenObjects, writtenProperties) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parent->AddChild(onode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// reading xml in
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
wxxVariant wxReader::ReadPropertyValueNoAssign(wxXmlNode *Node,
|
||||||
|
wxClassInfo *ClassInfo,
|
||||||
|
const wxPropertyInfo * &pi ,
|
||||||
|
wxIDepersist *Callbacks)
|
||||||
|
{
|
||||||
|
wxxVariant res;
|
||||||
|
int ChildID;
|
||||||
|
|
||||||
|
// form is:
|
||||||
|
// <propname type=foo>value</propname>
|
||||||
|
|
||||||
|
//ISSUE: NULL component references are streamed out as "null" text
|
||||||
|
// node. This is not in keeping with the XML mindset.
|
||||||
|
|
||||||
|
pi = ClassInfo->FindPropertyInfo(Node->GetName());
|
||||||
|
if (!pi)
|
||||||
|
{
|
||||||
|
// error handling, please
|
||||||
|
assert(!"Property not found in extended class info");
|
||||||
|
}
|
||||||
|
|
||||||
|
const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( pi->GetTypeInfo() ) ;
|
||||||
|
if ( cti )
|
||||||
|
{
|
||||||
|
const wxClassInfo* eci = cti->GetClassInfo() ;
|
||||||
|
|
||||||
|
ChildID = ReadComponent(Node , Callbacks);
|
||||||
|
if (ChildID != -1)
|
||||||
|
{
|
||||||
|
if (genCode)
|
||||||
|
res = wxxVariant(GetObjectName(ChildID));
|
||||||
|
else
|
||||||
|
res = eci->InstanceToVariant(GetObject(ChildID));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (genCode)
|
||||||
|
res = wxxVariant(wxString("NULL"));
|
||||||
|
else
|
||||||
|
res = eci->InstanceToVariant(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const wxDelegateTypeInfo* dti = dynamic_cast< const wxDelegateTypeInfo* > ( pi->GetTypeInfo() ) ;
|
||||||
|
if ( dti )
|
||||||
|
{
|
||||||
|
if (genCode)
|
||||||
|
{
|
||||||
|
// in which form should we code these ?
|
||||||
|
res = wxxVariant( wxXmlGetContentFromNode(Node) ) ;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = wxxVariant( wxXmlGetContentFromNode(Node) ) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (genCode)
|
||||||
|
{
|
||||||
|
if ( pi->GetTypeInfo()->GetKind() == wxT_STRING )
|
||||||
|
res = wxxVariant( wxString::Format("wxString(\"%s\")",wxXmlGetContentFromNode(Node)));
|
||||||
|
else
|
||||||
|
res = wxxVariant( wxString::Format("%s(%s)",pi->GetTypeName(),wxXmlGetContentFromNode(Node) ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
res = pi->GetAccessor()->ReadValue(Node) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxReader::ReadPropertyValue(wxXmlNode *Node,
|
||||||
|
wxClassInfo *ClassInfo,
|
||||||
|
int ObjectID ,
|
||||||
|
wxIDepersist *Callbacks)
|
||||||
|
{
|
||||||
|
const wxPropertyInfo *pi;
|
||||||
|
wxxVariant res = ReadPropertyValueNoAssign( Node , ClassInfo, pi , Callbacks ) ;
|
||||||
|
|
||||||
|
const wxDelegateTypeInfo* dti = dynamic_cast< const wxDelegateTypeInfo* > ( pi->GetTypeInfo() ) ;
|
||||||
|
|
||||||
|
if ( dti )
|
||||||
|
{
|
||||||
|
wxString resstring = res.Get<wxString>() ;
|
||||||
|
wxInt32 pos = resstring.Find('.') ;
|
||||||
|
assert( pos != wxNOT_FOUND ) ;
|
||||||
|
int handlerOid = atol(resstring.Left(pos)) ;
|
||||||
|
wxString handlerName = resstring.Mid(pos+1) ;
|
||||||
|
|
||||||
|
if (Callbacks)
|
||||||
|
Callbacks->SetConnect( ObjectID , ClassInfo , dti->GetEventType() , handlerName , handlerOid ) ;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Callbacks)
|
||||||
|
Callbacks->SetProperty(ObjectID, ClassInfo, pi , res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wxReader::wxReaderInternal
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Code streamer will be storing names here. Runtime object streamer
|
||||||
|
will be storing actual pointers to objects here. The two are never
|
||||||
|
mixed. So the Objects array either has data, or the ObjectNames
|
||||||
|
array has data. Never both. Keyed by ObjectID (int)
|
||||||
|
*/
|
||||||
|
map<int,wxObject *> Objects;
|
||||||
|
|
||||||
|
map<int,string> ObjectNames;
|
||||||
|
// only used when generating code, since the names loose the type info
|
||||||
|
map<int,wxClassInfo*> ObjectClasses;
|
||||||
|
};
|
||||||
|
|
||||||
|
wxReader::wxReader(bool GenerateCode) : genCode(GenerateCode)
|
||||||
|
{
|
||||||
|
Data = new wxReaderInternal;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxReader::~wxReader()
|
||||||
|
{
|
||||||
|
delete Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxObject *wxReader::GetObject(int id)
|
||||||
|
{
|
||||||
|
assert( Data->Objects.find(id) != Data->Objects.end() );
|
||||||
|
return Data->Objects[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
wxString wxReader::GetObjectName(int id)
|
||||||
|
{
|
||||||
|
assert( Data->ObjectNames.find(id) != Data->ObjectNames.end() );
|
||||||
|
return wxString(Data->ObjectNames[id].c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
wxClassInfo* wxReader::GetObjectClassInfo(int id)
|
||||||
|
{
|
||||||
|
assert( Data->ObjectClasses.find(id) != Data->ObjectClasses.end() );
|
||||||
|
return Data->ObjectClasses[id] ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxReader::SetObject(int id, wxObject *Object)
|
||||||
|
{
|
||||||
|
assert( Data->Objects.find(id) == Data->Objects.end() ) ;
|
||||||
|
Data->Objects[id] = Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxReader::SetObjectName(int id, const wxString &Name, wxClassInfo *ClassInfo )
|
||||||
|
{
|
||||||
|
assert( Data->ObjectNames.find(id) == Data->ObjectNames.end() ) ;
|
||||||
|
Data->ObjectNames[id] = (const char *)Name;
|
||||||
|
Data->ObjectClasses[id] = ClassInfo ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reading components has not to be extended for components
|
||||||
|
as properties are always sought by typeinfo over all levels
|
||||||
|
and create params are always toplevel class only
|
||||||
|
*/
|
||||||
|
|
||||||
|
int wxReader::ReadComponent(wxXmlNode *Node, wxIDepersist *Callbacks)
|
||||||
|
{
|
||||||
|
wxString ClassName;
|
||||||
|
wxClassInfo *ClassInfo;
|
||||||
|
|
||||||
|
wxxVariant *CreateParams ;
|
||||||
|
wxXmlNode *Children;
|
||||||
|
int ObjectID;
|
||||||
|
|
||||||
|
Callbacks->NotifyReader(this);
|
||||||
|
|
||||||
|
Children = Node->GetChildren();
|
||||||
|
if (!Node->GetPropVal("class", &ClassName))
|
||||||
|
{
|
||||||
|
// No class name. Eek. FIXME: error handling
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ClassInfo = wxClassInfo::FindClass(ClassName);
|
||||||
|
if (Node->GetType() == wxXML_TEXT_NODE)
|
||||||
|
{
|
||||||
|
assert( wxXmlGetContentFromNode(Node) == "null" ) ;
|
||||||
|
// this must be a NULL component reference. We just bail out
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxString ObjectIdString ;
|
||||||
|
if (!Node->GetPropVal("id", &ObjectIdString))
|
||||||
|
{
|
||||||
|
// No object id. Eek. FIXME: error handling
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectID = atoi( ObjectIdString.c_str() ) ;
|
||||||
|
// is this object already has been streamed in, return it here
|
||||||
|
if ( genCode )
|
||||||
|
{
|
||||||
|
if ( Data->ObjectNames.find( ObjectID ) != Data->ObjectNames.end() )
|
||||||
|
return ObjectID ;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( Data->Objects.find( ObjectID ) != Data->Objects.end() )
|
||||||
|
return ObjectID ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// new object, start with allocation
|
||||||
|
Callbacks->AllocateObject(ObjectID, ClassInfo);
|
||||||
|
|
||||||
|
//
|
||||||
|
// stream back the Create parameters first
|
||||||
|
CreateParams = new wxxVariant[ ClassInfo->GetCreateParamCount() ] ;
|
||||||
|
|
||||||
|
typedef map<string, wxXmlNode *> PropertyNodes ;
|
||||||
|
typedef vector<string> PropertyNames ;
|
||||||
|
|
||||||
|
PropertyNodes propertyNodes ;
|
||||||
|
PropertyNames propertyNames ;
|
||||||
|
|
||||||
|
while( Children )
|
||||||
|
{
|
||||||
|
propertyNames.push_back( Children->GetName().c_str() ) ;
|
||||||
|
propertyNodes[Children->GetName().c_str()] = Children ;
|
||||||
|
Children = Children->GetNext() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i = 0 ; i <ClassInfo->GetCreateParamCount() ; ++i )
|
||||||
|
{
|
||||||
|
const wxChar* paramName = ClassInfo->GetCreateParamName(i) ;
|
||||||
|
PropertyNodes::iterator propiter = propertyNodes.find( paramName ) ;
|
||||||
|
// if we don't have the value of a create param set in the xml
|
||||||
|
// we use the default value
|
||||||
|
if ( propiter != propertyNodes.end() )
|
||||||
|
{
|
||||||
|
wxXmlNode* prop = propiter->second ;
|
||||||
|
wxPropertyInfo* pi ;
|
||||||
|
CreateParams[i] = ReadPropertyValueNoAssign( prop , ClassInfo , pi , Callbacks ) ;
|
||||||
|
// CreateParams[i] = ClassInfo->FindPropertyInfo( ClassInfo->GetCreateParamName(i) ->GetAccessor()->ReadValue( prop ) ;
|
||||||
|
for ( size_t j = 0 ; j < propertyNames.size() ; ++j )
|
||||||
|
{
|
||||||
|
if ( propertyNames[j] == paramName )
|
||||||
|
{
|
||||||
|
propertyNames[j] = "" ;
|
||||||
|
break ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CreateParams[i] = ClassInfo->FindPropertyInfo( paramName )->GetDefaultValue() ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// got the parameters. Call the Create method
|
||||||
|
Callbacks->CreateObject(ObjectID,
|
||||||
|
ClassInfo,
|
||||||
|
ClassInfo->GetCreateParamCount(),
|
||||||
|
&CreateParams[0]);
|
||||||
|
|
||||||
|
// now stream in the rest of the properties, in the sequence their properties were written in the xml
|
||||||
|
for ( size_t j = 0 ; j < propertyNames.size() ; ++j )
|
||||||
|
{
|
||||||
|
if ( propertyNames[j].length() )
|
||||||
|
{
|
||||||
|
PropertyNodes::iterator propiter = propertyNodes.find( propertyNames[j] ) ;
|
||||||
|
if ( propiter != propertyNodes.end() )
|
||||||
|
{
|
||||||
|
wxXmlNode* prop = propiter->second ;
|
||||||
|
string name = propiter->first ;
|
||||||
|
ReadPropertyValue( prop , ClassInfo , ObjectID , Callbacks ) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
for( PropertyNodes::iterator propiter = propertyNodes.begin() ; propiter != propertyNodes.end() ; propiter++ )
|
||||||
|
{
|
||||||
|
wxXmlNode* prop = propiter->second ;
|
||||||
|
string name = propiter->first ;
|
||||||
|
ReadPropertyValue( prop , ClassInfo , ObjectID , Callbacks ) ;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// FIXME: if the list of children is not NULL now, then that means that
|
||||||
|
// there were properties in the XML not represented in the meta data
|
||||||
|
// this just needs error handling.
|
||||||
|
assert(!Children);
|
||||||
|
|
||||||
|
delete[] CreateParams ;
|
||||||
|
|
||||||
|
return ObjectID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// depersisting to memory
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void wxIDepersistRuntime::AllocateObject(int ObjectID, wxClassInfo *ClassInfo)
|
||||||
|
{
|
||||||
|
wxObject *O;
|
||||||
|
O = ClassInfo->CreateObject();
|
||||||
|
Reader->SetObject(ObjectID, O);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxIDepersistRuntime::CreateObject(int ObjectID,
|
||||||
|
wxClassInfo *ClassInfo,
|
||||||
|
int ParamCount,
|
||||||
|
wxxVariant *Params)
|
||||||
|
{
|
||||||
|
wxObject *O;
|
||||||
|
O = Reader->GetObject(ObjectID);
|
||||||
|
ClassInfo->Create(O, ParamCount, Params);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxIDepersistRuntime::SetProperty(int ObjectID,
|
||||||
|
wxClassInfo *WXUNUSED(ClassInfo),
|
||||||
|
const wxPropertyInfo* PropertyInfo,
|
||||||
|
const wxxVariant &Value)
|
||||||
|
{
|
||||||
|
wxObject *O;
|
||||||
|
O = Reader->GetObject(ObjectID);
|
||||||
|
PropertyInfo->GetAccessor()->SetProperty( O , Value ) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxIDepersistRuntime::SetConnect(int EventSourceObjectID,
|
||||||
|
wxClassInfo *WXUNUSED(EventSourceClassInfo),
|
||||||
|
int eventType ,
|
||||||
|
const wxString &handlerName ,
|
||||||
|
int EventSinkObjectID )
|
||||||
|
{
|
||||||
|
wxWindow *ehsource = dynamic_cast< wxWindow* >( Reader->GetObject( EventSourceObjectID ) ) ;
|
||||||
|
wxEvtHandler *ehsink = dynamic_cast< wxEvtHandler *>(Reader->GetObject(EventSinkObjectID) ) ;
|
||||||
|
|
||||||
|
if ( ehsource && ehsink )
|
||||||
|
{
|
||||||
|
ehsource->Connect( ehsource->GetId() , eventType ,
|
||||||
|
ehsink->GetClassInfo()->FindHandlerInfo(handlerName)->GetEventFunction() , NULL /*user data*/ ,
|
||||||
|
ehsink ) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// depersisting to code
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
void wxIDepersistCode::AllocateObject(int ObjectID, wxClassInfo *ClassInfo)
|
||||||
|
{
|
||||||
|
wxString objectName = wxString::Format( "LocalObject_%d" , ObjectID ) ;
|
||||||
|
fp->WriteString( wxString::Format( "\t%s *%s = new %s;\n",
|
||||||
|
ClassInfo->GetClassName(),
|
||||||
|
objectName,
|
||||||
|
ClassInfo->GetClassName()) );
|
||||||
|
Reader->SetObjectName(ObjectID, objectName, ClassInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxIDepersistCode::CreateObject(int ObjectID,
|
||||||
|
wxClassInfo *WXUNUSED(ClassInfo),
|
||||||
|
int ParamCount,
|
||||||
|
wxxVariant *Params)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
fp->WriteString( wxString::Format( "\t%s->Create(", Reader->GetObjectName(ObjectID) ) );
|
||||||
|
for (i = 0; i < ParamCount; i++)
|
||||||
|
{
|
||||||
|
fp->WriteString( wxString::Format( "%s", (const char *)Params[i].Get<wxString>() ) );
|
||||||
|
if (i < ParamCount - 1)
|
||||||
|
fp->WriteString( ", ");
|
||||||
|
}
|
||||||
|
fp->WriteString( ");\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxIDepersistCode::SetProperty(int ObjectID,
|
||||||
|
wxClassInfo *WXUNUSED(ClassInfo),
|
||||||
|
const wxPropertyInfo* PropertyInfo,
|
||||||
|
const wxxVariant &Value)
|
||||||
|
{
|
||||||
|
wxString d = Value.Get<wxString>() ;
|
||||||
|
fp->WriteString( wxString::Format( "\t%s->%s(%s);\n",
|
||||||
|
Reader->GetObjectName(ObjectID),
|
||||||
|
PropertyInfo->GetAccessor()->GetSetterName(),
|
||||||
|
d) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxIDepersistCode::SetConnect(int EventSourceObjectID,
|
||||||
|
wxClassInfo *WXUNUSED(EventSourceClassInfo),
|
||||||
|
int eventType ,
|
||||||
|
const wxString &handlerName ,
|
||||||
|
int EventSinkObjectID )
|
||||||
|
{
|
||||||
|
wxString ehsource = Reader->GetObjectName( EventSourceObjectID ) ;
|
||||||
|
wxString ehsink = Reader->GetObjectName(EventSinkObjectID) ;
|
||||||
|
wxString ehsinkClass = Reader->GetObjectClassInfo(EventSinkObjectID)->GetClassName() ;
|
||||||
|
|
||||||
|
fp->WriteString( wxString::Format( "\t%s->Connect( %s->GetId() , %d , (wxObjectEventFunction)(wxEventFunction) & %s::%s , NULL , %s ) ;" ,
|
||||||
|
ehsource , ehsource , eventType , ehsinkClass , handlerName , ehsink ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Reference in New Issue
Block a user