Commit 88b4c99b authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum
Browse files

[ADD #295] - added base classes for reading and parsing project files.

[CHANGE] - adopted existing project loading to new structure
parent ef840dc6
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#include <fstream>
#include <utility>
#include <boost/regex.hpp>
#include "../kernel/WKernel.h"
#include "../kernel/combiner/WModuleProjectFileCombiner.h"
#include "exceptions/WFileNotFound.h"
#include "WProjectFile.h"
WProjectFile::WProjectFile( boost::filesystem::path project ):
WThreadedRunner(),
boost::enable_shared_from_this< WProjectFile >(),
m_project( project )
{
// initialize members
// The module graph parser
m_parsers.push_back( new WModuleProjectFileCombiner() );
// The ROI parser
// m_parsers.push_back( new W???() );
// The Camera parser
// m_parsers.push_back( new W???() );
}
WProjectFile::~WProjectFile()
{
// cleanup
}
void WProjectFile::run()
{
// the instance needs to be added here, as it else could be freed before the thread finishes ( remember: it is a shared_ptr ).
WKernel::getRunningKernel()->getRootContainer()->addPendingThread( shared_from_this() );
// actually run
WThreadedRunner::run();
}
void WProjectFile::threadMain()
{
try
{
// Parse the file
wlog::info( "Project File" ) << "Loading project file \"" << m_project.file_string() << "\".";
// read the file
std::ifstream input( m_project.file_string().c_str() );
if ( !input.is_open() )
{
throw WFileNotFound( "The project file \"" + m_project.file_string() + "\" does not exist." );
}
// the comment
static const boost::regex commentRe( "^//.*$" );
// read it line by line
std::string line; // the current line
int i = 0; // line counter
bool match = false; // true of a parser successfully parsed the line
boost::smatch matches; // the list of matches
while ( std::getline( input, line ) )
{
++i; // line number
match = false;
// allow each parser to handle the line.
for ( std::vector< WProjectFileParser* >::const_iterator iter = m_parsers.begin(); iter != m_parsers.end(); ++iter )
{
if ( ( *iter )->parse( line, i ) )
{
match = true;
// the first parser matching this line -> next line
break;
}
}
// did someone match this line? Or is it empty or a comment?
if ( !match && !line.empty() && !boost::regex_match( line, matches, commentRe ) )
{
// no it is something else -> warning!
wlog::warn( "Project Loader" ) << "Line " << i << ": Malformed. Skipping.";
}
}
input.close();
// finally, let every one know that we have finished
for ( std::vector< WProjectFileParser* >::const_iterator iter = m_parsers.begin(); iter != m_parsers.end(); ++iter )
{
( *iter )->done();
}
}
catch ( const std::exception& e )
{
// remove from thread list
WKernel::getRunningKernel()->getRootContainer()->finishedPendingThread( shared_from_this() );
// re-throw
throw e;
}
// remove from thread list
WKernel::getRunningKernel()->getRootContainer()->finishedPendingThread( shared_from_this() );
}
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#ifndef WPROJECTFILE_H
#define WPROJECTFILE_H
#include <vector>
#include <string>
#include <boost/shared_ptr.hpp>
#include <boost/filesystem.hpp>
#include "WProjectFileParser.h"
/**
* Class loading project files. This class opens an file and reads it line by line. It delegates the actual parsing to each of the known
* WProjectFileParser instances which then do their job.
*/
class WProjectFile: public WThreadedRunner,
public boost::enable_shared_from_this< WProjectFile >
{
public:
/**
* Default constructor. It does NOT parse the file. Parsing is done by apply().
*
* \param project the project file to load.
*/
explicit WProjectFile( boost::filesystem::path project );
/**
* Destructor.
*/
virtual ~WProjectFile();
/**
* Parses the project file and applies it. It applies the project file asynchronously!
*/
virtual void run();
protected:
/**
* Function that has to be overwritten for execution. It gets executed in a separate thread after run()
* has been called.
*/
virtual void threadMain();
/**
* The project file to parse.
*/
boost::filesystem::path m_project;
/**
* The parser instances. They are used to parse the file.
*/
std::vector< WProjectFileParser* > m_parsers;
private:
};
#endif // WPROJECTFILE_H
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#include "WProjectFileParser.h"
WProjectFileParser::WProjectFileParser()
{
// initialize
}
WProjectFileParser::~WProjectFileParser()
{
// cleanup!
}
void WProjectFileParser::done()
{
// do nothing here. Overwrite this method if your specific parser needs to do some post processing.
}
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#ifndef WPROJECTFILEPARSER_H
#define WPROJECTFILEPARSER_H
#include <string>
/**
* A base class for all parts of OpenWalnut which can be serialized to a project file. It is used by WProjectFile to actually parse the file line
* by line. Derive from this class if you write your own parser and use it to fill your internal data structures.
*/
class WProjectFileParser
{
public:
/**
* Default constructor.
*/
WProjectFileParser();
/**
* Destructor.
*/
virtual ~WProjectFileParser();
/**
* This method parses the specified line and interprets it. It gets called line by line by WProjectFile.
*
* \param line the current line as string
* \param lineNumber the current line number. Useful for error/warning/debugging output.
*
* \return true if the line could be parsed.
*/
virtual bool parse( std::string line, unsigned int lineNumber ) = 0;
/**
* Called whenever the end of the project file has been reached. This is useful if your specific parser class wants to do some post
* processing after parsing line by line.
*/
virtual void done();
protected:
private:
};
#endif // WPROJECTFILEPARSER_H
......@@ -52,7 +52,7 @@
#include "../../common/WColor.h"
#include "../../common/WPreferences.h"
#include "../../kernel/WKernel.h"
#include "../../kernel/combiner/WModuleProjectFileCombiner.h"
#include "../../common/WProjectFile.h"
#include "../../modules/data/WMData.h"
#include "../../modules/navSlices/WMNavSlices.h"
......@@ -391,9 +391,11 @@ void WMainWindow::projectLoad()
QStringList::const_iterator constIterator;
for ( constIterator = fileNames.constBegin(); constIterator != fileNames.constEnd(); ++constIterator )
{
boost::shared_ptr< WModuleProjectFileCombiner > proj = boost::shared_ptr< WModuleProjectFileCombiner >(
new WModuleProjectFileCombiner( ( *constIterator ).toStdString() )
boost::shared_ptr< WProjectFile > proj = boost::shared_ptr< WProjectFile >(
new WProjectFile( ( *constIterator ).toStdString() )
);
// This call is asynchronous. It parses the file and the starts a thread to actually do all the stuff
proj->run();
}
}
......
......@@ -38,7 +38,7 @@
#include "../../common/WIOTools.h"
#include "../../graphicsEngine/WGraphicsEngine.h"
#include "../../kernel/WKernel.h"
#include "../../kernel/combiner/WModuleProjectFileCombiner.h"
#include "../../common/WProjectFile.h"
#include "../../dataHandler/WDataHandler.h"
#include "../../dataHandler/WSubject.h"
#include "WOpenCustomDockWidgetEvent.h"
......@@ -167,9 +167,10 @@ int WQt4Gui::run()
{
try
{
boost::shared_ptr< WModuleProjectFileCombiner > proj = boost::shared_ptr< WModuleProjectFileCombiner >(
new WModuleProjectFileCombiner( m_optionsMap["project"].as< std::string >() )
boost::shared_ptr< WProjectFile > proj = boost::shared_ptr< WProjectFile >(
new WProjectFile( m_optionsMap["project"].as< std::string >() )
);
// This call is asynchronous. It parses the file and the starts a thread to actually do all the stuff
proj->run();
}
......
......@@ -45,18 +45,16 @@
#include "WModuleProjectFileCombiner.h"
WModuleProjectFileCombiner::WModuleProjectFileCombiner( boost::filesystem::path project, boost::shared_ptr< WModuleContainer > target ):
WModuleProjectFileCombiner::WModuleProjectFileCombiner( boost::shared_ptr< WModuleContainer > target ):
WModuleCombiner( target ),
m_project( project )
WProjectFileParser()
{
parse();
}
WModuleProjectFileCombiner::WModuleProjectFileCombiner( boost::filesystem::path project ):
WModuleProjectFileCombiner::WModuleProjectFileCombiner():
WModuleCombiner( WKernel::getRunningKernel()->getRootContainer() ),
m_project( project )
WProjectFileParser()
{
parse();
}
WModuleProjectFileCombiner::~WModuleProjectFileCombiner()
......@@ -64,121 +62,102 @@ WModuleProjectFileCombiner::~WModuleProjectFileCombiner()
// cleanup
}
void WModuleProjectFileCombiner::parse()
bool WModuleProjectFileCombiner::parse( std::string line, unsigned int lineNumber )
{
// Parse the file
wlog::info( "Kernel" ) << "Loading project file \"" << m_project.file_string() << "\".";
// read the file
std::ifstream input( m_project.file_string().c_str() );
if ( !input.is_open() )
{
throw WFileNotFound( "The project file \"" + m_project.file_string() + "\" does not exist." );
}
// 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 commentRe( "^//.*$" );
// read it line by line
std::string line; // the current line
boost::smatch matches; // the list of matches
int i = 0; // line counter
while ( std::getline( input, line ) )
if ( boost::regex_match( line, matches, modRe ) )
{
i++;
if ( boost::regex_match( line, matches, modRe ) )
{
// it is a module line
// matches[1] is the ID
// matches[2] is the name of the module
// it is a module line
// matches[1] is the ID
// matches[2] is the name of the module
wlog::debug( "Project Loader [Parser]" ) << "Line " << i << ": Module \"" << matches[2] << "\" with ID " << matches[1];
wlog::debug( "Project Loader [Parser]" ) << "Line " << lineNumber << ": Module \"" << matches[2] << "\" with ID " << matches[1];
// create a module instance
boost::shared_ptr< WModule > proto = WModuleFactory::getModuleFactory()-> isPrototypeAvailable( matches[2] );
// create a module instance
boost::shared_ptr< WModule > proto = WModuleFactory::getModuleFactory()-> isPrototypeAvailable( matches[2] );
// data modules are not allowed here
if ( !proto )
{
wlog::error( "Project Loader" ) << "There is no prototype available for module \"" << matches[2] << "\". Skipping.";
}
else if ( proto->getType() == MODULE_DATA )
{
wlog::error( "Project Loader" ) << "Data modules are not allowed to be specified in a \"MODULE\" Statement." <<
" Use the \"DATA\" statement instead. Skipping.";
}
else
{
boost::shared_ptr< WModule > module = WModuleFactory::getModuleFactory()->create( proto );
m_modules.insert( ModuleID( boost::lexical_cast< unsigned int >( matches[1] ), module ) );
}
// data modules are not allowed here
if ( !proto )
{
wlog::error( "Project Loader" ) << "There is no prototype available for module \"" << matches[2] << "\". Skipping.";
}
else if ( proto->getType() == MODULE_DATA )
{
wlog::error( "Project Loader" ) << "Data modules are not allowed to be specified in a \"MODULE\" Statement." <<
" Use the \"DATA\" statement instead. Skipping.";
}
else
{
boost::shared_ptr< WModule > module = WModuleFactory::getModuleFactory()->create( proto );
m_modules.insert( ModuleID( boost::lexical_cast< unsigned int >( matches[1] ), module ) );
}
}
else if ( boost::regex_match( line, matches, dataRe ) )
{
// it is a dataset line
// matches[1] is the ID
// matches[2] is the filename
wlog::debug( "Project Loader [Parser]" ) << "Line " << lineNumber << ": Data \"" << matches[2] << "\" with ID " << matches[1];
// create a module instance
boost::shared_ptr< WModule > proto = WModuleFactory::getModuleFactory()-> isPrototypeAvailable( "Data Module" );
if ( !proto )
{
wlog::error( "Project Loader" ) << "There is no prototype available for module \"" << "Data Module" << "\"."
<< " This should not happen!. Skipping.";
}
else if ( boost::regex_match( line, matches, dataRe ) )
else
{
// it is a dataset line
// matches[1] is the ID
// matches[2] is the filename
wlog::debug( "Project Loader [Parser]" ) << "Line " << i << ": Data \"" << matches[2] << "\" with ID " << matches[1];
// create a module instance
boost::shared_ptr< WModule > proto = WModuleFactory::getModuleFactory()-> isPrototypeAvailable( "Data Module" );
if ( !proto )
std::string parameter = std::string( matches[2] );
boost::shared_ptr< WModule > module = WModuleFactory::getModuleFactory()->create( proto );
if ( parameter.empty() )
{
wlog::error( "Project Loader" ) << "There is no prototype available for module \"" << "Data Module" << "\"."
<< " This should not happen!. Skipping.";
wlog::error( "Project Loader" ) << "Data modules need an additional filename parameter. Skipping.";
}
else
{
std::string parameter = std::string( matches[2] );
boost::shared_ptr< WModule > module = WModuleFactory::getModuleFactory()->create( proto );
if ( parameter.empty() )
{
wlog::error( "Project Loader" ) << "Data modules need an additional filename parameter. Skipping.";
}
else
{
boost::shared_static_cast< WMData >( module )->setFilename( parameter );
m_modules.insert( ModuleID( boost::lexical_cast< unsigned int >( matches[1] ), module ) );
}
boost::shared_static_cast< WMData >( module )->setFilename( parameter );
m_modules.insert( ModuleID( boost::lexical_cast< unsigned int >( matches[1] ), module ) );
}
}
else if ( boost::regex_match( line, matches, conRe ) )
{
// it is a connector line
// matches[1] and [2] are the module ID and connector name of the output connector
// matches[3] and [4] are the module ID and connector name of the target input connector
}
else if ( boost::regex_match( line, matches, conRe ) )
{
// it is a connector line
// matches[1] and [2] are the module ID and connector name of the output connector
// matches[3] and [4] are the module ID and connector name of the target input connector
wlog::debug( "Project Loader [Parser]" ) << "Line " << i << ": Connection between \"" << matches[2] << "\" of module " << matches[1] <<
" and \"" << matches[4] << "\" of module " << matches[3] << ".";
wlog::debug( "Project Loader [Parser]" ) << "Line " << lineNumber << ": Connection between \"" << matches[2] << "\" of module " << matches[1] <<
" and \"" << matches[4] << "\" of module " << matches[3] << ".";
// now we search in modules[ matches[1] ] for an output connector named matches[2]
m_connections.push_back( Connection( Connector( boost::lexical_cast< unsigned int >( matches[1] ), matches[2] ),
Connector( boost::lexical_cast< unsigned int >( matches[3] ), matches[4] ) ) );
}
else if ( boost::regex_match( line, matches, propRe ) )
{
// it is a property line
// matches[1] is the module ID
// matches[2] is the property name
// matches[3] is the property value
// now we search in modules[ matches[1] ] for an output connector named matches[2]
m_connections.push_back( Connection( Connector( boost::lexical_cast< unsigned int >( matches[1] ), matches[2] ),
Connector( boost::lexical_cast< unsigned int >( matches[3] ), matches[4] ) ) );
}
else if ( boost::regex_match( line, matches, propRe ) )
{
// it is a property line
// matches[1] is the module ID
// matches[2] is the property name
// matches[3] is the property value
wlog::debug( "Project Loader [Parser]" ) << "Line " << i << ": Property \"" << matches[2] << "\" of module " << matches[1] << " set to "
<< matches[3];
wlog::debug( "Project Loader [Parser]" ) << "Line " << lineNumber << ": Property \"" << matches[2] << "\" of module " << matches[1] << " set to "
<< matches[3];
m_properties.push_back( PropertyValue( Property( boost::lexical_cast< unsigned int >( matches[1] ), matches[2] ), matches[3] ) );
}
else if ( !line.empty() && !boost::regex_match( line, matches, commentRe ) )
{
wlog::debug( "Project Loader [Parser]" ) << "Line " << i << ": Malformed. Skipping.";
}
m_properties.push_back( PropertyValue( Property( boost::lexical_cast< unsigned int >( matches[1] ), matches[2] ), matches[3] ) );
}
else
{
return false;
}
// close it
input.close();
return true;
}
void WModuleProjectFileCombiner::apply()
......@@ -305,3 +284,8 @@ void WModuleProjectFileCombiner::apply()
m_properties.clear();
}
void WModuleProjectFileCombiner::done()
{
apply();
}