+ tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument( );
+ tinyxml2::XMLElement* root = doc->NewElement( "cpPlugins_Workspace" );
+ std::set< std::string > used_plugins;
+
+ // Save filter data
+ for( auto i = this->m_Filters.begin( ); i != this->m_Filters.end( ); ++i )
+ {
+ auto filter = i->second;
+ used_plugins.insert( filter->GetPluginName( ) );
+ tinyxml2::XMLElement* e = doc->NewElement( "Filter" );
+ e->SetAttribute( "Category", filter->GetClassCategory( ) );
+ e->SetAttribute( "Class", filter->GetClassName( ) );
+ e->SetAttribute( "Name", filter->GetName( ) );
+ e->SetAttribute( "ViewX", filter->GetViewX( ) );
+ e->SetAttribute( "ViewY", filter->GetViewY( ) );
+ e->SetAttribute(
+ "ExplicitExecution", ( filter->GetExplicitExecution( ) )? 1: 0
+ );
+
+ auto params = filter->GetParameters( );
+ params->ToXML( doc, e );
+ root->LinkEndChild( e );
+
+ } // rof
+
+ // Save used plugins
+ tinyxml2::XMLElement* plugins = doc->NewElement( "Plugins" );
+ for( auto pIt = used_plugins.begin( ); pIt != used_plugins.end( ); ++pIt )
+ {
+ tinyxml2::XMLElement* e = doc->NewElement( "Plugin" );
+ e->SetAttribute( "Name", pIt->c_str( ) );
+ plugins->LinkEndChild( e );
+
+ } // rof
+ root->LinkEndChild( plugins );
+
+ // Save connections
+ for( auto i = this->m_Filters.begin( ); i != this->m_Filters.end( ); ++i )
+ {
+ auto orig = i->second;
+ auto outputs = orig->GetOutputsNames( );
+ if( outputs.size( ) == 0 )
+ continue;
+ for( auto j = this->m_Filters.begin( ); j != this->m_Filters.end( ); ++j )
+ {
+ if( i == j )
+ continue;
+ auto dest = j->second;
+ auto inputs = dest->GetInputsNames( );
+ if( inputs.size( ) == 0 )
+ continue;
+
+ for( auto oIt = outputs.begin( ); oIt != outputs.end( ); ++oIt )
+ {
+ auto od = orig->GetOutput( *oIt );
+ for( auto iIt = inputs.begin( ); iIt != inputs.end( ); ++iIt )
+ {
+ auto id = dest->GetInput( *iIt );
+ if( od != NULL && od == id )
+ {
+ tinyxml2::XMLElement* e_conn = doc->NewElement( "Connection" );
+ tinyxml2::XMLElement* e_orig = doc->NewElement( "Origin" );
+ tinyxml2::XMLElement* e_dest = doc->NewElement( "Destination" );
+ e_orig->SetAttribute( "Filter", orig->GetName( ) );
+ e_orig->SetAttribute( "Name", oIt->c_str( ) );
+ e_dest->SetAttribute( "Filter", dest->GetName( ) );
+ e_dest->SetAttribute( "Name", iIt->c_str( ) );
+ e_conn->LinkEndChild( e_orig );
+ e_conn->LinkEndChild( e_dest );
+ root->LinkEndChild( e_conn );
+
+ } // fi
+
+ } // rof
+
+ } // rof
+
+ } // rof
+
+ } // rof
+
+
+ // Save exposed ports
+ auto eipIt = this->m_ExposedInputs.begin( );
+ for( ; eipIt != this->m_ExposedInputs.end( ); ++eipIt )
+ {
+ tinyxml2::XMLElement* port = doc->NewElement( "ExposedInput" );
+ port->SetAttribute( "Name", eipIt->first.c_str( ) );
+ port->SetAttribute( "Filter", eipIt->second.first.c_str( ) );
+ port->SetAttribute( "Input", eipIt->second.second.c_str( ) );
+ root->LinkEndChild( port );
+
+ } // rof
+
+ auto eopIt = this->m_ExposedOutputs.begin( );
+ for( ; eopIt != this->m_ExposedOutputs.end( ); ++eopIt )
+ {
+ tinyxml2::XMLElement* port = doc->NewElement( "ExposedOutput" );
+ port->SetAttribute( "Name", eopIt->first.c_str( ) );
+ port->SetAttribute( "Filter", eopIt->second.first.c_str( ) );
+ port->SetAttribute( "Output", eopIt->second.second.c_str( ) );
+ root->LinkEndChild( port );
+
+ } // rof
+
+ // Physical write and return
+ doc->LinkEndChild( root );
+ auto error = doc->SaveFile( fname.c_str( ) );
+ delete doc;
+ if( error != tinyxml2::XML_SUCCESS )
+ {
+ std::string m;
+ switch( error )
+ {
+ case tinyxml2::XML_NO_ATTRIBUTE:
+ m = "No attribute."; break;
+ case tinyxml2::XML_WRONG_ATTRIBUTE_TYPE:
+ m = "Wrong attribute."; break;
+ case tinyxml2::XML_ERROR_FILE_NOT_FOUND:
+ m = "File not found."; break;
+ case tinyxml2::XML_ERROR_FILE_COULD_NOT_BE_OPENED:
+ m = "File not opened."; break;
+ case tinyxml2::XML_ERROR_FILE_READ_ERROR:
+ m = "File not read."; break;
+ case tinyxml2::XML_ERROR_ELEMENT_MISMATCH:
+ m = "Element mismatch."; break;
+ case tinyxml2::XML_ERROR_PARSING_ELEMENT:
+ m = "Parsing element."; break;
+ case tinyxml2::XML_ERROR_PARSING_ATTRIBUTE:
+ m = "Parsing attribute."; break;
+ case tinyxml2::XML_ERROR_IDENTIFYING_TAG:
+ m = "Tag Id."; break;
+ case tinyxml2::XML_ERROR_PARSING_TEXT:
+ m = "Parsing text."; break;
+ case tinyxml2::XML_ERROR_PARSING_CDATA:
+ m = "Parsing cdata."; break;
+ case tinyxml2::XML_ERROR_PARSING_COMMENT:
+ m = "Parsing comment."; break;
+ case tinyxml2::XML_ERROR_PARSING_DECLARATION:
+ m = "Parsing declaration."; break;
+ case tinyxml2::XML_ERROR_PARSING_UNKNOWN:
+ m = "Parsing unknown."; break;
+ case tinyxml2::XML_ERROR_EMPTY_DOCUMENT:
+ m = "Empty document."; break;
+ case tinyxml2::XML_ERROR_MISMATCHED_ELEMENT:
+ m = "Mismatched element."; break;
+ case tinyxml2::XML_ERROR_PARSING:
+ m = "Parsing."; break;
+ case tinyxml2::XML_CAN_NOT_CONVERT_TEXT:
+ m = "Cannot convert."; break;
+ case tinyxml2::XML_NO_TEXT_NODE:
+ m = "No text."; break;
+ default:
+ m = "Unknown error."; break;
+ } // hctiws
+ throw std::runtime_error(
+ std::string( "cpPlugins::Workspace: Error while saving \"" ) +
+ fname + std::string( "\": " ) + m
+ );
+
+ } // fi