Configuring validation requests

Understanding validation processes

Validation processes in Diagrammer are configured via requestManager instance in the Diagrammer. Validation means letting diagrammer know that for a given operation a request should be done and specified to be correctly processed : Each request requires a response given by a function or via a DiagramResponseEvent. It is encapsulated in a RequestDescriptor instance that gives information about the way validation is processed (asynchronous via event or synchronous via responseFunction) : All request types are registered as constants in the DiagramRequestEvent and it deals especially with : To register a validation process, you need to register a requestDescriptor for a given action operation via registerRequestDescriptor method on the requestManager of Diagrammer.
diagrammer.requestManager.registerRequestDescriptor(DiagrammerRequestEvent.NODE_CREATION_REQUEST,
						requestDescriptor);
For each operation, the requestDescriptor content is read and according to its specifications, a synchronous or asynchronous validation process starts.

Experiencing validation processes

In this part, we will be discussing several integration scenarios of validation processes. We will be dealing with DropAction and LinkAction as it groups the major scenarios that can be encountered. Other validation scenarios can be inspired for these samples.

Drop Action

The scenario on which the following snippet is based, we assume that a library containing rectangles and ellipses is attached to the Diagrammer and that we want to have only and only one rectangle present in the graph. This means that at drop operation we must validate the creation of a node symbol given its type. The validation can be done using the responseFunction or asynchronous call. We have chosen to use asynchronous call.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
			   xmlns:s="library://ns.adobe.com/flex/spark" 
			   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" xmlns:diagrammer="fr.kapit.diagrammer.*">
	<fx:Script>
		<![CDATA[
			import fr.kapit.diagrammer.events.DiagrammerRequestEvent;
			import fr.kapit.diagrammer.events.DiagrammerResponseEvent;
			import fr.kapit.diagrammer.managers.data.RequestDescriptor;
			import fr.kapit.diagrammer.managers.data.ResponseDecriptor;
			import fr.kapit.visualizer.base.ISprite;
			import fr.kapit.visualizer.events.VisualizerEvent;
			
			import mx.containers.Canvas;
			import mx.events.FlexEvent;
			private function myRendererFunction(value:Object):Canvas
			{
				var o:Canvas = new Canvas();
				o.setStyle('backgroundColor',value.color);
				o.setStyle('cornerRadius',value.roundRadius);
				o.width=60;
				o.height=60;
				return o;
			}
			protected function diagrammer_creationCompleteHandler(event:FlexEvent):void
			{
				diagrammer.requestManager.registerRequestDescriptor(DiagrammerRequestEvent.NODE_CREATION_REQUEST,getAsyncDragRequestDescriptor());
			}
			protected function getAsyncDragRequestDescriptor():RequestDescriptor
			{
				var requestDescriptor:RequestDescriptor = new RequestDescriptor();
				requestDescriptor.useAsynchronousCall = true; // set to false if asynchronous call isn't needed
				requestDescriptor.responseFunction = dropValidationFunction;
				return requestDescriptor;
			}
			protected function diagrammer_nodeCreationRequestHandler(event:DiagrammerRequestEvent):void
			{
				var data:Object = event.data;
				var isApproved:Boolean = (data.data.type.indexOf('Rectangle')==-1 || rectanglesNumber<1);
				
				// We can assume that the response event is dispatched after an MVC cycle. We have taken the simple way ;).
				diagrammer.dispatchDiagrammerResponseEvent(DiagrammerResponseEvent.NODE_CREATION_RESPONSE,isApproved);
			}
			protected function dropValidationFunction(data:Object):ResponseDecriptor
			{
				var isApproved:Boolean = (data.data.type.indexOf('Rectangle')==-1 || rectanglesNumber<1);
				return new ResponseDecriptor(isApproved,null,null);
				
			}
			private var rectanglesNumber:Number=0;
			protected function diagrammer_elementsCreatedHandler(event:VisualizerEvent):void
			{
				var node:ISprite = event.items[0];
				if(node.data.type.indexOf('Rectangle')!=-1)
					rectanglesNumber++;
			}


			protected function diagrammer_elementsDeletedHandler(event:VisualizerEvent):void
			{
				var node:ISprite = event.items[0];
				if(node.data.type.indexOf('Rectangle')!=-1)
					rectanglesNumber--;
			}

		]]>
	</fx:Script>
	
	<fx:Declarations>
		<s:ArrayCollection id="myLib">
			<fx:Object type="RectangleBlue" color="0x0000FF" roundRadius="0"/>
			<fx:Object type="RectangleRed" color="0xFF0000" roundRadius="0"/>
			<fx:Object type="EllipseBlue" color="0x00FFFF" roundRadius="30"/>
			<fx:Object type="RoundRectangle" color="0xFF00FF" roundRadius="5"/>
		</s:ArrayCollection>
	</fx:Declarations>
	<mx:HBox width="100%" height="100%">
		<mx:VBox width="200" height="100%">
			<s:List dataProvider="{myLib}" dragEnabled="true" labelField="type"/>
			<s:Label text="Note : Drag and Drop items from the List"/>
		</mx:VBox>
		<diagrammer:Diagrammer
			id="diagrammer"
			width="100%"
			height="100%"
			nodeRendererFunction="myRendererFunction"
			creationComplete="diagrammer_creationCompleteHandler(event)"
			nodeCreationRequest="diagrammer_nodeCreationRequestHandler(event)"
			elementsCreated="diagrammer_elementsCreatedHandler(event)"
			elementsDeleted="diagrammer_elementsDeletedHandler(event)"
			/>
	</mx:HBox>
	
