├── .gitignore ├── LICENSE ├── Readme.textile ├── docs ├── AC_OETags.js ├── all-classes.html ├── all-index-A.html ├── all-index-B.html ├── all-index-C.html ├── all-index-D.html ├── all-index-E.html ├── all-index-F.html ├── all-index-G.html ├── all-index-H.html ├── all-index-I.html ├── all-index-J.html ├── all-index-K.html ├── all-index-L.html ├── all-index-M.html ├── all-index-N.html ├── all-index-O.html ├── all-index-P.html ├── all-index-Q.html ├── all-index-R.html ├── all-index-S.html ├── all-index-T.html ├── all-index-U.html ├── all-index-V.html ├── all-index-W.html ├── all-index-X.html ├── all-index-Y.html ├── all-index-Z.html ├── asdoc.js ├── class-summary.html ├── cookies.js ├── help.js ├── images │ ├── AirIcon12x12.gif │ ├── P_AlternativeMetadataIndicator_30x28_N.png │ ├── collapsed.gif │ ├── detailHeaderRule.jpg │ ├── detailSectionHeader.jpg │ ├── expanded.gif │ ├── inherit-arrow.gif │ ├── inheritedSummary.gif │ ├── logo.jpg │ ├── titleTableBottom.jpg │ ├── titleTableMiddle.jpg │ └── titleTableTop.jpg ├── index-list.html ├── index.html ├── org │ └── robotlegs │ │ └── utilities │ │ └── undoablecommand │ │ ├── CommandEvent.html │ │ ├── CommandHistory.html │ │ ├── HistoryEvent.html │ │ ├── UndoableCommand.html │ │ ├── UndoableCommandBase.html │ │ ├── class-list.html │ │ ├── commands │ │ ├── StepBackwardCommand.html │ │ ├── StepForwardCommand.html │ │ ├── class-list.html │ │ └── package-detail.html │ │ ├── interfaces │ │ ├── IUndoableCommand.html │ │ ├── class-list.html │ │ └── package-detail.html │ │ └── package-detail.html ├── override.css ├── package-frame.html ├── package-list.html ├── package-summary.html ├── print.css ├── style.css └── title-bar.html └── src ├── FlexUnitApplication.mxml ├── org └── robotlegs │ └── utilities │ └── undoablecommand │ ├── CommandEvent.as │ ├── CommandHistory.as │ ├── HistoryEvent.as │ ├── UndoableCommand.as │ ├── UndoableCommandBase.as │ ├── commands │ ├── StepBackwardCommand.as │ └── StepForwardCommand.as │ └── interfaces │ └── IUndoableCommand.as └── tests ├── MockUndoableCommand.as ├── MockUndoableCommandBase.as ├── TestHistory.as ├── TestHistoryEvents.as ├── TestManagedUndoableCommand.as └── TestUndoableCommand.as /.gitignore: -------------------------------------------------------------------------------- 1 | bin-debug 2 | html-template 3 | *.swf 4 | *.swp 5 | *.air 6 | .metadata 7 | .actionScriptProperties 8 | .flexProperties 9 | .flexLibProperties 10 | .metadata 11 | .project 12 | .settings* 13 | TEST-* 14 | bin 15 | .FlexUnitSettings 16 | *.orig 17 | report 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2009, 2010 the original author or authors 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. -------------------------------------------------------------------------------- /Readme.textile: -------------------------------------------------------------------------------- 1 | h1. Undoable Commands and History Controller for the Robotlegs Framework 2 | 3 | Undoable Commands aims to provide the most useful functions you'd need for undo/redo functionality in a gui app. I've successfully used in on a number of private projects. 4 | 5 | h2. Ddddddeprecated! 6 | 7 | Great news everyone! After years of inactivity (sadly, I no longer work on the Flash platform), `UndoableCommand` development continues courteousy of d3zza on his fork: "d3zza/robotlegs-utilities-UndoableCommand":https://github.com/d3zza/robotlegs-utilities-UndoableCommand. Check it out! Thanks d3zza! 8 | 9 | h2. Features 10 | 11 | * Keeps a linear history of executed Commands 12 | * Undo/Redo 13 | * Rewind/Fast Forward history 14 | * Rewrite history 15 | * Cancellable commands 16 | * Gets the ladies and/or gents 17 | 18 | h2. Important Classes 19 | 20 | h3. UndoableCommandBase 21 | 22 | Fairly barebones undoable command. You can use this with your own history controller or use the classes below to gain access to history control. 23 | 24 | h3. CommandHistory 25 | 26 | The history controller that provides the interface to move forward and backward through your command history. 27 | 28 | h3. UndoableCommand 29 | 30 | This command handles adding itself to a provided/injected CommandHistory object. 31 | 32 | _See the generated asdocs provided in the repository for more information_ 33 | 34 | h2. Quickstart 35 | 36 | * Download the "latest release swc":http://github.com/secoif/robotlegs-utilities-UndoableCommand/downloads or feel free to download the source and compile for yourself, the test cases depend on FlexUnit4. 37 | * Include downloaded swc in your project 38 | * Create your command which extends UndoableCommand 39 | * Override the protected methods doExecute and undoExecute. doExecute should contain the code you want to execute when the command is fired. undoExecute should contain whatever code is needed to manually undo the actions performed by doExecute. The last line in both of these methods should be the call to super.doExecute()/undoExecute(). 40 | * Put the following lines (+ necessary imports) into your Robotlegs context: 41 | 42 |
43 | 	// Create a CommandHistory to manages undo/redo history
44 | 	injector.mapSingleton(CommandHistory);
45 | 	// Events to trigger undo and redo
46 | 	commandMap.mapEvent(HistoryEvent.STEP_FORWARD, StepForwardCommand, HistoryEvent);
47 | 	commandMap.mapEvent(HistoryEvent.STEP_BACKWARD, StepBackwardCommand, HistoryEvent);
48 | 	
49 | 50 | * Map some event to the Command you created (just like you would with any normal robotlegs command) 51 | * Set a Button/Mediator to actually fire the HistoryEvent.STEP_FORWARD/BACKWARD events on the robotlegs event bus and you're done! :) 52 | 53 | h4. Cancelling a Command 54 | 55 | If you want to cancel a command you can call cancel() in your doExecute method and the command will not be added to the history stack (though you will have to ensure you don't actually make any changes to your data after you do this) 56 | 57 | h4. TODO 58 | Implement a minimal linked list variation based on UndoableCommandBase with no history controller 59 | -------------------------------------------------------------------------------- /docs/AC_OETags.js: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // ADOBE SYSTEMS INCORPORATED 4 | // Copyright 2008 Adobe Systems Incorporated 5 | // All Rights Reserved. 6 | // 7 | // NOTICE: Adobe permits you to use, modify, and distribute this file 8 | // in accordance with the terms of the license agreement accompanying it. 9 | // 10 | //////////////////////////////////////////////////////////////////////////////// 11 | 12 | 13 | //v1.0 14 | function AC_AddExtension(src, ext) 15 | { 16 | if (src.indexOf('?') != -1) 17 | return src.replace(/\?/, ext+'?'); 18 | else 19 | return src + ext; 20 | } 21 | 22 | function AC_Generateobj(objAttrs, params, embedAttrs) 23 | { 24 | var str = ' '; 30 | str += ' 2 | 3 | 4 | All Classes - API Documentation 5 | 6 | 7 | 8 | 9 | 10 | 11 |

All Classes

12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
CommandEvent
CommandHistory
HistoryEvent
IUndoableCommand
StepBackwardCommand
StepForwardCommand
UndoableCommand
UndoableCommandBase
38 | 39 | 40 | -------------------------------------------------------------------------------- /docs/all-index-A.html: -------------------------------------------------------------------------------- 1 | A 6 |

A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  
A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  

-------------------------------------------------------------------------------- /docs/all-index-B.html: -------------------------------------------------------------------------------- 1 | B 6 |

A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  
A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  

-------------------------------------------------------------------------------- /docs/all-index-G.html: -------------------------------------------------------------------------------- 1 | G 6 |

A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  
A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  

-------------------------------------------------------------------------------- /docs/all-index-J.html: -------------------------------------------------------------------------------- 1 | J 6 |

A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  
A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  

-------------------------------------------------------------------------------- /docs/all-index-K.html: -------------------------------------------------------------------------------- 1 | K 6 |

