Skip to content

11 Context Selections

Robert Silverton edited this page Jul 3, 2014 · 3 revisions

View this tutorial's changes on GitHub.

If you're working with the tutorial repo, open a Git Shell in the CoreEditor-HelloWorld-Example-as folder and run the following command:

git checkout -f step-11

Otherwise, follow the instructions below.


In the Operations tutorial, we saw how we can use interfaces to extend the behaviour of our StringListContext to include an OperationManager. We did this by implementing the IOperationManagerContext, and providing a getter for the Context’s operationManager instance.

In this tutorial we are going to see how, through the same mechanism, we can upgrade our Context to become an ISelectionContext. Copy and paste the following changes into your StringListContext class:

package helloWorld.contexts
{
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	
	import core.app.CoreApp;
	import core.app.entities.URI;
	import core.app.operations.ReadFileAndDeserializeOperation;
	import core.appEx.core.contexts.IOperationManagerContext;
	import core.appEx.core.contexts.ISelectionContext;
	import core.appEx.events.OperationManagerEvent;
	import core.appEx.managers.OperationManager;
	import core.appEx.operations.SerializeAndWriteFileOperation;
	import core.data.ArrayCollection;
	import core.editor.CoreEditor;
	import core.editor.contexts.IEditorContext;
	
	import helloWorld.ui.views.StringListView;

	[Event( type="flash.events.Event", name="change" )]
	
	public class StringListContext extends EventDispatcher implements IEditorContext, IOperationManagerContext, ISelectionContext
	{
		private var _view			:StringListView;
		
		private var _dataProvider		:ArrayCollection;
		private var _selection			:ArrayCollection;
		private var _operationManager	:OperationManager;
		
		private var _uri				:URI;
		private var _changed			:Boolean = false;
		protected var _isNewFile		:Boolean = false;
		
		public function StringListContext()
		{
			_view = new StringListView();
			
			_operationManager = new OperationManager();
			_operationManager.addEventListener(OperationManagerEvent.CHANGE, changeOperationManagerHandler);
			_dataProvider = new ArrayCollection();
			
			_view.dataProvider = _dataProvider;
			
			_selection = new ArrayCollection();
			_view.addEventListener(Event.CHANGE, listChangeHandler);
		}
		
		public function get view():DisplayObject
		{
			return _view;
		}
		
		public function dispose():void
		{
			_operationManager.removeEventListener(OperationManagerEvent.CHANGE, changeOperationManagerHandler);
			_operationManager.dispose();
			
			_view.removeEventListener(Event.CHANGE, listChangeHandler);
		}
		
		private function listChangeHandler( event:Event ):void
		{
			_selection.source = _view.selectedItems;
		}
		
		public function enable():void
		{
			// Do nothing
		}
		
		public function disable():void
		{
			// Do nothing
		}
		
		public function publish():void
		{
			// Do nothing
		}
		
		public function save():void
		{
			var serializeOperation:SerializeAndWriteFileOperation = new SerializeAndWriteFileOperation( _dataProvider, _uri, CoreApp.fileSystemProvider );
			CoreEditor.operationManager.addOperation(serializeOperation);
			changed = false;
		}
		
		public function load():void
		{
			var deserializeOperation:ReadFileAndDeserializeOperation = new ReadFileAndDeserializeOperation( _uri, CoreApp.fileSystemProvider );
			deserializeOperation.addEventListener(Event.COMPLETE, deserializeCompleteHandler);
			CoreEditor.operationManager.addOperation(deserializeOperation); 
		}
		
		private function deserializeCompleteHandler( event:Event ):void
		{
			var deserializeOperation:ReadFileAndDeserializeOperation = ReadFileAndDeserializeOperation(event.target);
			
			// Handle case where the file on disk is empty. This occurs when we're opening a newly created file.
			if ( deserializeOperation.getResult() == null )
			{
				_dataProvider = new ArrayCollection();
			}
			else
			{
				_dataProvider = ArrayCollection( deserializeOperation.getResult() );
			}
			_view.dataProvider = _dataProvider;
			changed = false;
		}
		
		public function set uri( value:URI ):void
		{
			_uri = value;
		}
		
		public function get uri():URI { return _uri; }
		
		public function set changed( value:Boolean ):void
		{
			if ( value == _changed ) return;
			_changed = value;
			dispatchEvent( new Event( Event.CHANGE) );
		}
		
		public function get changed():Boolean { return _changed; }
		
		private function changeOperationManagerHandler( event:OperationManagerEvent ):void
		{
			changed = true;
		}
		
		public function set isNewFile( value:Boolean ):void
		{
			_isNewFile = value;
		}
		public function get isNewFile():Boolean { return _isNewFile; } 
		
		
		public function get dataProvider():ArrayCollection { return _dataProvider; }
		
		public function get operationManager():OperationManager { return _operationManager; }
		
		public function get selection():ArrayCollection { return _selection; }
	}
}

The ISelectionContext interface is very simple. Much like the IOperationManagerContext interface, it exposes a single getter function – in this case an ArrayCollection called ‘selection’. We’ve also added some behaviour that listens in to the StringListView’s list component for its CHANGE event. When this happens we update the Context’s own selection to match that of our view.

So far this doesn’t contribute any perceivable changes in behaviour when we run the application. However it now means we can write some code against this interface to access this Context’s selection. Contexts don't tend to make changes to themselves. Instead they implement interfaces that allow CommandHandlers to perform the work (or delegate out to Operations). This decoupling and use of interfaces allows a single CommandHandler to treat multiple Contexts in the same way. It's the reason why your StringListContext has already been able to have Save, Save As, Open,. Undo and Redo Commands performed on it without you having to write a line of code.

To do this lets give our first Context, the HelloWorldContext, some more behaviour. What we are looking to achieve is our HelloWorldView displaying the strings we have selected from within the StringListContext.


Add the following code to your HelloWorldContext:

package helloWorld.contexts
{
	import flash.display.DisplayObject;
	
	import core.appEx.core.contexts.ISelectionContext;
	import core.appEx.core.contexts.IVisualContext;
	import core.appEx.events.ContextSelectionValidatorEvent;
	import core.appEx.validators.ContextSelectionValidator;
	import core.editor.CoreEditor;
	
	import helloWorld.ui.views.HelloWorldView;
	
	public class HelloWorldContext implements IVisualContext
	{
		private var _view		:HelloWorldView;
		private var contextSelectionValidator	:ContextSelectionValidator;
		
		public function HelloWorldContext()
		{
			_view = new HelloWorldView();
			_view.text = "Hello World";
			
			contextSelectionValidator = new ContextSelectionValidator(CoreEditor.contextManager, ISelectionContext, String);
			contextSelectionValidator.addEventListener(ContextSelectionValidatorEvent.VALID_SELECTION_CHANGED, selectionChangeHandler);
		}
		
		public function get view():DisplayObject
		{
			return _view;
		}
		
		public function dispose():void
		{
			contextSelectionValidator.removeEventListener(ContextSelectionValidatorEvent.VALID_SELECTION_CHANGED, selectionChangeHandler);
			contextSelectionValidator.dispose();
		}
		
		private function selectionChangeHandler(event:ContextSelectionValidatorEvent):void
		{
			_view.text = "";
			
			var selection:Array = contextSelectionValidator.getValidSelection();
			for ( var i:int = 0; i < selection.length; i++ )
			{
				var item:String = selection[i];
				_view.text += item + "\n";
			}
		}		
	}
}

Here we see an example of how versatile Validators can be. We are creating a ContextSelectionValidator instance during init(). We are passing to its constructor all the parameters it needs to monitor a selection on a particular type of Context. Here’s a brief description of each parameter.

  • contextManager – We need to pass the Validator a reference to the application’s ContextManager. As mentioned previously, Validators are part of the CoreApp Framework and do not have knowledge of this particular CoreEditor Application, so are unable to access it directly.
  • contextType – Here we pass the type of Context this Validator should monitor. Notice that we’re not passing StringListContext as a type here, and instead making this bit of behaviour more generic by allowing it to work with any Context with a selection on it.
  • selectionType – Here we are passing the type of object we want in the selection. For the sake of simplicity we are only going to handle Strings.

The ContextSelectionValidator dispatches a range of events. We’re only interested in being notified when the selection on a Context of type ISelectionContext is updated to contain items of type String. We can grab a copy of this selection from the ContextSelectionValidator at any time using the getValidSelection() method. This will return an empty array if no Context’s selection is matching our criteria.


If you build and run the application, open an instance of the StringListContext by opening an existing “strlist” file or by creating a new one. Then make sure your HelloWorldContext is open. Select some items in your StringListContext and watch what happens in your HelloWorldView.


< Previous | Next >