Commit ed0214a1 authored by cfouard's avatar cfouard
Browse files

ADDED actionstatemachine now works with 2 command line argument

TODO add component and actions to load to these arguments
ADDED schema for asm xml files
FIXED now the example xml files is valid with respect to schemas

git-svn-id: svn+ssh://scm.forge.imag.fr/var/lib/gforge/chroot/scmrepos/svn/camitk/trunk/camitk@510 ec899d31-69d1-42ba-9299-647d76f65fb3
parent 188816a1
......@@ -52,7 +52,7 @@
// constructor
ActionStateMachine::ActionStateMachine(int &argc, char ** argv) throw(AbortException) :
ActionStateMachine::ActionStateMachine(int &argc, char ** argv, QString inputFileName, QString outputDirectory) throw(AbortException) :
Application("Action State Machine Main Window", argc, argv)
{
statesMap = new QMap<QString, ActionState *>();
......@@ -65,20 +65,41 @@ Application("Action State Machine Main Window", argc, argv)
// CamiTK Application main window
initMainWindow();
// Load File
// Read parameters or ask for scxml file name and output save directory
QString filename;
if (argc < 2)
{
if (inputFileName.isEmpty()) {
filename = QFileDialog::getOpenFileName( NULL, "Please select an xml file");
}
else {
filename = argv[1];
filename = inputFileName;
}
// check the given file
this->checkSCXMLFile(filename);
// Get the name of the saving directory
if (outputDirectory.isEmpty()) {
saveDirectory = QFileDialog::getExistingDirectory(this->mainWindow, "Please select a directory where to save log and component files");
}
else {
saveDirectory = QDir(outputDirectory);
}
QDate date = QDate::currentDate();
QTime time = QTime::currentTime();
QString newDir = QString("%1-%2-%3at%4h%5").arg(date.year())
.arg(date.month())
.arg(date.day())
.arg(time.hour())
.arg(time.minute());
if (! saveDirectory.mkdir(newDir)) {
saveDirectory = QFileDialog::getExistingDirectory(this->mainWindow, "Please select a directory where to save log and component files");
saveDirectory.mkdir(newDir);
}
saveDirectory.cd(newDir);
// parse XML file and store actions and transitions in states
name = this->parseSCXMLTree();
mainWindow->setWindowSubtitle(name);
......@@ -96,7 +117,6 @@ Application("Action State Machine Main Window", argc, argv)
// Starting the Machine !!
//create the main timer
QDate date = QDate::currentDate();
startTime = new QTime();
startTime->start();
......@@ -104,6 +124,7 @@ Application("Action State Machine Main Window", argc, argv)
(*logStream) << "<?xml-stylesheet type='text/xsl' href='log2html.xsl'?>" << endl << endl;
(*logStream) << "<application xmlns='http://ujf-grenoble.fr/camitk/logApplication'>" << endl;
(*logStream) << " <name>" << name << "</name>" << endl;
(*logStream) << " <inputXmlFile>" << filename << "</inputXmlFile>" << endl;
(*logStream) << " <startDate>" << date.toString("yyyy-MM-dd") << "</startDate>" << endl;
(*logStream) << " <startTime>" << startTime->toString("hh:mm:ss:zzz") << "</startTime>" << endl;
......@@ -175,29 +196,7 @@ QString ActionStateMachine::parseSCXMLTree() throw(AbortException) {
// Get the name of the application
QString applicationName = "";
QDomElement docElem = scxmlDoc.documentElement();
applicationName = docElem.attribute("camitk:applicationName");
// Get the name of the saving directory
QString saveDir = docElem.attribute("camitk:saveDirectory");
if (saveDir.isEmpty()) {
saveDirectory = QFileDialog::getExistingDirectory(this->mainWindow, "Please select a directory where to save log and component files");
}
else {
saveDirectory = QDir(saveDir);
}
QDate date = QDate::currentDate();
QTime time = QTime::currentTime();
QString newDir = QString("%1-%2-%3at%4h%5").arg(date.year())
.arg(date.month())
.arg(date.day())
.arg(time.hour())
.arg(time.minute());
if (! saveDirectory.mkdir(newDir)) {
saveDirectory = QFileDialog::getExistingDirectory(this->mainWindow, "Please select a directory where to save log and component files");
saveDirectory.mkdir(newDir);
}
saveDirectory.cd(newDir);
applicationName = docElem.attribute("applicationName");
QString logFileName = this->saveDirectory.absolutePath() + "/log.xml";
logFile = new QFile(logFileName);
......@@ -307,7 +306,7 @@ void ActionStateMachine::createTransitions(QDomNodeList nodeList) throw(AbortExc
QString targetName = transElement.attribute("target");
// Apply the previous action during this transition ?
QString applyActionStr = transElement.attribute("camitk:applyAction", "true");
QString applyActionStr = transElement.attribute("applyAction", "true");
bool applyAction = (applyActionStr.toLower() == "true");
// Find disable conditions
......
......@@ -64,7 +64,7 @@ class ActionStateMachine : public Application
public:
/// construtor
ActionStateMachine(int &argc, char ** argv) throw(AbortException);
ActionStateMachine(int &argc, char ** argv, QString inputFileName="", QString outputDirectory="") throw(AbortException);
/// destructor
virtual ~ActionStateMachine();
......
......@@ -26,10 +26,55 @@
// -- Application Action State Machine Stuff
#include "ActionStateMachine.h"
#include <iostream>
#include <QString>
#include <QMap>
int main(int argc, char **argv)
{
QString scxmlFileName = "";
QString outputDirName = "";
QString progName = argv[0];
QString helpline = "usage: " + progName + " -file xmlInputFileName -outDir saveDirectoryName\n";
for (int i = 1; i < argc; i++) {
QString current = QString(argv[i]);
if ((current == QString("-help")) || (current == QString("--help"))) {
std::cout << helpline.toStdString().c_str() << endl;
return 0;
}
else if (current == "-file") {
if (i == argc-1) {
std::cout << "Error in parsing arguments: -file option used, but no file name given" << std::endl;
std::cout << helpline.toStdString().c_str() << endl;
return 1;
}
else {
i = i+1;
scxmlFileName = QString(argv[i]);
}
}
else if (current == "-outDir") {
if (i == argc-1) {
std::cout << "Error in parsing arguments: -outDir option used but no output directory given";
std::cout << std::endl;
std::cout << helpline.toStdString().c_str() << endl;
return 1;
}
else {
i = i+1;
outputDirName = QString(argv[i]);
}
}
else {
std::cout << "Error in parsing arguments: unknown argument " << argv[i] << endl;
std::cout << helpline.toStdString().c_str() << endl;
return 1;
}
}
// create a camitk application
ActionStateMachine am(argc, argv);
ActionStateMachine am(argc, argv, scxmlFileName, outputDirName);
return am.exec();
}
......
......@@ -152,6 +152,7 @@ td.simple {
<h3> Runned the <xsl:value-of select="/log:application/log:startDate"/></h3>
<h3> Start: <xsl:value-of select="/log:application/log:startTime"/> Stop: <xsl:value-of select="/log:application/log:endTime"/> </h3>
<h2> duration: <xsl:value-of select="floor($duration div 3600000)"/> h <xsl:value-of select="floor(($duration mod 3600000) div 3600000)"/> min <xsl:value-of select="floor((($duration mod (3600000)) mod (60000)) div 1000)"/> s <xsl:value-of select="floor($duration mod 1000)"/> ms</h2>
<h3>Input xml file name: <xsl:value-of select="/log:application/log:inputXmlFile"/></h3>
</div>
<div class="stateFrame">
......
<?xml version="1.0" encoding="UTF-8"?>
<!--
This file is a test input file for ActionStateMachine.
The ASM here is very simple:
- Open an image with the Open Action
- Name it openedImage
- Apply a manual threshol on this image
- with low threshold to arbitrary set to 58
- with high threshold arbitrary set to 153
- Name the output image thresholdImage
- Save this output image in the same directory as the input image.
-->
<scxml xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://camitk.imag.fr/3/smallScxml'
xmlns:camitk='http://camitk.imag.fr/3/asm'
xsi:schemaLocation='http://camitk.imag.fr/3/smallScxml smallScxml.xsd'
applicationName = "Simple Image Filter"
initial="Initialize"
>
<state id="Initialize">
<onentry>
<camitk:onState>
<camitk:description>
<![CDATA[
This Action State Machine performs a very simple image processing pipeline:<br/>
<ul>
<li>Open an image with the Open Action</li>
<li>Name the output image openedImage</li>
<li>Apply a manual threshol on this image
<ul>
<li>with low threshold to arbitrary set to 58</li>
<li>with high threshold arbitrary set to 153</li>
</ul>
<li>Name the output image thresholdImage</li>
<li>Save this output image in the same directory as the input image.</li>
<li>Quit the application</li>
]]>
</camitk:description>
</camitk:onState>
</onentry>
<transition event="Next" target="Image Open"/>
</state>
<state id="Image Open">
<onentry>
<camitk:onState>
<camitk:description>Open a new volume image and display it.</camitk:description>
<camitk:action>
<camitk:name>Open</camitk:name>
<camitk:outputs>
<camitk:component type="ImageComponent" name="openedImage"/>
</camitk:outputs>
</camitk:action>
</camitk:onState>
</onentry>
<transition event="Quit" target="Bye" applyAction="false"/>
<transition event="Acquire New Image" target="Image Display" applyAction="true" />
</state>
<state id="Image Display">
<onentry>
<camitk:onState>
<camitk:description>
<![CDATA[
Please check that this image is the right image.
]]>
</camitk:description>
<camitk:altDescription previousStatus="ABORTED ERROR">
<![CDATA[
<font color='#ff0000'>
The image has not been opened correctly. <br/>
Please retry to open an image.
</font>
]]>
</camitk:altDescription>
</camitk:onState>
</onentry>
<transition event="Back" target="Image Open" >
<camitk:onTransition>
<camitk:close>
<camitk:component type="ImageComponent" name="openedImage"/>
</camitk:close>
</camitk:onTransition>
</transition>
<transition event="Next" target="Image Threshold" disable="ABORTED ERROR"/>
</state>
<state id="Image Threshold">
<onentry>
<camitk:onState>
<camitk:description>Image Processing Step</camitk:description>
<camitk:action>
<camitk:name>Manual Threshod Filter</camitk:name>
<camitk:parameters>
<camitk:parameter name="lowThreshold" type="int" value="58"/>
<camitk:parameter name="highThreshold" type="int" value="153"/>
</camitk:parameters>
<camitk:inputs>
<camitk:component type="ImageCompoent" name="openedImage"/>
</camitk:inputs>
<camitk:outputs>
<camitk:component type="ImageComponent" name="thresholdImage"/>
</camitk:outputs>
</camitk:action>
</camitk:onState>
</onentry>
<transition event="Back" target="Image Display" applyAction="false">
<camitk:onTransition>
<camitk:close>
<camitk:component type="ImageComponent" name="thresholdImage"/>
</camitk:close>
</camitk:onTransition>
</transition>
<transition event="Next" target="Save Image" applyAction="true"/>
</state>
<state id="Save Image">
<onentry>
<camitk:onState>
<camitk:description>Save the threshold image</camitk:description>
<camitk:action>
<camitk:name>Save</camitk:name>
<camitk:inputs>
<camitk:component type="ImageComponent" name="thresholdImage" suffix=".mha"/>
</camitk:inputs>
</camitk:action>
</camitk:onState>
</onentry>
<transition event="Back" target="Image Threshold" applyAction="false"/>
<transition event="Next" target="Bye"/>
</state>
<state id="Bye" final="true">
<onentry>
<camitk:onState>
<camitk:description>
<![CDATA[
<b><i> Congratulations ! </i></b><br/>
<i>Press <b>Quit</b> to quit the application or <b>Back to the Beginning</b> to
to re-run the application from the beginning.
]]>
</camitk:description>
</camitk:onState>
</onentry>
<transition event="Back to the Beginning" target="Initialize">
<camitk:onTransition>
<camitk:close>
<camitk:component type="ImageComponent" name="openedImage"/>
<camitk:component type="ImageComponent" name="thresholdImage"/>
</camitk:close>
</camitk:onTransition>
</transition>
</state>
</scxml>
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://camitk.imag.fr/3/asm"
xmlns:camitk="http://camitk.imag.fr/3/asm"
elementFormDefault="qualified">
<xsd:attributeGroup name="scxmlCamitkAttributes">
<xsd:attribute name="applicationName" type="xsd:string" use="required"/>
<xsd:attribute name="saveDirectory" type="xsd:anyURI" use="optional"/>
</xsd:attributeGroup>
<xsd:attributeGroup name="transitionCamitkAttributes">
<xsd:attribute name="applyAction" type="xsd:boolean" use="optional" default="true"/>
<xsd:attribute name="disable" type="camitk:PreviousStatus"/>
</xsd:attributeGroup>
<xsd:complexType name="Description" mixed="true"/>
<xsd:complexType name="AltDescription" mixed="true">
<xsd:attribute name="previousStatus" type="camitk:PreviousStatus"/>
</xsd:complexType>
<xsd:element name="onState" type="camitk:StateDef"/>
<xsd:complexType name="StateDef">
<xsd:sequence>
<xsd:element name="description" type="camitk:Description"/>
<xsd:element name="altDescription" type="camitk:AltDescription" minOccurs="0"/>
<xsd:element name="action" type="camitk:Action" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Action">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="parameters" type="camitk:Parameters" minOccurs="0"/>
<xsd:element name="inputs" type="camitk:IOComponents" minOccurs="0"/>
<xsd:element name="outputs" type="camitk:IOComponents" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Parameters">
<xsd:sequence>
<xsd:element name="parameter" type="camitk:Parameter" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Parameter">
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="type" type="camitk:ParameterType" use="required"/>
<xsd:attribute name="value" type="xsd:string"/>
</xsd:complexType>
<xsd:complexType name="IOComponents">
<xsd:sequence>
<xsd:element name="component" type="camitk:Component" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Component">
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="type" type="xsd:string" use="required"/>
<!-- The suffix is optional as it does not consern all the actions.
However, it is MANDATORY for the Save action.
-->
<xsd:attribute name="suffix" type="xsd:string" use="optional"/>
<xsd:attribute name="saveDirectory" type="xsd:anyURI" use="optional"/>
</xsd:complexType>
<xsd:simpleType name="ParameterType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="int"/>
<xsd:enumeration value="bool"/>
<xsd:enumeration value="double"/>
<xsd:enumeration value="QString"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="PreviousStatus">
<xsd:list itemType="camitk:Status"/>
</xsd:simpleType>
<xsd:simpleType name="Status">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="SUCCESS"/>
<xsd:enumeration value="ERROR"/>
<xsd:enumeration value="WARNING"/>
<xsd:enumeration value="ABORTED"/>
<xsd:enumeration value="TRIGGERED"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="LogFileName">
<xsd:attribute name="pattern" type="xsd:anyURI"/>
</xsd:complexType>
<xsd:element name="onTransition" type="camitk:OnTransition"/>
<xsd:complexType name="OnTransition">
<xsd:sequence>
<xsd:element name="close" type="camitk:IOComponents" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
<?xml version="1.0" encoding="windows-1252"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://camitk.imag.fr/3/smallScxml"
xmlns="http://camitk.imag.fr/3/smallScxml"
xmlns:camitk="http://camitk.imag.fr/3/asm"
elementFormDefault="qualified">
<xsd:import namespace="http://camitk.imag.fr/3/asm" schemaLocation="camitkAsm.xsd"/>
<xsd:element name="scxml" type="Scxml"/>
<xsd:annotation>
<xsd:documentation>
This schema is freely adapted from W3C State Chart XML (SCXML) language
(http://www.w3.org/2005/07/scxml).
It contains less features (the only ones supported by CamiTK).
Eventually CamiTK Action State Machine may support the whole scxml
language, but meanwhile, to ease example validation, we use
this limited language.
</xsd:documentation>
</xsd:annotation>
<xsd:complexType name="Scxml">
<xsd:sequence>
<xsd:element name="state" type="State" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attributeGroup ref="scxmlAttributes"/>
<xsd:attributeGroup ref="camitk:scxmlCamitkAttributes"/>
</xsd:complexType>
<xsd:attributeGroup name="scxmlAttributes">
<xsd:attribute name="initial" type="xsd:string" use="required"/>
</xsd:attributeGroup>
<xsd:complexType name="State">
<xsd:sequence>
<xsd:element name="onentry" type="OnEntry"/>
<xsd:element name="transition" type="Transition" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string" use="required"/>
<xsd:attribute name="final" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
<xsd:complexType name="OnEntry">
<xsd:sequence>
<xsd:any namespace="http://camitk.imag.fr/3/asm" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Transition">
<xsd:sequence>
<xsd:any namespace="http://camitk.imag.fr/3/asm" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="event" type="xsd:string" use="required"/>
<xsd:attribute name="target" type="xsd:string" use="required"/>
<xsd:attributeGroup ref="camitk:transitionCamitkAttributes"/>
</xsd:complexType>
</xsd:schema>
<?xml version="1.0"?>
<!--
This file is a test input file for ActionStateMachine.
The ASM here is very simple:
- Open an image with the Open Action
- Name it openedImage
- Apply a manual threshol on this image
- with low threshold to arbitrary set to 58
- with high threshold arbitrary set to 153
- Name the output image thresholdImage
- Save this output image in the same directory as the input image.
-->
<scxml xmlns="http://www.w3.org/2005/07/scxml"
xmlns:camitk="http://camitk.imag.fr/3/asm"
camitk:applicationName = "Simple Image Filter"
initial="Initialize">
<state id="Initialize">
<onentry>
<camitk:description>
<![CDATA[
This Action State Machine performs a very simple image processing pipeline:<br/>
<ul>
<li>Open an image with the Open Action</li>
<li>Name the output image openedImage</li>
<li>Apply a manual threshol on this image
<ul>
<li>with low threshold to arbitrary set to 58</li>
<li>with high threshold arbitrary set to 153</li>
</ul>
<li>Name the output image thresholdImage</li>
<li>Save this output image in the same directory as the input image.</li>
<li>Quit the application</li>
]]>
</camitk:description>
<camitk:logFileName pattern="D:/cfouard/tmp"/>
</onentry>
<transition event="Next" target="Image Open"/>
</state>
<state id="Image Open">
<onentry>
<camitk:description>Open a new volume image and display it.</camitk:description>
<camitk:action>
<camitk:name>Open</camitk:name>
<camitk:outputs>
<camitk:component type="ImageComponent" name="openedImage"/>
</camitk:outputs>
</camitk:action>
</onentry>
<transition event="Quit" target="Bye" camitk:applyAction="false"/>
<transition event="Acquire New Image" target="Image Display" camitk:applyAction="true" />
</state>
<state id="Image Display">
<onentry>
<camitk:description><![CDATA[
Please check that this image is the right image.
]]></camitk:description>
<camitk:altDescription camitk:previousStatus="ABORTED, ERROR"><![CDATA[
<font color='#ff0000'>
The image has not been opened correctly. <br/>
Please retry to open an image.
</font>
]]></camitk:altDescription>
</onentry>
<transition event="Back" target="Image Open" >
<camitk:close><camitk:component type="ImageComponent" name="openedImage"/></camitk:close>
</transition>
<transition event="Next" target="Image Threshold" camitk:disable="ABORTED, ERROR"/>
</state>
<state id="Image Threshold">
<onentry>
<camitk:description>Image Processing Step</camitk:description>
<camitk:action>
<camitk:name>Manual Threshod Filter</camitk:name>
<camitk:parameters>
<camitk:parameter name="lowThreshold" type="int" value="58"/>
<camitk:parameter name="highThreshold" type="int" value="153"/>
</camitk:parameters>
<camitk:inputs>
<camitk:component type="ImageCompoent" name="openedImage"/>
</camitk:inputs>
<camitk:outputs>
<camitk:component type="ImageComponent" name="thresholdImage"/>
</camitk:outputs>