</s:Applicatio>>
Note that the data provided by the action operation and used when handling DiagramRequestEvent or processing in the responseFunction contains : Such information is enough to let developers control the validation process of dropping elements in Diagrammer. In addition to this option, the responseDescriptor provided by the DiagramResponseEvent or the reponseFunction can contain the data model and data model id of the approved dropped node in order to save additional calls for acquiring node data models.

Link Action

The scenario on which the following snippet is based, we assume that a library containing rectangles and ellipses is attached to the Diagrammer. We have the following constraints regarding link creation tool : By registering request descriptors for link pre-accept and creation operations, we will be using response functions to provide correct behavior of link creation.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
			   xmlns:s="library://ns.adobe.com/flex/spark" 
			   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" xmlns:diagrammer="fr.kapit.diagrammer.*">
	<fx:Script>
		<![CDATA[
			import fr.kapit.diagrammer.actions.LinkAction;
			import fr.kapit.diagrammer.events.DiagrammerRequestEvent;
			import fr.kapit.diagrammer.events.DiagrammerResponseEvent;
			import fr.kapit.diagrammer.managers.data.RequestDescriptor;
			import fr.kapit.diagrammer.managers.data.ResponseDecriptor;
			import fr.kapit.visualizer.base.ISprite;
			import fr.kapit.visualizer.events.VisualizerEvent;
			
			import mx.containers.Canvas;
			import mx.events.FlexEvent;
			private function myRendererFunction(value:Object):Canvas
			{
				var o:Canvas = new Canvas();
				o.setStyle('backgroundColor',value.color);
				o.setStyle('cornerRadius',value.roundRadius);
				o.width=60;
				o.height=60;
				return o;
			}
			protected function diagrammer_creationCompleteHandler(event:FlexEvent):void
			{
				diagrammer.requestManager.registerRequestDescriptor(DiagrammerRequestEvent.LINK_SOURCE_PREACCEPT_REQUEST,
					new RequestDescriptor(false, linkSourcePreAcceptFunction));
				diagrammer.requestManager.registerRequestDescriptor(DiagrammerRequestEvent.LINK_TARGET_PREACCEPT_REQUEST,
					new RequestDescriptor(false, linkTargetPreAcceptFunction));
				diagrammer.requestManager.registerRequestDescriptor(DiagrammerRequestEvent.LINK_CREATION_REQUEST,
					new RequestDescriptor(false, linkAcceptFunction));
			}
			protected function linkSourcePreAcceptFunction(data:Object):ResponseDecriptor
			{
				var source:ISprite = ISprite(data);
				var isApproved:Boolean = (source.data.type.indexOf('Rectangle')!=-1)
				return new ResponseDecriptor(isApproved,null,null);
				
			}
			protected function linkTargetPreAcceptFunction(data:Object):ResponseDecriptor
			{
				var isApproved:Boolean = (data.data.type.indexOf('RoundRectangle')==-1);
				return new ResponseDecriptor(isApproved,null,null);
				
			}
			protected function linkAcceptFunction(data:Object):ResponseDecriptor
			{
				var source:ISprite = data[0];
				var target:ISprite = data[1];
				var isApproved:Boolean = (source.data.type!='RectangleBlue' || target.data.type!='RectangleRed');
				return new ResponseDecriptor(isApproved,null,null);
				
			}

			private var linkActivated:Boolean;
			protected function linkAction_clickHandler(event:MouseEvent):void
			{
				linkActivated = !linkActivated;
				if(linkActivated)
					diagrammer.activateAction(LinkAction.ID);
				else
					diagrammer.deactivateAction(LinkAction.ID);
			}

		]]>
	</fx:Script>
	
	<fx:Declarations>
		<s:ArrayCollection id="myLib">
			<fx:Object type="RectangleBlue" color="0x0000FF" roundRadius="0"/>
			<fx:Object type="RectangleRed" color="0xFF0000" roundRadius="0"/>
			<fx:Object type="EllipseBlue" color="0x00FFFF" roundRadius="30"/>
			<fx:Object type="RoundRectangle" color="0xFF00FF" roundRadius="5"/>
		</s:ArrayCollection>
	</fx:Declarations>
	<mx:HBox width="100%" height="100%">
		<mx:VBox width="200" height="100%">
			<s:List dataProvider="{myLib}" dragEnabled="true" labelField="type"/>
			<s:Button id="linkActionBtn" label="activateLink" click="linkAction_clickHandler(event)"/>
			<s:Label text="Note : Drag and Drop items from the List"/>
		</mx:VBox>
		<diagrammer:Diagrammer
			id="diagrammer"
			width="100%"
			height="100%"
			nodeRendererFunction="myRendererFunction"
			creationComplete="diagrammer_creationCompleteHandler(event)"
			/>
	</mx:HBox>
	
</s:Application>
Note that data provided by the link operation and used when handling DiagramRequestEvent or processing in the responseFunction differs from an operation to another : When validating link creation, the data model and its id can be provided in the response descriptor and injected in the created link automatically. This method saves additional calls.