A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  
A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  

-------------------------------------------------------------------------------- /docs/all-index-L.html: -------------------------------------------------------------------------------- 1 | L 6 |

A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  
A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  

-------------------------------------------------------------------------------- /docs/all-index-M.html: -------------------------------------------------------------------------------- 1 | M 6 |

A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  
A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  

-------------------------------------------------------------------------------- /docs/all-index-Q.html: -------------------------------------------------------------------------------- 1 | Q 6 |

A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  
A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  

-------------------------------------------------------------------------------- /docs/all-index-T.html: -------------------------------------------------------------------------------- 1 | T 6 |

A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  
A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  

-------------------------------------------------------------------------------- /docs/all-index-V.html: -------------------------------------------------------------------------------- 1 | V 6 |

A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  
A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  

-------------------------------------------------------------------------------- /docs/all-index-W.html: -------------------------------------------------------------------------------- 1 | W 6 |

A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  
A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  

-------------------------------------------------------------------------------- /docs/all-index-X.html: -------------------------------------------------------------------------------- 1 | X 6 |

A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  
A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  

-------------------------------------------------------------------------------- /docs/all-index-Y.html: -------------------------------------------------------------------------------- 1 | Y 6 |

A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  
A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  

-------------------------------------------------------------------------------- /docs/all-index-Z.html: -------------------------------------------------------------------------------- 1 | Z 6 |

A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  
A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  

-------------------------------------------------------------------------------- /docs/class-summary.html: -------------------------------------------------------------------------------- 1 | All Classes 6 |

Documentation for classes includes syntax, usage information, and code samples for methods, properties, and event handlers and listeners for those APIs that belong to a specific class in ActionScript. The classes are listed alphabetically. If you are not sure to which class a certain method or property belongs, you can look it up in the Index.


 ClassPackageDescription
 CommandEvent
org.robotlegs.utilities.undoablecommand 14 | CommandEvents are fired when single commands finish executing, finish undoing or are cancelled.
 CommandHistory
org.robotlegs.utilities.undoablecommand 15 | Provides an interface to manage undo/redo history and fires events on the eventDispatcher 16 | when history events occur.
 HistoryEvent
org.robotlegs.utilities.undoablecommand 17 | These events fire when operations occur on a CommandHistory object, or to control a CommandHistory object.
 IUndoableCommand
org.robotlegs.utilities.undoablecommand.interfaces 
 StepBackwardCommand
org.robotlegs.utilities.undoablecommand.commands 18 | Map this command to the HistoryEvent.STEP_BACKWARD event to trigger an undo action.
 StepForwardCommand
org.robotlegs.utilities.undoablecommand.commands 19 | Map this command to the HistoryEvent.STEP_FORWARD event to trigger a redo action.
 UndoableCommand
org.robotlegs.utilities.undoablecommand 20 | This command handles adding itself to the provided/injected CommandHistory.
 UndoableCommandBase
org.robotlegs.utilities.undoablecommand 

-------------------------------------------------------------------------------- /docs/cookies.js: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // ADOBE SYSTEMS INCORPORATED 4 | // Copyright 2006-2008 Adobe Systems Incorporated 5 | // All Rights Reserved. 6 | // 7 | // NOTICE: Adobe permits you to use, modify, and distribute this file 8 | // in accordance with the terms of the license agreement accompanying it. 9 | // 10 | //////////////////////////////////////////////////////////////////////////////// 11 | 12 | /** 13 | * Read the JavaScript cookies tutorial at: 14 | * http://www.netspade.com/articles/javascript/cookies.xml 15 | */ 16 | 17 | /** 18 | * Sets a Cookie with the given name and value. 19 | * 20 | * name Name of the cookie 21 | * value Value of the cookie 22 | * [expires] Expiration date of the cookie (default: end of current session) 23 | * [path] Path where the cookie is valid (default: path of calling document) 24 | * [domain] Domain where the cookie is valid 25 | * (default: domain of calling document) 26 | * [secure] Boolean value indicating if the cookie transmission requires a 27 | * secure transmission 28 | */ 29 | function setCookie(name, value, expires, path, domain, secure) 30 | { 31 | document.cookie= name + "=" + escape(value) + 32 | ((expires) ? "; expires=" + expires.toGMTString() : "") + 33 | ((path) ? "; path=" + path : "") + 34 | ((domain) ? "; domain=" + domain : "") + 35 | ((secure) ? "; secure" : ""); 36 | } 37 | 38 | /** 39 | * Gets the value of the specified cookie. 40 | * 41 | * name Name of the desired cookie. 42 | * 43 | * Returns a string containing value of specified cookie, 44 | * or null if cookie does not exist. 45 | */ 46 | function getCookie(name) 47 | { 48 | var dc = document.cookie; 49 | var prefix = name + "="; 50 | var begin = dc.indexOf("; " + prefix); 51 | if (begin == -1) 52 | { 53 | begin = dc.indexOf(prefix); 54 | if (begin != 0) return null; 55 | } 56 | else 57 | { 58 | begin += 2; 59 | } 60 | var end = document.cookie.indexOf(";", begin); 61 | if (end == -1) 62 | { 63 | end = dc.length; 64 | } 65 | return unescape(dc.substring(begin + prefix.length, end)); 66 | } 67 | 68 | /** 69 | * Deletes the specified cookie. 70 | * 71 | * name name of the cookie 72 | * [path] path of the cookie (must be same as path used to create cookie) 73 | * [domain] domain of the cookie (must be same as domain used to create cookie) 74 | */ 75 | function deleteCookie(name, path, domain) 76 | { 77 | if (getCookie(name)) 78 | { 79 | document.cookie = name + "=" + 80 | ((path) ? "; path=" + path : "") + 81 | ((domain) ? "; domain=" + domain : "") + 82 | "; expires=Thu, 01-Jan-70 00:00:01 GMT"; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /docs/images/AirIcon12x12.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timoxley/robotlegs-utilities-UndoableCommand/5c220ac70cef2225fd4e1ca21f29fac148fef506/docs/images/AirIcon12x12.gif -------------------------------------------------------------------------------- /docs/images/P_AlternativeMetadataIndicator_30x28_N.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timoxley/robotlegs-utilities-UndoableCommand/5c220ac70cef2225fd4e1ca21f29fac148fef506/docs/images/P_AlternativeMetadataIndicator_30x28_N.png -------------------------------------------------------------------------------- /docs/images/collapsed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timoxley/robotlegs-utilities-UndoableCommand/5c220ac70cef2225fd4e1ca21f29fac148fef506/docs/images/collapsed.gif -------------------------------------------------------------------------------- /docs/images/detailHeaderRule.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timoxley/robotlegs-utilities-UndoableCommand/5c220ac70cef2225fd4e1ca21f29fac148fef506/docs/images/detailHeaderRule.jpg -------------------------------------------------------------------------------- /docs/images/detailSectionHeader.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timoxley/robotlegs-utilities-UndoableCommand/5c220ac70cef2225fd4e1ca21f29fac148fef506/docs/images/detailSectionHeader.jpg -------------------------------------------------------------------------------- /docs/images/expanded.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timoxley/robotlegs-utilities-UndoableCommand/5c220ac70cef2225fd4e1ca21f29fac148fef506/docs/images/expanded.gif -------------------------------------------------------------------------------- /docs/images/inherit-arrow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timoxley/robotlegs-utilities-UndoableCommand/5c220ac70cef2225fd4e1ca21f29fac148fef506/docs/images/inherit-arrow.gif -------------------------------------------------------------------------------- /docs/images/inheritedSummary.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timoxley/robotlegs-utilities-UndoableCommand/5c220ac70cef2225fd4e1ca21f29fac148fef506/docs/images/inheritedSummary.gif -------------------------------------------------------------------------------- /docs/images/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timoxley/robotlegs-utilities-UndoableCommand/5c220ac70cef2225fd4e1ca21f29fac148fef506/docs/images/logo.jpg -------------------------------------------------------------------------------- /docs/images/titleTableBottom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timoxley/robotlegs-utilities-UndoableCommand/5c220ac70cef2225fd4e1ca21f29fac148fef506/docs/images/titleTableBottom.jpg -------------------------------------------------------------------------------- /docs/images/titleTableMiddle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timoxley/robotlegs-utilities-UndoableCommand/5c220ac70cef2225fd4e1ca21f29fac148fef506/docs/images/titleTableMiddle.jpg -------------------------------------------------------------------------------- /docs/images/titleTableTop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timoxley/robotlegs-utilities-UndoableCommand/5c220ac70cef2225fd4e1ca21f29fac148fef506/docs/images/titleTableTop.jpg -------------------------------------------------------------------------------- /docs/index-list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | API Documentation 4 | 5 | 6 | 7 | 8 | 9 |

