Commit 83f43403 authored by Frédéric Larue's avatar Frédéric Larue
Browse files

Script parsing mechanism added to define new tools as a combination of existing ones.

parent a0990d75
......@@ -11,6 +11,26 @@
#include "ui_AlgorithmSelector.h"
#include "UIMultiProgressDialog.h"
#include <QLabel>
#include "ScriptParser.h"
QString AlgorithmSelector::ToolDescriptor::getName() const
{
return plugin? plugin->name(id) : script->GetName();
}
QString AlgorithmSelector::ToolDescriptor::getDescription() const
{
return plugin? plugin->description(id) : script->GetDescription();
}
void AlgorithmSelector::ToolDescriptor::getAcceptedDataTypes( QVector<QString> &types ) const
{
if( plugin )
plugin->acceptedDataTypes( id, types );
}
......@@ -39,6 +59,8 @@ AlgorithmSelector::AlgorithmSelector(QWidget *parent) :
AlgorithmSelector::~AlgorithmSelector()
{
for( auto &tool : m_ToolsByName )
delete tool.script;
delete m_CurrentToolProgress;
delete m_ui;
}
......@@ -86,6 +108,50 @@ void AlgorithmSelector::populateTools( ToolInterface *plugin )
}
bool AlgorithmSelector::populateTools( const QString &scriptFileName )
{
ScriptParser *script = new ScriptParser();
script->SetAvailableTools( this );
if( !script->ParseFile(scriptFileName) )
{
delete script;
return false;
}
bool categoryDeclared = false;
int categoryId = -1;
for( int i=0; i<ToolCategory::categoryCount(); ++i )
if( script->GetCategory() == ToolCategory::categoryName(i) )
{
categoryId = i;
categoryDeclared = true;
break;
}
if( categoryDeclared )
{
ToolDescriptor tool;
tool.script = script;
tool.param = new UIParamSet( "Tool options", this );
//plugin->declareParameters( i, *tool.param );
tool.param->SetHidden();
//tool.param->setMaximumWidth(360);
//connect( tool.param, SIGNAL(parameterUpdated(UIParam*)), tool.plugin, SLOT(updateParameter(UIParam*)) );
//foreach( UIParamAction* act, tool.param->GetActions() )
// connect( act->Widget(), SIGNAL(clicked(bool)), this, SLOT(emitActionSignal()) );
m_ToolsByName[ script->GetName() ] = tool;
m_ToolsByCategory[categoryId].push_back( tool );
m_ui->widgetToolGroupBoxes->layout()->addWidget( tool.param );
}
return true;
}
void AlgorithmSelector::releaseAllTools()
{
for( auto &category : m_ToolsByCategory )
......@@ -97,16 +163,16 @@ void AlgorithmSelector::releaseAllTools()
void AlgorithmSelector::finalizeTools()
{
// Sort tools by name for each category.
for( QVector<QVector<ToolDescriptor>>::iterator category=m_ToolsByCategory.begin(); category!=m_ToolsByCategory.end(); ++category )
for( auto &category : m_ToolsByCategory )
{
QMap<QString,ToolDescriptor> toolByName;
foreach( ToolDescriptor tool, *category )
toolByName[tool.plugin->name(tool.id)] = tool;
for( ToolDescriptor &tool : category )
toolByName[tool.getName()] = tool;
category->clear();
category.clear();
for( QMap<QString,ToolDescriptor>::iterator tool=toolByName.begin(); tool!=toolByName.end(); ++tool )
category->push_back( *tool );
for( auto &tool : toolByName )
category.push_back( tool );
}
......@@ -187,7 +253,12 @@ bool AlgorithmSelector::selectCategory( int categoryId )
// Populate the combobox with the names of all tools associated to the selected category.
m_ui->comboAvailableTools->clear();
foreach( ToolDescriptor tool, m_ToolsByCategory[categoryId] )
m_ui->comboAvailableTools->addItem( tool.plugin->name(tool.id) );
{
if( tool.script )
m_ui->comboAvailableTools->addItem( QIcon(":/images/resources/iconScript.png"), tool.getName() );
else
m_ui->comboAvailableTools->addItem( tool.getName() );
}
m_ui->comboAvailableTools->setCurrentIndex( lastUsedId );
selectTool( lastUsedId );
......@@ -213,7 +284,7 @@ bool AlgorithmSelector::selectTool( int n )
{
m_SelectedTool = &m_ToolsByCategory[m_SelectedCategory][n];
QString description = m_SelectedTool->plugin->description( m_SelectedTool->id );
QString description = m_SelectedTool->getDescription();
if( description.isNull() || description.isEmpty() )
m_ui->groupToolDescription->hide();
else
......@@ -223,7 +294,7 @@ bool AlgorithmSelector::selectTool( int n )
m_ui->labelToolDescription->setEnabled( true );
QVector<QString> acceptedTypes;
m_SelectedTool->plugin->acceptedDataTypes( m_SelectedTool->id, acceptedTypes );
m_SelectedTool->getAcceptedDataTypes(acceptedTypes);
if( acceptedTypes.empty() )
m_ui->labelToolDescription->setToolTip( "" );
else
......@@ -352,41 +423,48 @@ void AlgorithmSelector::applyCurrentToolOn( const QList<GenericUIData*> &items,
m_ToolContext.glviewer = glviewer;
m_ToolContext.project = project;
QVector<QString> acceptedTypes;
m_SelectedTool->plugin->acceptedDataTypes( m_SelectedTool->id, acceptedTypes );
bool executionOk = true;
if( m_SelectedTool->plugin )
{
QVector<QString> acceptedTypes;
m_SelectedTool->plugin->acceptedDataTypes( m_SelectedTool->id, acceptedTypes );
QMap<QString,int> acceptedTypeIds;
for( int i=0; i<acceptedTypes.size(); ++i )
acceptedTypeIds[ acceptedTypes[i] ] = i;
QMap<QString,int> acceptedTypeIds;
for( int i=0; i<acceptedTypes.size(); ++i )
acceptedTypeIds[ acceptedTypes[i] ] = i;
UIToolDataSet dataSet;
dataSet.items.resize( acceptedTypes.size() );
UIToolDataSet dataSet;
dataSet.items.resize( acceptedTypes.size() );
for( GenericUIData *m : items )
{
auto found = acceptedTypeIds.find( m->GetTypeString() );
if( found != acceptedTypeIds.end() )
dataSet.items[ found.value() ].push_back( m );
}
for( GenericUIData *m : items )
{
auto found = acceptedTypeIds.find( m->GetTypeString() );
if( found != acceptedTypeIds.end() )
dataSet.items[ found.value() ].push_back( m );
}
connect( m_SelectedTool->plugin, SIGNAL(notifyCreateProgressBars(int)), this, SLOT(createProgressBars(int)) );
connect( m_SelectedTool->plugin, SIGNAL(notifyDeleteProgressBars()), this, SLOT(deleteProgressBars()) );
connect( m_SelectedTool->plugin, SIGNAL(notifyCreateProgressBars(int)), this, SLOT(createProgressBars(int)) );
connect( m_SelectedTool->plugin, SIGNAL(notifyDeleteProgressBars()), this, SLOT(deleteProgressBars()) );
if( project )
project->StartNewDataTracking();
if( project )
project->StartNewDataTracking();
bool executionOk;
if( m_ActionId.isNull() )
executionOk = m_SelectedTool->plugin->exec( m_SelectedTool->id, dataSet, *m_SelectedTool->param, m_ToolContext );
else
executionOk = m_SelectedTool->plugin->execAction( m_SelectedTool->id, m_ActionId, dataSet, *m_SelectedTool->param, m_ToolContext );
if( m_ActionId.isNull() )
executionOk = m_SelectedTool->plugin->exec( m_SelectedTool->id, dataSet, *m_SelectedTool->param, m_ToolContext );
else
executionOk = m_SelectedTool->plugin->execAction( m_SelectedTool->id, m_ActionId, dataSet, *m_SelectedTool->param, m_ToolContext );
if( project )
project->StopNewDataTracking();
if( project )
project->StopNewDataTracking();
disconnect( m_SelectedTool->plugin, SIGNAL(notifyCreateProgressBars(int)), this, SLOT(createProgressBars(int)) );
disconnect( m_SelectedTool->plugin, SIGNAL(notifyDeleteProgressBars()), this, SLOT(deleteProgressBars()) );
deleteProgressBars();
disconnect( m_SelectedTool->plugin, SIGNAL(notifyCreateProgressBars(int)), this, SLOT(createProgressBars(int)) );
disconnect( m_SelectedTool->plugin, SIGNAL(notifyDeleteProgressBars()), this, SLOT(deleteProgressBars()) );
deleteProgressBars();
}
else if( m_SelectedTool->script )
{
executionOk = m_SelectedTool->script->RunScript( m_ToolContext );
}
emit toolExecutionFinished( executionOk );
}
......
......@@ -17,6 +17,7 @@
#include <QVector>
#include "UIParam.h"
#include "UIContext.h"
class ScriptParser;
......@@ -34,9 +35,14 @@ class AlgorithmSelector : public QWidget
public:
struct ToolDescriptor
{
ToolInterface *plugin;
UIParamSet *param;
int id;
ToolInterface *plugin = NULL;
ScriptParser *script = NULL;
UIParamSet *param = NULL;
int id = 0;
QString getName() const;
QString getDescription() const;
void getAcceptedDataTypes( QVector<QString> &types ) const;
};
private:
......@@ -61,6 +67,7 @@ public:
~AlgorithmSelector();
void populateTools( ToolInterface *tool );
bool populateTools( const QString &scriptFileName );
void releaseAllTools();
void finalizeTools();
inline QString currentToolName() const { return m_SelectedTool->plugin->name( m_SelectedTool->id ); }
......
This diff is collapsed.
/*
* (c) LSIIT, UMR CNRS/UdS
* Authors: O. Gnevaux, F. Larue.
*
* See licence.txt for additional information.
*/
#ifndef __SCRIPTPARSER_H__
#define __SCRIPTPARSER_H__
#include "UIData/UIProject.h"
#include "GUI_main/AlgorithmSelector.h"
class AlgorithmSelector;
struct AlgorithmSelector::ToolDescriptor;
class ScriptParser
{
static const QString TOKEN;
static const QString STRING;
static const QString INSIDE_BRACKETS;
static const QString INSIDE_PARENTHESES;
struct DataFilter
{
QVector<DataFilter*> children;
DataFilter *sub = NULL;
QString value;
bool isString;
int depth;
inline ~DataFilter()
{
for( auto c : children )
delete c;
children.clear();
delete sub;
}
};
struct PlugInParam
{
QString name;
QString value;
QString backupValue;
bool show;
};
struct PlugIn
{
QString type;
QString name;
QVector<PlugInParam> params;
};
enum InstructionType
{
RunPlugIn ,
AssignVariable ,
LoopOverData
};
struct Instruction
{
InstructionType type;
DataFilter *data = NULL;
inline Instruction() {}
inline Instruction( InstructionType _type ) : type(_type) {}
inline virtual ~Instruction() { delete data; }
};
struct InstructionAssignment : public Instruction
{
QString assignment;
inline InstructionAssignment() : Instruction(InstructionType::AssignVariable) {}
};
struct InstructionPlugin : public Instruction
{
QString assignment;
PlugIn plugin;
AlgorithmSelector::ToolDescriptor *toolDesc = NULL;
inline InstructionPlugin() : Instruction(InstructionType::RunPlugIn) {}
};
struct InstructionLoop : public Instruction
{
QString loopVar;
ScriptParser* subScript = NULL;
inline InstructionLoop() : Instruction(InstructionType::LoopOverData) {}
inline ~InstructionLoop() { delete subScript; }
};
struct Variable
{
ScriptParser *scope = NULL;
QList<GenericUIData*> content;
QStringList stringContent;
inline Variable() {}
inline Variable(QList<GenericUIData*> &_content, ScriptParser *_scope ) : content(_content), scope(_scope) {}
inline Variable(QStringList &_content, ScriptParser *_scope ) : stringContent(_content), scope(_scope) {}
};
using VariableMap = QMap<QString,Variable>;
QString m_Name;
QString m_Description;
QString m_Category;
int m_CurrentPos;
QList<Instruction*> m_Instructions;
static QMap<QString,QString> m_ToolsByScriptName;
static AlgorithmSelector *m_ToolSelector;
QString GetTrimmedScript( const QString &inputScript ) const;
bool ParseDirective(VariableMap &declaredVariables, const QString &script, bool &error);
bool ParseLoopBegin(VariableMap &declaredVariables, const QString &script, bool &error );
bool ParseLoopEnd( const QString &script );
QString ParseAssignment( const QString &script );
DataFilter* ParseData(VariableMap &declaredVariables, const QString &script );
DataFilter* ParseDataFilterTree(const QString &script);
void DisplayDataFilterTree(DataFilter *data, QString offset = "");
bool DataFilterTreeSemanticCheck(VariableMap &declaredVariables, DataFilter *data, int depth = 0 );
bool ParsePlugIn(VariableMap &declaredVariables, const QString &script, PlugIn &plugin, DataFilter *&data, bool &error );
bool AddInstruction(VariableMap &declaredVariables, QString assignment, PlugIn &plugin, DataFilter *data );
bool AddInstruction( ScriptParser *subScript, const QString &loopVar, DataFilter *data );
QSet<GenericUIData*> GatherItemsFromTree( DataFilter *data, VariableMap &declaredVariables, const QSet<GenericUIData*> &items = QSet<GenericUIData*>() );
QList<GenericUIData*> GatherItems( VariableMap &declaredVariables, Instruction *inst, UIProject *project );
void BindTool( InstructionPlugin *inst );
void UnbindTool( InstructionPlugin *inst );
bool ParseSubScript( VariableMap &declaredVariables, const QString &inputScript );
bool RunSubScript( VariableMap &declaredVariables, UIContext &context );
void SetVariable(VariableMap &declaredVariables, const QString &name, QList<GenericUIData*> &content, ScriptParser *scope);
void SetStringVariable(VariableMap &declaredVariables, const QString &name, QStringList &content, ScriptParser *scope);
void DeclareVariable(VariableMap &declaredVariables, const QString &name, ScriptParser *scope);
void DeleteVariablesInScope(VariableMap &declaredVariables, ScriptParser *scope);
static bool NameMatches( const QString& name, const QString& filter );
public:
~ScriptParser();
inline const QString& GetName() const { return m_Name; }
inline const QString& GetDescription() const { return m_Description; }
inline const QString& GetCategory() const { return m_Category; }
static QString GetToolScriptName( const QString &toolName );
static QString GetToolScriptString( const AlgorithmSelector::ToolDescriptor &desc );
void SetAvailableTools( AlgorithmSelector *algoSelector );
bool ParseFile( const QString &filename );
bool ParseScript( const QString &inputScript );
bool RunScript( UIContext &context );
};
#endif //__SCRIPTPARSER_H__
......@@ -26,6 +26,7 @@
#include "UIParamDialog.h"
#include "ThemeSettingsDialog.h"
#include "UISettings.h"
#include "ScriptParser.h"
#include "NodeEditor.h"
//#include "ShaderGraph.h"
......@@ -429,6 +430,19 @@ void UIMainWindow::loadPlugins()
}
}
// Load scripts.
QDir scriptsDir( qApp->applicationDirPath() );
if( scriptsDir.cd( "scripts" ) )
{
scriptsDir.setFilter(QDir::Files);
for( QString &fileName : scriptsDir.entryList() )
{
ui->toolSelector->populateTools(scriptsDir.absolutePath() + "/" + fileName);
}
}
ui->toolSelector->finalizeTools();
}
......@@ -506,6 +520,17 @@ void UIMainWindow::update( bool mustBeUpdated )
bool UIMainWindow::newProject()
{
//ScriptParser parser;
//parser.SetAvailableTools( ui->toolSelector );
//bool parsingOK = parser.ParseFile("D:/tmp/test.txt");
//std::cout << "Parsing " << (parsingOK? "succeeded!" : "failed...") << std::endl;
//if( parsingOK )
//{
// if( !getCurrentProject() )
// loadProject("D:/Data/testVenus/TestVenus.xml");
// parser.RunScript( this, getCurrentViewer(), getCurrentProject() );
//}
//return false;
/* Create the dialog box for asking information about the project to create */
UIParamDialog dlg( "Project settings", this );
dlg.Add( new UIParamString("name", "Project name", "Name of the new project to create.", "Default project" ) );
......@@ -1049,7 +1074,7 @@ bool UIMainWindow::saveProjectOptions( const QString &filePath, UIProject *proje
for( auto &tool : ui->toolSelector->allTools() )
if( tool.param )
{
QString name = tool.plugin->name( tool.id );
QString name = tool.getName();
QList<UIParam*> params = tool.param->GetAll();
if( params.isEmpty() )
......
......@@ -11,6 +11,7 @@
<file>resources/icon2DViewer.png</file>
<file>resources/icon3DViewer.png</file>
<file>resources/iconClone.png</file>
<file>resources/iconScript.png</file>
<file>resources/animationStart.png</file>
<file>resources/animationPause.png</file>
<file>resources/animationStop.png</file>
......
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