3D PLM Enterprise Architecture

User Interface - Commands

Getting Started with State Dialog Commands

A first simple but complete example of a state dialog command
Technical Article

Abstract

This article shows, using an example, how to design and program a state dialog command, and how to make it available. The example is a command that creates lines in the 3D space, named the Line command.


Designing the Line Command

The Line command is a state dialog command. It is an interactive command running in the application frame and that creates line geometrical elements. A state dialog command is a state machine that uses states to let the end user input the requested parameters, and transitions between states to process these input parameters and progress in the statechart.

The Line command allows the end user to create a line by providing two points. To simplify the example, it does not feature any undo capability.

Designing a dialog command follows these steps:

Once the state dialog command is designed, you can create a class and the methods to provide the command behavior. Then, you can integrate it into the application to make it available for its targeted document type.

[Top]

Dialog Specification

The Line command creates a line when the end user has provided two points. This simple task may be described by the following dialog between the end user and the Line command:

And the Line command creates the line using the two points input using the mouse indication.

[Top]

Dialog Description

Statechart diagrams allow you to describe a state dialog command as a state machine in a graphical format. The Unified Modeling Language (UML) is used for such diagrams.

GettingStartedStateChart.gif (9621 bytes)

The dialog flow starts with the initial state, which is a pseudo state that has no incoming transition. The command is never in the initial state that automatically skips to the first state. This first state is dedicated to the start point input and is shown in the box using its state identifier. A prompt linked to the first state can invite the end user to indicate this start point. The transition between the first state and the second state is triggered as soon as the end user indicates a valid point. This happens when the expected event is detected (the mouse left key is pressed), and when the guard condition is satisfied. The transition action, that is create a temporary point, is executed. A prompt linked to the second state can then invite the end user to indicate the end point. The transition to the final state is triggered as soon as the end user indicates a valid point. This creates the line.

[Top]

Creating the Line Command

The Line command creation is described as a step-by-step process to follow the statechart diagram. Some parts of the code are not shown, such as the line creation in the document. The complete code can be found in the CAADegGeoCommands.m module of the CAADialogEngine.edu framework.

The Line command is created as the CAADegCreateLineCmd class deriving from the CATStateCommand class that is provided as a template for all state dialog commands. The CAADegCreateLineCmd class creation follows the following steps:

[Top]

Declaring the State Dialog Command Class

This shows how to create the class header file. The main to do is:

The complete header file is provided below.

#include "CATStateCommand.h"
#include "CATMathPoint.h"

class CATISO;
class CATIndicationAgent;
class CAAISysPoint;

class CAADegCreateLineCmd : public CATStateCommand
{
  CATDeclareClass;
  CmdDeclareResource(CAADegCreateLineCmd,CATStateCommand);
  public :
    CAADegCreateLineCmd();
    virtual ~CAADegCreateLineCmd();

    CATStatusChangeRC Activate   (CATCommand * iCmd, CATNotification * iNotif);
    CATStatusChangeRC Desactivate(CATCommand * iCmd, CATNotification * iNotif);
    CATStatusChangeRC Cancel     (CATCommand * iCmd, CATNotification * iNotif);

    virtual void BuildGraph();

    CATBoolean  CheckStartPoint(void * iUsefulData);
    CATBoolean  CheckEndPoint(void * iUsefulData);
    CATBoolean  CreatePoint(void * iUsefulData);
    CATBoolean  CreateLine(void * iUsefulData);
    
  private :
      void NewLine(const CATMathPoint &iPoint); // To actually create the line
      
  private :
    CATIndicationAgent  * _daIndication;
    CAAISysPoint        * _FirstPoint;        // Temporary point
    CATISO              * _ISO;               // To display the temporary point
    CATBaseUnknown      * _RootObject;        // Used by NewLine and condition methods
    CATBaseUnknown      * _RootContainer;     // Used by NewLine
};

