Public Types | Public Member Functions | Static Public Member Functions | Protected Member Functions | Protected Attributes | Friends

mitk::StateMachine Class Reference
[Interaction Classes]

Superior statemachineRealizes the methods, that every statemachine has to have. Undo can be enabled and disabled through EnableUndo. More...

#include <mitkStateMachine.h>

Inheritance diagram for mitk::StateMachine:
Inheritance graph
[legend]
Collaboration diagram for mitk::StateMachine:
Collaboration graph
[legend]

List of all members.

Public Types

typedef StateMachine Self
typedef itk::Object Superclass
typedef itk::SmartPointer< SelfPointer
typedef itk::SmartPointer
< const Self
ConstPointer
typedef std::map< int,
TStateMachineFunctor * > 
ActionFunctionsMapType
 Map to connect action IDs with method calls. Use AddActionFunction or (even better) the CONNECT_ACTION macro to fill the map.
typedef std::vector
< State::Pointer
StartStateVectorType
 Type for a vector of StartStatePointers.

Public Member Functions

virtual const char * GetClassName () const
std::string GetType () const
 Get the name and with this the type of the StateMachine.
virtual bool HandleEvent (StateEvent const *stateEvent)
 handles an Event accordingly to its current State
void EnableUndo (bool enable)
 Enables or disabled Undo.

Static Public Member Functions

static Pointer New (const char *_arg)
 New Macro with one parameter for creating this object with static New(..) method.

Protected Member Functions

 StateMachine (const char *type)
 Default Constructor. Obsolete to instanciate it with this method! Use New(..) method instead. Set the "type" and with this the pattern of the StateMachine.
 ~StateMachine ()
 Default Destructor.
void AddActionFunction (int action, TStateMachineFunctor *functor)
 Adds the Function to ActionList.
virtual bool ExecuteAction (Action *action, StateEvent const *stateEvent)
 Method called in HandleEvent after Statechange.
const StateGetCurrentState (unsigned int timeStep=0) const
 returns the current state
void IncCurrGroupEventId ()
 Friend protected function of OperationEvent; that way all StateMachines can set GroupEventId to be incremented!
virtual void ExecuteOperation (Operation *operation)
 A statemachine is also an OperationActor due to the UndoMechanism.
void ResetStatemachineToStartState (unsigned int timeStep=0)
 Resets the current state from the given timeStep to the StartState with undo functionality! Use carefully!
void ExpandStartStateVector (unsigned int timeSteps)
 Check if the number of timeSteps is equal to the number of stored StartStates. Nothing is changed if the number is equal.
void InitializeStartStates (unsigned int timeSteps)
 initializes m_CurrentStateVector
virtual void UpdateTimeStep (unsigned int timeStep)
 Update the TimeStep of the statemachine with undo-support if undo enabled.

Protected Attributes

bool m_UndoEnabled
 if true, then UndoFunctionality is enabled
UndoControllerm_UndoController
 holds an UndoController, that can be accessed from all StateMachines. For ExecuteAction
unsigned int m_TimeStep
 Current TimeStep if the data which is to be interacted on, has more than 1 TimeStep.

Friends

class UndoModel
 Friend so that UndoModel can call ExecuteOperation for Undo.
class GlobalInteraction

Detailed Description

Superior statemachine

Realizes the methods, that every statemachine has to have. Undo can be enabled and disabled through EnableUndo.

To implement your own state machine, you have to derive a class from mitk::StateMachine and either

The second version is recommended, since it provides more structured code. The following piece of code demonstrates how to use the CONNECT_ACTION macro. The important detail is to provide a typedef classname Self

class LightSwitch : public StateMachine
{
  public:

    mitkClassMacro(LightSwitch, StateMachine); // this creates the Self typedef

    LightSwitch(const char*);

    bool DoSwitchOn(Action*, const StateEvent*);
    bool DoSwitchOff(Action*, const StateEvent*);
}

LightSwitch::LightSwitch(const char* type)
:StateMachine(type)
{
  // make sure that AcSWITCHON and AcSWITCHOFF are defined int constants somewhere (e.g. mitkInteractionConst.h)
  CONNECT_ACTION( AcSWITCHON, DoSwitchOn );
  CONNECT_ACTION( AcSWITCHOFF, DoSwitchOff );
}

bool LightSwitch::DoSwitchOn(Action*, const StateEvent*)
{
  std::cout << "Enlightenment" << std::endl;
}

bool LightSwitch::DoSwitchOff(Action*, const StateEvent*)
{
  std::cout << "Confusion" << std::endl;
}