Index

10 | 11 | 12 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
AN
BO
CP
DQ
ER
FS
GT
HU
IV
JW
KX
LY
MZ
70 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | API Documentation 4 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | <body> 31 | <h2>Frame Alert</h2> 32 | <p> 33 | This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. 34 | <br> 35 | Link to <a href="package-summary.html">Non-frame version.</a> 36 | </p> 37 | </body> 38 | 39 | 40 | -------------------------------------------------------------------------------- /docs/org/robotlegs/utilities/undoablecommand/class-list.html: -------------------------------------------------------------------------------- 1 | org.robotlegs.utilities.undoablecommand - API Documentation

Package org.robotlegs.utilities.undoablecommand

Classes
CommandEvent
CommandHistory
HistoryEvent
UndoableCommand
UndoableCommandBase
-------------------------------------------------------------------------------- /docs/org/robotlegs/utilities/undoablecommand/commands/StepBackwardCommand.html: -------------------------------------------------------------------------------- 1 | org.robotlegs.utilities.undoablecommand.commands.StepBackwardCommand 6 |
Packageorg.robotlegs.utilities.undoablecommand.commands
Classpublic class StepBackwardCommand
InheritanceStepBackwardCommand Inheritance Object

14 | Map this command to the HistoryEvent.STEP_BACKWARD event to trigger an undo action. 15 | Provided for convenience. 16 |



Public Properties
 PropertyDefined By
  commandHistory : CommandHistory
StepBackwardCommand
Public Methods
 MethodDefined By
  
execute():void
17 | Will undo a single command, if possible.
StepBackwardCommand
Property Detail
commandHistoryproperty
public var commandHistory:CommandHistory

Method Detail
execute()method
public function execute():void

20 | Will undo a single command, if possible. Fails silently if not. 21 |





-------------------------------------------------------------------------------- /docs/org/robotlegs/utilities/undoablecommand/commands/StepForwardCommand.html: -------------------------------------------------------------------------------- 1 | org.robotlegs.utilities.undoablecommand.commands.StepForwardCommand 6 |
Packageorg.robotlegs.utilities.undoablecommand.commands
Classpublic class StepForwardCommand
InheritanceStepForwardCommand Inheritance Object

14 | Map this command to the HistoryEvent.STEP_FORWARD event to trigger a redo action. 15 | Provided for convenience. 16 |



Public Properties
 PropertyDefined By
  commandHistory : CommandHistory
StepForwardCommand
Public Methods
 MethodDefined By
  
execute():void
17 | Will redo a single command, if possible.
StepForwardCommand
Property Detail
commandHistoryproperty
public var commandHistory:CommandHistory

Method Detail
execute()method
public function execute():void

20 | Will redo a single command, if possible. Fails silently if not. 21 |





-------------------------------------------------------------------------------- /docs/org/robotlegs/utilities/undoablecommand/commands/class-list.html: -------------------------------------------------------------------------------- 1 | org.robotlegs.utilities.undoablecommand.commands - API Documentation

Package org.robotlegs.utilities.undoablecommand.commands

Classes
StepBackwardCommand
StepForwardCommand
-------------------------------------------------------------------------------- /docs/org/robotlegs/utilities/undoablecommand/commands/package-detail.html: -------------------------------------------------------------------------------- 1 | org.robotlegs.utilities.undoablecommand.commands Summary 6 |



Classes
 ClassDescription
 StepBackwardCommand 14 | Map this command to the HistoryEvent.STEP_BACKWARD event to trigger an undo action.
 StepForwardCommand 15 | Map this command to the HistoryEvent.STEP_FORWARD event to trigger a redo action.

-------------------------------------------------------------------------------- /docs/org/robotlegs/utilities/undoablecommand/interfaces/IUndoableCommand.html: -------------------------------------------------------------------------------- 1 | org.robotlegs.utilities.undoablecommand.interfaces.IUndoableCommand 6 |
Packageorg.robotlegs.utilities.undoablecommand.interfaces
Interfacepublic interface IUndoableCommand
Implementors UndoableCommandBase



Public Properties
 PropertyDefined By
  eventDispatcher : IEventDispatcher
14 | Fire events when you execute or undo 15 |
IUndoableCommand
Public Methods
 MethodDefined By
  
execute():void
16 | Perform an action 17 |
IUndoableCommand
  
undo():void
18 | Reverse the performed action 19 |
IUndoableCommand
Property Detail
eventDispatcherproperty
eventDispatcher:IEventDispatcher

22 | Fire events when you execute or undo 23 |


Implementation
    public function get eventDispatcher():IEventDispatcher
    public function set eventDispatcher(value:IEventDispatcher):void
Method Detail
execute()method
public function execute():void

24 | Perform an action 25 |

undo()method 
public function undo():void

26 | Reverse the performed action 27 |





-------------------------------------------------------------------------------- /docs/org/robotlegs/utilities/undoablecommand/interfaces/class-list.html: -------------------------------------------------------------------------------- 1 | org.robotlegs.utilities.undoablecommand.interfaces - API Documentation

Package org.robotlegs.utilities.undoablecommand.interfaces

Interfaces
IUndoableCommand
 
-------------------------------------------------------------------------------- /docs/org/robotlegs/utilities/undoablecommand/interfaces/package-detail.html: -------------------------------------------------------------------------------- 1 | org.robotlegs.utilities.undoablecommand.interfaces Summary 6 |



Interfaces
 InterfaceDescription
 IUndoableCommand 

-------------------------------------------------------------------------------- /docs/org/robotlegs/utilities/undoablecommand/package-detail.html: -------------------------------------------------------------------------------- 1 | org.robotlegs.utilities.undoablecommand Summary 6 |



Classes
 ClassDescription
 CommandEvent 14 | CommandEvents are fired when single commands finish executing, finish undoing or are cancelled.
 CommandHistory 15 | Provides an interface to manage undo/redo history and fires events on the eventDispatcher 16 | when history events occur.
 HistoryEvent 17 | These events fire when operations occur on a CommandHistory object, or to control a CommandHistory object.
 UndoableCommand 18 | This command handles adding itself to the provided/injected CommandHistory.
 UndoableCommandBase 

-------------------------------------------------------------------------------- /docs/override.css: -------------------------------------------------------------------------------- 1 | /* 2 | //////////////////////////////////////////////////////////////////////////////// 3 | // 4 | // ADOBE SYSTEMS INCORPORATED 5 | // Copyright 2008 Adobe Systems Incorporated 6 | // All Rights Reserved. 7 | // 8 | // NOTICE: Adobe permits you to use, modify, and distribute this file 9 | // in accordance with the terms of the license agreement accompanying it. 10 | // 11 | //////////////////////////////////////////////////////////////////////////////// 12 | */ -------------------------------------------------------------------------------- /docs/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | API Documentation 4 | 5 | 6 | 7 | 8 | 9 | <body> 10 | <h2>Frame Alert</h2> 11 | <p>This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. 12 | <br> 13 | Link to<a href="package-summary.html">Non-frame version.</a> 14 | </p> 15 | </body> 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/package-list.html: -------------------------------------------------------------------------------- 1 | Package List - API Documentation

Packages

org.robotlegs.utilities.undoablecommand
org.robotlegs.utilities.undoablecommand.commands
org.robotlegs.utilities.undoablecommand.interfaces
-------------------------------------------------------------------------------- /docs/package-summary.html: -------------------------------------------------------------------------------- 1 | All Packages 6 |


 packageDescription
 org.robotlegs.utilities.undoablecommand
 org.robotlegs.utilities.undoablecommand.commands
 org.robotlegs.utilities.undoablecommand.interfaces