The methods and data members that are not mentioned above are used by the dialog agent, or used to show the temporary point created, or finally to actually create the line and update the document with the new line.

[Top]

Managing the Command Lifecycle

The command lifecycle is managed using the constructor and the destructor, and using the three methods Activate, Desactivate, and Cancel.

[Top]

Defining the End User Input

The end user input is defined in the BuildGraph method by creating the states, creating the dialog agent(s), and plugging the dialog agent(s)  to these states.

  1. Creating the dialog states. They are created using:

    Note that:

  2. Creating the dialog agent. The Line command uses one instance of the CATIndicationAgent class to read the start point and the end point input by the end user. The end user clicks in the screen plane, but the indication happens in fact in a plane defined thanks to the SetMathPlane method that assigns this plane to the dialog agent. In this command, the plane is a projection plane  parallel to the screen plane. It is the default plane, when the SetMathPlane is not used.  The point clicked on the screen is projected onto this plane. 
    _daIndication = new CATIndicationAgent("PointIndication");
    
  3. Plugging the dialog agent to these states. This dialog agent is enabled when it is plugged to a dialog state. This is done using the AddDialogAgent method.
    stStartState->AddDialogAgent(_daIndication);
    stEndState->AddDialogAgent(_daIndication);

    The BuildGraph method is as follows:

    void CAADegCreateLineCmd::BuildGraph()
    {
      CATDialogState * stStartState = GetInitialState("stStartPointId");
      CATDialogState * stEndState = AddDialogState("stEndPointId");
    
      _daIndication = new CATIndicationAgent("PointIndication");
      _daIndication->SetMathPlane(_ProjPlane);
    
      stStartState->AddDialogAgent(_daIndication);
      stEndState->AddDialogAgent(_daIndication);
    ...
    }

[Top]

Linking States and Providing Behavior

The states are linked with transitions that trigger actions if the guard conditions are satisfied.

[Top]

Providing Condition and Action Methods

This is the implementation of the command behavior declared using the BuildGraph method. The two condition methods are as follows:

  1. The CheckStartPoint method checks that the point can be created, that is, that  the object that holds the point factory, here _RootObject, exists.
    CATBoolean CAADegCreateLineCmd::CheckStartPoint(void * iDummy)
    {
      CATBoolean ret = TRUE;
      if ( ! _RootObject ) ret = FALSE;
      return ret;
    }
    
  2. The CheckEndPoint retrieves the end point from the dialog agent as a CATMathPoint2D instance on the projection plane of the dialog agent using the GetValue method. The GetMathPlane retrieves the projection plane. It converts it as a CATMathPoint instance, that is a 3D point, using the EvalPoint method, and compares the distance between start and end points to a minimum tolerance EPSILON. If the two points are identical with respect to this tolerance, the dialog agent is recycled to be reused in the second state that becomes current again, because FALSE is returned. This enables the end user to select another end point. Otherwise, TRUE is returned.
    CATBoolean CAADegCreateLineCmd::CheckEndPoint(void * iDummy)
    {
      CATBoolean ret = TRUE;
      if ( _FirstPoint ) 
      {
        CATMathPoint2D point2D = _daIndication->GetValue();
        CATMathPoint EndPoint;
        CATMathPlane ProjPlane = _daIndication->GetMathPlane();
        ProjPlane .EvalPoint(point2D.GetX(),point2D.GetY(), EndPoint);
    
        float x,y,z ;
        _FirstPoint->GetCoord(x,y,z);
        CATMathPoint StartPoint(x,y,z);
        if ( EndPoint.DistanceTo(StartPoint) < EPSILON ) 
        { 
          ret = FALSE;
          _daIndication->InitializeAcquisition(); // Recycle dialog agent
        }
      }
      else ret = FALSE;
      return ret;
    }

