X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/14f355c2b5c71fc7c3d680aea366582d2ac60f7b..1e52188741389278cd99abf79218162c87024ba3:/src/common/xtistrm.cpp diff --git a/src/common/xtistrm.cpp b/src/common/xtistrm.cpp index 621341ae4f..372602c376 100644 --- a/src/common/xtistrm.cpp +++ b/src/common/xtistrm.cpp @@ -31,9 +31,12 @@ #include "wx/txtstrm.h" #if wxUSE_EXTENDED_RTTI + +#include "wx/beforestd.h" #include #include #include +#include "wx/afterstd.h" using namespace std ; @@ -56,132 +59,213 @@ wxWriter::~wxWriter() struct wxWriter::wxWriterInternalPropertiesData { - map< string , int > m_writtenProperties ; + char nothing ; } ; -void wxWriter::WriteObject(const wxObject *object, const wxClassInfo *classInfo , wxPersister *persister , const wxString &name ) +void wxWriter::ClearObjectContext() +{ + delete m_data ; + m_data = new wxWriterInternal() ; + m_data->m_nextId = 0 ; +} + +void wxWriter::WriteObject(const wxObject *object, const wxClassInfo *classInfo , wxPersister *persister , const wxString &name , wxxVariantArray &metadata ) { - if ( persister->BeforeWriteObject( object , classInfo , name ) ) + DoBeginWriteTopLevelEntry( name ) ; + WriteObject( object , classInfo , persister , false , metadata) ; + DoEndWriteTopLevelEntry( name ) ; +} + +void wxWriter::WriteObject(const wxObject *object, const wxClassInfo *classInfo , wxPersister *persister , bool isEmbedded, wxxVariantArray &metadata ) +{ + // hack to avoid writing out embedded windows, these are windows that are constructed as part of other windows, they would + // doubly constructed afterwards + + const wxWindow * win = dynamic_cast(object) ; + if ( win && win->GetId() < 0 ) + return ; + + if ( persister->BeforeWriteObject( this , object , classInfo , metadata) ) { - int oid = m_data->m_nextId++ ; - m_data->m_writtenObjects[object] = oid ; - DoBeginWriteObject( object , classInfo , oid , name ) ; - wxWriterInternalPropertiesData data ; - WriteAllProperties( object , classInfo , persister , &data ) ; - DoEndWriteObject( object , classInfo , oid , name ) ; + if ( object == NULL ) + DoWriteNullObject() ; + else if ( IsObjectKnown( object ) ) + DoWriteRepeatedObject( GetObjectID(object) ) ; + else + { + int oid = m_data->m_nextId++ ; + if ( !isEmbedded ) + m_data->m_writtenObjects[object] = oid ; + + // in case this object is a wxDynamicObject we also have to insert is superclass + // instance with the same id, so that object relations are streamed out correctly + const wxDynamicObject* dynobj = dynamic_cast( object ) ; + if ( !isEmbedded && dynobj ) + m_data->m_writtenObjects[dynobj->GetSuperClassInstance()] = oid ; + + DoBeginWriteObject( object , classInfo , oid , metadata ) ; + wxWriterInternalPropertiesData data ; + WriteAllProperties( object , classInfo , persister , &data ) ; + DoEndWriteObject( object , classInfo , oid ) ; + } + persister->AfterWriteObject( this ,object , classInfo ) ; } } -void wxWriter::WriteAllProperties( const wxObject * obj , const wxClassInfo* ci , wxPersister *persister, wxWriterInternalPropertiesData * data ) +void wxWriter::FindConnectEntry(const wxWindow * evSource,const wxDelegateTypeInfo* dti, const wxObject* &sink , const wxHandlerInfo *&handler) { - const wxPropertyInfo *pi = ci->GetFirstProperty() ; - while( pi ) + wxList *dynamicEvents = evSource->GetDynamicEventTable() ; + + if ( dynamicEvents ) { - if ( data->m_writtenProperties.find( pi->GetName() ) == data->m_writtenProperties.end() ) + wxList::compatibility_iterator node = dynamicEvents->GetFirst(); + while (node) { - data->m_writtenProperties[ pi->GetName() ] = 1 ; - const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( pi->GetTypeInfo() ) ; - if ( cti ) + wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData(); + + // find the match + if ( entry->m_fn && (dti->GetEventType() == entry->m_eventType) && + (entry->m_id == -1 || + (entry->m_lastId == -1 && evSource->GetId() == entry->m_id) || + (entry->m_lastId != -1 && + (evSource->GetId() >= entry->m_id && evSource->GetId() <= entry->m_lastId) ) ) && + entry->m_eventSink + ) { - const wxClassInfo* pci = cti->GetClassInfo() ; - wxxVariant value = pi->GetAccessor()->GetProperty(obj) ; - if ( persister->BeforeWritePropertyAsObject( obj , ci , pi , value ) ) + sink = entry->m_eventSink ; + const wxClassInfo* sinkClassInfo = sink->GetClassInfo() ; + const wxHandlerInfo* sinkHandler = sinkClassInfo->GetFirstHandler() ; + while ( sinkHandler ) { - wxObject *vobj = pci->VariantToInstance( value ) ; - bool embeddedObject = cti->GetKind() == wxT_OBJECT ; - - if ( vobj == NULL || IsObjectKnown( vobj ) ) + if ( sinkHandler->GetEventFunction() == entry->m_fn ) { - DoWriteObjectReference( obj , ci , vobj , pci , GetObjectID(vobj) , pi ) ; - } - else - { - int oid = m_data->m_nextId++ ; - if ( !embeddedObject) - m_data->m_writtenObjects[vobj] = oid ; - - DoBeginWriteParamAsObject( obj , ci , vobj , pci , oid , pi ) ; - if ( vobj != NULL ) - { - wxWriterInternalPropertiesData data ; - WriteAllProperties( vobj , pci , persister , &data ) ; - } - DoEndWriteParamAsObject( obj , ci , vobj , pci , oid , pi ) ; + handler = sinkHandler ; + break ; } + sinkHandler = sinkHandler->GetNext() ; } + break ; } - else + node = node->GetNext(); + } + } +} +void wxWriter::WriteAllProperties( const wxObject * obj , const wxClassInfo* ci , wxPersister *persister, wxWriterInternalPropertiesData * data ) +{ + wxPropertyInfoMap map ; + ci->GetProperties( map ) ; + for ( int i = 0 ; i < ci->GetCreateParamCount() ; ++i ) + { + wxString name = ci->GetCreateParamName(i) ; + const wxPropertyInfo* prop = map.find(name)->second ; + wxASSERT_MSG( prop , wxT("Create Parameter not found in declared RTTI Parameters") ) ; + WriteOneProperty( obj , prop->GetDeclaringClass() , prop , persister , data ) ; + map.erase( name ) ; + } + + for( wxPropertyInfoMap::iterator iter = map.begin() ; iter != map.end() ; ++iter ) + { + const wxPropertyInfo* prop = iter->second ; + if ( prop->GetFlags() & wxPROP_OBJECT_GRAPH ) + { + WriteOneProperty( obj , prop->GetDeclaringClass() , prop , persister , data ) ; + } + } + + for( wxPropertyInfoMap::iterator iter = map.begin() ; iter != map.end() ; ++iter ) + { + const wxPropertyInfo* prop = iter->second ; + if ( !(prop->GetFlags() & wxPROP_OBJECT_GRAPH) ) + { + WriteOneProperty( obj , prop->GetDeclaringClass() , prop , persister , data ) ; + } + } +} + +void wxWriter::WriteOneProperty( const wxObject *obj , const wxClassInfo* ci , const wxPropertyInfo* pi , wxPersister *persister , wxWriterInternalPropertiesData *data ) +{ + // make sure that we are picking the correct object for accessing the property + const wxDynamicObject* dynobj = dynamic_cast< const wxDynamicObject* > (obj ) ; + if ( dynobj && (dynamic_cast(ci) == NULL) ) + obj = dynobj->GetSuperClassInstance() ; + + DoBeginWriteProperty( pi ) ; + if ( pi->GetTypeInfo()->GetKind() == wxT_COLLECTION ) + { + wxxVariantArray data ; + pi->GetAccessor()->GetPropertyCollection(obj, data) ; + const wxTypeInfo * elementType = dynamic_cast< const wxCollectionTypeInfo* >( pi->GetTypeInfo() )->GetElementType() ; + for ( size_t i = 0 ; i < data.GetCount() ; ++i ) + { + DoBeginWriteElement() ; + wxxVariant value = data[i] ; + if ( persister->BeforeWriteProperty( this , pi , value ) ) { - const wxDelegateTypeInfo* dti = dynamic_cast< const wxDelegateTypeInfo* > ( pi->GetTypeInfo() ) ; - if ( dti ) + const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( elementType ) ; + if ( cti ) { - const wxObject* sink = NULL ; - const wxHandlerInfo *handler = NULL ; - - const wxWindow * evSource = dynamic_cast(obj) ; - wxASSERT_MSG( evSource , wxT("Illegal Object Class (Non-Window) as Event Source") ) ; + const wxClassInfo* pci = cti->GetClassInfo() ; + wxObject *vobj = pci->VariantToInstance( value ) ; + wxxVariantArray md ; + WriteObject( vobj , (vobj ? vobj->GetClassInfo() : pci ) , persister , cti->GetKind()== wxT_OBJECT , md ) ; + } + else + { + DoWriteSimpleType( value ) ; + } + } + DoEndWriteElement() ; + } + } + else + { + const wxDelegateTypeInfo* dti = dynamic_cast< const wxDelegateTypeInfo* > ( pi->GetTypeInfo() ) ; + if ( dti ) + { + const wxObject* sink = NULL ; + const wxHandlerInfo *handler = NULL ; - wxList *dynamicEvents = evSource->GetDynamicEventTable() ; + const wxWindow * evSource = dynamic_cast(obj) ; + wxASSERT_MSG( evSource , wxT("Illegal Object Class (Non-Window) as Event Source") ) ; - if ( dynamicEvents ) - { - wxList::compatibility_iterator node = dynamicEvents->GetFirst(); - while (node) - { - wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData(); - - // find the match - if ( entry->m_fn && (dti->GetEventType() == entry->m_eventType) && - (entry->m_id == -1 || - (entry->m_lastId == -1 && evSource->GetId() == entry->m_id) || - (entry->m_lastId != -1 && - (evSource->GetId() >= entry->m_id && evSource->GetId() <= entry->m_lastId) ) ) && - entry->m_eventSink - ) - { - sink = entry->m_eventSink ; - const wxClassInfo* sinkClassInfo = sink->GetClassInfo() ; - const wxHandlerInfo* sinkHandler = sinkClassInfo->GetFirstHandler() ; - while ( sinkHandler ) - { - if ( sinkHandler->GetEventFunction() == entry->m_fn ) - { - handler = sinkHandler ; - break ; - } - sinkHandler = sinkHandler->GetNext() ; - } - break ; - } - node = node->GetNext(); - } - } - if ( persister->BeforeWriteDelegate( obj , ci , pi , sink , handler ) ) - { - if ( sink != NULL && handler != NULL ) - { - wxASSERT_MSG( IsObjectKnown( sink ) , wxT("Streaming delegates for not already streamed objects not yet supported") ) ; - DoWriteDelegate( obj , ci , pi , sink , GetObjectID( sink ) , sink->GetClassInfo() , handler ) ; - } - } + FindConnectEntry( evSource , dti , sink , handler ) ; + if ( persister->BeforeWriteDelegate( this , obj , ci , pi , sink , handler ) ) + { + if ( sink != NULL && handler != NULL ) + { + wxASSERT_MSG( IsObjectKnown( sink ) , wxT("Streaming delegates for not already streamed objects not yet supported") ) ; + DoWriteDelegate( obj , ci , pi , sink , GetObjectID( sink ) , sink->GetClassInfo() , handler ) ; } - else + } + } + else + { + wxxVariant value ; + pi->GetAccessor()->GetProperty(obj, value) ; + if ( persister->BeforeWriteProperty( this , pi , value ) ) + { + const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( pi->GetTypeInfo() ) ; + if ( cti ) { - wxxVariant value = pi->GetAccessor()->GetProperty(obj) ; - if ( persister->BeforeWriteProperty( obj , ci , pi , value ) ) + const wxClassInfo* pci = cti->GetClassInfo() ; + wxObject *vobj = pci->VariantToInstance( value ) ; + wxxVariantArray md ; + WriteObject( vobj , (vobj ? vobj->GetClassInfo() : pci ) , persister , cti->GetKind()== wxT_OBJECT , md) ; + } + else + { + if ( pi->GetFlags() & wxPROP_ENUM_STORE_LONG ) { - DoWriteProperty( obj , ci , pi , value ) ; + const wxEnumTypeInfo *eti = dynamic_cast( pi->GetTypeInfo() ) ; + wxASSERT_MSG( eti , wxT("Type must have enum - long conversion") ) ; + eti->ConvertFromLong( value.Get() , value ) ; } + DoWriteSimpleType( value ) ; } } } - pi = pi->GetNext() ; - } - const wxClassInfo** parents = ci->GetParents() ; - for ( int i = 0 ; parents[i] ; ++ i ) - { - WriteAllProperties( obj , parents[i] , persister , data ) ; } + DoEndWriteProperty( pi ) ; } int wxWriter::GetObjectID(const wxObject *obj) @@ -221,6 +305,18 @@ struct wxXmlWriter::wxXmlWriterInternal wxXmlNode *m_root ; wxXmlNode *m_current ; vector< wxXmlNode * > m_objectStack ; + + void Push( wxXmlNode *newCurrent ) + { + m_objectStack.push_back( m_current ) ; + m_current = newCurrent ; + } + + void Pop() + { + m_current = m_objectStack.back() ; + m_objectStack.pop_back() ; + } } ; wxXmlWriter::wxXmlWriter( wxXmlNode * rootnode ) @@ -235,87 +331,100 @@ wxXmlWriter::~wxXmlWriter() delete m_data ; } -// start of writing the root object -void wxXmlWriter::DoBeginWriteObject(const wxObject *WXUNUSED(object), const wxClassInfo *classInfo, int objectID , const wxString &name ) +void wxXmlWriter::DoBeginWriteTopLevelEntry( const wxString &name ) { - wxXmlNode *onode; - onode = new wxXmlNode(wxXML_ELEMENT_NODE, name); - onode->AddProperty(wxString("class"), wxString(classInfo->GetClassName())); - onode->AddProperty(wxString("id"), wxString::Format( "%d" , objectID ) ); + wxXmlNode *pnode; + pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("entry")); + pnode->AddProperty(wxString("name"), name); + m_data->m_current->AddChild(pnode) ; + m_data->Push( pnode ) ; +} - m_data->m_current->AddChild(onode) ; - m_data->m_objectStack.push_back( m_data->m_current ) ; - m_data->m_current = onode ; +void wxXmlWriter::DoEndWriteTopLevelEntry( const wxString &WXUNUSED(name) ) +{ + m_data->Pop() ; +} + +void wxXmlWriter::DoBeginWriteObject(const wxObject *WXUNUSED(object), const wxClassInfo *classInfo, int objectID , wxxVariantArray &metadata ) +{ + wxXmlNode *pnode; + pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("object")); + pnode->AddProperty(wxT("class"), wxString(classInfo->GetClassName())); + pnode->AddProperty(wxT("id"), wxString::Format( "%d" , objectID ) ); + + for ( size_t i = 0 ; i < metadata.GetCount() ; ++i ) + { + pnode->AddProperty( metadata[i].GetName() , metadata[i].GetAsString() ) ; + } + m_data->m_current->AddChild(pnode) ; + m_data->Push( pnode ) ; } // end of writing the root object -void wxXmlWriter::DoEndWriteObject(const wxObject *WXUNUSED(object), const wxClassInfo *WXUNUSED(classInfo), int WXUNUSED(objectID) , const wxString &WXUNUSED(name) ) +void wxXmlWriter::DoEndWriteObject(const wxObject *WXUNUSED(object), const wxClassInfo *WXUNUSED(classInfo), int WXUNUSED(objectID) ) { - m_data->m_current = m_data->m_objectStack.back() ; - m_data->m_objectStack.pop_back() ; + m_data->Pop() ; } // writes a property in the stream format -void wxXmlWriter::DoWriteProperty( const wxObject *WXUNUSED(obj), const wxClassInfo* WXUNUSED(classInfo) , const wxPropertyInfo *pi , wxxVariant &value ) +void wxXmlWriter::DoWriteSimpleType( wxxVariant &value ) +{ + wxXmlAddContentToNode( m_data->m_current ,value.GetAsString() ) ; +} + +void wxXmlWriter::DoBeginWriteElement() { wxXmlNode *pnode; - pnode = new wxXmlNode(wxXML_ELEMENT_NODE, pi->GetName() ); - wxXmlAddContentToNode( pnode ,value.GetAsString() ) ; - m_data->m_current->AddChild(pnode); + pnode = new wxXmlNode(wxXML_ELEMENT_NODE, "element" ); + m_data->m_current->AddChild(pnode) ; + m_data->Push( pnode ) ; } -void wxXmlWriter::DoBeginWriteParamAsObject(const wxObject *WXUNUSED(parentObject), const wxClassInfo *WXUNUSED(parentClassInfo), const wxObject *WXUNUSED(valueObject), - const wxClassInfo *valueObjectClassInfo, int valueObjectID , const wxPropertyInfo *propInfo ) +void wxXmlWriter::DoEndWriteElement() { - wxXmlNode *onode; - onode = new wxXmlNode(wxXML_ELEMENT_NODE, propInfo->GetName()); - onode->AddProperty(wxString("class"), wxString(valueObjectClassInfo->GetClassName())); - onode->AddProperty(wxString("id"), wxString::Format( "%d" , valueObjectID ) ); - m_data->m_current->AddChild(onode) ; - m_data->m_objectStack.push_back( m_data->m_current ) ; - m_data->m_current = onode ; + m_data->Pop() ; } -// insert an object reference to an already written object -void wxXmlWriter::DoWriteObjectReference(const wxObject *WXUNUSED(parentObject), const wxClassInfo *WXUNUSED(parentClassInfo), const wxObject *valueObject, - const wxClassInfo *valueObjectClassInfo, int valueObjectID , const wxPropertyInfo *propInfo ) +void wxXmlWriter::DoBeginWriteProperty(const wxPropertyInfo *pi ) { - wxXmlNode *onode; - onode = new wxXmlNode(wxXML_ELEMENT_NODE, propInfo->GetName()); - onode->AddProperty(wxString("class"), wxString(valueObjectClassInfo->GetClassName())); - if ( valueObject == NULL ) - { - wxXmlNode* nullnode = new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, "null"); - onode->AddChild(nullnode); - } - else - { - onode->AddProperty(wxString("id"), wxString::Format( "%d" , valueObjectID ) ); - } + wxXmlNode *pnode; + pnode = new wxXmlNode(wxXML_ELEMENT_NODE, "prop" ); + pnode->AddProperty(wxT("name"), pi->GetName() ); + m_data->m_current->AddChild(pnode) ; + m_data->Push( pnode ) ; +} - m_data->m_current->AddChild(onode) ; +void wxXmlWriter::DoEndWriteProperty(const wxPropertyInfo *WXUNUSED(propInfo) ) +{ + m_data->Pop() ; } -void wxXmlWriter::DoEndWriteParamAsObject(const wxObject *WXUNUSED(parentObject), const wxClassInfo *WXUNUSED(parentClassInfo), const wxObject *WXUNUSED(valueObject), - const wxClassInfo *WXUNUSED(valueObjectClassInfo), int WXUNUSED(valueObjectID) , const wxPropertyInfo *WXUNUSED(propInfo) ) + + +// insert an object reference to an already written object +void wxXmlWriter::DoWriteRepeatedObject( int objectID ) { - m_data->m_current = m_data->m_objectStack.back() ; - m_data->m_objectStack.pop_back() ; + wxXmlNode *pnode; + pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("object")); + pnode->AddProperty(wxString("href"), wxString::Format( "%d" , objectID ) ); + m_data->m_current->AddChild(pnode) ; } +// insert a null reference +void wxXmlWriter::DoWriteNullObject() +{ + wxXmlNode *pnode; + pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("object")); + m_data->m_current->AddChild(pnode) ; +} // writes a delegate in the stream format -void wxXmlWriter::DoWriteDelegate( const wxObject *WXUNUSED(object), const wxClassInfo* WXUNUSED(classInfo) , const wxPropertyInfo *pi , +void wxXmlWriter::DoWriteDelegate( const wxObject *WXUNUSED(object), const wxClassInfo* WXUNUSED(classInfo) , const wxPropertyInfo *WXUNUSED(pi) , const wxObject *eventSink, int sinkObjectID , const wxClassInfo* WXUNUSED(eventSinkClassInfo) , const wxHandlerInfo* handlerInfo ) { if ( eventSink != NULL && handlerInfo != NULL ) { - wxXmlNode *pnode; - pnode = new wxXmlNode(wxXML_ELEMENT_NODE, pi->GetName() ); - wxString s ; - s.Printf(wxT("%d.%s"), sinkObjectID , handlerInfo->GetName() ) ; - wxXmlAddContentToNode( pnode ,s ) ; - m_data->m_current->AddChild(pnode); + wxXmlAddContentToNode( m_data->m_current ,wxString::Format(wxT("%d.%s"), sinkObjectID , handlerInfo->GetName()) ) ; } } @@ -368,6 +477,7 @@ and create params are always toplevel class only int wxXmlReader::ReadComponent(wxXmlNode *node, wxDepersister *callbacks) { + wxASSERT_MSG( callbacks , wxT("Does not support reading without a Depersistor") ) ; wxString className; wxClassInfo *classInfo; @@ -376,38 +486,56 @@ int wxXmlReader::ReadComponent(wxXmlNode *node, wxDepersister *callbacks) const wxClassInfo** createClassInfos ; wxXmlNode *children; int objectID; + wxString ObjectIdString ; children = node->GetChildren(); + if (!children) + { + // check for a null object or href + if (node->GetPropVal("href" , &ObjectIdString ) ) + { + objectID = atoi( ObjectIdString.c_str() ) ; + wxASSERT_MSG( HasObjectClassInfo( objectID ) , wxT("Forward hrefs are not supported") ) ; + return objectID ; + } + if ( !node->GetPropVal("id" , &ObjectIdString ) ) + { + return wxNullObjectID; + } + } if (!node->GetPropVal("class", &className)) { // No class name. Eek. FIXME: error handling return wxInvalidObjectID; } classInfo = wxClassInfo::FindClass(className); - if (children && children->GetType() == wxXML_TEXT_NODE) - { - assert( wxXmlGetContentFromNode(node) == "null" ) ; - // this must be a NULL component reference. We just bail out - return wxNullObjectID; - } - - wxString ObjectIdString ; + wxASSERT_MSG( classInfo , wxString::Format(wxT("unknown class %s"),className ) ) ; + wxASSERT_MSG( !children || children->GetType() != wxXML_TEXT_NODE , wxT("objects cannot have XML Text Nodes") ) ; if (!node->GetPropVal("id", &ObjectIdString)) { + wxASSERT_MSG(0,wxT("Objects must have an id attribute") ) ; // No object id. Eek. FIXME: error handling return wxInvalidObjectID; } - objectID = atoi( ObjectIdString.c_str() ) ; // is this object already has been streamed in, return it here - if ( HasObjectClassInfo( objectID ) ) - return objectID ; + wxASSERT_MSG( !HasObjectClassInfo( objectID ) , wxString::Format(wxT("Doubly used id : %d"), objectID ) ) ; // new object, start with allocation // first make the object know to our internal registry SetObjectClassInfo( objectID , classInfo ) ; - callbacks->AllocateObject(objectID, classInfo); + wxxVariantArray metadata ; + wxXmlProperty *xp = node->GetProperties() ; + while ( xp ) + { + if ( xp->GetName() != wxString("class") && xp->GetName() != wxString("id") ) + { + metadata.Add( new wxxVariant( xp->GetValue() , xp->GetName() ) ) ; + } + xp = xp->GetNext() ; + } + callbacks->AllocateObject(objectID, classInfo, metadata); // // stream back the Create parameters first @@ -423,8 +551,10 @@ int wxXmlReader::ReadComponent(wxXmlNode *node, wxDepersister *callbacks) while( children ) { - propertyNames.push_back( children->GetName().c_str() ) ; - propertyNodes[children->GetName().c_str()] = children ; + wxString name ; + children->GetPropVal( wxT("name") , &name ) ; + propertyNames.push_back( name.c_str() ) ; + propertyNodes[name.c_str()] = children->GetChildren() ; children = children->GetNext() ; } @@ -433,6 +563,7 @@ int wxXmlReader::ReadComponent(wxXmlNode *node, wxDepersister *callbacks) const wxChar* paramName = classInfo->GetCreateParamName(i) ; PropertyNodes::iterator propiter = propertyNodes.find( paramName ) ; const wxPropertyInfo* pi = classInfo->FindPropertyInfo( paramName ) ; + wxASSERT_MSG(pi,wxString::Format("Unkown Property %s",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() ) @@ -446,7 +577,16 @@ int wxXmlReader::ReadComponent(wxXmlNode *node, wxDepersister *callbacks) else { createParamOids[i] = wxInvalidObjectID ; - createParams[i] = ReadValue( prop , pi->GetAccessor() ) ; + createParams[i] = ReadValue( prop , pi->GetTypeInfo() ) ; + if( pi->GetFlags() & wxPROP_ENUM_STORE_LONG ) + { + const wxEnumTypeInfo *eti = dynamic_cast( pi->GetTypeInfo() ) ; + wxASSERT_MSG( eti , wxT("Type must have enum - long conversion") ) ; + + long realval ; + eti->ConvertToLong( createParams[i] , realval ) ; + createParams[i] = wxxVariant( realval ) ; + } createClassInfos[i] = NULL ; } @@ -468,7 +608,7 @@ int wxXmlReader::ReadComponent(wxXmlNode *node, wxDepersister *callbacks) // got the parameters. Call the Create method callbacks->CreateObject(objectID, classInfo, classInfo->GetCreateParamCount(), - createParams, createParamOids, createClassInfos); + createParams, createParamOids, createClassInfos, metadata ); // 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 ) @@ -480,37 +620,69 @@ int wxXmlReader::ReadComponent(wxXmlNode *node, wxDepersister *callbacks) { wxXmlNode* prop = propiter->second ; const wxPropertyInfo* pi = classInfo->FindPropertyInfo( propertyNames[j].c_str() ) ; - if ( pi->GetTypeInfo()->IsObjectType() ) + if ( pi->GetTypeInfo()->GetKind() == wxT_COLLECTION ) { - int valueId = ReadComponent( prop , callbacks ) ; - if ( callbacks ) + const wxCollectionTypeInfo* collType = dynamic_cast< const wxCollectionTypeInfo* >( pi->GetTypeInfo() ) ; + const wxTypeInfo * elementType = collType->GetElementType() ; + while( prop ) { - if ( valueId != wxInvalidObjectID ) + wxASSERT_MSG(prop->GetName() == wxT("element") , wxT("A non empty collection must consist of 'element' nodes")) ; + wxXmlNode* elementContent = prop->GetChildren() ; + if ( elementContent ) { - callbacks->SetPropertyAsObject( objectID , classInfo , pi , valueId ) ; - if ( pi->GetTypeInfo()->GetKind() == wxT_OBJECT && valueId != wxNullObjectID ) - callbacks->DestroyObject( valueId , GetObjectClassInfo( valueId ) ) ; + // we skip empty elements + if ( elementType->IsObjectType() ) + { + int valueId = ReadComponent( elementContent , callbacks ) ; + if ( valueId != wxInvalidObjectID ) + { + if ( pi->GetAccessor()->HasAdder() ) + callbacks->AddToPropertyCollectionAsObject( objectID , classInfo , pi , valueId ) ; + // TODO for collections we must have a notation on taking over ownership or not + if ( elementType->GetKind() == wxT_OBJECT && valueId != wxNullObjectID ) + callbacks->DestroyObject( valueId , GetObjectClassInfo( valueId ) ) ; + } + } + else + { + wxxVariant elementValue = ReadValue( elementContent , elementType ) ; + if ( pi->GetAccessor()->HasAdder() ) + callbacks->AddToPropertyCollection( objectID , classInfo ,pi , elementValue ) ; + } } + prop = prop->GetNext() ; + } + } + else if ( pi->GetTypeInfo()->IsObjectType() ) + { + int valueId = ReadComponent( prop , callbacks ) ; + if ( valueId != wxInvalidObjectID ) + { + callbacks->SetPropertyAsObject( objectID , classInfo , pi , valueId ) ; + if ( pi->GetTypeInfo()->GetKind() == wxT_OBJECT && valueId != wxNullObjectID ) + callbacks->DestroyObject( valueId , GetObjectClassInfo( valueId ) ) ; } } else if ( pi->GetTypeInfo()->IsDelegateType() ) { - wxString resstring = wxXmlGetContentFromNode(prop) ; - wxInt32 pos = resstring.Find('.') ; - assert( pos != wxNOT_FOUND ) ; - int sinkOid = atol(resstring.Left(pos)) ; - wxString handlerName = resstring.Mid(pos+1) ; - wxClassInfo* sinkClassInfo = GetObjectClassInfo( sinkOid ) ; - - if (callbacks) + if ( prop ) + { + wxString resstring = prop->GetContent() ; + wxInt32 pos = resstring.Find('.') ; + assert( pos != wxNOT_FOUND ) ; + int sinkOid = atol(resstring.Left(pos)) ; + wxString handlerName = resstring.Mid(pos+1) ; + wxClassInfo* sinkClassInfo = GetObjectClassInfo( sinkOid ) ; + callbacks->SetConnect( objectID , classInfo , dynamic_cast(pi->GetTypeInfo()) , sinkClassInfo , - sinkClassInfo->FindHandlerInfo(handlerName) , sinkOid ) ; + sinkClassInfo->FindHandlerInfo(handlerName) , sinkOid ) ; + } } else { - if ( callbacks ) - callbacks->SetProperty( objectID, classInfo ,pi , ReadValue( prop , pi->GetAccessor() ) ) ; + wxxVariant nodeval ; + callbacks->SetProperty( objectID, classInfo ,pi , ReadValue( prop , pi->GetTypeInfo() ) ) ; } } } @@ -524,14 +696,30 @@ int wxXmlReader::ReadComponent(wxXmlNode *node, wxDepersister *callbacks) } wxxVariant wxXmlReader::ReadValue(wxXmlNode *node, - wxPropertyAccessor *accessor ) + const wxTypeInfo *type ) { - return accessor->ReadValue(wxXmlGetContentFromNode( node ) ) ; + wxString content ; + if ( node ) + content = node->GetContent() ; + wxxVariant result ; + type->ConvertFromString( content , result ) ; + return result ; } -int wxXmlReader::ReadObject(wxDepersister *callbacks) +int wxXmlReader::ReadObject( const wxString &name , wxDepersister *callbacks) { - return ReadComponent( m_parent , callbacks ) ; + wxXmlNode *iter = m_parent->GetChildren() ; + while ( iter ) + { + wxString entryName ; + if ( iter->GetPropVal("name", &entryName) ) + { + if ( entryName == name ) + return ReadComponent( iter->GetChildren() , callbacks ) ; + } + iter = iter->GetNext() ; + } + return wxInvalidObjectID ; } // ---------------------------------------------------------------------------- @@ -567,7 +755,8 @@ wxRuntimeDepersister::~wxRuntimeDepersister() delete m_data ; } -void wxRuntimeDepersister::AllocateObject(int objectID, wxClassInfo *classInfo) +void wxRuntimeDepersister::AllocateObject(int objectID, wxClassInfo *classInfo , + wxxVariantArray &metadata) { wxObject *O; O = classInfo->CreateObject(); @@ -579,7 +768,8 @@ void wxRuntimeDepersister::CreateObject(int objectID, int paramCount, wxxVariant *params, int *objectIdValues, - const wxClassInfo **objectClassInfos) + const wxClassInfo **objectClassInfos , + wxxVariantArray &metadata) { wxObject *o; o = m_data->GetObject(objectID); @@ -589,6 +779,13 @@ void wxRuntimeDepersister::CreateObject(int objectID, { wxObject *o; o = m_data->GetObject(objectIdValues[i]); + // if this is a dynamic object and we are asked for another class + // than wxDynamicObject we cast it down manually. + wxDynamicObject *dyno = dynamic_cast< wxDynamicObject * > (o) ; + if ( dyno!=NULL && (objectClassInfos[i] != dyno->GetClassInfo()) ) + { + o = dyno->GetSuperClassInstance() ; + } params[i] = objectClassInfos[i]->InstanceToVariant(o) ; } } @@ -603,25 +800,33 @@ void wxRuntimeDepersister::DestroyObject(int objectID, wxClassInfo *WXUNUSED(cla } void wxRuntimeDepersister::SetProperty(int objectID, - const wxClassInfo *WXUNUSED(classInfo), + const wxClassInfo *classInfo, const wxPropertyInfo* propertyInfo, const wxxVariant &value) { wxObject *o; o = m_data->GetObject(objectID); - propertyInfo->GetAccessor()->SetProperty( o , value ) ; + classInfo->SetProperty( o , propertyInfo->GetName() , value ) ; } void wxRuntimeDepersister::SetPropertyAsObject(int objectID, - const wxClassInfo *WXUNUSED(classInfo), + const wxClassInfo *classInfo, const wxPropertyInfo* propertyInfo, int valueObjectId) { wxObject *o, *valo; o = m_data->GetObject(objectID); valo = m_data->GetObject(valueObjectId); - propertyInfo->GetAccessor()->SetProperty( o , - (dynamic_cast(propertyInfo->GetTypeInfo()))->GetClassInfo()->InstanceToVariant(valo) ) ; + const wxClassInfo* valClassInfo = (dynamic_cast(propertyInfo->GetTypeInfo()))->GetClassInfo() ; + // if this is a dynamic object and we are asked for another class + // than wxDynamicObject we cast it down manually. + wxDynamicObject *dynvalo = dynamic_cast< wxDynamicObject * > (valo) ; + if ( dynvalo!=NULL && (valClassInfo != dynvalo->GetClassInfo()) ) + { + valo = dynvalo->GetSuperClassInstance() ; + } + + classInfo->SetProperty( o , propertyInfo->GetName() , valClassInfo->InstanceToVariant(valo) ) ; } void wxRuntimeDepersister::SetConnect(int eventSourceObjectID, @@ -647,6 +852,38 @@ wxObject *wxRuntimeDepersister::GetObject(int objectID) return m_data->GetObject( objectID ) ; } +// adds an element to a property collection +void wxRuntimeDepersister::AddToPropertyCollection( int objectID , + const wxClassInfo *classInfo, + const wxPropertyInfo* propertyInfo , + const wxxVariant &value) +{ + wxObject *o; + o = m_data->GetObject(objectID); + classInfo->AddToPropertyCollection( o , propertyInfo->GetName() , value ) ; +} + +// sets the corresponding property (value is an object) +void wxRuntimeDepersister::AddToPropertyCollectionAsObject(int objectID, + const wxClassInfo *classInfo, + const wxPropertyInfo* propertyInfo , + int valueObjectId) +{ + wxObject *o, *valo; + o = m_data->GetObject(objectID); + valo = m_data->GetObject(valueObjectId); + const wxCollectionTypeInfo * collectionTypeInfo = dynamic_cast< const wxCollectionTypeInfo * >(propertyInfo->GetTypeInfo() ) ; + const wxClassInfo* valClassInfo = (dynamic_cast(collectionTypeInfo->GetElementType()))->GetClassInfo() ; + // if this is a dynamic object and we are asked for another class + // than wxDynamicObject we cast it down manually. + wxDynamicObject *dynvalo = dynamic_cast< wxDynamicObject * > (valo) ; + if ( dynvalo!=NULL && (valClassInfo != dynvalo->GetClassInfo()) ) + { + valo = dynvalo->GetSuperClassInstance() ; + } + + classInfo->AddToPropertyCollection( o , propertyInfo->GetName() , valClassInfo->InstanceToVariant(valo) ) ; +} // ---------------------------------------------------------------------------- // depersisting to code @@ -682,7 +919,8 @@ wxCodeDepersister::~wxCodeDepersister() delete m_data ; } -void wxCodeDepersister::AllocateObject(int objectID, wxClassInfo *classInfo) +void wxCodeDepersister::AllocateObject(int objectID, wxClassInfo *classInfo , + wxxVariantArray &metadata) { wxString objectName = wxString::Format( "LocalObject_%d" , objectID ) ; m_fp->WriteString( wxString::Format( "\t%s *%s = new %s;\n", @@ -724,7 +962,8 @@ void wxCodeDepersister::CreateObject(int objectID, int paramCount, wxxVariant *params, int *objectIDValues, - const wxClassInfo **WXUNUSED(objectClassInfos) + const wxClassInfo **WXUNUSED(objectClassInfos) , + wxxVariantArray &metadata ) { int i; @@ -771,6 +1010,26 @@ void wxCodeDepersister::SetPropertyAsObject(int objectID, m_data->GetObjectName( valueObjectId) ) ); } +void wxCodeDepersister::AddToPropertyCollection( int objectID , + const wxClassInfo *classInfo, + const wxPropertyInfo* propertyInfo , + const wxxVariant &value) +{ + m_fp->WriteString( wxString::Format( "\t%s->%s(%s);\n", + m_data->GetObjectName(objectID), + propertyInfo->GetAccessor()->GetAdderName(), + ValueAsCode(value)) ); +} + +// sets the corresponding property (value is an object) +void wxCodeDepersister::AddToPropertyCollectionAsObject(int objectID, + const wxClassInfo *classInfo, + const wxPropertyInfo* propertyInfo , + int valueObjectId) +{ + // TODO +} + void wxCodeDepersister::SetConnect(int eventSourceObjectID, const wxClassInfo *WXUNUSED(eventSourceClassInfo), const wxDelegateTypeInfo *delegateInfo , @@ -788,4 +1047,8 @@ void wxCodeDepersister::SetConnect(int eventSourceObjectID, ehsource , ehsource , eventType , ehsinkClass , handlerName , ehsink ) ); } +#include + +WX_DEFINE_OBJARRAY(wxxVariantArray); + #endif