-------------------------------------------------------------------------------- /docs/print.css: -------------------------------------------------------------------------------- 1 | /* 2 | //////////////////////////////////////////////////////////////////////////////// 3 | // 4 | // ADOBE SYSTEMS INCORPORATED 5 | // Copyright 2005-2008 Adobe Systems Incorporated 6 | // All Rights Reserved. 7 | // 8 | // NOTICE: Adobe permits you to use, modify, and distribute this file 9 | // in accordance with the terms of the license agreement accompanying it. 10 | // 11 | //////////////////////////////////////////////////////////////////////////////// 12 | */ 13 | 14 | body { 15 | color: #000000; 16 | background: #ffffff; 17 | font-family: "Times New Roman", Times, serif; 18 | font-size: 12pt; 19 | } 20 | a { 21 | text-decoration: none; 22 | color: #000000; 23 | } 24 | pre { 25 | white-space: -moz-pre-wrap; /* Mozilla */ 26 | white-space: -pre-wrap; /* Opera 4-6 */ 27 | white-space: -o-pre-wrap; /* Opera 7 */ 28 | word-wrap: break-word; /* IE */ 29 | } 30 | .titleTableTopNav, .titleTableSubNav, .logoImage { 31 | display: none; 32 | } 33 | .packageFrame { 34 | display: none; 35 | } 36 | .titleTableSubTitle { 37 | font-weight: bold; 38 | } 39 | .classHeaderTableLabel { 40 | padding-right: 10px; 41 | vertical-align: top; 42 | } 43 | .showHideLinks { 44 | display: none; 45 | } 46 | html>body code { 47 | font-size: 10pt; 48 | } 49 | .summaryTableTitle, .detailSectionHeader { 50 | font-size: 14pt; 51 | font-weight: bold; 52 | padding-top: 15px; 53 | padding-bottom: 5px; 54 | } 55 | .summaryTable { 56 | border: 1px solid #000000; 57 | border-collapse: collapse; 58 | width: 100%; 59 | } 60 | .summaryTableDescription { 61 | padding-bottom: 20px; 62 | } 63 | .summaryTableSignatureCol, .summaryTableOwnerCol, .summaryTableLastCol, .summaryTableCol { 64 | border: 1px solid #000000; 65 | } 66 | .summaryTablePaddingCol { 67 | border: 1px solid #000000; 68 | border-right: 0px; 69 | } 70 | .summaryTableInheritanceCol, .summaryTableOperatorCol, .summaryTableStatementCol, .summaryTableSecondCol { 71 | border: 1px solid #000000; 72 | border-left: 0px; 73 | } 74 | .summaryTableLastCol { 75 | vertical-align: top; 76 | } 77 | .detailHeader { 78 | font-size: 13pt; 79 | padding-top: 100px; 80 | } 81 | .detailHeaderName { 82 | font-weight: bold; 83 | } 84 | .detailHeaderType { 85 | padding-left: 5px; 86 | } 87 | .detailHeaderRule { 88 | background: #FF0000; 89 | } 90 | .seeAlso { 91 | padding-bottom: 20px; 92 | margin-top: -20px; 93 | } 94 | .innertable { 95 | border-collapse: collapse; 96 | } 97 | .innertable td,.innertable th { 98 | border: 1px solid #000000; 99 | padding-left: 5px; 100 | padding-right: 5px; 101 | } 102 | .listing { 103 | font-size: 10pt; 104 | } 105 | .feedbackLink { 106 | display: none; 107 | } 108 | .copyright { 109 | font-size: 10pt; 110 | } -------------------------------------------------------------------------------- /docs/title-bar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | API Documentation 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 22 | 23 | 24 | 25 | 38 | 39 |
13 | 14 | 15 | 16 | 19 | 20 |
API Documentation  17 | All Packages  |  All Classes  |  Index  |  No Frames 18 |
21 |
26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 |
 
 
37 |
40 | 41 | -------------------------------------------------------------------------------- /src/FlexUnitApplication.mxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/undoablecommand/CommandEvent.as: -------------------------------------------------------------------------------- 1 | package org.robotlegs.utilities.undoablecommand 2 | { 3 | import flash.events.Event; 4 | 5 | import org.robotlegs.utilities.undoablecommand.interfaces.IUndoableCommand; 6 | 7 | /** 8 | * CommandEvents are fired when single commands finish executing, finish undoing or are cancelled. 9 | * 10 | */ 11 | public class CommandEvent extends Event 12 | { 13 | /** 14 | * CommandEvent of this type will be fired when a command has completed executing/redoing. 15 | */ 16 | public static const EXECUTE_COMPLETE:String = "executeComplete"; 17 | 18 | /** 19 | * CommandEvent of this type will be fired when a command has completed undoing. 20 | */ 21 | public static const UNDO_EXECUTE_COMPLETE:String = "undoExecuteComplete"; 22 | 23 | /** 24 | * CommandEvent of this type will be fired when execution of a command was cancelled. 25 | */ 26 | public static const CANCELLED:String = "executeCancelled"; 27 | 28 | /** 29 | * The command associated with the event. 30 | */ 31 | public var command:IUndoableCommand; 32 | 33 | /** 34 | * @param type The type of event 35 | * @param command The command associated with the event 36 | */ 37 | public function CommandEvent(type:String, command:IUndoableCommand) { 38 | super(type, false, false); 39 | this.command = command; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/undoablecommand/CommandHistory.as: -------------------------------------------------------------------------------- 1 | package org.robotlegs.utilities.undoablecommand 2 | { 3 | import flash.events.IEventDispatcher; 4 | 5 | import org.robotlegs.utilities.undoablecommand.interfaces.*; 6 | 7 | /** 8 | * Provides an interface to manage undo/redo history and fires events on the eventDispatcher 9 | * when history events occur. 10 | */ 11 | public class CommandHistory 12 | { 13 | /** 14 | * Command history data store. 15 | * Vector chosen over array for strong typing & speed 16 | */ 17 | private var _historyStack:Vector.; 18 | 19 | /** 20 | * Pointer to the current command in the history stack. 21 | * First command starts at index 1. 22 | * If this is 0, we are pointing to no command (null) at the start of the stack 23 | */ 24 | public var currentPosition:uint; 25 | 26 | /** 27 | * Supplied event bus to fire events upon. 28 | */ 29 | [Inject] 30 | public var eventDispatcher:IEventDispatcher; 31 | 32 | public function CommandHistory() { 33 | _historyStack = new Vector.(); 34 | currentPosition = 0; 35 | } 36 | 37 | /** 38 | * True if there's a command to redo. 39 | * @return true if there's a command to redo 40 | */ 41 | public function get canStepForward():Boolean { 42 | return (currentPosition < numberOfHistoryItems); 43 | } 44 | 45 | /** 46 | * True if there's a command to undo. 47 | * @return true if there's a command to undo 48 | */ 49 | public function get canStepBackward():Boolean { 50 | return (currentPosition > 0); 51 | } 52 | 53 | /** 54 | * 55 | * Redo/execute the next command on the history stack. 56 | * @return position in history stack after this operation 57 | */ 58 | public function stepForward():uint { 59 | if (canStepForward) { 60 | _historyStack[currentPosition].execute(); 61 | currentPosition++; 62 | } 63 | this.eventDispatcher.dispatchEvent(new HistoryEvent(HistoryEvent.STEP_FORWARD_COMPLETE, currentCommand)); 64 | 65 | return currentPosition; 66 | } 67 | 68 | /** 69 | * Undo the previous command on the history stack and set the currentCommand to the previous command. 70 | * @return position in history stack after this operation 71 | */ 72 | public function stepBackward():uint { 73 | var storeCurrentPosition:uint = currentPosition; 74 | if (canStepBackward) { 75 | // This is a hacky workaround: 76 | // If the undo was invoked from a CommandHistory object, 77 | // _historyStack[currentPosition - 1].undo() calls 78 | // stepBackward() again, in which case we want to prevent it from 79 | // updating the current position twice. I'm certain thar be a better way. 80 | // Update 6 months later: I have no idea what I'm talking about here. 81 | // I recall this whole business produced some fairly retarded program flow, 82 | // need to rethink design. 83 | _historyStack[currentPosition - 1].undo(); 84 | currentPosition = storeCurrentPosition - 1; 85 | } 86 | 87 | // If there's no undone command, 88 | // dispatch null as the historyevent command 89 | var undoneCommand:IUndoableCommand; 90 | if (_historyStack.length > 0 && currentPosition != 0) { 91 | //the undone command 92 | undoneCommand = _historyStack[currentPosition]; 93 | } else { 94 | undoneCommand = null; 95 | } 96 | 97 | this.eventDispatcher.dispatchEvent(new HistoryEvent(HistoryEvent.STEP_BACKWARD_COMPLETE, undoneCommand)); 98 | 99 | return currentPosition; 100 | } 101 | 102 | /** 103 | * Undo all or some number of commands. 104 | * @param numTimes number of positions to move backward. The default, 0, rewinds to the start of the history (undoes all commands) 105 | * @return position in history stack after the rewind operation completes 106 | */ 107 | public function rewind(numTimes:uint = 0):uint { 108 | var positionToMoveTo:uint; 109 | 110 | if (numTimes == 0) { 111 | positionToMoveTo = 0; 112 | } else { 113 | positionToMoveTo = currentPosition - numTimes; 114 | } 115 | 116 | // Move backward while possible 117 | while(canStepBackward && currentPosition != positionToMoveTo) { 118 | stepBackward(); 119 | } 120 | 121 | this.eventDispatcher.dispatchEvent(new HistoryEvent(HistoryEvent.REWIND_COMPLETE, currentCommand)); 122 | return currentPosition; 123 | } 124 | 125 | /** 126 | * Redo all or some number of commands. 127 | * @param numTimes number of positions to move forward. 128 | * The default, 0, fast forwards to the last item in the history (most recent). 129 | * @return position in history stack after the fastForward operation completes 130 | */ 131 | public function fastForward(numTimes:uint = 0):uint { 132 | var positionToMoveTo:uint; 133 | 134 | if (numTimes == 0) { 135 | positionToMoveTo = numberOfHistoryItems; 136 | } else { 137 | positionToMoveTo = currentPosition + numTimes; 138 | } 139 | 140 | // Move forward 141 | while(canStepForward && currentPosition != positionToMoveTo) { 142 | stepForward(); 143 | } 144 | 145 | this.eventDispatcher.dispatchEvent(new HistoryEvent(HistoryEvent.FAST_FORWARD_COMPLETE, currentCommand)); 146 | 147 | return currentPosition; 148 | } 149 | 150 | /** 151 | * Total number of items in history, irrespective of their undone/redone state. 152 | * @return total number of items in history 153 | */ 154 | public function get numberOfHistoryItems():uint { 155 | return _historyStack.length; 156 | } 157 | 158 | /** 159 | * Push a new command into the current position on the history stack and execute it. 160 | * If there are commands further forward in the history stack, 161 | * those commands are removed and this command becomes the 162 | * new top of the command stack. 163 | * 164 | * @return position in history stack after this operation 165 | */ 166 | public function push(command:IUndoableCommand):uint { 167 | 168 | if (currentPosition != numberOfHistoryItems) { 169 | _historyStack = _historyStack.slice(0, currentPosition); 170 | } 171 | 172 | _historyStack.push(command); 173 | 174 | // Execute the command & move pointer forward 175 | stepForward(); 176 | return currentPosition; 177 | } 178 | 179 | /** 180 | * Gets the command at the top of the history stack. This command will have already been executed. 181 | * @return command at the current position in the history stack, 182 | * or null if we're at position 0, in this case, there may be no commands on the stack at all. 183 | * @see currentPosition 184 | * @see numberOfHistoryItems 185 | */ 186 | public function get currentCommand():IUndoableCommand { 187 | if (_historyStack.length == 0 || currentPosition == 0) { 188 | return null; 189 | } 190 | return _historyStack[currentPosition - 1]; 191 | } 192 | 193 | /** 194 | * @private 195 | */ 196 | public function toString():String { 197 | var output:String = ""; 198 | var count:uint = 0; 199 | for each(var command:IUndoableCommand in _historyStack) { 200 | output += String(count) + String(command) + "\n"; 201 | count++; 202 | } 203 | return output; 204 | } 205 | } 206 | } -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/undoablecommand/HistoryEvent.as: -------------------------------------------------------------------------------- 1 | package org.robotlegs.utilities.undoablecommand 2 | { 3 | import org.robotlegs.utilities.undoablecommand.interfaces.IUndoableCommand; 4 | 5 | /** 6 | * These events fire when operations occur on a CommandHistory object, or to control a CommandHistory object. 7 | */ 8 | public class HistoryEvent extends CommandEvent 9 | { 10 | /** 11 | * You should Map this event to StepBackwardCommand to trigger an undo action. 12 | * Provided for convenience. Is not fired internally. 13 | * 14 | * // In your Robotlegs context: 15 | * commandMap.mapEvent(HistoryEvent.STEP_BACKWARD, StepBackwardCommand, HistoryEvent); 16 | * 17 | */ 18 | public static const STEP_BACKWARD:String = "stepBackward"; 19 | 20 | /** 21 | * You should map this event to a StepForwardCommand to trigger a redo action. 22 | * Provided for convenience. Is not fired internally. 23 | * 24 | * // In your Robotlegs context: 25 | * commandMap.mapEvent(HistoryEvent.STEP_FORWARD, StepForwardCommand, HistoryEvent); 26 | * 27 | */ 28 | public static const STEP_FORWARD:String = "stepForward"; 29 | 30 | 31 | /** 32 | * You should map this event to a command to trigger a rewind action. 33 | * 34 | * Provided for convenience. Is not fired internally. 35 | * TODO: Create a default RewindCommand 36 | */ 37 | public static const REWIND:String = "rewind"; 38 | 39 | /** 40 | * You should map this event to a command to trigger a fast-forward action. 41 | * 42 | * Provided for convenience. Is not fired internally. 43 | * TODO: Create a default FastForwardCommand 44 | */ 45 | public static const FAST_FORWARD:String = "fastForward"; 46 | 47 | /** 48 | * HistoryEvent with this type will be fired each time a command is executed/redone. 49 | * HistoryEvent with this type will be fired multiple times if performing a multi-step fast-forward. 50 | */ 51 | public static const STEP_FORWARD_COMPLETE:String = "stepForwardComplete"; 52 | 53 | /** 54 | * HistoryEvent with this type will be fired each time a command is undone. 55 | * HistoryEvent with this type will be fired multiple times if performing a multi-step rewind. 56 | */ 57 | public static const STEP_BACKWARD_COMPLETE:String = "stepBackwardComplete"; 58 | 59 | 60 | 61 | /** 62 | * HistoryEvent with this type will be fired when a rewind completes. 63 | */ 64 | public static const REWIND_COMPLETE:String = "rewindComplete"; 65 | 66 | /** 67 | * HistoryEvent with this type will be fired when a fast forward completes. 68 | */ 69 | public static const FAST_FORWARD_COMPLETE:String = "fastForwardComplete"; 70 | 71 | public function HistoryEvent(type:String, command:IUndoableCommand = null) { 72 | super(type, command); 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/undoablecommand/UndoableCommand.as: -------------------------------------------------------------------------------- 1 | package org.robotlegs.utilities.undoablecommand 2 | { 3 | import mx.messaging.messages.ErrorMessage; 4 | 5 | /** 6 | * This command handles adding itself to the provided/injected CommandHistory. 7 | * 8 | * UndoableCommands are pushed to the CommandHistory only once the Command has been executed, 9 | * and are removed once the Command has been undone. Undoable commands can be cancelled by calling cancel() from within 10 | * their doExecute() function, and they will not be added to the history. 11 | * 12 | * All functions assume the CommandHistory dependency has been provided as the public property 'history'. 13 | */ 14 | public class UndoableCommand extends UndoableCommandBase 15 | { 16 | 17 | /** 18 | * @private 19 | * Flag true after this Command has been pushed to CommandHistory 20 | */ 21 | private var hasRegisteredWithHistory:Boolean; 22 | 23 | /** 24 | * @private 25 | * Flag true after this Command has been stepped back by CommandHistory 26 | */ 27 | private var hasSteppedBack:Boolean; 28 | 29 | protected var isCancelled:Boolean = false; 30 | 31 | /** 32 | * Reference to the CommandHistory being used by this Command 33 | */ 34 | [Inject] 35 | public var history:CommandHistory; 36 | 37 | /** 38 | * @inheritDoc 39 | */ 40 | public function UndoableCommand(doFunction:Function = null, undoFunction:Function = null) { 41 | super(doFunction, undoFunction); 42 | } 43 | 44 | /** 45 | * Call this function in your doExecute method to prevent this item from being added to the history stack. 46 | * TODO: Throw an error if cancelling within a redo. Currently assumes if the cancel condition did not fire 47 | * on the first run, they will pass on subsequent executions. This is faulty. 48 | */ 49 | public function cancel():void { 50 | isCancelled = true; 51 | } 52 | 53 | /** 54 | * Executes the command. 55 | * Override this function in your subclasses to implement your command's actions. 56 | * You may call cancel() at any point in this function to prevent it from being added 57 | * to the history stack, but remember that execution does not stop when you call cancel and 58 | * you will need to ensure the doExecute method did not actually make any changes. 59 | * 60 | * Ensure you call super.doExecute() at the end of your subclassed method. 61 | * Note command is only automatically pushed to history once we try to execute this command 62 | * @inheritDoc 63 | * @see undoExecute 64 | */ 65 | override protected function doExecute():void { 66 | // Only push to history once we actually try to execute this command 67 | if (!hasRegisteredWithHistory && !isCancelled) { 68 | hasRegisteredWithHistory = true; 69 | hasExecuted = true; 70 | history.push(this); 71 | } 72 | super.doExecute(); 73 | } 74 | 75 | /** 76 | * Override this function in your subclasses to implement the undo of the actions performed in doExecute(). Ensure you call super.undoExecute() at the end of your subclassed method. 77 | * @inheritDoc 78 | * @see doExecute 79 | * @throws Error Prevents history corruption by throwing error if trying to undo this command and it's not at the top of the history (i.e. next to be undone). 80 | */ 81 | override protected function undoExecute():void { 82 | if (hasExecuted) { 83 | this.hasExecuted = false; 84 | 85 | if (!hasSteppedBack) { 86 | hasSteppedBack = true; 87 | if (history.currentCommand != this) { 88 | throw new Error("Cannot undo command unless this command is first in command history!"); 89 | } 90 | 91 | history.stepBackward(); 92 | hasSteppedBack = false; 93 | } 94 | 95 | } 96 | if (isCancelled) { 97 | throw new Error("Trying to undo a cancelled command!"); 98 | } 99 | super.undoExecute(); 100 | } 101 | 102 | /** 103 | * @private 104 | * Checks if this command has added itself to the command history. 105 | * Ensures we don't let this Command push to the CommandHistory more than once. 106 | */ 107 | private function registerIfRequired():void { 108 | if (!hasRegisteredWithHistory) { 109 | hasRegisteredWithHistory = true; 110 | history.push(this); 111 | } 112 | } 113 | } 114 | } -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/undoablecommand/UndoableCommandBase.as: -------------------------------------------------------------------------------- 1 | package org.robotlegs.utilities.undoablecommand 2 | { 3 | import flash.events.EventDispatcher; 4 | import flash.events.IEventDispatcher; 5 | 6 | import org.robotlegs.utilities.undoablecommand.interfaces.IUndoableCommand; 7 | 8 | public class UndoableCommandBase implements IUndoableCommand 9 | { 10 | /** 11 | * Keeps track of whether this command has been executed, 12 | * to prevent undoing commands that have not been yet been executed. 13 | */ 14 | protected var hasExecuted:Boolean; 15 | 16 | /** 17 | * @private 18 | * Reference to the function to execute in the execute() function 19 | */ 20 | private var doFunction:Function; 21 | 22 | /** 23 | * @private 24 | * Reference to the undo function to execute in the undo() function 25 | */ 26 | private var undoFunction:Function; 27 | 28 | private var _eventDispatcher:IEventDispatcher; 29 | 30 | private static const EXECUTE:String = "doExecuteCommand"; 31 | 32 | /** 33 | * Creates a new UndoableCommand 34 | * @param doFunction the function to execute 35 | * @param undoFunction execute this function to undo the operations of doFunction 36 | * @param autoExecute automatically executes this command on creation. Be careful when setting this false 37 | */ 38 | public function UndoableCommandBase(doFunction:Function = null, undoFunction:Function = null) { 39 | // set function defaults 40 | if (doFunction is Function) { 41 | this.doFunction = doFunction; 42 | } else { 43 | this.doFunction = doExecute; 44 | } 45 | 46 | if (undoFunction is Function) { 47 | this.undoFunction = undoFunction; 48 | } else { 49 | this.undoFunction = undoExecute; 50 | } 51 | } 52 | 53 | /** 54 | * Executes the command. 55 | * If we passed in an execute function to the constructor, 56 | * execute passed-in function, otherwise execute overriden 57 | * doExecute function. 58 | * Will not execute more than once without first undoing 59 | */ 60 | public final function execute():void { 61 | if (!hasExecuted) { 62 | doFunction(); 63 | hasExecuted = true; 64 | eventDispatcher.dispatchEvent(new CommandEvent(CommandEvent.EXECUTE_COMPLETE, this)); 65 | } 66 | } 67 | 68 | /** 69 | * Executes the undo function. 70 | * If we passed in an undo function to the constructor, 71 | * execute passed-in undo function, otherwise execute overriden 72 | * undoExecute function. 73 | * Will not undo if function has not executed. 74 | */ 75 | public final function undo():void { 76 | if (hasExecuted) { 77 | undoFunction(); 78 | hasExecuted = false; 79 | eventDispatcher.dispatchEvent(new CommandEvent(CommandEvent.UNDO_EXECUTE_COMPLETE, this)); 80 | } 81 | } 82 | 83 | /** 84 | * Subclasses MUST override this function with the body of their command. 85 | */ 86 | protected function doExecute():void { 87 | 88 | } 89 | 90 | /** 91 | * Subclasses must override this function. This function should undo whatever the doExecute command did. 92 | */ 93 | protected function undoExecute():void { 94 | 95 | } 96 | 97 | /** 98 | * Event bus to dispatch events on. 99 | */ 100 | [Inject] 101 | public function get eventDispatcher():IEventDispatcher { 102 | return _eventDispatcher; 103 | } 104 | 105 | public function set eventDispatcher(value:IEventDispatcher):void { 106 | _eventDispatcher = value; 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/undoablecommand/commands/StepBackwardCommand.as: -------------------------------------------------------------------------------- 1 | package org.robotlegs.utilities.undoablecommand.commands 2 | { 3 | import org.robotlegs.utilities.undoablecommand.CommandHistory; 4 | 5 | 6 | /** 7 | * Map this command to the HistoryEvent.STEP_BACKWARD event to trigger an undo action. 8 | * Provided for convenience. 9 | */ 10 | public class StepBackwardCommand 11 | { 12 | [Inject] 13 | public var commandHistory:CommandHistory; 14 | 15 | /** 16 | * Will undo a single command, if possible. Fails silently if not. 17 | */ 18 | public function execute():void { 19 | commandHistory.stepBackward(); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/undoablecommand/commands/StepForwardCommand.as: -------------------------------------------------------------------------------- 1 | package org.robotlegs.utilities.undoablecommand.commands 2 | { 3 | import org.robotlegs.utilities.undoablecommand.CommandHistory; 4 | 5 | /** 6 | * Map this command to the HistoryEvent.STEP_FORWARD event to trigger a redo action. 7 | * Provided for convenience. 8 | */ 9 | public class StepForwardCommand 10 | { 11 | [Inject] 12 | public var commandHistory:CommandHistory; 13 | 14 | /** 15 | * Will redo a single command, if possible. Fails silently if not. 16 | */ 17 | public function execute():void { 18 | commandHistory.stepForward(); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/undoablecommand/interfaces/IUndoableCommand.as: -------------------------------------------------------------------------------- 1 | package org.robotlegs.utilities.undoablecommand.interfaces 2 | { 3 | import flash.events.IEventDispatcher; 4 | 5 | public interface IUndoableCommand { 6 | 7 | /** 8 | * Perform an action 9 | */ 10 | function execute():void; 11 | 12 | /** 13 | * Reverse the performed action 14 | */ 15 | function undo():void; 16 | 17 | /** 18 | * Fire events when you execute or undo 19 | */ 20 | function get eventDispatcher():IEventDispatcher; 21 | function set eventDispatcher(value:IEventDispatcher):void; 22 | } 23 | } -------------------------------------------------------------------------------- /src/tests/MockUndoableCommand.as: -------------------------------------------------------------------------------- 1 | package tests { 2 | import org.robotlegs.utilities.undoablecommand.UndoableCommand; 3 | 4 | 5 | /** 6 | * @private 7 | */ 8 | public class MockUndoableCommand extends UndoableCommand { 9 | 10 | /** 11 | * Reference to some array to be tested on. 12 | */ 13 | public var testArray:Array; 14 | public var shouldCancel:Boolean = false; 15 | 16 | /** 17 | * Cause some change to the array 18 | */ 19 | override protected function doExecute():void { 20 | if (shouldCancel) { 21 | cancel(); 22 | return; 23 | } 24 | this.testArray.push(new Object()); 25 | super.doExecute(); 26 | } 27 | 28 | /** 29 | * Undo the change on the array 30 | */ 31 | override protected function undoExecute():void { 32 | // pop() isn't the best undo is it? 33 | // will do for now. 34 | this.testArray.pop(); 35 | super.undoExecute(); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/tests/MockUndoableCommandBase.as: -------------------------------------------------------------------------------- 1 | package tests 2 | { 3 | import flash.events.EventDispatcher; 4 | 5 | import org.robotlegs.utilities.undoablecommand.UndoableCommandBase; 6 | import org.robotlegs.utilities.undoablecommand.interfaces.IUndoableCommand; 7 | 8 | /** 9 | * @private 10 | */ 11 | public class MockUndoableCommandBase extends UndoableCommandBase implements IUndoableCommand 12 | { 13 | public static var testArray:Array = new Array(); 14 | 15 | public function MockUndoableCommandBase() { 16 | eventDispatcher = new EventDispatcher(); 17 | super(); 18 | } 19 | 20 | /** 21 | * Cause damage to the array 22 | */ 23 | override protected function doExecute():void { 24 | 25 | trace("Do ta:" + testArray); 26 | testArray.push(new Object()); 27 | super.doExecute(); 28 | } 29 | 30 | /** 31 | * Undo the damage on the array 32 | */ 33 | override protected function undoExecute():void { 34 | trace("Undo ta:" + testArray); 35 | testArray.pop(); 36 | super.undoExecute(); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/tests/TestHistoryEvents.as: -------------------------------------------------------------------------------- 1 | package tests 2 | { 3 | import flash.events.EventDispatcher; 4 | 5 | import flexunit.framework.Assert; 6 | 7 | import org.flexunit.async.Async; 8 | import org.robotlegs.utilities.undoablecommand.CommandHistory; 9 | import org.robotlegs.utilities.undoablecommand.HistoryEvent; 10 | 11 | public class TestHistoryEvents 12 | { 13 | // Reference declaration for class to test 14 | private var history:CommandHistory; 15 | private var eventBus:EventDispatcher; 16 | private var bananaCommand:MockUndoableCommandBase; 17 | private var appleCommand:MockUndoableCommandBase; 18 | private var pineappleCommand:MockUndoableCommandBase; 19 | 20 | public function TestHistoryEvents() 21 | { 22 | } 23 | 24 | [Before] 25 | public function setupTests():void { 26 | history = new CommandHistory(); 27 | eventBus = new EventDispatcher() 28 | history.eventDispatcher = eventBus; 29 | MockUndoableCommandBase.testArray = new Array() 30 | bananaCommand = new MockUndoableCommandBase(); 31 | bananaCommand.eventDispatcher = eventBus; 32 | appleCommand = new MockUndoableCommandBase(); 33 | appleCommand.eventDispatcher = eventBus; 34 | pineappleCommand = new MockUndoableCommandBase(); 35 | pineappleCommand.eventDispatcher = eventBus; 36 | } 37 | 38 | [After] 39 | public function reset():void { 40 | history = null; 41 | eventBus = null; 42 | MockUndoableCommandBase.testArray = null; 43 | } 44 | 45 | 46 | [Test(async)] 47 | public function testFastForwardEvents():void { 48 | Async.handleEvent(this, history.eventDispatcher, HistoryEvent.FAST_FORWARD_COMPLETE, function(event:HistoryEvent, passThrough:Object):void { 49 | Assert.assertStrictlyEquals(pineappleCommand, event.command) 50 | }); 51 | 52 | history.push(bananaCommand); 53 | history.push(appleCommand); 54 | history.push(pineappleCommand); 55 | history.rewind(); 56 | history.fastForward(); 57 | } 58 | 59 | [Test(async)] 60 | public function testRewindEvents():void { 61 | Async.handleEvent(this, history.eventDispatcher, HistoryEvent.REWIND_COMPLETE, function(event:HistoryEvent, passThrough:Object):void { 62 | Assert.assertNull(event.command); 63 | 64 | }); 65 | 66 | history.push(bananaCommand); 67 | history.push(appleCommand); 68 | history.push(pineappleCommand); 69 | history.rewind(); 70 | } 71 | 72 | [Test(async)] 73 | public function testStepBackwardEvents():void { 74 | Async.handleEvent(this, history.eventDispatcher, HistoryEvent.STEP_BACKWARD_COMPLETE, function(event:HistoryEvent, passThrough:Object):void { 75 | Assert.assertStrictlyEquals(pineappleCommand, event.command); 76 | }); 77 | 78 | history.push(bananaCommand); 79 | history.push(appleCommand); 80 | history.push(pineappleCommand); 81 | history.stepBackward(); 82 | } 83 | 84 | [Test(async)] 85 | public function testStepForwardEvents():void 86 | { 87 | Async.handleEvent(this, history.eventDispatcher, HistoryEvent.STEP_FORWARD_COMPLETE, function(event:HistoryEvent, passThrough:Object):void { 88 | Assert.assertStrictlyEquals(bananaCommand, event.command); 89 | 90 | }); 91 | 92 | history.push(bananaCommand); 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /src/tests/TestManagedUndoableCommand.as: -------------------------------------------------------------------------------- 1 | package tests 2 | { 3 | import flash.display.DisplayObjectContainer; 4 | import flash.events.EventDispatcher; 5 | 6 | import flexunit.framework.Assert; 7 | 8 | import org.robotlegs.utilities.undoablecommand.CommandHistory; 9 | 10 | 11 | /** 12 | * @private 13 | */ 14 | public class TestManagedUndoableCommand 15 | { 16 | // Reference declaration for class to test 17 | private var _managedUndoableCommand:MockUndoableCommand; 18 | 19 | public function TestManagedUndoableCommand() 20 | { 21 | } 22 | 23 | private var testArray:Array; 24 | private var contextView:DisplayObjectContainer; 25 | 26 | private var history:CommandHistory; 27 | private var eventBus:EventDispatcher; 28 | 29 | [Before] 30 | public function setupTests():void { 31 | eventBus = new EventDispatcher(); 32 | testArray = new Array(); 33 | history = new CommandHistory(); 34 | history.eventDispatcher = eventBus; 35 | _managedUndoableCommand = createCommand(); 36 | } 37 | 38 | private function createCommand():MockUndoableCommand { 39 | var newCommand:MockUndoableCommand = new MockUndoableCommand(); 40 | newCommand.testArray = testArray; 41 | newCommand.history = history; 42 | newCommand.eventDispatcher = eventBus; 43 | 44 | return newCommand; 45 | } 46 | 47 | [After] 48 | public function reset():void { 49 | testArray = null; 50 | _managedUndoableCommand = null; 51 | history = null; 52 | } 53 | 54 | [Test] 55 | public function testInitialisation():void { 56 | Assert.assertNotNull(_managedUndoableCommand); 57 | Assert.assertNotNull(testArray); 58 | } 59 | 60 | [Test] 61 | public function testExecute():void { 62 | Assert.assertEquals(0, testArray.length); 63 | _managedUndoableCommand.execute(); 64 | Assert.assertEquals(1, testArray.length); 65 | } 66 | 67 | [Test] 68 | public function testUndo():void { 69 | _managedUndoableCommand.execute(); 70 | Assert.assertEquals(1, testArray.length); 71 | _managedUndoableCommand.undo(); 72 | Assert.assertEquals(0, testArray.length); 73 | } 74 | 75 | [Test] 76 | public function testExecuteMultiple():void { 77 | _managedUndoableCommand.execute(); 78 | _managedUndoableCommand.execute(); 79 | _managedUndoableCommand.execute(); 80 | Assert.assertEquals(1, testArray.length); 81 | 82 | } 83 | 84 | [Test] 85 | public function testUndoMultiple():void { 86 | _managedUndoableCommand.execute(); 87 | Assert.assertEquals(1, testArray.length); 88 | _managedUndoableCommand.undo(); 89 | _managedUndoableCommand.undo(); 90 | _managedUndoableCommand.undo(); 91 | Assert.assertEquals(0, testArray.length); 92 | } 93 | 94 | [Test] 95 | public function testUndoNothingToUndo():void { 96 | _managedUndoableCommand.undo(); 97 | Assert.assertEquals(0, testArray.length); 98 | } 99 | 100 | [Test] 101 | public function testDefaultFunctions():void { 102 | var command:MockUndoableCommand = createCommand();/// = new MockManagedUndoableCommand(); 103 | 104 | command.testArray = testArray; 105 | command.history = history; 106 | command.execute(); 107 | Assert.assertEquals(1, testArray.length); 108 | command.undo(); 109 | Assert.assertEquals(0, testArray.length); 110 | } 111 | 112 | [Test] 113 | // Test forward/back/position settings while 114 | // moving backwards & forwards 115 | public function testGetCurrentCommand():void { 116 | Assert.assertNull(history.currentCommand); 117 | Assert.assertEquals(0, history.currentPosition); 118 | 119 | var appleCommand:MockUndoableCommand = createCommand(); 120 | 121 | var bananaCommand:MockUndoableCommand = createCommand(); 122 | 123 | var pineappleCommand:MockUndoableCommand = createCommand(); 124 | 125 | /*_testHistory.push(appleCommand); 126 | _testHistory.push(bananaCommand); 127 | _testHistory.push(pineappleCommand);*/ 128 | 129 | appleCommand.execute(); 130 | bananaCommand.execute(); 131 | pineappleCommand.execute(); 132 | 133 | Assert.assertEquals(pineappleCommand, history.currentCommand); 134 | history.stepBackward(); 135 | Assert.assertEquals(bananaCommand, history.currentCommand); 136 | history.stepForward(); 137 | Assert.assertEquals(pineappleCommand, history.currentCommand); 138 | history.stepBackward(); 139 | history.stepBackward(); 140 | Assert.assertEquals(appleCommand, history.currentCommand); 141 | } 142 | 143 | [Test] 144 | // Test forward/back/position settings while 145 | // moving backwards & forwards 146 | public function testAddToHistory():void { 147 | var appleCommand:MockUndoableCommand = createCommand(); 148 | Assert.assertNull(history.currentCommand); 149 | appleCommand.execute(); 150 | Assert.assertEquals(appleCommand, history.currentCommand); 151 | Assert.assertEquals(1, testArray.length); 152 | } 153 | 154 | [Test] 155 | // Test forward/back/position settings while 156 | // moving backwards & forwards 157 | public function testCommandUndo():void { 158 | var appleCommand:MockUndoableCommand = createCommand(); 159 | Assert.assertNull(history.currentCommand); 160 | appleCommand.execute(); 161 | 162 | Assert.assertEquals(appleCommand, history.currentCommand); 163 | Assert.assertEquals(1, testArray.length); 164 | appleCommand.undo(); 165 | Assert.assertNull(history.currentCommand); 166 | Assert.assertEquals(0, testArray.length); 167 | 168 | } 169 | 170 | [Test] 171 | // Test forward/back/position settings while 172 | // moving backwards & forwards 173 | public function testHistoryUndo():void { 174 | var appleCommand:MockUndoableCommand = createCommand(); 175 | Assert.assertNull(history.currentCommand); 176 | appleCommand.execute(); 177 | Assert.assertEquals(1, testArray.length); 178 | Assert.assertEquals(appleCommand, history.currentCommand); 179 | Assert.assertEquals(1, history.currentPosition); 180 | history.stepBackward(); 181 | Assert.assertEquals(0, history.currentPosition); 182 | Assert.assertNull(history.currentCommand); 183 | Assert.assertEquals(0, testArray.length); 184 | history.stepForward(); 185 | Assert.assertEquals(1, testArray.length); 186 | Assert.assertEquals(appleCommand, history.currentCommand); 187 | Assert.assertEquals(1, history.currentPosition); 188 | } 189 | 190 | [Test] 191 | // Test cancelling the command 192 | public function testCancellingDoesNothing():void { 193 | var appleCommand:MockUndoableCommand = createCommand(); 194 | appleCommand.shouldCancel = true; 195 | appleCommand.execute(); 196 | //Make sure nothing actually happened 197 | Assert.assertEquals(0, history.currentPosition); 198 | Assert.assertNull(history.currentCommand); 199 | Assert.assertEquals(0, testArray.length); 200 | 201 | } 202 | 203 | [Test(expects="Error")] 204 | // Test trying to undo a cancelled command throws an error 205 | public function testUndoingACancelledCommandErrors():void { 206 | var appleCommand:MockUndoableCommand = createCommand(); 207 | appleCommand.shouldCancel = true; 208 | appleCommand.execute(); 209 | appleCommand.undo(); 210 | } 211 | } 212 | } -------------------------------------------------------------------------------- /src/tests/TestUndoableCommand.as: -------------------------------------------------------------------------------- 1 | package tests 2 | { 3 | import flash.events.EventDispatcher; 4 | 5 | import flexunit.framework.Assert; 6 | 7 | import org.robotlegs.utilities.undoablecommand.UndoableCommandBase; 8 | 9 | /** 10 | * @private 11 | */ 12 | public class TestUndoableCommand 13 | { 14 | // Reference declaration for class to test 15 | private var _undoableCommand:UndoableCommandBase; 16 | 17 | private var testArray:Array; 18 | private var testObject:Object; 19 | private var eventBus:EventDispatcher; 20 | 21 | private function doStuff():void { 22 | testArray.push(testObject); 23 | } 24 | 25 | private function undoStuff():void { 26 | testArray.pop(); 27 | } 28 | 29 | [Before] 30 | public function setupTests():void { 31 | testArray = new Array(); 32 | eventBus = new EventDispatcher(); 33 | _undoableCommand = new UndoableCommandBase(doStuff, undoStuff); 34 | _undoableCommand.eventDispatcher = eventBus; 35 | } 36 | 37 | [After] 38 | public function reset():void { 39 | _undoableCommand = null; 40 | testArray = null; 41 | eventBus = null; 42 | } 43 | 44 | [Test] 45 | public function testInitialisation():void { 46 | Assert.assertNotNull(_undoableCommand); 47 | Assert.assertNotNull(testArray); 48 | } 49 | 50 | [Test] 51 | public function testExecute():void { 52 | _undoableCommand.execute(); 53 | Assert.assertEquals(testArray.length, 1); 54 | } 55 | 56 | [Test] 57 | public function testUndo():void { 58 | _undoableCommand.execute(); 59 | Assert.assertEquals(testArray.length, 1); 60 | _undoableCommand.undo(); 61 | Assert.assertEquals(testArray.length, 0); 62 | } 63 | 64 | [Test] 65 | public function testExecuteMultiple():void { 66 | _undoableCommand.execute(); 67 | _undoableCommand.execute(); 68 | _undoableCommand.execute(); 69 | Assert.assertEquals(testArray.length, 1); 70 | } 71 | 72 | [Test] 73 | public function testUndoMultiple():void { 74 | _undoableCommand.execute(); 75 | _undoableCommand.undo(); 76 | _undoableCommand.undo(); 77 | _undoableCommand.undo(); 78 | Assert.assertEquals(testArray.length, 0); 79 | } 80 | 81 | [Test] 82 | public function testUndoNothingToUndo():void { 83 | _undoableCommand.undo(); 84 | Assert.assertEquals(testArray.length, 0); 85 | } 86 | 87 | [Test] 88 | public function testDefaultFunctions():void { 89 | var command:MockUndoableCommandBase = new MockUndoableCommandBase(); 90 | MockUndoableCommandBase.testArray = testArray; 91 | command.execute(); 92 | Assert.assertEquals(testArray.length, 1); 93 | command.undo(); 94 | Assert.assertEquals(testArray.length, 0); 95 | } 96 | 97 | } 98 | } --------------------------------------------------------------------------------