What CONNECT_ACTION does, is call StateMachine::AddActionFunction(...) to add some function pointer wrapping class (functor) to a std::map of StateMachine. Whenever StateMachines ExecuteAction is called, StateMachine will lookup the desired Action in its map and call the appropriate method in your derived class.

Definition at line 134 of file mitkStateMachine.h.


Member Typedef Documentation

Map to connect action IDs with method calls. Use AddActionFunction or (even better) the CONNECT_ACTION macro to fill the map.

Definition at line 143 of file mitkStateMachine.h.

typedef itk::SmartPointer<const Self> mitk::StateMachine::ConstPointer
typedef itk::SmartPointer<Self> mitk::StateMachine::Pointer

Type for a vector of StartStatePointers.

Definition at line 154 of file mitkStateMachine.h.

typedef itk::Object mitk::StateMachine::Superclass

Constructor & Destructor Documentation

mitk::StateMachine::StateMachine ( const char *  type ) [protected]

Default Constructor. Obsolete to instanciate it with this method! Use New(..) method instead. Set the "type" and with this the pattern of the StateMachine.

Constructor daclares a new StateMachine and connects it to a StateMachine of Type type; Also the undo mechanism is instanciated and enabled/disabled.

here the Undo mechanism is enabled / disabled for all interactors.

Definition at line 38 of file mitkStateMachine.cpp.

References InitializeStartStates(), m_TimeStep, m_UndoController, m_UndoEnabled, and mitk::UndoController::VERBOSE_LIMITEDLINEARUNDO.

: m_UndoController(NULL), m_Type("")
{
  if(type!=NULL) //no need to throw a warning here, because the statemachine yet here doesn't have to be set up. 
  {
    m_Type = type;
    
    //the statemachine doesn't know yet anything about the number of timesteps of the data. So we initialize it with one element.
    this->InitializeStartStates(1);
  }
  
  if (!m_UndoController)
  {
    m_UndoController = new UndoController(UndoController::VERBOSE_LIMITEDLINEARUNDO);//switch to LLU or add LLU
    
    m_UndoEnabled = true;
  }

  m_TimeStep = 0;
}
mitk::StateMachine::~StateMachine (  ) [protected]

Default Destructor.

Definition at line 62 of file mitkStateMachine.cpp.

{
  //clean up map using deletes
  for ( mitk::StateMachine::ActionFunctionsMapType::iterator iter = m_ActionFunctionsMap.begin();
        iter != m_ActionFunctionsMap.end();
        ++iter )
  {
    delete iter->second;
  }

  delete m_UndoController;
}

Member Function Documentation

void mitk::StateMachine::AddActionFunction ( int  action,
mitk::TStateMachineFunctor functor 
) [protected]

Adds the Function to ActionList.

Definition at line 201 of file mitkStateMachine.cpp.

{
  if (!functor) return;

  // make sure double calls for same action won't cause memory leaks
  delete m_ActionFunctionsMap[action]; // delete NULL does no harm

  m_ActionFunctionsMap[action] = functor;
}
void mitk::StateMachine::EnableUndo ( bool  enable )

Enables or disabled Undo.

Definition at line 177 of file mitkStateMachine.cpp.

{
  m_UndoEnabled = enable;
}
bool mitk::StateMachine::ExecuteAction ( Action action,
StateEvent const *  stateEvent 
) [protected, virtual]

Method called in HandleEvent after Statechange.

look up which object method is associated to the given action and call the method

Each statechange has actions, which can be assigned by it's number. If you are developing a new statemachine, declare all your operations here and send them to Undo-Controller and to the Data. Object- and group-EventId can also be accessed through static methods from OperationEvent

Reimplemented in mitk::CameraRotationController, mitk::SliceNavigationController, mitk::SlicesCoordinator, mitk::SlicesRotator, mitk::SlicesSwiveller, mitk::AffineInteractor, mitk::CoordinateSupplier, mitk::DisplayVectorInteractor, mitk::GlobalInteraction, mitk::MoveSurfaceInteractor, mitk::PointSetInteractor, mitk::PositionTracker, mitk::AffineInteractor3D, mitk::ConnectPointsInteractor, mitk::ContourInteractor, mitk::DisplayPointSetInteractor, mitk::ExtrudedContourInteractor, mitk::PointInteractor, mitk::PointSelectorInteractor, mitk::SeedsInteractor, mitk::SurfaceDeformationInteractor3D, and mitk::PlanarFigureInteractor.

Definition at line 188 of file mitkStateMachine.cpp.

References mitk::TStateMachineFunctor::DoAction(), and mitk::Action::GetActionId().