The two action methods are as follows:

  1. The CreatePoint method is called when the first transition is triggered. It creates the start point as a temporary point and puts it in the Interactive Set of Objects (this is not described here). It then recycles the dialog agent that can be reused for the second state.
    CATBoolean CAADegCreateLineCmd::CreatePoint(void * iDummy)
    {
      ... // Include here the code to create the first 3D point 
      _daIndication->InitializeAcquisition(); // Recycle dialog agent
      return TRUE;
    }
  2. The CreateLine method creates the line. It takes the start point as argument and retrieves the end point from the dialog agent.
    ...
    CATBoolean CAADegCreateLineCmd::CreateLine(void * iData)
    {
      ... // Include here the code to create the line
    }
    ...

[Top]

Providing the Command Resources

The command resources are the prompts displayed in the status bar for each state. They are stored in the CAADegCreateLineCmd.CATNls file located in your framework's CNext\resources\msgcatalog directory. This file contains the following prompts, associated with the identifiers set for each states in Defining End User Input:

CAADegCreateLineCmd.stStartPointId.Message = "Click to indicate the first point";
CAADegCreateLineCmd.stEndPointId.Message   = 
"Move the mouse and click to indicate the second point";

[Top]

Integrating the Line Command into the Application

The Line command is integrated into the application by following these steps:

[Top]

Creating the Line Command Creation Function

The CATCreateClass macro inserted in the command class CAADegCreateLineCmd.cpp file creates a creation function for the Line command. This enables the command class to be instantiated by the application using a command header. This macro is provided by the CATCreateExternalObject.h header file.

...
#include "CATCreateExternalObject.h"
CATCreateClass(CAADegCreateLineCmd);
...

[Top]

Creating the Line Command Header

The command header class should be created in the chosen workshop, workbench, or add-in class using the MacDeclareHeader macro. The command header is an instance of this class created in the CreateCommands method of the workshop, workbench, or add-in class. Then the command header is associated with a command starter and arranged with the other commands in the CreateWorkshop, CreateWorkbench, or CreateToolbars method of the workshop, workbench, or add-in class respectively.

The Line command header is created in the Geometry workshop. MacDeclareHeader creates the CAAGeometryHeader class for the header file, and this class is instantiated in the CreateCommands method. It is then put in the Insert menu, associated with a command starter and arranged after the Point command in the CreateWorkshop method, as follows:

#include "CATCommandHeader.h"
MacDeclareHeader(CAAGeometryHeader);
...
void Geometry::CreateCommands()
{
  ...
  new CAAGeometryHeader("Line",                  // Command header identifier
                        "CATDegEduGeometryCmd",  // Command shared library or DLL
                        "CAADegCreateLineCmd",      // Command class
                        (void *) NULL);          // Argument to pass to the command
  ...
}
...
CATCmdWorkshop * Geometry::CreateWorkshop()      
{
  ...
  NewAccess(CATCmdStarter,pLineInsert,LineInsert);
  SetAccessCommand(pLineInsert,"Line");
  SetAccessNext(pPointInsert,pLineInsert);
  ...
}

[Top]

Providing the Line Command Header Resources

You should now provide the resources for the command header. They are stored in files located in your framework's CNext\resources\msgcatalog directory. The resource keys are built using the command header class name concatenated to the command header identifier using a dot, that is, CAAGeometryHeader.Line, concatenated to other keywords depending on the resources. These resources include:

[Top]


In Short

A state dialog command is a dialog command designed as a state machine, each state enabling end user input, that enables the end user to pass from state to state using transitions between these states triggered when requested events happen and when requested guard conditions are satisfied, and that execute the declared actions. It is modeled using a class deriving from the CATStateCommand class.

The statechart diagram is implemented using the BuildGraph method, and the command life cycle is managed by the Activate, Desactivate, and Cancel methods in addition to the command class constructor and destructor.

[Top]


History

Version: 1 [Jan 2000] Document created
[Top]

Copyright © 2000, Dassault Systèmes. All rights reserved.