-/*
- 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 , false , writtenobjects ) ;
-}
-
-void WriteComponent(wxObject *obj, const wxClassInfo *classInfo, wxXmlNode *parent, const wxString& nodeName , int &nextId, bool embeddedObject, 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
- // embedded objects have to be written out fully always, their address will be reused and is not a valid key
- if ( !embeddedObject && (writtenObjects.find( obj ) != writtenObjects.end()) )
- {
- onode->AddProperty(wxString("id"), wxString::Format( "%d" , writtenObjects[obj] ) );
- }
- else
- {
- int id = nextId++ ;
- if ( !embeddedObject )
- writtenObjects[obj] = id ;
- onode->AddProperty(wxString("id"), wxString::Format( "%d" , id ) );
- WriteComponentProperties( obj , classInfo , onode , nextId , writtenObjects, writtenProperties) ;
- }
- }
-
- parent->AddChild(onode);
+struct wxWriter::wxWriterInternalPropertiesData
+{
+ char nothing ;
+} ;
+
+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 )
+{
+ 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 )
+{
+ if ( !classInfo->BeforeWriteObject( object , this , persister , metadata) )
+ return ;
+
+ if ( persister->BeforeWriteObject( this , object , classInfo , metadata) )
+ {
+ 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<const wxDynamicObject *>( 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::FindConnectEntry(const wxEvtHandler * evSource,const wxDelegateTypeInfo* dti, const wxObject* &sink , const wxHandlerInfo *&handler)
+{
+ wxList *dynamicEvents = evSource->GetDynamicEventTable() ;
+
+ 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_eventSink != NULL ) )
+ {
+ 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();
+ }
+ }
+}
+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 ;
+ if ( prop )
+ {
+ WriteOneProperty( obj , prop->GetDeclaringClass() , prop , persister , data ) ;
+ }
+ else
+ {
+ wxLogError( _("Create Parameter not found in declared RTTI Parameters") ) ;
+ }
+ map.erase( name ) ;
+ }
+ { // Extra block for broken compilers
+ 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 ) ;
+ }
+ }
+ }
+ { // Extra block for broken compilers
+ 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 *WXUNUSED(data) )
+{
+ if ( pi->GetFlags() & wxPROP_DONT_STREAM )
+ return ;
+
+ // 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<const wxDynamicClassInfo*>(ci) == NULL) )
+ obj = dynobj->GetSuperClassInstance() ;
+
+ 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 )
+ {
+ if ( i == 0 )
+ DoBeginWriteProperty( pi ) ;
+
+ DoBeginWriteElement() ;
+ wxxVariant value = data[i] ;
+ if ( persister->BeforeWriteProperty( this , obj, pi , value ) )
+ {
+ const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( elementType ) ;
+ if ( cti )
+ {
+ 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() ;
+ if ( i == data.GetCount() - 1 )
+ DoEndWriteProperty( pi ) ;
+ }
+ }
+ else
+ {
+ const wxDelegateTypeInfo* dti = dynamic_cast< const wxDelegateTypeInfo* > ( pi->GetTypeInfo() ) ;
+ if ( dti )
+ {
+ const wxObject* sink = NULL ;
+ const wxHandlerInfo *handler = NULL ;
+
+ const wxEvtHandler * evSource = dynamic_cast<const wxEvtHandler *>(obj) ;
+ if ( evSource )
+ {
+ FindConnectEntry( evSource , dti , sink , handler ) ;
+ if ( persister->BeforeWriteDelegate( this , obj , ci , pi , sink , handler ) )
+ {
+ if ( sink != NULL && handler != NULL )
+ {
+ DoBeginWriteProperty( pi ) ;
+ if ( IsObjectKnown( sink ) )
+ {
+ DoWriteDelegate( obj , ci , pi , sink , GetObjectID( sink ) , sink->GetClassInfo() , handler ) ;
+ DoEndWriteProperty( pi ) ;
+ }
+ else
+ {
+ wxLogError( _("Streaming delegates for not already streamed objects not yet supported") ) ;
+ }
+ }
+ }
+ }
+ else
+ {
+ wxLogError(_("Illegal Object Class (Non-wxEvtHandler) as Event Source") ) ;
+ }
+ }
+ else
+ {
+ wxxVariant value ;
+ pi->GetAccessor()->GetProperty(obj, value) ;
+
+ // avoid streaming out void objects
+ if( value.IsEmpty() )
+ return ;
+
+ if ( pi->GetFlags() & wxPROP_ENUM_STORE_LONG )
+ {
+ const wxEnumTypeInfo *eti = dynamic_cast<const wxEnumTypeInfo*>( pi->GetTypeInfo() ) ;
+ if ( eti )
+ {
+ eti->ConvertFromLong( value.wxTEMPLATED_MEMBER_CALL(Get , long) , value ) ;
+ }
+ else
+ {
+ wxLogError( _("Type must have enum - long conversion") ) ;
+ }
+ }
+
+ // avoid streaming out default values
+ if ( pi->GetTypeInfo()->HasStringConverters() && !pi->GetDefaultValue().IsEmpty() )
+ {
+ if ( value.GetAsString() == pi->GetDefaultValue().GetAsString() )
+ return ;
+ }
+
+ // avoid streaming out null objects
+ const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( pi->GetTypeInfo() ) ;
+
+ if ( cti && value.GetAsObject() == NULL )
+ return ;
+
+ if ( persister->BeforeWriteProperty( this , obj, pi , value ) )
+ {
+ DoBeginWriteProperty( pi ) ;
+ if ( cti )
+ {
+ const wxClassInfo* pci = cti->GetClassInfo() ;
+ wxObject *vobj = pci->VariantToInstance( value ) ;
+ if ( vobj && pi->GetTypeInfo()->HasStringConverters() )
+ {
+ wxString stringValue ;
+ cti->ConvertToString( value , stringValue ) ;
+ wxxVariant convertedValue(stringValue) ;
+ DoWriteSimpleType( convertedValue ) ;
+ }
+ else
+ {
+ wxxVariantArray md ;
+ WriteObject( vobj , (vobj ? vobj->GetClassInfo() : pci ) , persister , cti->GetKind()== wxT_OBJECT , md) ;
+ }
+ }
+ else
+ {
+ DoWriteSimpleType( value ) ;
+ }
+ DoEndWriteProperty( pi ) ;
+ }
+ }
+ }
+}
+
+int wxWriter::GetObjectID(const wxObject *obj)
+{
+ if ( !IsObjectKnown( obj ) )
+ return wxInvalidObjectID ;
+
+ return m_data->m_writtenObjects[obj] ;
+}
+
+bool wxWriter::IsObjectKnown( const wxObject *obj )
+{
+ return m_data->m_writtenObjects.find( obj ) != m_data->m_writtenObjects.end() ;