{
  if (!action) return false;

  int actionId = action->GetActionId();

  TStateMachineFunctor* actionFunction = m_ActionFunctionsMap[actionId];
  if (!actionFunction) return false;

  bool retVal = actionFunction->DoAction(action, stateEvent);
  return retVal;
}
void mitk::StateMachine::ExecuteOperation ( Operation operation ) [protected, virtual]

A statemachine is also an OperationActor due to the UndoMechanism.

The statechange is done in ExecuteOperation, so that the statechange can be undone by UndoMechanism. Is set private here and in superclass it is set public, so UndoController can reach ist, but it can't be overwritten by a subclass

Implements mitk::OperationActor.

Reimplemented in mitk::SliceNavigationController, mitk::DisplayVectorInteractor, and mitk::Interactor.

Definition at line 212 of file mitkStateMachine.cpp.

References mitk::Operation::GetOperationType(), mitk::StateTransitionOperation::GetState(), mitk::StateTransitionOperation::GetTime(), mitk::OpDELETE, mitk::OpNOTHING, mitk::OpSTATECHANGE, mitk::OpTIMECHANGE, mitk::OpUNDELETE, and STATEMACHINE_WARN.

Referenced by mitk::SlicesRotator::ExecuteAction(), and mitk::SlicesRotator::RotateToPoint().

{
  switch (operation->GetOperationType())
  {
  case OpNOTHING:
    break;
  case OpSTATECHANGE:
    {
      mitk::StateTransitionOperation* stateTransOp = dynamic_cast<mitk::StateTransitionOperation *>(operation);
      if (stateTransOp == NULL)
      {
        STATEMACHINE_WARN<<"Error! see mitkStateMachine.cpp";
        return;
      }
      unsigned int time = stateTransOp->GetTime();
      m_CurrentStateVector[time] = stateTransOp->GetState();
    }
    break;
  case OpTIMECHANGE:
    {
      mitk::StateTransitionOperation* stateTransOp = dynamic_cast<mitk::StateTransitionOperation *>(operation);
      if (stateTransOp == NULL)
      {
        STATEMACHINE_WARN<<"Error! see mitkStateMachine.cpp";
        return;
      }
      m_TimeStep = stateTransOp->GetTime();
    }
    break;
  case OpDELETE:
    {
      //delete this!
      //before all lower statemachines has to be deleted in a action
      //this->Delete();//might not work!!!check itk!
    }
  case OpUNDELETE:
    {
      //now the m_CurrentState has to be set on a special State
      //that way a delete of a StateMachine can be undone 
      //IMPORTANT: The type has to be the same!!!Done by a higher instance, that creates this!
      mitk::StateTransitionOperation* stateTransOp = dynamic_cast<mitk::StateTransitionOperation *>(operation);
      if (stateTransOp != NULL)
      {
        unsigned int time = stateTransOp->GetTime();
        m_CurrentStateVector[time] = stateTransOp->GetState();
      }
    }
  default:
    ;
  }
}
void mitk::StateMachine::ExpandStartStateVector ( unsigned int  timeSteps ) [protected]

Check if the number of timeSteps is equal to the number of stored StartStates. Nothing is changed if the number is equal.

Definition at line 288 of file mitkStateMachine.cpp.

References mitk::GlobalInteraction::GetInstance(), and mitk::GlobalInteraction::GetStartState().

{
  unsigned int oldSize = m_CurrentStateVector.size();

  if ( timeSteps > oldSize )
  {
    State::Pointer startState = mitk::GlobalInteraction::GetInstance()->GetStartState(m_Type.c_str());
    for ( unsigned int i = oldSize; i < timeSteps; ++i )
      m_CurrentStateVector.insert(m_CurrentStateVector.end(), startState);
  }
}
virtual const char* mitk::StateMachine::GetClassName (  ) const [virtual]
const mitk::State * mitk::StateMachine::GetCurrentState ( unsigned int  timeStep = 0 ) const [protected]

returns the current state

Definition at line 80 of file mitkStateMachine.cpp.

{
  if (m_CurrentStateVector.size() > timeStep) //the size of the vector has to be one integer higher than the timeStep.
    return m_CurrentStateVector[timeStep].GetPointer();
  return NULL;
}
std::string mitk::StateMachine::GetType (  ) const

Get the name and with this the type of the StateMachine.

Definition at line 75 of file mitkStateMachine.cpp.

{
  return m_Type;
}
bool mitk::StateMachine::HandleEvent ( StateEvent const *  stateEvent ) [virtual]

handles an Event accordingly to its current State

Statechange with Undo functionality; EventMapper gives each event a new objectEventId and a StateMachine::ExecuteAction can descide weather it gets a new GroupEventId or not, depending on its state (e.g. finishedNewObject then new GroupEventId). Object- and group-EventId can also be accessed through static methods from OperationEvent

Reimplemented in mitk::Interactor.

Definition at line 104 of file mitkStateMachine.cpp.

References mitk::Transition::GetActionBeginIterator(), mitk::Transition::GetActionEndIterator(), mitk::State::GetId(), mitk::StateEvent::GetId(), mitk::State::GetName(), mitk::Transition::GetNextState(), mitk::OpSTATECHANGE, STATEMACHINE_DEBUG, and STATEMACHINE_ERROR.

Referenced by mitk::SlicesRotator::ExecuteAction(), mitk::WiiMoteAddOn::ForwardEvent(), mitk::SpaceNavigatorAddOn::ForwardEvent(), mitk::TDMouseEventThrower::KeyDown(), mitk::EventMapper::MapEvent(), QmitkStdMultiWidget::MoveCrossToPosition(), and mitk::TDMouseEventThrower::SensorInput().

{
  if (stateEvent == NULL)
    return false;

  if (m_CurrentStateVector.empty())
  {
    STATEMACHINE_ERROR << "Error in mitkStateMachine.cpp: StateMachine not initialized!\n";
    return false;//m_CurrentStateVector needs to be initialized!
  }

  if (m_TimeStep >= m_CurrentStateVector.size())
  {
    STATEMACHINE_ERROR << "Error in mitkStateMachine.cpp: StateMachine not initialized for this time step!\n";
    return false;
  }

  if (m_CurrentStateVector[m_TimeStep].IsNull())
  {
    STATEMACHINE_ERROR << "Error in mitkStateMachine.cpp: StateMachine not initialized with the right temporal information!\n";
    return false;//m_CurrentState needs to be initialized!
  }

  //get the Transition from m_CurrentState which waits for this EventId
  const Transition *tempTransition = m_CurrentStateVector[m_TimeStep]->GetTransition(stateEvent->GetId());
  if (tempTransition == NULL) //no transition in this state for that EventId
  {
    return false;
  }

  //get next State
  State *tempNextState = tempTransition->GetNextState();
  if (tempNextState == NULL) //wrong built up statemachine!
  {
    STATEMACHINE_ERROR << "Error in mitkStateMachine.cpp: StateMachinePattern not defined correctly!\n";
    return false;
  }

  //and ActionId to execute later on
  if ( m_CurrentStateVector[m_TimeStep]->GetId() != tempNextState->GetId() )//statechange only if there is a real statechange
  {
    if ( m_UndoEnabled )  //write to UndoMechanism if Undo is enabled
    {
      //UNDO for this statechange; since we directly change the state, we don't need the do-Operation in case m_UndoEnables == false
      StateTransitionOperation* doOp = new StateTransitionOperation(OpSTATECHANGE, tempNextState, m_TimeStep);
      StateTransitionOperation* undoOp = new StateTransitionOperation(OpSTATECHANGE, m_CurrentStateVector[m_TimeStep], m_TimeStep);
      OperationEvent *operationEvent = new OperationEvent(((mitk::OperationActor*)(this)), doOp, undoOp);
      m_UndoController->SetOperationEvent(operationEvent);
    }

    STATEMACHINE_DEBUG("StateChange")<<this->GetType()<<" from " << m_CurrentStateVector[m_TimeStep]->GetId() 
      << " " << m_CurrentStateVector[m_TimeStep]->GetName()
      <<" to " << tempNextState->GetId() <<" "<<tempNextState->GetName();

    //first following StateChange(or calling ExecuteOperation(tempNextStateOp)), then operation(action)
    m_CurrentStateVector[m_TimeStep] = tempNextState;
  }

  mitk::Transition::ActionVectorIterator actionIdIterator = tempTransition->GetActionBeginIterator();
  mitk::Transition::ActionVectorConstIterator actionIdIteratorEnd = tempTransition->GetActionEndIterator();
  bool ok = true;

  while ( actionIdIterator != actionIdIteratorEnd ) 
  {
    if ( !ExecuteAction(*actionIdIterator, stateEvent) )
    {
      ok = false;
    }
    actionIdIterator++;
  }
  return ok;
}
void mitk::StateMachine::IncCurrGroupEventId (  ) [protected]

Friend protected function of OperationEvent; that way all StateMachines can set GroupEventId to be incremented!

Definition at line 182 of file mitkStateMachine.cpp.

References mitk::UndoStackItem::IncCurrGroupEventId().

void mitk::StateMachine::InitializeStartStates ( unsigned int  timeSteps ) [protected]

