Commit 785b74eb authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum

[CHANGE #295] - basic save functionality for the module graph

parent fb4b3f35
......@@ -55,6 +55,12 @@ bool WProperties::setAsString( std::string /*value*/ )
return true;
}
std::string WProperties::getAsString()
{
// groups can't be set in any way. -> ignore it.
return "";
}
bool WProperties::propNamePredicate( boost::shared_ptr< WPropertyBase > prop1, boost::shared_ptr< WPropertyBase > prop2 ) const
{
return ( prop1->getName() == prop2->getName() );
......
......@@ -229,6 +229,14 @@ public:
*/
virtual bool setAsString( std::string value );
/**
* Returns the current value as a string. This is useful for debugging or project files. It is not implemented as << operator, since the <<
* should also print min/max constraints and so on. This simply is the value.
*
* \return the value as a string.
*/
virtual std::string getAsString();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Convenience methods to create and add properties
// NOTE: these methods use the type of the initial parameter to automatically use the proper type.
......
......@@ -102,6 +102,14 @@ public:
*/
virtual bool setAsString( std::string value ) = 0;
/**
* Returns the current value as a string. This is useful for debugging or project files. It is not implemented as << operator, since the <<
* should also print min/max constraints and so on. This simply is the value.
*
* \return the value as a string.
*/
virtual std::string getAsString() = 0;
/**
* This method returns a condition which gets fired whenever the property changes somehow. It is fired when:
* \li \ref setHidden is called and the hidden state changes
......
......@@ -297,6 +297,14 @@ public:
*/
virtual bool setAsString( std::string value );
/**
* Returns the current value as a string. This is useful for debugging or project files. It is not implemented as << operator, since the <<
* should also print min/max constraints and so on. This simply is the value.
*
* \return the value as a string.
*/
virtual std::string getAsString();
protected:
/**
......@@ -457,6 +465,16 @@ bool WPropertyVariable< T >::setAsString( std::string value )
return true;
}
template < typename T >
std::string WPropertyVariable< T >::getAsString()
{
std::string val;
val = boost::lexical_cast< std::string >( WFlag< T >::get() );
// try catch( const boost::bad_lexical_cast &e ) ? No if this happens something is wrong with the value
return val;
}
template < typename T >
bool WPropertyVariable< T >::ensureValidity( T newValidValue, bool suppressNotification )
{
......
......@@ -412,7 +412,6 @@ void WMainWindow::projectSave()
QString message = "<b>Problem while saving project file.</b><br/><br/><b>File: </b>" + ( *constIterator ) +
"<br/><b>Message: </b>" + QString::fromStdString( e.what() );
QMessageBox::critical( this, title, message );
}
}
}
......
......@@ -44,6 +44,8 @@
class WModuleConnector: public boost::enable_shared_from_this<WModuleConnector>
{
friend class WModuleConnectorTest;
friend class WModuleProjectFileCombiner;
public:
/**
......
......@@ -48,6 +48,7 @@
WModuleContainer::WModuleContainer( std::string name, std::string description ):
WModule(),
m_moduleAccess( m_modules.getAccessObject() ),
m_name( name ),
m_description( description ),
m_crashIfModuleCrashes( true )
......@@ -100,9 +101,10 @@ void WModuleContainer::add( boost::shared_ptr< WModule > module, bool run )
}
// get write lock
boost::unique_lock<boost::shared_mutex> lock = boost::unique_lock<boost::shared_mutex>( m_moduleSetLock );
m_modules.insert( module );
lock.unlock();
m_moduleAccess->beginWrite();
m_moduleAccess->get().insert( module );
m_moduleAccess->endWrite();
module->setAssociatedContainer( boost::shared_static_cast< WModuleContainer >( shared_from_this() ) );
WLogger::getLogger()->addLogMessage( "Associated module \"" + module->getName() + "\" with container." , "ModuleContainer (" + getName() + ")",
LL_INFO );
......@@ -159,9 +161,10 @@ void WModuleContainer::remove( boost::shared_ptr< WModule > module )
module->wait( true );
// get write lock
boost::unique_lock<boost::shared_mutex> lock = boost::unique_lock<boost::shared_mutex>( m_moduleSetLock );
m_modules.erase( module );
lock.unlock();
m_moduleAccess->beginWrite();
m_moduleAccess->get().erase( module );
m_moduleAccess->endWrite();
module->setAssociatedContainer( boost::shared_ptr< WModuleContainer >() );
// TODO(ebaum): remove signal subscriptions
......@@ -173,10 +176,10 @@ WModuleContainer::DataModuleListType WModuleContainer::getDataModules()
{
DataModuleListType l;
boost::shared_lock<boost::shared_mutex> slock = boost::shared_lock<boost::shared_mutex>( m_moduleSetLock );
m_moduleAccess->beginRead();
// iterate module list
for( std::set< boost::shared_ptr< WModule > >::iterator iter = m_modules.begin(); iter != m_modules.end(); ++iter )
for( ModuleConstIterator iter = m_moduleAccess->get().begin(); iter != m_moduleAccess->get().end(); ++iter )
{
// is this module a data module?
if ( ( *iter )->getType() == MODULE_DATA )
......@@ -190,7 +193,7 @@ WModuleContainer::DataModuleListType WModuleContainer::getDataModules()
}
}
}
slock.unlock();
m_moduleAccess->endRead();
// now sort the list using the sorter
......@@ -213,19 +216,19 @@ void WModuleContainer::stop()
WLogger::getLogger()->addLogMessage( "Stopping modules." , "ModuleContainer (" + getName() + ")", LL_INFO );
// read lock
slock = boost::shared_lock<boost::shared_mutex>( m_moduleSetLock );
for( std::set< boost::shared_ptr< WModule > >::iterator listIter = m_modules.begin(); listIter != m_modules.end(); ++listIter )
m_moduleAccess->beginRead();
for( ModuleConstIterator listIter = m_moduleAccess->get().begin(); listIter != m_moduleAccess->get().end(); ++listIter )
{
WLogger::getLogger()->addLogMessage( "Waiting for module \"" + ( *listIter )->getName() + "\" to finish." ,
"ModuleContainer (" + getName() + ")", LL_INFO );
( *listIter )->wait( true );
}
slock.unlock();
m_moduleAccess->endRead();
// get write lock
boost::unique_lock<boost::shared_mutex> lock = boost::unique_lock<boost::shared_mutex>( m_moduleSetLock );
m_modules.clear();
lock.unlock();
m_moduleAccess->beginWrite();
m_moduleAccess->get().clear();
m_moduleAccess->endWrite();
}
const std::string WModuleContainer::getName() const
......@@ -387,3 +390,8 @@ void WModuleContainer::setCrashIfModuleCrashes( bool crashIfCrashed )
m_crashIfModuleCrashes = crashIfCrashed;
}
WModuleContainer::ModuleSharedContainerType::WSharedAccess WModuleContainer::getAccessObject()
{
return m_moduleAccess;
}
......@@ -35,6 +35,8 @@
#include <boost/signals2/signal.hpp>
#include <boost/function.hpp>
#include "../common/WSharedObject.h"
#include "WModuleSignals.h"
class WThreadedRunner;
......@@ -52,6 +54,34 @@ class WModuleContainer: public WModule
{
public:
// the following typedefs are for convenience; to help accessing the container in a thread safe way.
/**
* For shortening: a type defining a shared vector of WModule pointers.
*/
typedef std::set< boost::shared_ptr< WModule > > ModuleContainerType;
/**
* The alias for a shared container.
*/
typedef WSharedObject< ModuleContainerType > ModuleSharedContainerType;
/**
* The access type
*/
typedef ModuleSharedContainerType::WSharedAccess ModuleAccessType;
/**
* The const iterator type of the container.
*/
typedef ModuleContainerType::const_iterator ModuleConstIterator;
/**
* The iterator type of the container.
*/
typedef ModuleContainerType::iterator ModuleIterator;
/**
* Constructor. Initializes container.
*
......@@ -203,6 +233,13 @@ public:
*/
void setCrashIfModuleCrashes( bool crashIfCrashed = true );
/**
* Returns the access object usable to iterate the module list in a thread safe manner. DO not modify the list.
*
* \return the access control object.
*/
ModuleSharedContainerType::WSharedAccess getAccessObject();
protected:
/**
......@@ -212,14 +249,14 @@ protected:
virtual void moduleMain();
/**
* Lock for module set.
* The modules associated with this container.
*/
boost::shared_mutex m_moduleSetLock;
ModuleSharedContainerType m_modules;
/**
* The modules associated with this container.
* Access to the above module set.
*/
std::set< boost::shared_ptr< WModule > > m_modules;
ModuleSharedContainerType::WSharedAccess m_moduleAccess;
/**
* Name of the module.
......
......@@ -101,7 +101,7 @@ void WProjectFile::threadMain()
}
// the comment
static const boost::regex commentRe( "^//.*$" );
static const boost::regex commentRe( "^ *//.*$" );
// read it line by line
std::string line; // the current line
......
......@@ -24,6 +24,7 @@
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <string>
#include <utility>
......@@ -41,6 +42,10 @@
#include "../exceptions/WModuleConnectorNotFound.h"
#include "../../common/exceptions/WFileNotFound.h"
#include "../../common/WProperties.h"
#include "../../common/WPropertyBase.h"
#include "../../common/WPropertyVariable.h"
#include "../../common/WPropertyTypes.h"
#include "../../common/WLogger.h"
#include "WModuleProjectFileCombiner.h"
......@@ -65,10 +70,10 @@ WModuleProjectFileCombiner::~WModuleProjectFileCombiner()
bool WModuleProjectFileCombiner::parse( std::string line, unsigned int lineNumber )
{
// this is the proper regular expression for modules
static const boost::regex modRe( "^MODULE:([0-9]*):(.*)$" );
static const boost::regex dataRe( "^DATA:([0-9]*):(.*)$" );
static const boost::regex conRe( "^CONNECTION:\\(([0-9]*),(.*)\\)->\\(([0-9]*),(.*)\\)$" );
static const boost::regex propRe( "^PROPERTY:\\(([0-9]*),(.*)\\)=(.*)$" );
static const boost::regex modRe( "^ *MODULE:([0-9]*):(.*)$" );
static const boost::regex dataRe( "^ *DATA:([0-9]*):(.*)$" );
static const boost::regex conRe( "^ *CONNECTION:\\(([0-9]*),(.*)\\)->\\(([0-9]*),(.*)\\)$" );
static const boost::regex propRe( "^ *PROPERTY:\\(([0-9]*),(.*)\\)=(.*)$" );
boost::smatch matches; // the list of matches
if ( boost::regex_match( line, matches, modRe ) )
......@@ -289,8 +294,111 @@ void WModuleProjectFileCombiner::done()
apply();
}
/**
* Recursively prints the properties and nested properties.
*
* \param output the output stream to print to
* \param props the properties to recursively print
* \param indent the indentation level
* \param prefix the prefix (name prefix of property)
* \param module the module ID to use
*/
void printProperties( std::ostream& output, boost::shared_ptr< WProperties > props, std::string indent, std::string prefix, unsigned int module )
{
// get access object
WProperties::PropertyAccessType a = props->getAccessObject();
a->beginWrite(); // use write lock here to avoid manipulation of properties list during file write
output << indent << "// Property Group: " << props->getName() << std::endl;
// iterate of them and print them to output
for ( WProperties::PropertyConstIterator iter = a->get().begin(); iter != a->get().end(); ++iter )
{
if ( ( *iter )->getType() != PV_GROUP )
{
output << indent + " " << "PROPERTY:(" << module << "," << prefix + ( *iter )->getName() << ")="
<< ( *iter )->getAsString() << std::endl;
}
else
{
// it is a group -> recursively print it
if ( prefix.empty() )
{
printProperties( output, ( *iter )->toPropGroup(), indent + " ", ( *iter )->getName() + "/", module );
}
else
{
printProperties( output, ( *iter )->toPropGroup(), indent + " ", prefix + ( *iter )->getName() + "/", module );
}
}
}
output << indent << "// Property Group END: " << props->getName() << std::endl;
a->endWrite();
}
void WModuleProjectFileCombiner::save( std::ostream& output )
{
// grab access object of root container
WModuleContainer::ModuleAccessType container = WKernel::getRunningKernel()->getRootContainer()->getAccessObject();
std::map< boost::shared_ptr< WModule >, unsigned int > moduleToIDMap;
// get a write access to avoid others to modify the container while project file is written.
container->beginWrite();
output << "// Modules and Properties" << std::endl <<std::endl;
// iterate all modules:
unsigned int i = 0;
for ( WModuleContainer::ModuleConstIterator iter = container->get().begin(); iter != container->get().end(); ++iter )
{
// store the mapping of ptr to ID
moduleToIDMap[ ( *iter ) ] = i;
// handle data modules separately
if ( ( *iter )->getType() == MODULE_DATA )
{
output << "DATA:" << i << ":" << boost::shared_static_cast< WMData >( ( *iter ) )->getFilename() << std::endl;
}
else
{
output << "MODULE:" << i << ":" << ( *iter )->getName() << std::endl;
}
// the properties:
printProperties( output, ( *iter )->getProperties(), "", "", i );
// some readability:
output << std::endl;
++i;
}
// finally, process all connections for each module
output << "// Connections" << std::endl;
// iterate over all modules
for ( WModuleContainer::ModuleConstIterator iter = container->get().begin(); iter != container->get().end(); ++iter )
{
// iterate over all outputs
const std::set< boost::shared_ptr< WModuleOutputConnector > >& outs = ( *iter )->getOutputConnectors();
for ( std::set< boost::shared_ptr< WModuleOutputConnector > >::const_iterator citer = outs.begin(); citer != outs.end(); ++citer )
{
// iterate over all connections:
// TODO(ebaum): iterating over a protected member variable? Thats ugly. This should be adopted to WSharedAccess
boost::unique_lock<boost::shared_mutex> lock( ( *citer )->m_connectionListLock );
for ( std::set<boost::shared_ptr<WModuleConnector> >::const_iterator iciter = ( *citer )->m_connected.begin();
iciter != ( *citer )->m_connected.end(); ++iciter )
{
output << "CONNECTION:(" << moduleToIDMap[ ( *iter ) ] << "," << ( *citer )->getName() << ")->(" <<
moduleToIDMap[ ( *iciter )->m_module ] << "," << ( *iciter )->getName() << ")" << std::endl;
}
lock.unlock();
}
}
// thats it
container->endWrite();
}
......@@ -344,7 +344,7 @@ void WMTemplate::moduleMain()
// This example code now shows how to modify your OSG nodes basing on changes in your dataset or properties.
// The if statement also checks for data validity as it uses the data! You should also always do that.
if ( m_anInteger->changed() || m_aDouble->changed() || ( dataChanged && dataValid ) )
if ( ( m_anInteger->changed() || m_aDouble->changed() || dataChanged ) && dataValid )
{
debugLog() << "Creating new OSG node";
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment