PageRenderTime 42ms CodeModel.GetById 11ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 1ms

/flight/domain/MacroCommand.as

https://code.google.com/
ActionScript | 228 lines | 160 code | 29 blank | 39 comment | 34 complexity | 784e900ef7fbb885f7c0638030d45482 MD5 | raw file
  1////////////////////////////////////////////////////////////////////////////////
  2//
  3// Copyright (c) 2009 Tyler Wright, Robert Taylor, Jacob Wright
  4// 
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to deal
  7// in the Software without restriction, including without limitation the rights
  8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9// copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11// 
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14// 
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 21// THE SOFTWARE.
 22//
 23////////////////////////////////////////////////////////////////////////////////
 24
 25package flight.domain
 26{
 27	import flash.events.Event;
 28	
 29	import flight.commands.IAsyncCommand;
 30	import flight.commands.ICommand;
 31	import flight.commands.IUndoableCommand;
 32	import flight.errors.CommandError;
 33	import flight.events.PropertyEvent;
 34	import flight.list.ArrayList;
 35	import flight.utils.getClassName;
 36	
 37	/**
 38	 * The MacroCommand class is a single command that executes
 39	 * a list of many commands.
 40	 */
 41	[DefaultProperty("commands")]
 42	public class MacroCommand extends AsyncCommand
 43	{
 44		public var queue:Boolean = true;
 45		public var atomic:Boolean = true;
 46		
 47		private var currentCommand:ICommand;
 48		private var undone:Boolean;
 49		private var _commands:ArrayList = new ArrayList();
 50		private var _merging:Boolean = false;
 51		
 52		public function MacroCommand(commands:Array = null)
 53		{
 54			this.commands = commands;
 55		}
 56		
 57		public function get merging():Boolean
 58		{
 59			return _merging;
 60		}
 61		public function set merging(value:Boolean):void
 62		{
 63			_merging = value;
 64		}
 65		
 66		/**
 67		 * The list of commands to be executed.
 68		 */
 69		[ArrayElementType("flight.commands.ICommand")]
 70		[Bindable(event="commandsChange")]
 71		public function get commands():ArrayList
 72		{
 73			return _commands;
 74		}
 75		public function set commands(value:*):void
 76		{
 77			if (_commands == value) {
 78				return;
 79			}
 80			
 81			if ( !(value is ArrayList) ) {
 82				_commands.source = value;
 83				return;
 84			}
 85			
 86			var oldValue:Object = _commands;
 87			_commands = value;
 88			PropertyEvent.dispatchChange(this, "commands", oldValue, _commands);
 89		}
 90		
 91		/**
 92		 * Runs through the command list in order, executing each.
 93		 */
 94		override public function execute():void
 95		{
 96			currentCommand = null;
 97			executeNext();
 98		}
 99		
100		/**
101		 * Runs through the list of commands in reverse order, verifying that
102		 * each is undable before calling undo on the individual command.
103		 */
104		public function undo():void
105		{
106			var i:int = (currentCommand != null) ? _commands.getItemIndex(currentCommand) :
107												_commands.length - 1;
108			if (i == _commands.length - 1) {
109				
110				for (i; i >= 0; i--) {
111					var command:ICommand = _commands.getItemAt(i) as ICommand;
112					if (command is IUndoableCommand) {
113						IUndoableCommand(command).undo();
114					}
115				}
116				currentCommand = null;
117				undone = true;
118			}
119		}
120		
121		public function redo():void
122		{
123			if (undone) {
124				
125				for (var i:int = 0; i < _commands.length; i++) {
126					var command:ICommand = _commands.getItemAt(i) as ICommand;
127					if (command is IUndoableCommand) {
128						IUndoableCommand(command).redo();
129					}
130				}
131				currentCommand = command;
132				undone = false;
133			}
134		}
135		
136		public function merge(source:Object):Boolean
137		{
138			if (source is MacroCommand) {
139				var sourceCommands:ArrayList = MacroCommand(source)._commands;
140				var num:int = sourceCommands.length;
141				for (var i:int = 0; i < num; i++) {
142					var command:ICommand = sourceCommands.getItemAt(i) as ICommand;
143					_commands.addItem(command);
144				}
145			} else if (source is ICommand) {
146				_commands.addItem(source);
147			} else {
148				return false;
149			}
150			
151			return true;
152		}
153		
154		protected function executeNext(command:ICommand = null):void
155		{
156			var i:int = 0;
157			
158			if (command != null) {
159				
160				i = _commands.getItemIndex(command);
161				if (i == -1) {
162					throw new Error("Comand " + getClassName(command) + " does not exist in macro " + getClassName(this));
163				}
164				
165			} else if (currentCommand != null) {
166				i = _commands.getItemIndex(currentCommand) + 1;
167			}
168			
169			
170			if (i < _commands.length) {
171				
172				currentCommand = _commands.getItemAt(i) as ICommand;
173				
174				if (currentCommand is IAsyncCommand && queue) {
175					var asyncCommand:IAsyncCommand = currentCommand as IAsyncCommand;
176					// give internal listeners a negative priority to allow external
177					// listeners to interrupt regular flow.
178					asyncCommand.addEventListener(Event.COMPLETE, onAsyncComplete, false, -1)
179					asyncCommand.addEventListener(Event.CANCEL, onAsyncCancel, false, -1);
180					asyncCommand.execute();
181				} else {
182					try {
183						currentCommand.execute();
184						executeNext();
185					} catch (error:CommandError) {
186						onCommandFault(error);
187					}
188				}
189			} else {
190				response.complete(this);
191			}
192		}
193		
194		private function releaseAsyncCommand(command:IAsyncCommand):void
195		{
196			command.removeEventListener(Event.COMPLETE, onAsyncComplete);
197			command.removeEventListener(Event.CANCEL, onAsyncCancel);
198		}
199		
200		private function onAsyncComplete(event:Event):void
201		{
202			var asyncCommand:IAsyncCommand = event.target as IAsyncCommand;
203			releaseAsyncCommand(asyncCommand);
204			if (asyncCommand == currentCommand) {
205				executeNext();
206			}
207		}
208		
209		private function onAsyncCancel(event:Event):void
210		{
211			var asyncCommand:IAsyncCommand = event.target as IAsyncCommand;
212			releaseAsyncCommand(asyncCommand);
213			if (asyncCommand == currentCommand) {
214				asyncCommand.response.addFaultHandler(onCommandFault);
215			}
216		}
217		
218		private function onCommandFault(error:Error):void
219		{
220			if (atomic) {
221				response.cancel(error);
222			} else {
223				executeNext();
224			}
225		}
226		
227	}
228}