initializes m_CurrentStateVector

Definition at line 264 of file mitkStateMachine.cpp.

References mitk::GlobalInteraction::GetInstance(), mitk::GlobalInteraction::GetStartState(), and STATEMACHINE_FATAL.

Referenced by StateMachine().

{
  //get the startstate of the pattern
  State::Pointer startState = mitk::GlobalInteraction::GetInstance()->GetStartState(m_Type.c_str());

  if (startState.IsNull())
  {
    STATEMACHINE_FATAL << "Fatal Error in mitkStateMachine.cpp: Initialization of statemachine unsuccessfull! Initialize GlobalInteraction!\n";
  }

  //clear the vector
  m_CurrentStateVector.clear();
  //add n=timesteps pointers pointing to to the startstate
  for (unsigned int i = 0; i < timeSteps; i++)
    m_CurrentStateVector.push_back(startState);
}
static Pointer mitk::StateMachine::New ( const char *  _arg ) [inline, static]

New Macro with one parameter for creating this object with static New(..) method.

Definition at line 143 of file mitkStateMachine.h.

Referenced by mitk::FeedbackContourTool::FeedbackContourTool(), mitkStateMachineTest(), mitk::MorphologicTool::MorphologicTool(), and mitk::PaintbrushTool::PaintbrushTool().

void mitk::StateMachine::ResetStatemachineToStartState ( unsigned int  timeStep = 0 ) [protected]

Resets the current state from the given timeStep to the StartState with undo functionality! Use carefully!

Parameters:
[in]timeStepIf the statemachine has several timesteps to take care of, specify the according timestep

Definition at line 87 of file mitkStateMachine.cpp.

References mitk::GlobalInteraction::GetInstance(), mitk::GlobalInteraction::GetStartState(), and mitk::OpSTATECHANGE.

Referenced by mitk::Tool::Deactivated().

{
  mitk::State* startState = mitk::GlobalInteraction::GetInstance()->GetStartState((const char *)(&m_Type[0]));

  if ( m_UndoEnabled )  //write to UndoMechanism if Undo is enabled
  {
    //UNDO for this statechange; 
    StateTransitionOperation* doOp = new StateTransitionOperation(OpSTATECHANGE, startState, timeStep);
    StateTransitionOperation* undoOp = new StateTransitionOperation(OpSTATECHANGE, m_CurrentStateVector[timeStep], timeStep);
    OperationEvent *operationEvent = new OperationEvent(((mitk::OperationActor*)(this)), doOp, undoOp);
    m_UndoController->SetOperationEvent(operationEvent);
  }
  //can be done without calling this->ExecuteOperation()
  m_CurrentStateVector[timeStep] = startState;

}
void mitk::StateMachine::UpdateTimeStep ( unsigned int  timeStep ) [protected, virtual]

Update the TimeStep of the statemachine with undo-support if undo enabled.

Reimplemented in mitk::Interactor.

Definition at line 300 of file mitkStateMachine.cpp.

References mitk::OpTIMECHANGE.

{
  //don't need to fill up the memory if the time is uptodate
  if (timeStep == m_TimeStep)
    return;

  //create an operation that changes the time and send it to undocontroller 
  StateTransitionOperation* doOp = new StateTransitionOperation(OpTIMECHANGE, NULL, timeStep);
  if ( m_UndoEnabled )  //write to UndoMechanism if Undo is enabled
  {
    StateTransitionOperation* undoOp = new StateTransitionOperation(OpTIMECHANGE, NULL, m_TimeStep);
    OperationEvent *operationEvent = new OperationEvent(((mitk::OperationActor*)(this)), doOp, undoOp);
    m_UndoController->SetOperationEvent(operationEvent);
  }
  this->ExecuteOperation(doOp);
}

Friends And Related Function Documentation

friend class GlobalInteraction [friend]

Definition at line 182 of file mitkStateMachine.h.

friend class UndoModel [friend]

Friend so that UndoModel can call ExecuteOperation for Undo.

Definition at line 180 of file mitkStateMachine.h.


Member Data Documentation

unsigned int mitk::StateMachine::m_TimeStep [protected]

Current TimeStep if the data which is to be interacted on, has more than 1 TimeStep.

Definition at line 265 of file mitkStateMachine.h.

Referenced by StateMachine().

holds an UndoController, that can be accessed from all StateMachines. For ExecuteAction

Definition at line 230 of file mitkStateMachine.h.

Referenced by StateMachine().

if true, then UndoFunctionality is enabled

Default value is true;

Definition at line 220 of file mitkStateMachine.h.

Referenced by StateMachine().


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines