-
Notifications
You must be signed in to change notification settings - Fork 263
State Chart Editor Programming Discussion
The ATF State Chart Editor Sample shows another example of using the ATF graph framework to create a graph editor for a statechart, which is a way of graphically presenting a state machine. It bears a strong resemblance to the ATF Fsm Editor Sample and somewhat to ATF Circuit Editor Sample, which are also graph editors based on ATF graph facilities. This figure shows the statechart editor sample application:
ATF offers support for statecharts in its graph classes. For more details, see Statechart Graph Support.
Statechart concepts are described in the paper by David Harel A Visual Formalism for Complex Systems at http://www.wisdom.weizmann.ac.il/~dharel/SCANNED.PAPERS/Statecharts.pdf. A statechart oriented state machine tool based on ATF has also been developed.
StateChartEditor is, in several ways, a little more complex version of the ATF Fsm Editor Sample, and the two samples have much in common. You can learn about that sample's internals in FSM Editor Programming Discussion; this topic often references sections in this discussion.
StateChartEditor uses the ATF graph interfaces and classes, with its statechart version of the graph interface IGraph
. For information about graph support for statecharts, see Statechart Graph Support.
The data model takes into account the containment hierarchy: an ordinary state can contain other states and transitions. A statechart can have pseudo-states, such as the start state, as well as a normal state, and these all extend a base state type.
Like the FsmEditor sample, most of StateChartEditor's classes are DOM adapters, one for each type of object a statechart can contain, for instance. Other DOM adapters handle documents, contexts, and statechart validation.
The Editor
component is the document client and control host client for the control that holds the statechart, a D2dAdaptableControl
. These clients are implemented very similarly to those in the Editor
class of the FsmEditor. You can also print statecharts with the PrintableDocument
class.
The contexts in StateChartEditor also strongly resemble those of FsmEditor. The EditingContext
class implements interfaces similarly to the corresponding class in FsmEditor; however, it also implements the IGraph
interface containing properties listing statechart objects.
This sample's validator classes check that parent states' bounds are adjusted when child states change, that only legitimate transitions are added, and that locked states can't be edited.
Statecharts specialize the ATF graph model embodied by the IGraph
interface: IGraph<IState, IGraphEdge<IState, BoundaryRoute>, BoundaryRoute>
. For a description of this specialized interface, see Statechart Graph Support.
StateChartEditor's data model is defined in the XML Schema file Statechart.xsd
. Because both are state machine editors, StateChartEditor's data model resembles that of the ATF Fsm Editor Sample. Both have state, transition, annotation, prototype, and prototype folder types. Unlike ATF Fsm Editor Sample, StateChartEditor has inheritance in its types. Here are the types and types based on them:
- annotationType: annotation on a statechart.
- prototypeFolderType: prototype folder containing prototypes and other prototype folders.
- prototypeType: prototype containing states and transitions that can be reused.
- reactionType: event/guard/action triple; a guard is a condition for a state transition.
- transitionType: transition connecting a source state to a destination state.
- stateBaseType: base state.
- conditionalStateType: conditional pseudo-state.
- finalStateType: final pseudo-state.
- historyStateType: history pseudo-state.
- startStateType: start pseudo-state.
- stateType: normal state (not a pseudo-state) that can contain statecharts.
- statechartType: statechart that contains states.
- statechartDocumentType: root statechart, containing all transitions, annotations, and prototypes. It also contains states by virtue of being based on statechartType.
This differs from the FsmEditor in its hierarchy. The "stateType" type can contain "reactionType" and "statechartType" types. The "statechartType" type contains only "stateBaseType", representing all the various state types, including "stateType" the only non-psedudo-state type. This means that a state can contain states (all the different ones) and transitions, since a transition is a "reactionType". The type "statechartDocumentType", based on "statechartType", is the root type and can contain "transitionType", "annotationType", and "prototypeFolderType", which allows it to contain everything. Thus, the "stateType" type does not need to contain annotations or prototypes, which simplifies it.
StateChartEditor uses the GenSchemaDef.bat
command file for DomGen to create the Schema
class (containing type metadata classes) from Statechart.xsd
.
StateChartEditor has a SchemaLoader
class, derived from XmlSchemaTypeLoader
as usual. Its overridden OnSchemaSetLoaded()
also performs the typical tasks of adding data to the Schema
class's metadata class objects:
- Defining DOM adapters on types. For details, see StateChartEditor DOM Adapters.
- Adding
NodeTypePaletteItem
objects for palette items. This implementation follows the pattern of palettes in other samples, such as in ATF Simple DOM Editor Sample, so it is not discussed here. For information on creating palettes, see Using a Palette. - Defining property descriptors for type attributes. Again, these descriptors are defined very similarly to ones in other samples. For an example in ATF Simple DOM Editor Sample, see Create Property Descriptors.
Like other graph editor samples, most of the classes are DOM adapters. There is a DOM adapter for every type in the data model, for instance; for details, see StateChartEditor Types DOM Adapters.
Most of the DOM adapters are defined for the "statechartDocumentType" type, which represents the whole statechart. The root element of the DomNode
tree is of "statechartDocumentType". These adapters fall in a few categories:
- Document handling. For more information, see StateChartEditor Documents.
- Context handling. For details, see StateChartEditor Contexts.
- Validation. For details, see Validating StateCharts.
Each of the types in the data model, such as "stateType" and "transitionType", has a DOM adapter defined for it. Here are their definitions in SchemaLoader.OnSchemaSetLoaded()
:
// register the statechart model interfaces
Schema.prototypeFolderType.Type.Define(new ExtensionInfo<PrototypeFolder>());
Schema.prototypeType.Type.Define(new ExtensionInfo<Prototype>());
Schema.annotationType.Type.Define(new ExtensionInfo<Annotation>());
Schema.statechartType.Type.Define(new ExtensionInfo<Statechart>());
Schema.stateType.Type.Define(new ExtensionInfo<State>());
Schema.conditionalStateType.Type.Define(new ExtensionInfo<ConditionalState>());
Schema.finalStateType.Type.Define(new ExtensionInfo<FinalState>());
Schema.historyStateType.Type.Define(new ExtensionInfo<HistoryState>());
Schema.reactionType.Type.Define(new ExtensionInfo<Reaction>());
Schema.startStateType.Type.Define(new ExtensionInfo<StartState>());
Schema.transitionType.Type.Define(new ExtensionInfo<Transition>());
The following table describes the DOM adapter for each type. Most of these DOM adapters are very simple. They have properties that get and set type attribute values, using the DomNode.GetAttribute()
and DomNode.SetAttribute()
methods on the attribute metadata class members, defined in the Schema
class. Some of the DOM adapters use the DomNodeAdapter.GetChildList()
to get a list of attributes.
Type | DOM Adapter | Derives from, Implements | Properties, Methods | Notes |
---|---|---|---|---|
annotationType |
Annotation
|
DomNodeAdapter , IAnnotation
|
Bounds , Location , Text , SetTextSize()
|
Comment on the canvas. Identical to Annotation in ATF Fsm Editor Sample. For more details, see Annotation DOM Adapter in FSM Editor Programming Discussion.
|
conditionalStateType |
ConditionalState
|
StateBase
|
Type
|
A conditional pseudostate, which indicates a state with conditions to reduce the number of transitions. |
finalStateType |
FinalState
|
StateBase
|
Type
|
The final pseudostate, which is the last state that a state machine can be in. |
historyStateType |
HistoryState
|
StateBase
|
Type
|
A history pseudostate, which may be shallow or deep. History determines which states become active in a destination state's child state machines when the transition is taken to this destination. For a discussion of how history works in the StateMachine application built from ATF, see State Machine History. |
prototypeFolderType |
PrototypeFolder
|
DomNodeAdapter
|
Folders , Name , Prototypes
|
Folder of prototypes. Identical to PrototypeFolder in ATF Fsm Editor Sample. For details, see Prototype and PrototypeFolder DOM Adapters in FSM Editor Programming Discussion.
|
prototypeType |
Prototype
|
DomNodeAdapter
|
Name , States , Transitions
|
Prototype containing states and transitions that can be reused. Almost identical to Prototype in ATF Fsm Editor Sample. For details, see Prototype and PrototypeFolder DOM Adapters in FSM Editor Programming Discussion.
|
reactionType |
Reaction
|
DomNodeAdapter
|
Action , Event , Guard , ToString()
|
Adapts DomNodes to reactions, which are contained in states. For more information, see Reaction DOM Adapter. |
startStateType |
StartState
|
StateBase
|
Type
|
The start pseudostate, which points to the first state that is active when the state machine starts running. |
statechartType |
Statechart
|
DomNodeAdapter
|
AllStates , Bounds , Parent , States
|
Statechart that contains states. The AllStates property gets the states in the statechart and all sub-statecharts.
|
stateType |
State
|
StateBase . IComplexState<StateBase, Transition>
|
EntryAction , ExitAction , IsPseudoState , IsSimple , Name , Reactions , Size , Statecharts , SubStates , Type
|
Regular state machine state. For details, see State DOM Adapter. This adapter is not very similar to State in ATF Fsm Editor Sample.
|
transitionType |
Transition
|
Reaction , IGraphEdge<StateBase, BoundaryRoute>
|
FromPosition , FromState , ToPosition , ToState
|
Transition from a state to a state. For details, see Transition DOM Adapter. Also, Transition is similar to Transition in ATF Fsm Editor Sample; for details, see Transition DOM Adapter in FSM Editor Programming Discussion.
|
N/A |
StateBase
|
DomNodeAdapter , IState
|
Bounds , Indicators , IsPseudoState , Locked , Parent , Position , Size , Type
|
Base for other state DOM adapters, such as State and ConditionalState . For more information, see StateBase DOM Adapter.
|
Much of this adapter is devoted to the task of many adapters: setting up type attribute values as gettable and/or settable properties.
State
also implements IComplexState<StateBase, Transition>
, the interface for states in statechart diagrams that are non-pseudo-states. State
is the only state in StateChartEditor that is not a pseudo-state. IComplexState
's only property is Text
, which gets the state's interior text, displayed as a popup when the state is hovered over. This is a concatenation of text from EntryAction
, ExitAction
, and the Reaction
s associated with the state.
IComplexState
implements IHierarchicalGraphNode<StateBase, Transition, BoundaryRoute>
, and its property SubNodes
, the sequence of nodes that are children of this hierarchical graph node. Because a non-psudo-state can contain a state machine, this interface provides a way to access that information. SubNodes
simply gets the property SubStates
, an enumeration of the states inside the state, also known as substates.
A reaction tells how a state reacts to events. Its properties, all string
values, are:
-
Event
: event the state sees. -
Guard
: what triggers a transition from the state. -
Action
: action associated with an event.
ToString()
method returns a string
containing all these properties' values.
Note that State
's Reactions
property lists all the Reaction
objects associated with the state.
Transition
derives from Reaction
and adds properties:
-
FromState
,ToState
: source and destination states of transition. -
FromPosition
,ToPosition
: theBoundaryRoute
route position on the perimeter of the state at which this transition begins and ends. Its range is \[0..4\[,]and]it starts and ends at the top-left, going in a clockwise direction. The range from 0 to 1 is on the right side, from 1 to 2 on the bottom, and so forth.
Transition
also implements IGraphEdge&lt;StateBase, BoundaryRoute&gt;
, which implements IGraphEdge&lt;StateBase&gt;
. The first interface provides the properties FromRoute
and ToRoute
that get the BoundaryRoute
at each end of the transition; these are the same as FromPosition
and ToPosition
. For more details, see BoundaryRoute Class. The second interface provides FromNode
, ToNode
, and Label
: the from and to State
and the label on the state displayed to the user.
StateBase
is the base class for all state type DOM adapters and provides their common properties:
-
Bounds
: Get or set the state's bounding rectangle. -
IsPseudoState
: Get whether this is a pseudo-state. -
Locked
: Get or set the locked state, used in locking states. For further discussion, see LockingValidator Class. -
Parent
: Get or set the state's parentStatechart
. -
Position
: Get or set the state position, which is at the state's upper-left corner. -
Size
: Get or set the state size.
StateBase
also implements IState
, the interface for states in state-transition diagrams, and IState
implements IGraphNode
. For more information, see IState Interface.
StateChartEditor implements both document and document client interfaces. For a general discussion of documents, see Implementing a Document and Its Client.
Document
, a DOM adapter defined for the "statechartDocumentType", derives from DomDocument
that implements IDocument
. Document
is very similar to the Document
class in ATF Fsm Editor Sample. It implements the same methods in an almost identical way and is very simple.
Where it differs is that StateChartEditor's Document
implements IAnnotatedDiagram
, for diagrams that contain annotations. Its Annotations
property gets the list of annotations on the statechart from the root DomNode
, which has the type "statechartDocumentType", because this type contains the type "annotationType":
public IList<IAnnotation> Annotations
{
get { return GetChildList<IAnnotation>(Schema.statechartDocumentType.annotationChild); }
}
The Editor
component is the document client and control host client for the control that holds the statechart, and so it implements both IDocumentClient
and IControlHostClient
:
public class Editor : IDocumentClient, IControlHostClient, IInitializable
These clients also bear a strong resemblance to the clients in ATF Fsm Editor Sample. For a discussion of the FsmEditor clients, see Editor Component.
The differences from FsmEditor are primarily in the IDocumentClient.Open()
method. Like FsmEditor, this method creates a D2dAdaptableControl
and constructs a set of control adapters for it. One simple addition is to draw a grid on the canvas with D2dGridAdapter
:
var gridAdapter = new D2dGridAdapter();
Another difference is the graph adapter:
var statechartAdapter = new StatechartGraphAdapter(m_statechartRenderer, transformAdapter);
First, notice the renderer, constructed like this:
m_diagramTheme = new D2dDiagramTheme();
D2dGradientStop[] gradStops =
{
new D2dGradientStop(Color.WhiteSmoke,0),
new D2dGradientStop(Color.LightGray,1)
};
m_diagramTheme.FillGradientBrush = D2dFactory.CreateLinearGradientBrush(gradStops);
m_diagramTheme.FillBrush = D2dFactory.CreateSolidBrush(Color.WhiteSmoke);
m_statechartRenderer = new D2dStatechartRenderer<StateBase, Transition>(m_diagramTheme);
D2dStatechartRenderer
, which derives from D2dGraphRenderer
, is the class to handle rendering and hit testing on statechart graphs. For information about this renderer, see D2dStatechartRenderer Class. D2dStatechartRenderer
takes a D2dDiagramTheme
parameter to specify its theme. FsmEditor's renderer also used a D2dDiagramTheme
; for more information about D2dDiagramTheme
, see Document Client. Here the D2dDiagramTheme
is configured by setting its FillGradientBrush
and FillBrush
properties. The FillGradientBrush
draws a gradient, using the specified D2dGradientStop
array, between the colors specified in this array.
To return to the adapter, StatechartGraphAdapter
is a custom class deriving from D2dGraphAdapter
:
private class StatechartGraphAdapter : D2dGraphAdapter<StateBase, Transition, BoundaryRoute>
D2dGraphAdapter
is a general control adapter to reference and render a graph diagram. All StatechartGraphAdapter
does is to override its base class's OnRender()
method to draw the statechart the way it wants, using the D2dStatechartRenderer
. For information on D2dGraphAdapter
, see D2dGraphAdapter Class.
This sample, like FsmEditor, uses the control adapters D2dGraphNodeEditAdapter
and D2dGraphEdgeEditAdapter
to allow dragging states and transitions. These control adapters use the renderer D2dStatechartRenderer
and the graph adapter StatechartGraphAdapter
defined here; these adapters' constructors take a D2dGraphRenderer
and D2dGraphAdapter
.
When the cursor moves over a state, this information window displays:
Both this sample and FsmEditor use a HoverAdapter
to display information when the cursor hovers over canvas items:
var hoverAdapter = new HoverAdapter();
hoverAdapter.HoverStarted += control_HoverStarted;
hoverAdapter.HoverStopped += control_HoverStopped;
Hovering sheds light on both the hover adapter and property descriptors.
The HoverStarted
event handler simply gets the hover form when the cursor is over an object on the canvas:
private void control_HoverStarted(object sender, HoverEventArgs<object, object> e)
{
m_hoverForm = GetHoverForm(e.Object);
}
The e.Object
object is the object hovered over, which is passed to GetHoverForm()
.
HoverStopped
's handler closes and disposes of this form:
private void control_HoverStopped(object sender, EventArgs e)
{
if (m_hoverForm != null)
{
m_hoverForm.Close();
m_hoverForm.Dispose();
}
}
The GetHoverForm()
method creates the form (based on information from the hovered over object) and displays it:
private HoverBase GetHoverForm(object hoverItem)
{
HoverBase result = CreateHoverForm(hoverItem);
if (result != null)
{
Point p = Control.MousePosition;
result.Location = new Point(p.X - (result.Width + 12), p.Y + 12);
result.ShowWithoutFocus();
}
return result;
}
Finally, CreateHoverForm()
gets a property descriptor associated with the hovered over object, gets its attributes, and formats the text to show in the hover window:
// create hover form for primitive state or transition
private static HoverBase CreateHoverForm(object hoverTarget)
{
// handle states and transitions
StringBuilder sb = new StringBuilder();
ICustomTypeDescriptor customTypeDescriptor = Adapters.As<ICustomTypeDescriptor>(hoverTarget);
if (customTypeDescriptor != null)
{
// Get properties interface
foreach (System.ComponentModel.PropertyDescriptor property in customTypeDescriptor.GetProperties())
{
object value = property.GetValue(hoverTarget);
if (value != null)
{
sb.Append(property.Name);
sb.Append(": ");
sb.Append(value.ToString());
sb.Append("\n");
}
}
}
HoverBase result = null;
if (sb.Length > 0) // remove trailing '\n'
{
sb.Length = sb.Length - 1;
result = new HoverLabel(sb.ToString());
}
return result;
}
The parameter hoverTarget
is the object hovered over, which is a State
object of "stateType". State
derives from StateBase
, which derives from DomNodeAdapter
, which adapts a DomNode
, so ultimately, this object is a DomNode
representing a state.
To understand what the CreateHoverForm()
method is doing, consider this line in Program.cs
, which nearly all samples, including StateChartEditor, have:
DomNodeType.BaseOfAllTypes.AddAdapterCreator(new AdapterCreator<CustomTypeDescriptorNodeAdapter>());
AddAdapterCreator()
adds an adapter creator onto every type for CustomTypeDescriptorNodeAdapter
, which implements ICustomTypeDescriptor
. This means that an adapter can be found for ICustomTypeDescriptor
for every type in StateChartEditor. That is, every DomNode
can be adapted to ICustomTypeDescriptor
. This is useful in extracting attribute information from the DomNode
.
CreateHoverForm()
first tries to adapt the hovered over object to ICustomTypeDescriptor
, that is, to determine if the object implements ICustomTypeDescriptor
and to get an object on which this interface can be used:
ICustomTypeDescriptor customTypeDescriptor = Adapters.As<ICustomTypeDescriptor>(hoverTarget);
This works because an adapter for CustomTypeDescriptorNodeAdapter
was added for every type of DomNode
. So the variable customTypeDescriptor
is not null and the loop iterates on the property collection obtained by customTypeDescriptor.GetProperties()
. The SchemaLoader.OnSchemaSetLoaded()
method created this property descriptor the the "stateType":
Schema.stateType.Type.SetTag(
new PropertyDescriptorCollection(
new PropertyDescriptor[] {
new AttributePropertyDescriptor(
Localizer.Localize("Label"),
Schema.stateType.labelAttribute, // 'nameAttribute' is unique id, label is user visible name
null,
Localizer.Localize("State label"),
false),
new AttributePropertyDescriptor(
Localizer.Localize("Entry Action"),
Schema.stateType.entryActionAttribute,
null,
Localizer.Localize("Action taken when state is entered"),
false),
new AttributePropertyDescriptor(
Localizer.Localize("Exit Action"),
Schema.stateType.exitActionAttribute,
null,
Localizer.Localize("Action taken when state is exited"),
false),
new AttributePropertyDescriptor(
Localizer.Localize("Width"),
Schema.stateType.widthAttribute,
null,
Localizer.Localize("Width of state"),
false),
new AttributePropertyDescriptor(
Localizer.Localize("Height"),
Schema.stateType.heightAttribute,
null,
Localizer.Localize("Height of state"),
false),
}));
The PropertyDescriptor
collection for the state object thus includes each of the properties listed above. The value can then be obtained for each property:
object value = property.GetValue(hoverTarget);
The subsequent code uses a StringBuilder
to build the hover text from the property's Name
and its value text obtained from value.ToString()
. The assembled string is then encapsulated in a HoverLabel
object, which CreateHoverForm()
returns. GetHoverForm()
then displays this value in the hover window by invoking ShowWithoutFocus()
on the HoverLabel
.
When the state object is selected, these property values are shown in the property editor:
This is the same object that was hovered over in the previous figure, and the property values are the same as shown in the hover window, just as expected, because they come from the same source.
PrintableDocument
provides what's needed to print statecharts. This class is almost the same as PrintableDocument
in ATF Fsm Editor Sample. For information on this FsmEditor class, see PrintableDocument Class.
StateChartEditor has the same contexts as FsmEditor, and their functions and implementations have a lot in common.
Like the EditingContext
in FsmEditor, this one derives from Sce.Atf.Dom.EditingContext
and implements many of the same interfaces:
public class EditingContext : Sce.Atf.Dom.EditingContext,
IEnumerableContext,
IObservableContext,
INamingContext,
ILockingContext,
IInstancingContext,
IGraph<StateBase, Transition, BoundaryRoute>,
IEditableGraph<StateBase, Transition, BoundaryRoute>
The implementations of IEnumerableContext
, IObservableContext
, INamingContext
, and IInstancingContext
resemble their FsmEditor counterparts. Some of the differences are due to the type hierarchy differences, discussed in StateChartEditor Data Model.
StateChartEditor includes the StandardLockCommands
component, which creates Lock and Unlock items under the Edit menu. This permits locking states so they can't be changed. Supporting this also requires implementing the ILockingContext
, which EditingContext
does. StateBase
has a Locked
property, which is handled by the methods in ILockingContext
that test whether an item can be or is locked and also set the locked state. For more information on how locking works, see LockingValidator Class.
Because this sample uses the ATF graph facilities, IGraph
must be implemented somewhere. In this case, EditingContext
implements IGraph&lt;StateBase, Transition, BoundaryRoute&gt;
. For a description of this incarnation of the IGraph
interface, see Statechart Graph Support. Its implementation consists simply of creating the properties Nodes
and Edges
, to get lists of StateBase
and Transition
objects in the entire statechart.
Like FsmEditor, StateChartEditor's EditingContext
uses IEditableGraph&lt;State, Transition, NumberedRoute&gt;
to make and break connections between states, that is, to add and remove transitions. The methods CanConnect
, Connect
, CanDisconnect
, and Disconnect
test whether transitions can be created or removed, and make and destroy transitions. Here's the most complicated method:
Transition IEditableGraph<StateBase, Transition, BoundaryRoute>.Connect(
StateBase fromNode, BoundaryRoute fromRoute, StateBase toNode, BoundaryRoute toRoute, Transition existingEdge)
{
DomNode domNode = new DomNode(Schema.transitionType.Type);
Transition transition = domNode.As<Transition>();
transition.FromState = fromNode;
transition.FromPosition = fromRoute.Position;
transition.ToState = toNode;
transition.ToPosition = toRoute.Position;
if (existingEdge != null)
{
Transition existingTransition = existingEdge as Transition;
transition.Event = existingTransition.Event;
transition.Guard = existingTransition.Guard;
transition.Action = existingTransition.Action;
}
m_transitions.Add(transition);
return transition;
}
In this sequence, a DomNode
is created of the "transitionType" and adapted to Transition
. Its FromState
, FromPosition
, ToState
, and ToPosition
properties are set from the method's parameters. If the transition already existed, it is adapted to Transition
and the previous Event
, Guard
, and Action
properties copied over. Finally, the new Transition
is added to the transition list m_transitions
, created in the OnNodeSet()
method for EditingContext
:
m_transitions = new DomNodeListAdapter<Transition>(DomNode, Schema.statechartDocumentType.transitionChild);
PrototypingContext
is almost identical to PrototypingContext
in the FsmEditor and also to Sce.Atf.Controls.Adaptable.Graphs.PrototypingContext
, differing only in some DOM adapter names. For a discussion of FsmEditor's PrototypingContext
, see PrototypingContext Class. For information on Sce.Atf.Controls.Adaptable.Graphs.PrototypingContext
, see PrototypingContext Class.
Again, this context is almost identical to the ViewingContext
in FsmEditor. For information on that sample's context, see ViewingContext Class.
SchemaLoader.OnSchemaSetLoaded()
defines several validating DOM adapters on the "statechartDocumentType" type:
Schema.statechartDocumentType.Type.Define(new ExtensionInfo<BoundsValidator>());
Schema.statechartDocumentType.Type.Define(new ExtensionInfo<StatechartValidator>());
...
Schema.statechartDocumentType.Type.Define(new ExtensionInfo<UniqueIdValidator>());
Schema.statechartDocumentType.Type.Define(new ExtensionInfo<ReferenceValidator>());
Schema.statechartDocumentType.Type.Define(new ExtensionInfo<LockingValidator>());
All validating DOM adapters are defined on the root element type, so the entire tree of DomNode
s is checked.
UniqueIdValidator
and ReferenceValidator
have pretty much the same aim as in ATF Fsm Editor Sample: to make sure that IDs for states are unique and all references to these IDs are valid. This XML Schema from Statechart.xsd
shows that "stateBaseType" has an ID attribute ("xs:ID") and "transitionType" references this ID ("xs:IDREF"):
<!--
A state has a name (id), position, and can be referenced by transitions.
-->
<xs:complexType name ="stateBaseType" abstract="true">
<xs:attribute name="name" type="xs:ID" use="required" />
<xs:attribute name="x" type="xs:int" use="required" />
<xs:attribute name="y" type="xs:int" use="required" />
</xs:complexType>
...
<!--
A transition is a reaction, and connects the source state to the destination state.
The positions of the transition ends are determined by the fromPosition and toPosition
values, which are in the range [0..3].
-->
<xs:complexType name="transitionType">
<xs:complexContent>
<xs:extension base="reactionType">
<xs:attribute name="fromState" type="xs:IDREF" use="required" />
<xs:attribute name="fromPosition" type="xs:float" />
<xs:attribute name="toState" type="xs:IDREF" use="required" />
<xs:attribute name="toPosition" type="xs:float" />
</xs:extension>
</xs:complexContent>
</xs:complexType>
UniqueIdValidator
guarantees that every StateBase
element has a unique ID. ReferenceValidator
makes sure that the references to these IDs are valid as the DomNode
tree changes by adding and removing states and transitions. For more details on these validator's use in FsmEditor, see Validating State Machines.
When a child state is moved around inside its container state, the container resizes to accommodate its child state. BoundsValidator
derives from Validator
and tracks changes to states and updates their bounds to be big enough to hold any child states.
More precisely, BoundsValidator
monitors changes to states with various event handlers, such as OnAttributeChanged()
and OnChildInserted()
. These handlers are called as a result of BoundsValidator
being derived from Validator
and Observer
, which track changes to the tree of DomNode
s.
These event handlers may invalidate the layout by setting m_layoutInvalid
true
to force a redraw when validation is occurring:
protected override void OnAttributeChanged(object sender, AttributeEventArgs e)
{
if (Validating)
m_layoutInvalid = true;
base.OnAttributeChanged(sender, e);
}
Validating
is a property of Validator
that is set true when a validation context changes.
At the end of the change, OnEnding()
is called. If m_layoutInvalid
is true, it calls the Layout()
method for the entire statechart, which calls the Layout()
method for each StateBase
in the statechart. This latter Layout()
method gets the union of its state's child states' bounds and resizes its state's bounds when necessary.
StatechartValidator
tracks changes to the statechart and enforce constraints on states and transitions. In its OnNodeSet()
method, it subscribes to the ChildInserting
event, so it can check any newly added DomNode
. The event handler checks for various constraint violations, such as trying to create a transition from a final state, raising an InvalidTransactionException
in such cases.
LockingValidator
is in the namespace Sce.Atf.Dom
and not part of StateChartEditor, per se. It derives from Validator
and tracks locked data in the tree of DomNode
s. Its purpose is to prevent changing locked StateBase
objects.
Recall that EditingContext
implements ILockingContext
, as described in EditingContext Class.
LockingValidator
's OnNodeSet()
method is:
protected override void OnNodeSet()
{
m_lockingContext = this.Cast<ILockingContext>(); // required ILockingContext
// receive notification before attribute changes, to handle changes to lock state
DomNode.AttributeChanging += OnAttributeChanging;
base.OnNodeSet();
}
The first line gets an adapter for LockingValidator
to the interface ILockingContext
; EditingContext
is obtained. Because this class is not part of StateChartEditor, it does not know which classes implement ILockingContext
, so it uses adaptation to find a suitable object. For details on how this adaptation functions, see Adapting to All Available Interfaces. Support for the ILockingContext
interface provided by m_lockingContext
is required in several methods to test whether a DomNode
is locked, so it can't be edited.
OnNodeSet()
subscribes to AttributeChanging
, so it can monitor all DomNode
attribute changes in the tree; StatechartValidator
is defined on the root type, so the whole DomNode
tree is checked.
When a change begins, OnBeginning()
is called:
protected override void OnBeginning(object sender, EventArgs e)
{
m_modified = new HashSet<DomNode>();
}
The field m_modified
holds a set of all DomNode
s modified during a validation event. When events occur, like adding or removing a DomNode
, the DomNode
is added to the set, as in OnChildInserted()
:
protected override void OnChildInserted(object sender, ChildEventArgs e)
{
if (Validating)
m_modified.Add(e.Child);
}
Finally, OnEnding()
is called when the change ends:
protected override void OnEnding(object sender, EventArgs e)
{
try
{
HashSet<DomNode> knownUnlocked = new HashSet<DomNode>();
List<DomNode> discoveredUnlocked = new List<DomNode>();
foreach (DomNode modified in m_modified)
{
foreach (DomNode node in modified.Lineage)
{
if (knownUnlocked.Contains(node))
break;
if (m_lockingContext.IsLocked(node))
throw new InvalidTransactionException("item is locked");
discoveredUnlocked.Add(node);
}
foreach (DomNode node in discoveredUnlocked)
knownUnlocked.Add(node);
discoveredUnlocked.Clear();
}
}
finally
{
m_modified = null;
}
}
This method iterates through the DomNode
set in m_modified
and throws InvalidTransactionException
if a locked DomNode
was modified.
- Circuit Editor Programming Discussion: Learn how ATF handles graphs, and provides editors for kinds of graphs, such as circuits.
- Code Editor Programming Discussion: Shows how to interface third party software to an ATF application: the ActiproSoftware SyntaxEditor.
- Diagram Editor Programming Discussion: Very simply combines components from the CircuitEditor, FsmEditor, and StateChartEditor samples into one application, with the abilities of all three, showing the power of components.
-
DOM Property Editor Programming Discussion: Shows how to use the ATF DOM with an XML Schema to define application data with a large variety of attribute types, whose values can be viewed and edited using the ATF
PropertyEditor
component, using various value editors to view and edit attributes. - DOM Tree Editor Programming Discussion: Shows how to edit DOM data using a tree control and display properties in a variety of value editors.
- File Explorer Programming Discussion: Discusses the ATF File Explorer Sample using list and tree controls with adapters.
- FSM Editor Programming Discussion: Tells you about how the ATF FSM Editor Sample edits simple graphs for state machines, using DOM adapters for contexts and validation.
-
Model Viewer Programming Discussion: Shows how the ATF Model Viewer Sample is written, discussing how ATGI and Collada model data is handled, using rendering components, and using a
DesignControl
as a canvas for rendering. -
Simple DOM Editor Programming Discussion: Programming the ATF Simple DOM Editor Sample, creating a palette, using DOM adapters and contexts, editing application data, and searching
DomNode
s. - Simple DOM Editor WPF Programming Discussion: Programming the ATF Simple DOM Editor WPF Sample, which is similar to ATF Simple DOM Editor Sample, but implemented using ATF's WPF framework.
- Simple DOM No XML Editor Programming Discussion: Programming the ATF Simple DOM No XML Editor Sample, which is very similar to ATF Simple DOM Editor Sample, except that it doesn't use XML for either its data model or persisting application data.
- State Chart Editor Programming Discussion: Shows using ATF graph and other classes to create a statechart editor, using DOM adapters, documents, contexts, and validators.
- Target Manager Programming Discussion: Description of how a target manager is implemented using ATF components to manage target devices, such as PlayStation®Vita or PS3™ consoles. A target manager is used in other tools, such as the StateMachine tool.
- Timeline Editor Programming Discussion: Discusses how to create a fairly full-featured timeline editor using the ATF timeline facilities, such as the timeline renderer and the timeline control and its manipulators.
-
Tree List Control Programming Discussion: Demonstrates using the
TreeListControl
andTreeListItemRenderer
classes to display and edit hierarchical data in a tree view with details in columns. -
Tree List Editor Programming Discussion: Demonstrates how to use the ATF tree controls
TreeListView
and its enhancement,TreeListViewEditor
.TreeListView
usesTreeListViewAdapter
, which adaptsTreeListView
to display data in a tree. - Using Dom Programming Discussion: Shows how to use the various parts of the ATF DOM: an XML Schema, a schema metadata class file generated by DomGen, DOM adapters for the data types, a schema loader, and saving application data to an XML file.
- Home
- Getting Started
- Features & Benefits
- Requirements & Dependencies
- Gallery
- Technology & Samples
- Adoption
- News
- Release Notes
- ATF Community
- Searching Documentation
- Using Documentation
- Videos
- Tutorials
- How To
- Programmer's Guide
- Reference
- Code Samples
- Documentation Files
© 2014-2015, Sony Computer Entertainment America LLC