Commit e727b4a6 authored by saubatn's avatar saubatn
Browse files

NEW : Pipeline action history. One for each application.

NEW : HistoryItem to store a pipeline action in the history.
FIXED : action pre / post processing methods to store the action in the history.

git-svn-id: svn+ssh://scm.forge.imag.fr/var/lib/gforge/chroot/scmrepos/svn/camitk/trunk/camitk@456 ec899d31-69d1-42ba-9299-647d76f65fb3
parent b5ffe94f
......@@ -35,7 +35,7 @@
// from a DLL simpler. All files within this DLL are compiled with the COMPILE_CAMITK_API
// flag defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// CAMITK_API functions as being imported from a DLL, wheras this DLL sees symbols
// CAMITK_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#if defined(_WIN32) // MSVC and mingw
#ifdef COMPILE_CAMITK_API
......
......@@ -28,6 +28,10 @@
// -- Core stuff
#include "CamiTKAPI.h"
#include "HistoryItem.h"
// -- Qt stuff
#include <QStack>
namespace camitk
{
......@@ -62,7 +66,7 @@ public:
/// get more information about installation, etc...
static const QString getConfig();
///@}
/// @name miscallaneous utility method or variables
///@{
/// complete version string
......@@ -100,11 +104,11 @@ private:
/// does this plateform puts all dll/so/dylib in a CamiTK::shortVersion directory
static const bool hasBinaryVersionSubdir();
/// return the name of the bin directory
static const QString getBinDirName();
/// return the name of the bin directory
static const QString getBinDirName();
/// name of the bin directory (can be "bin" or "binDebug" for installed debug version!)
static QString binDirName;
/// name of the bin directory (can be "bin" or "binDebug" for installed debug version!)
static QString binDirName;
};
}
......
/*****************************************************************************
* $CAMITK_LICENCE_BEGIN$
*
* CamiTK - Computer Assisted Medical Intervention ToolKit
* (c) 2001-2013 UJF-Grenoble 1, CNRS, TIMC-IMAG UMR 5525 (GMCAO)
*
* Visit http://camitk.imag.fr for more information
*
* This file is part of CamiTK.
*
* CamiTK is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* CamiTK 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 version 3 for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with CamiTK. If not, see <http://www.gnu.org/licenses/>.
*
* $CAMITK_LICENCE_END$
****************************************************************************/
#include "HistoryItem.h"
namespace camitk {
// --------------- Constructor -------------------
HistoryItem::HistoryItem() { }
// --------------- Constructor -------------------
HistoryItem::HistoryItem( QString name )
{
this->name = name;
}
// --------------- Destructor -------------------
HistoryItem::~HistoryItem()
{
}
// --------------- addProperty -------------------
void HistoryItem::addProperty ( QByteArray name, QVariant value )
{
this->properties.insert(name, value);
}
// --------------- setInputComponents -------------------
void HistoryItem::setInputComponents ( ComponentList inputComponents )
{
this->setInputComponents(inputComponents);
}
// --------------- setOutputComponents -------------------
void HistoryItem::setOutputComponents ( ComponentList outputComponents )
{
this->setOutputComponents(outputComponents);
}
}
/*****************************************************************************
* $CAMITK_LICENCE_BEGIN$
*
* CamiTK - Computer Assisted Medical Intervention ToolKit
* (c) 2001-2013 UJF-Grenoble 1, CNRS, TIMC-IMAG UMR 5525 (GMCAO)
*
* Visit http://camitk.imag.fr for more information
*
* This file is part of CamiTK.
*
* CamiTK is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* CamiTK 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 version 3 for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with CamiTK. If not, see <http://www.gnu.org/licenses/>.
*
* $CAMITK_LICENCE_END$
****************************************************************************/
#ifndef HISTORYITEM_H
#define HISTORYITEM_H
// Qt stuffs
#include <QString>
#include <QVariant>
// CamiTK stuffs
#include <Component.h>
namespace camitk {
/**
* @class HistoryItem
* @brief HistoryItem class describes the entry of an action used in a pipeline, in the history.
*
* In CamiTK, every action is stored in a history. Each history entry is an instance of @class{HistoryItem}
* Each history item provides information about the processed action :
* - the name of the action processed
* - the properties (name, values)
* - its input components
* - its output components
* History item are mainly useful for getting back to a previous state, undoing an action or for scripting, storing in a file a pipeline of actions.
*
**/
class CAMITK_API HistoryItem
{
private:
/// The name of the action in the pipeline
QString name;
/// The properties stored for this action
QMap<QByteArray, QVariant> properties;
/// The input components for this action
ComponentList inputComponents;
/// The outpu components for this action
ComponentList outputComponents;
public:
/// Empty constructor
HistoryItem();
/// Default constructor
/// @param name
/// name of the action stored in the history
HistoryItem(QString name);
/// Virtual destructor
virtual ~HistoryItem();
/// Add a property of the corresponding action to the history item
/// @param name Name of the property to addProperty
/// @param value Value of the property to add (no type specified)
void addProperty(QByteArray name, QVariant value);
/// Set the input components of the history item action
/// @param inputComponents The list of input components
void setInputComponents(ComponentList inputComponents);
/// Set the output components of the historu item action
/// @param outputComponents The list of output components
void setOutputComponents(ComponentList outputComponents);
};
}
#endif // HISTORYITEM_H
......@@ -30,15 +30,18 @@
#include "Component.h"
#include "ActionWidget.h"
#include "Log.h"
#include "HistoryItem.h"
#include <QHBoxLayout>
#include <QGroupBox>
#include <QMessageBox>
namespace camitk {
namespace camitk
{
// -------------------- constructor --------------------
Action::Action(ActionExtension* extension): QObject() {
Action::Action ( ActionExtension* extension ) : QObject()
{
this->extension = extension;
this->component = "";
qAction = NULL;
......@@ -48,85 +51,102 @@ Action::Action(ActionExtension* extension): QObject() {
}
// -------------------- destructor --------------------
Action::~Action() {
Action::~Action()
{
}
// -------------------- setName --------------------
void Action::setName(QString name) {
void Action::setName ( QString name )
{
this->name = name;
setObjectName(name);
setObjectName ( name );
}
// -------------------- setDescription --------------------
void Action::setDescription(QString description) {
void Action::setDescription ( QString description )
{
this->description = description;
}
// -------------------- setComponent --------------------
void Action::setComponent(QString component) {
void Action::setComponent ( QString component )
{
this->component = component;
}
// -------------------- setFamily --------------------
void Action::setFamily(QString family) {
void Action::setFamily ( QString family )
{
this->family = family;
}
// -------------------- setTag --------------------
void Action::addTag(QString tag) {
this->tags.append(tag);
void Action::addTag ( QString tag )
{
this->tags.append ( tag );
}
// -------------------- setEmbedded --------------------
void Action::setEmbedded(bool isEmbedded) {
void Action::setEmbedded ( bool isEmbedded )
{
this->isEmbedded = isEmbedded;
}
// -------------------- setIcon --------------------
void Action::setIcon(QPixmap icon) {
void Action::setIcon ( QPixmap icon )
{
this->icon = icon;
}
// -------------------- getExtensionName --------------------
QString Action::getExtensionName() const {
QString Action::getExtensionName() const
{
return extension->getName();
}
// -------------------- getIcon --------------------
QPixmap Action::getIcon() {
QPixmap Action::getIcon()
{
return icon;
}
// -------------------- getTargets --------------------
const ComponentList Action::getTargets() const {
return targetComponents;
const ComponentList Action::getTargets() const
{
return targetComponents;
}
// -------------------- getWidget --------------------
QWidget* Action::getWidget() {
QWidget* Action::getWidget()
{
// build or update the widget
if (!actionWidget) {
if ( !actionWidget )
{
// Setting the widget containing the parameters, using the default widget
actionWidget = new ActionWidget(this);
actionWidget = new ActionWidget ( this );
}
else {
else
{
// make sure the widget has updated targets
dynamic_cast<ActionWidget*>(actionWidget)->updateTargets();
dynamic_cast<ActionWidget*> ( actionWidget )->updateTargets();
}
// make sure the widget updates its parameters
dynamic_cast<ActionWidget*>(actionWidget)->setAutoUpdateProperty(autoUpdateProperties);
dynamic_cast<ActionWidget*> ( actionWidget )->setAutoUpdateProperty ( autoUpdateProperties );
return actionWidget;
}
// -------------------- getQAction --------------------
QAction* Action::getQAction() {
if (!qAction) {
QAction* Action::getQAction()
{
if ( !qAction )
{
// create the corresponding QAction (using the icon, name and descriptions)
qAction = new QAction(getIcon(), getName(), this);
qAction->setStatusTip(getDescription());
qAction->setWhatsThis(getName() + "\n" + getDescription());
qAction = new QAction ( getIcon(), getName(), this );
qAction->setStatusTip ( getDescription() );
qAction->setWhatsThis ( getName() + "\n" + getDescription() );
// connect it to the trigger slot
connect ( qAction, SIGNAL ( triggered() ), this, SLOT ( trigger() ) );
}
......@@ -135,36 +155,44 @@ QAction* Action::getQAction() {
}
// -------------------- trigger --------------------
Action::ApplyStatus Action::trigger(QWidget * parent) {
Action::ApplyStatus Action::trigger ( QWidget * parent )
{
//-- build the list of valid targets
targetComponents.clear();
ComponentList selComp = Application::getSelectedComponents();
foreach (Component * comp, selComp) {
foreach ( Component * comp, selComp )
{
// check compatibility
if (comp->isInstanceOf(this->getComponent()))
targetComponents.append(comp);
if ( comp->isInstanceOf ( this->getComponent() ) )
targetComponents.append ( comp );
}
//-- if there are some valid targets or if the action is generic
if (targetComponents.size() > 0 || getComponent().isEmpty()) {
if (isEmbedded) {
if ( targetComponents.size() > 0 || getComponent().isEmpty() )
{
if ( isEmbedded )
{
// if there are no parents to use use the action viewer
if (!parent)
ActionViewer::getActionViewer()->embedActionWidget(this);
else {
getWidget()->setParent(parent);
if ( !parent )
ActionViewer::getActionViewer()->embedActionWidget ( this );
else
{
getWidget()->setParent ( parent );
getWidget()->show();
}
}
else {
else
{
QWidget * w = getWidget();
if (w) {
if ( w )
{
// non embeded, just show/raise the window
w->show();
}
else {
else
{
// non embeded, no widget -> call apply() directly
return apply();
}
......@@ -172,76 +200,86 @@ Action::ApplyStatus Action::trigger(QWidget * parent) {
return TRIGGERED;
}
else {
QMessageBox::information(parent, "Cannot apply this Action to selection", "Sorry, but the action \"" + getName() + "\" cannot be applied on the currently selected component(s)");
else
{
QMessageBox::information ( parent, "Cannot apply this Action to selection", "Sorry, but the action \"" + getName() + "\" cannot be applied on the currently selected component(s)" );
return ERROR;
}
}
// -------------------- applyInPipeline --------------------
Action::ApplyStatus Action::applyInPipeline() {
Action::ApplyStatus Action::applyInPipeline()
{
ApplyStatus status;
preProcess();
preProcess();
//-- if there are some valid targets or if the action is generic
if (targetComponents.size() > 0 || getComponent().isEmpty()) {
status = apply();
postProcess();
}
else
status = Action::ABORTED;
if ( targetComponents.size() > 0 || getComponent().isEmpty() )
{
status = apply();
postProcess();
}
else
status = Action::ABORTED;
return status;
}
// -------------------- setInputComponents --------------------
void Action::setInputComponents(ComponentList inputs) {
void Action::setInputComponents ( ComponentList inputs )
{
//-- build the list of valid targets
targetComponents.clear();
foreach (Component * comp, inputs) {
targetComponents.clear();
foreach ( Component * comp, inputs )
{
// check compatibility
if (comp->isInstanceOf(this->getComponent()))
targetComponents.append(comp);
}
if ( comp->isInstanceOf ( this->getComponent() ) )
targetComponents.append ( comp );
}
}
// -------------------- setInputComponent --------------------
void Action::setInputComponent(Component * input) {
void Action::setInputComponent ( Component * input )
{
targetComponents.clear();
// check compatibility
if (input->isInstanceOf(this->getComponent())) {
targetComponents.append(input);
// check compatibility
if ( input->isInstanceOf ( this->getComponent() ) )
{
targetComponents.append ( input );
}
}
// -------------------- getOutputComponents --------------------
ComponentList Action::getOutputComponents() {
ComponentList Action::getOutputComponents()
{
return this->outputComponents;
}
// -------------------- getOutputComponent --------------------
Component * Action::getOutputComponent() {
if (outputComponents.isEmpty())
Component * Action::getOutputComponent()
{
if ( outputComponents.isEmpty() )
return NULL;
else
return outputComponents.first();
}
// -------------------- preProcess --------------------
void Action::preProcess() {
// get track of alive components before applying the action so
// that we can deduce from list of components after the action,
// the components created by the action.
this->aliveBeforeComponents = Application::getAllComponents();
/*
Useless, just don't use trigger !
// unselect all components
ComponentList selComp = Application::getSelectedComponents();
void Action::preProcess()
{
// get track of alive components before applying the action so
// that we can deduce from list of components after the action,
// the components created by the action.
this->aliveBeforeComponents = Application::getAllComponents();
/*
Useless, just don't use trigger !
// unselect all components
ComponentList selComp = Application::getSelectedComponents();
foreach (Component * comp, selComp) {
comp->setSelected(false);
}
......@@ -250,43 +288,61 @@ void Action::preProcess() {
foreach (Component * comp, inputComponents) {
comp->setSelected(true);
}
*/
*/
}
// -------------------- postProcess --------------------
void Action::postProcess() {
outputComponents.clear();
ComponentList allComp = Application::getAllComponents();
foreach (Component * comp, allComp) {
if ((! wasHereBefore(comp)) || (comp->getModified())) {
outputComponents.append(comp);
}
}
void Action::postProcess()
{
outputComponents.clear();
ComponentList allComp = Application::getAllComponents();
foreach ( Component * comp, allComp )
{
if ( ( ! wasHereBefore ( comp ) ) || ( comp->getModified() ) )
{
outputComponents.append ( comp );
}
}
// TODO record history
// record the action as an history item in the core history
HistoryItem* item = new HistoryItem(this->getName());
// add the action's parameters to the history item
// get back all the properties dynamically added to the action using Qt meta object
foreach (QByteArray propertyName, dynamicPropertyNames())
item->addProperty(propertyName, property(propertyName));
// add the action's input components
item->setInputComponents(this->targetComponents);
// add the action's output components
item->setOutputComponents(this->outputComponents);
// add the item to the history
Application::getHistory().push(*item);
}
bool Action::wasHereBefore(Component *comp) {
ComponentList::const_iterator it = aliveBeforeComponents.begin();
bool Action::wasHereBefore ( Component *comp )
{
ComponentList::const_iterator it = aliveBeforeComponents.begin();
while (( it != aliveBeforeComponents.end()) && comp != (*it))
it++;
while ( ( it != aliveBeforeComponents.end() ) && comp != ( *it ) )
it++;
return (it != aliveBeforeComponents.end());
return ( it != aliveBeforeComponents.end() );
}
// -------------------- getAutoUpdateProperties --------------------
bool Action::getAutoUpdateProperties() const {
return autoUpdateProperties;
bool Action::getAutoUpdateProperties() const
{
return autoUpdateProperties;
}
// -------------------- setAutoUpdateProperties --------------------
void Action::setAutoUpdateProperties(bool autoUpdateProperties) {
this->autoUpdateProperties = autoUpdateProperties;
if (actionWidget)
dynamic_cast<ActionWidget*>(actionWidget)->setAutoUpdateProperty(autoUpdateProperties);
void Action::setAutoUpdateProperties ( bool autoUpdateProperties )
{
this->autoUpdateProperties = autoUpdateProperties;
if ( actionWidget )
dynamic_cast<ActionWidget*> ( actionWidget )->setAutoUpdateProperty ( autoUpdateProperties );
}
}
......
......@@ -238,7 +238,7 @@ public:
*/
QAction *getQAction();
/// the name of the component class that can be used by this action
/// get the name of the action
QString getName() const {
return name;
};
......@@ -316,7 +316,7 @@ protected:
/// These methods can not be redefined in subclasses but have to used to ensure name/description unicity
/// among CamiTK.
/// @{
/// the name of the component class that can be used by this action
/// set the name of the action class
void setName(QString name);
/// the description of the action
...