/******************************************************************************* * Copyright 2013 See AUTHORS File * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package com.mobidevelop.utils.commands; import java.util.*; /** * The {@code CommandManager} class manages the execution and reversal of {@link Command Commands}. * * @author Justin Shapcott */ public class CommandManager { private Deque<Command> undoStack; private Deque<Command> redoStack; public CommandManager() { undoStack = new ArrayDeque<Command>(); redoStack = new ArrayDeque<Command>(); } /** * Executes the given {@link Command} and adds it to the undo stack. * * @param command The {@link Command} to execute. */ public void execute(Command command) { command.execute(); undoStack.push(command); redoStack.clear(); } /** * Reverses the last executed {@link Command}. * * @throws RuntimeException if the undo stack is empty. */ public void undo() { if (undoStack.isEmpty()) { throw new RuntimeException("No commands to undo."); } Command command = undoStack.pop(); command.reverse(); redoStack.push(command); } /** * Reverses all previously executed commands up to the given count. * * @throws RuntimeException if the undo stack is empty. */ public void undo(int count) { if (undoStack.isEmpty()) { throw new RuntimeException("No commands to undo."); } while (!undoStack.isEmpty() && count > 0) { Command command = undoStack.pop(); command.reverse(); redoStack.push(command); count--; } } /** * Reverses all previously executed commands up and including the given {@link Command}. * * @param command The {@link Command} to reverse to. * * @throws RuntimeException if the command in not in the undo stack. */ public void undoTo(Command command) { if (!undoStack.contains(command)) { throw new RuntimeException("Command is not in the undo stack."); } while (undoStack.peek() != command) { undo(); } undo(); } /** * Executes the last reversed {@link Command}. * * @throws RuntimeException if the redo stack is empty. */ public void redo() { if (redoStack.isEmpty()) { throw new RuntimeException("No commands to redo."); } Command command = redoStack.pop(); command.execute(); undoStack.push(command); } public void redo(int count) { if (redoStack.isEmpty()) { throw new RuntimeException("No commands to redo."); } while (!undoStack.isEmpty() && count > 0) { Command command = redoStack.pop(); command.execute(); undoStack.push(command); count--; } } /** * Executes all previously reversed commands up and including the given {@link Command}. * * @param command The {@link Command} to execute to. * * @throws RuntimeException if the command in not in the undo stack. */ public void redoTo(Command command) { if (!redoStack.contains(command)) { throw new RuntimeException("Command is not in the redo stack."); } while (redoStack.peek() != command) { redo(); } redo(); } /** * Whether or not there are any {@link Command Commands} that can be reversed. * * @return if are any commands that can be reversed. */ public boolean canUndo() { return undoStack.size() > 0; } /** * Whether or not there are any previously reversed {@link Command Commands} that can be executed. * @return if there are any previously reversed commands that executed. */ public boolean canRedo() { return redoStack.size() > 0; } }