Revision: 483 http://skycastle.svn.sourceforge.net/skycastle/?rev=483&view=rev Author: zzorn Date: 2008-04-26 12:14:45 -0700 (Sat, 26 Apr 2008) Log Message: ----------- Implemented a CommandStack that enables running undoable commands, and which provides Undo and Redo Actions, as well as a practical overrideable CommandAction. Modified Paths: -------------- trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/Sketch3DUI.java trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SkycastleSketch.java Added Paths: ----------- trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SketchToolbarFactory.java trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SketchView.java trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/ trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/AbstractCommand.java trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/Command.java trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/CommandAction.java trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/CommandStack.java trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/CommandStackImpl.java trunk/skycastle/modules/utils/src/test/java/org/skycastle/util/command/ trunk/skycastle/modules/utils/src/test/java/org/skycastle/util/command/CommandStackTest.java Removed Paths: ------------- trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SketchUi.java Modified: trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/Sketch3DUI.java =================================================================== --- trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/Sketch3DUI.java 2008-04-26 17:03:10 UTC (rev 482) +++ trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/Sketch3DUI.java 2008-04-26 19:14:45 UTC (rev 483) @@ -179,8 +179,8 @@ private JComponent createNorthPanel() { - SketchUi sketchUi = new SketchUi(); - return sketchUi.createToolbar(); + SketchToolbarFactory sketchFactory = new SketchToolbarFactory(); + return sketchFactory.createToolbar(); } Copied: trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SketchToolbarFactory.java (from rev 481, trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SketchUi.java) =================================================================== --- trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SketchToolbarFactory.java (rev 0) +++ trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SketchToolbarFactory.java 2008-04-26 19:14:45 UTC (rev 483) @@ -0,0 +1,60 @@ +package org.skycastle.sketch; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +/** + * @author Hans Haggstrom + */ +public class SketchToolbarFactory +{ + + public JToolBar createToolbar() + { + final JToolBar toolBar = new JToolBar(); + toolBar.add( new JButton( new AbstractAction( "Quit" ) + { + + public void actionPerformed( final ActionEvent e ) + { + System.exit( 0 ); + } + + } ) ); + toolBar.add( new JButton( new AbstractAction( "New Page" ) + { + + public void actionPerformed( final ActionEvent e ) + { + } + + } ) ); + toolBar.add( new JButton( new AbstractAction( "Zoom Out" ) + { + + public void actionPerformed( final ActionEvent e ) + { + } + + } ) ); + toolBar.add( new JButton( new AbstractAction( "Zoom In" ) + { + + public void actionPerformed( final ActionEvent e ) + { + } + + } ) ); + toolBar.add( new JButton( new AbstractAction( "Zoom to show all" ) + { + + public void actionPerformed( final ActionEvent e ) + { + } + + } ) ); + + toolBar.setVisible( true ); + return toolBar; + } +} Deleted: trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SketchUi.java =================================================================== --- trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SketchUi.java 2008-04-26 17:03:10 UTC (rev 482) +++ trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SketchUi.java 2008-04-26 19:14:45 UTC (rev 483) @@ -1,60 +0,0 @@ -package org.skycastle.sketch; - -import javax.swing.*; -import java.awt.event.ActionEvent; - -/** - * @author Hans Haggstrom - */ -public class SketchUi -{ - - public JToolBar createToolbar() - { - final JToolBar toolBar = new JToolBar(); - toolBar.add( new JButton( new AbstractAction( "Quit" ) - { - - public void actionPerformed( final ActionEvent e ) - { - System.exit( 0 ); - } - - } ) ); - toolBar.add( new JButton( new AbstractAction( "New Page" ) - { - - public void actionPerformed( final ActionEvent e ) - { - } - - } ) ); - toolBar.add( new JButton( new AbstractAction( "Zoom Out" ) - { - - public void actionPerformed( final ActionEvent e ) - { - } - - } ) ); - toolBar.add( new JButton( new AbstractAction( "Zoom In" ) - { - - public void actionPerformed( final ActionEvent e ) - { - } - - } ) ); - toolBar.add( new JButton( new AbstractAction( "Zoom to show all" ) - { - - public void actionPerformed( final ActionEvent e ) - { - } - - } ) ); - - toolBar.setVisible( true ); - return toolBar; - } -} Added: trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SketchView.java =================================================================== --- trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SketchView.java (rev 0) +++ trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SketchView.java 2008-04-26 19:14:45 UTC (rev 483) @@ -0,0 +1,61 @@ +package org.skycastle.sketch; + +import org.skycastle.opengl.Canvas3D; +import org.skycastle.util.simpleui.SimpleFrame; + +import javax.swing.*; +import java.awt.BorderLayout; +import java.awt.Component; + +/** + * A view, which presents the 3D view of the sketch, and provides input events. + * + * @author Hans Häggström + */ +// TODO: Have both a navigation stack and an undo stack, that are independent +public class SketchView +{ + private Component myUiComponent; + private Canvas3D myCanvas3D; + private JToolBar myToolBar; + + /** + * Creates a new {@link org.skycastle.sketch.SketchView}. + */ + public SketchView() + { + + myCanvas3D = new Canvas3D(); + + + final JPanel panel = new JPanel( new BorderLayout() ); + panel.add( myCanvas3D.get3DView(), BorderLayout.CENTER ); + myToolBar = new JToolBar(); + panel.add( myToolBar, BorderLayout.NORTH ); + + + new SimpleFrame( panel ); + +/* + final StrokeRenderer strokeRenderer = new StrokeRenderer( createTestStroke() ); + myCanvas3D.set3DNode( strokeRenderer ); +*/ + + } + + /** + * An action / command in the application. + * + * @param action + */ + void addAction( Action action ) + { + + } + + + public Component getUiComponent() + { + return myUiComponent; + } +} Modified: trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SkycastleSketch.java =================================================================== --- trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SkycastleSketch.java 2008-04-26 17:03:10 UTC (rev 482) +++ trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SkycastleSketch.java 2008-04-26 19:14:45 UTC (rev 483) @@ -6,14 +6,11 @@ import com.jme.scene.Spatial; import com.jme.scene.shape.Box; import com.jme.scene.state.LightState; -import org.skycastle.opengl.Canvas3D; import org.skycastle.sketch.model.point.StrokePointImpl; import org.skycastle.sketch.model.stroke.Stroke; import org.skycastle.sketch.model.stroke.StrokeImpl; import org.skycastle.util.simpleui.SimpleFrame; -import javax.swing.*; -import java.awt.BorderLayout; import java.util.Random; import java.util.logging.Level; import java.util.logging.Logger; @@ -53,21 +50,12 @@ // This way the console output is a bit more relevant. LOGGER.setLevel( Level.WARNING ); + final SketchView sketchView = new SketchView(); - Canvas3D canvas3D = new Canvas3D(); + // TODO: Register a model modifying input listener and navigating input listener to the view - SketchUi sketchUi = new SketchUi(); + new SimpleFrame( sketchView.getUiComponent() ); - JPanel panel = new JPanel( new BorderLayout() ); - panel.add( canvas3D.get3DView(), BorderLayout.CENTER ); - panel.add( sketchUi.createToolbar(), BorderLayout.NORTH ); - - new SimpleFrame( panel ); - - - final StrokeRenderer strokeRenderer = new StrokeRenderer( createTestStroke() ); - canvas3D.set3DNode( strokeRenderer ); - /* Sketch3DUI sketch3DUI = new Sketch3DUI(); sketch3DUI.start(); @@ -82,8 +70,8 @@ { final StrokeImpl stroke = new StrokeImpl(); - float x = 0.0f; - float y = 0.0f; + float x = 0; + float y = 0; final Random random = new Random(); for ( int i = 0; i < 1000; i++ ) Added: trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/AbstractCommand.java =================================================================== --- trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/AbstractCommand.java (rev 0) +++ trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/AbstractCommand.java 2008-04-26 19:14:45 UTC (rev 483) @@ -0,0 +1,82 @@ +package org.skycastle.util.command; + +import org.skycastle.util.ParameterChecker; + +/** + * @author Hans Häggström + */ +public abstract class AbstractCommand + implements Command +{ + + //====================================================================== + // Private Fields + + private final String myDescription; + private final boolean myUndoable; + private final boolean myDisruptive; + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Constructors + + /** + * Creates a new non-disruptive {@link AbstractCommand}. + * + * @param description an user readable description of this command. + * @param undoable true if this is an undoable command. + */ + public AbstractCommand( final String description, final boolean undoable ) + { + this( description, undoable, false ); + } + + + /** + * Creates a new {@link AbstractCommand}. + * + * @param description an user readable description of this command. + * @param undoable true if this is an undoable command. + * @param disruptive true if this command should clear the previous undo and redo stacks. + */ + public AbstractCommand( final String description, final boolean undoable, final boolean disruptive ) + { + ParameterChecker.checkNotNull( description, "description" ); + + myDescription = description; + myUndoable = undoable; + myDisruptive = disruptive; + } + + //---------------------------------------------------------------------- + // Command Implementation + + public final String getDescription() + { + return myDescription; + } + + + public final boolean isUndoable() + { + return myUndoable; + } + + + public final boolean isDisruptive() + { + return myDisruptive; + } + + + /** + * Override this if undo is supported. Throws an exception by default. + */ + public void undoCommand() + { + throw new UnsupportedOperationException( "Undo not implemented" ); + } + +} Added: trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/Command.java =================================================================== --- trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/Command.java (rev 0) +++ trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/Command.java 2008-04-26 19:14:45 UTC (rev 483) @@ -0,0 +1,38 @@ +package org.skycastle.util.command; + +/** + * Used for undoable commands. + * <p/> + * Encapsulates both the parameters for a command, and logic for doing and undoing it. + * + * @author Hans Häggström + */ +public interface Command +{ + + /** + * @return an user readable description of what this command did. + */ + String getDescription(); + + /** + * @return true if this is an undoable command. + */ + boolean isUndoable(); + + /** + * @return true if this command should clear the previous undo and redo stacks. + */ + boolean isDisruptive(); + + /** + * Executes the command. + */ + void doCommand(); + + /** + * Undoes the command. + */ + void undoCommand(); + +} \ No newline at end of file Added: trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/CommandAction.java =================================================================== --- trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/CommandAction.java (rev 0) +++ trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/CommandAction.java 2008-04-26 19:14:45 UTC (rev 483) @@ -0,0 +1,105 @@ +package org.skycastle.util.command; + +import org.skycastle.util.ParameterChecker; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +/** + * An action that sends a command to an {@link CommandStack}. + * + * @author Hans Häggström + */ +@SuppressWarnings( { "serial", "NonSerializableFieldInSerializableClass" } ) +public abstract class CommandAction + extends AbstractAction +{ + + //====================================================================== + // Private Fields + + private final CommandStack myCommandStack; + + //====================================================================== + // Private Constants + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // ActionListener Implementation + + public final void actionPerformed( final ActionEvent e ) + { + myCommandStack.invoke( createCommand() ); + } + + //====================================================================== + // Protected Methods + + //---------------------------------------------------------------------- + // Protected Constructors + + /** + * Creates a new {@link CommandAction}. + * + * @param commandStack the {@link CommandStack} to use, or null if not in use. + */ + protected CommandAction( final CommandStack commandStack, + final String name ) + { + this( commandStack, name, null ); + } + + + /** + * Creates a new {@link CommandAction}. + * + * @param commandStack the {@link CommandStack} to use, or null if not in use. + * @param name the name of the action. + * @param description a tool tip text for the action. + */ + protected CommandAction( final CommandStack commandStack, + final String name, + final String description ) + { + this( commandStack, name, description, null ); + } + + + /** + * Creates a new {@link CommandAction}. + * + * @param commandStack the {@link CommandStack} to use, or null if not in use. + * @param name the name of the action. + * @param description a tool tip text for the action. + * @param icon an icon for the action. + */ + protected CommandAction( final CommandStack commandStack, + final String name, + final String description, + final Icon icon ) + { + super( name, icon ); + + ParameterChecker.checkNotNull( name, "name" ); + ParameterChecker.checkNotNull( commandStack, "commandStack" ); + + myCommandStack = commandStack; + + if ( description != null ) + { + putValue( SHORT_DESCRIPTION, description ); + } + } + + //---------------------------------------------------------------------- + // Abstract Protected Methods + + /** + * @return a {@link Command} for executing the action, containing both the parameters for the command and + * the logic to run, and optionally undo logic. + */ + protected abstract Command createCommand(); + +} Added: trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/CommandStack.java =================================================================== --- trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/CommandStack.java (rev 0) +++ trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/CommandStack.java 2008-04-26 19:14:45 UTC (rev 483) @@ -0,0 +1,63 @@ +package org.skycastle.util.command; + +import javax.swing.*; + +/** + * A CommandStack allows executing and undoing commands. + * <p/> + * You can call invoke directly, or subclass CommandAction for UI:s. + * + * @author Hans Häggström + */ +public interface CommandStack +{ + + /** + * Called when a {@link Command} is invoked from e.g. the UI. + * + * @param command the command object, which contains the necessary parameters and logic for running the + * command. + */ + void invoke( Command command ); + + /** + * @return an action that can be used to undo commands. + */ + Action getUndoAction(); + + /** + * @return an action that can be used to redo commands. + */ + Action getRedoAction(); + + /** + * @return true if undo can be done. + */ + boolean canUndo(); + + /** + * @return true if redo can be done. + */ + boolean canRedo(); + + /** + * Undoes the previous command if possible. + */ + void undo(); + + /** + * Redoes the previously undone command if possible. + */ + void redo(); + + /** + * @return description of the next command that can be undone. Null if none available. + */ + String getUndoCommandDescription(); + + /** + * @return description of the next command that can be redone. Null if none available. + */ + String getRedoCommandDescription(); + +} Added: trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/CommandStackImpl.java =================================================================== --- trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/CommandStackImpl.java (rev 0) +++ trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/command/CommandStackImpl.java 2008-04-26 19:14:45 UTC (rev 483) @@ -0,0 +1,170 @@ +package org.skycastle.util.command; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.util.ArrayDeque; +import java.util.Deque; + +/** + * A simple {@link CommandStack} that just invokes the tasks directly in the swing thread. + * + * @author Hans Häggström + */ +public final class CommandStackImpl + implements CommandStack +{ + + //====================================================================== + // Private Fields + + private final Deque<Command> myUndoStack = new ArrayDeque<Command>(); + private final Deque<Command> myRedoStack = new ArrayDeque<Command>(); + + @SuppressWarnings( { "serial" } ) + private final AbstractAction myUndoAction = new AbstractAction( "Undo" ) + { + + public void actionPerformed( final ActionEvent e ) + { + undo(); + } + + }; + + @SuppressWarnings( { "serial" } ) + private final AbstractAction myRedoAction = new AbstractAction( "Redo" ) + { + + public void actionPerformed( final ActionEvent e ) + { + redo(); + } + + }; + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Constructors + + /** + * Creates a new {@link CommandStackImpl}. + */ + public CommandStackImpl() + { + updateActionStatuses(); + } + + //---------------------------------------------------------------------- + // CommandStack Implementation + + public void invoke( final Command command ) + { + command.doCommand(); + + myRedoStack.clear(); + + if ( command.isDisruptive() ) + { + myUndoStack.clear(); + } + else if ( command.isUndoable() ) + { + myUndoStack.push( command ); + } + + updateActionStatuses(); + } + + + public Action getUndoAction() + { + return myUndoAction; + } + + + public Action getRedoAction() + { + return myRedoAction; + } + + + public boolean canUndo() + { + return !myUndoStack.isEmpty(); + } + + + public boolean canRedo() + { + return !myRedoStack.isEmpty(); + } + + + public void undo() + { + final Command command = myUndoStack.pop(); + + command.undoCommand(); + + myRedoStack.push( command ); + + updateActionStatuses(); + } + + + public void redo() + { + final Command command = myRedoStack.pop(); + + command.doCommand(); + + myUndoStack.push( command ); + + updateActionStatuses(); + } + + + public String getUndoCommandDescription() + { + final Command command = myUndoStack.peek(); + + if ( command != null ) + { + return "Undo " + command.getDescription(); + } + else + { + return "Nothing to Undo"; + } + } + + + public String getRedoCommandDescription() + { + final Command command = myRedoStack.peek(); + + if ( command != null ) + { + return "Redo " + command.getDescription(); + } + else + { + return "Nothing to Redo"; + } + } + + //====================================================================== + // Private Methods + + private void updateActionStatuses() + { + myRedoAction.setEnabled( canRedo() ); + myUndoAction.setEnabled( canUndo() ); + + myUndoAction.putValue( Action.SHORT_DESCRIPTION, getUndoCommandDescription() ); + myRedoAction.putValue( Action.SHORT_DESCRIPTION, getRedoCommandDescription() ); + } + +} Added: trunk/skycastle/modules/utils/src/test/java/org/skycastle/util/command/CommandStackTest.java =================================================================== --- trunk/skycastle/modules/utils/src/test/java/org/skycastle/util/command/CommandStackTest.java (rev 0) +++ trunk/skycastle/modules/utils/src/test/java/org/skycastle/util/command/CommandStackTest.java 2008-04-26 19:14:45 UTC (rev 483) @@ -0,0 +1,256 @@ +package org.skycastle.util.command; + +import junit.framework.TestCase; + +import javax.swing.*; + +/** + * @author Hans Häggström + */ +@SuppressWarnings( { "JavaDoc" } ) +public class CommandStackTest + extends TestCase +{ + + //====================================================================== + // Private Fields + + private int[] myCounter; + private CommandStack myCommandStack; + private CommandAction myCountdownAction; + private CommandAction myKaboomAction; + private CommandAction myMessageAction; + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Test Methods + + public void testUndoRedo() throws Exception + { + assertEquals( 4, myCounter[ 0 ] ); + + myCountdownAction.actionPerformed( null ); + assertEquals( 3, myCounter[ 0 ] ); + + myCountdownAction.actionPerformed( null ); + myCountdownAction.actionPerformed( null ); + assertEquals( 1, myCounter[ 0 ] ); + + myCommandStack.undo(); + assertEquals( 2, myCounter[ 0 ] ); + + myCommandStack.redo(); + assertEquals( 1, myCounter[ 0 ] ); + } + + public void testQueryMethodsForUndo() throws Exception + { + assertFalse( myCommandStack.canUndo() ); + + myCountdownAction.actionPerformed( null ); + + assertTrue( myCommandStack.canUndo() ); + + myCommandStack.undo(); + + assertFalse( myCommandStack.canUndo() ); + + myCommandStack.redo(); + + assertTrue( myCommandStack.canUndo() ); + } + + public void testQueryMethodsForRedo() throws Exception + { + assertFalse( myCommandStack.canRedo() ); + + myCountdownAction.actionPerformed( null ); + + assertFalse( myCommandStack.canRedo() ); + + myCommandStack.undo(); + + assertTrue( myCommandStack.canRedo() ); + + myCountdownAction.actionPerformed( null ); + + assertFalse( myCommandStack.canRedo() ); + } + + public void testUndoDescription() throws Exception + { + assertEquals( "Nothing to Undo", myCommandStack.getUndoCommandDescription() ); + + myCountdownAction.actionPerformed( null ); + + assertEquals( "Undo Set counter to 3", myCommandStack.getUndoCommandDescription() ); + assertEquals( "Undo Set counter to 3", + myCommandStack.getUndoAction().getValue( Action.SHORT_DESCRIPTION ) ); + } + + public void testRedoDescription() throws Exception + { + assertEquals( "Nothing to Redo", myCommandStack.getRedoCommandDescription() ); + + myCountdownAction.actionPerformed( null ); + myCountdownAction.actionPerformed( null ); + myCommandStack.undo(); + + assertEquals( "Redo Set counter to 2", myCommandStack.getRedoCommandDescription() ); + assertEquals( "Redo Set counter to 2", + myCommandStack.getRedoAction().getValue( Action.SHORT_DESCRIPTION ) ); + } + + public void testUndoAction() throws Exception + { + final Action undoAction = myCommandStack.getUndoAction(); + + assertFalse( undoAction.isEnabled() ); + + myCountdownAction.actionPerformed( null ); + assertEquals( 3, myCounter[ 0 ] ); + + assertTrue( undoAction.isEnabled() ); + + undoAction.actionPerformed( null ); + assertEquals( 4, myCounter[ 0 ] ); + } + + public void testRedoAction() throws Exception + { + final Action redoAction = myCommandStack.getRedoAction(); + + assertFalse( redoAction.isEnabled() ); + + myCountdownAction.actionPerformed( null ); + myCommandStack.undo(); + assertEquals( 4, myCounter[ 0 ] ); + + assertTrue( redoAction.isEnabled() ); + + redoAction.actionPerformed( null ); + assertEquals( 3, myCounter[ 0 ] ); + } + + public void testNonUndoableAction() throws Exception + { + myMessageAction.actionPerformed( null ); + + assertFalse( myCommandStack.canUndo() ); + + myCountdownAction.actionPerformed( null ); + myMessageAction.actionPerformed( null ); + + myCommandStack.undo(); + + assertFalse( myCommandStack.canUndo() ); + assertTrue( myCommandStack.canRedo() ); + } + + + public void testDisruptiveCommand() throws Exception + { + myCountdownAction.actionPerformed( null ); + myCountdownAction.actionPerformed( null ); + myCountdownAction.actionPerformed( null ); + + myCommandStack.undo(); + + assertTrue( myCommandStack.canUndo() ); + assertTrue( myCommandStack.canRedo() ); + + myKaboomAction.actionPerformed( null ); + + assertFalse( myCommandStack.canUndo() ); + assertFalse( myCommandStack.canRedo() ); + } + + //====================================================================== + // Protected Methods + + @Override + protected void setUp() throws Exception + { + myCounter = new int[]{ 4 }; + + myCommandStack = new CommandStackImpl(); + + myCountdownAction = new CommandAction( myCommandStack, "Countdown" ) + { + + private static final long serialVersionUID = 1L; + + @Override + protected Command createCommand() + { + final int oldValue = myCounter[ 0 ]; + final int newValue = myCounter[ 0 ] - 1; + + return new AbstractCommand( "Set counter to " + newValue, true ) + { + + public void doCommand() + { + myCounter[ 0 ] = newValue; + } + + + @Override + public void undoCommand() + { + myCounter[ 0 ] = oldValue; + } + + }; + } + + }; + + + myKaboomAction = new CommandAction( myCommandStack, "Kaboom" ) + { + + private static final long serialVersionUID = 1L; + + @Override + protected Command createCommand() + { + return new AbstractCommand( "Self Destructed", false, true ) + { + + public void doCommand() + { + myCounter[ 0 ] = -1; + } + + }; + } + + }; + + + myMessageAction = new CommandAction( myCommandStack, "Message" ) + { + + private static final long serialVersionUID = 1L; + + @Override + protected Command createCommand() + { + return new AbstractCommand( "Informative Message", false ) + { + + public void doCommand() + { + // println( "Self destruct sequence is ongoing, please evacuate" ); + } + + }; + } + + }; + } + +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.