| /* |
| |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You 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 org.apache.batik.apps.svgbrowser; |
| |
| import java.util.ArrayList; |
| import java.util.EventListener; |
| import java.util.EventObject; |
| |
| import javax.swing.event.EventListenerList; |
| |
| /** |
| * History browser. Manages perform of execute, undo and redo actions. |
| */ |
| public class HistoryBrowser { |
| |
| // The history browser states. Show whether the history browser is busy |
| // performing execute, undo or redo, or whether is idle. |
| /** |
| * The history browser is executing the command(s). |
| */ |
| public static final int EXECUTING = 1; |
| |
| /** |
| * The history browser is undoing the command(s). |
| */ |
| public static final int UNDOING = 2; |
| |
| /** |
| * The history browser is redoing the command(s). |
| */ |
| public static final int REDOING = 3; |
| |
| /** |
| * The history browser is in idle state - no command is being executed, |
| * undone or redone. |
| */ |
| public static final int IDLE = 4; |
| |
| /** |
| * Listeners list. |
| */ |
| protected EventListenerList eventListeners = |
| new EventListenerList(); |
| |
| /** |
| * Command history. |
| */ |
| protected ArrayList history; |
| |
| /** |
| * Current command pointer in history array. |
| */ |
| protected int currentCommandIndex = -1; |
| |
| /** |
| * History size. |
| */ |
| protected int historySize = 1000; |
| |
| /** |
| * The current state of the history browser. |
| */ |
| protected int state = IDLE; |
| |
| /** |
| * Tells the history browser how to execute, undo and redo the commands. |
| * Wraps the execute, undo and redo methods |
| */ |
| protected CommandController commandController; |
| |
| /** |
| * Constructor. |
| */ |
| public HistoryBrowser(CommandController commandController) { |
| this.history = new ArrayList(); |
| this.commandController = commandController; |
| } |
| |
| /** |
| * Constructor. |
| * @param historySize History size |
| */ |
| public HistoryBrowser(int historySize) { |
| this.history = new ArrayList(); |
| setHistorySize(historySize); |
| } |
| |
| /** |
| * Setter for the history size. |
| * |
| * @param size |
| * New history size |
| */ |
| protected void setHistorySize(int size) { |
| historySize = size; |
| } |
| |
| /** |
| * Sets the commandController. |
| * |
| * @param newCommandController |
| * The newCommandController to set |
| */ |
| public void setCommandController(CommandController newCommandController) { |
| this.commandController = newCommandController; |
| } |
| |
| /** |
| * Adds the given command to history array and executes it. |
| * |
| * @param command |
| * The given command |
| */ |
| public void addCommand(UndoableCommand command) { |
| // When the command is added to history array, the commands from the |
| // current position to the end of the list are removed from history |
| int n = history.size(); |
| for (int i = n - 1; i > currentCommandIndex; i--) { |
| history.remove(i); |
| } |
| // Executes the command |
| if (commandController != null) { |
| commandController.execute(command); |
| } else { |
| state = EXECUTING; |
| command.execute(); |
| state = IDLE; |
| } |
| // Adds it to the history array |
| history.add(command); |
| |
| // Updates the pointer to the current command |
| currentCommandIndex = history.size() - 1; |
| if (currentCommandIndex >= historySize) { |
| history.remove(0); |
| currentCommandIndex--; |
| } |
| fireExecutePerformed(new HistoryBrowserEvent(new CommandNamesInfo( |
| command.getName(), getLastUndoableCommandName(), |
| getLastRedoableCommandName()))); |
| } |
| |
| /** |
| * Undoes the last executed or 'redone' command. |
| */ |
| public void undo() { |
| // If history is empty, or the current command index is out of bounds |
| if (history.isEmpty() || currentCommandIndex < 0) { |
| return; |
| } |
| // Gets the command and performs undo |
| UndoableCommand command = (UndoableCommand) history |
| .get(currentCommandIndex); |
| if (commandController != null) { |
| commandController.undo(command); |
| } else { |
| state = UNDOING; |
| command.undo(); |
| state = IDLE; |
| } |
| // Updates the current command index |
| currentCommandIndex--; |
| fireUndoPerformed(new HistoryBrowserEvent(new CommandNamesInfo(command |
| .getName(), getLastUndoableCommandName(), |
| getLastRedoableCommandName()))); |
| } |
| |
| /** |
| * Redoes the last 'undone' command. |
| */ |
| public void redo() { |
| // If history is empty, or the current command index is out of bounds |
| if (history.isEmpty() || currentCommandIndex == history.size() - 1) { |
| return; |
| } |
| // Increases the current command index and redoes the command |
| UndoableCommand command = (UndoableCommand) history |
| .get(++currentCommandIndex); |
| if (commandController != null) { |
| commandController.redo(command); |
| } else { |
| state = REDOING; |
| command.redo(); |
| state = IDLE; |
| } |
| fireRedoPerformed(new HistoryBrowserEvent(new CommandNamesInfo(command |
| .getName(), getLastUndoableCommandName(), |
| getLastRedoableCommandName()))); |
| } |
| |
| /** |
| * Performs undo action the given number of times. |
| * |
| * @param undoNumber |
| * The given number of undo actions to perform |
| */ |
| public void compoundUndo(int undoNumber) { |
| for (int i = 0; i < undoNumber; i++) { |
| undo(); |
| } |
| } |
| |
| /** |
| * Performs redo action the given number of times. |
| * |
| * @param redoNumber |
| * The given number of redo actions to perform |
| */ |
| public void compoundRedo(int redoNumber) { |
| for (int i = 0; i < redoNumber; i++) { |
| redo(); |
| } |
| } |
| |
| /** |
| * Gets the last undoable command name. |
| * |
| * @return String or "" if there's no any |
| */ |
| public String getLastUndoableCommandName() { |
| if (history.isEmpty() || currentCommandIndex < 0) { |
| return ""; |
| } |
| return ((UndoableCommand) history.get(currentCommandIndex)).getName(); |
| } |
| |
| /** |
| * Gets the last redoable command name. |
| * |
| * @return String or "" if there's no any |
| */ |
| public String getLastRedoableCommandName() { |
| if (history.isEmpty() || currentCommandIndex == history.size() - 1) { |
| return ""; |
| } |
| return ((UndoableCommand) history.get(currentCommandIndex + 1)) |
| .getName(); |
| } |
| |
| /** |
| * Clears the history array. |
| */ |
| public void resetHistory() { |
| history.clear(); |
| currentCommandIndex = -1; |
| fireHistoryReset(new HistoryBrowserEvent(new Object())); |
| } |
| |
| /** |
| * Gets the state of this history browser. |
| * |
| * @return the state |
| */ |
| public int getState() { |
| if (commandController != null) { |
| return commandController.getState(); |
| } else { |
| return state; |
| } |
| } |
| |
| // Custom event support |
| |
| /** |
| * Event to pass to listener. |
| */ |
| public static class HistoryBrowserEvent extends EventObject { |
| |
| /** |
| * @param source |
| */ |
| public HistoryBrowserEvent(Object source) { |
| super(source); |
| } |
| } |
| |
| /** |
| * The HistoryBrowserListener. |
| */ |
| public static interface HistoryBrowserListener extends EventListener { |
| |
| /** |
| * The command has been executed. |
| */ |
| void executePerformed(HistoryBrowserEvent event); |
| |
| /** |
| * The undo has been performed on the command. |
| */ |
| void undoPerformed(HistoryBrowserEvent event); |
| |
| /** |
| * The redo has been performed on the command. |
| */ |
| void redoPerformed(HistoryBrowserEvent event); |
| |
| /** |
| * History has been reset, and all commands have been removed from the |
| * history. |
| */ |
| void historyReset(HistoryBrowserEvent event); |
| |
| /** |
| * The the atom command that should be wrapped with the compound command |
| * has been executed. |
| */ |
| void doCompoundEdit(HistoryBrowserEvent event); |
| |
| /** |
| * The compound command has been made from the atom commands that were |
| * executed and should be wrapped. |
| */ |
| void compoundEditPerformed(HistoryBrowserEvent event); |
| } |
| |
| /** |
| * The adapter to provide the default behavior. |
| */ |
| public static class HistoryBrowserAdapter implements HistoryBrowserListener { |
| |
| public void executePerformed(HistoryBrowserEvent event) { |
| } |
| |
| public void undoPerformed(HistoryBrowserEvent event) { |
| } |
| |
| public void redoPerformed(HistoryBrowserEvent event) { |
| } |
| |
| public void historyReset(HistoryBrowserEvent event) { |
| } |
| |
| public void compoundEditPerformed(HistoryBrowserEvent event) { |
| } |
| |
| public void doCompoundEdit(HistoryBrowserEvent event) { |
| } |
| } |
| |
| /** |
| * Adds the listener to the listener list. |
| * |
| * @param listener |
| * The listener to add |
| */ |
| public void addListener(HistoryBrowserListener listener) { |
| eventListeners.add(HistoryBrowserListener.class, listener); |
| } |
| |
| /** |
| * Fires the executePerformed event. |
| * |
| * @param event |
| * The associated HistoryBrowserEvent event |
| */ |
| public void fireExecutePerformed(HistoryBrowserEvent event) { |
| Object[] listeners = eventListeners.getListenerList(); |
| int length = listeners.length; |
| for (int i = 0; i < length; i += 2) { |
| if (listeners[i] == HistoryBrowserListener.class) { |
| ((HistoryBrowserListener) listeners[i + 1]) |
| .executePerformed(event); |
| } |
| } |
| } |
| |
| /** |
| * Fires the undoPerformed event. |
| * |
| * @param event |
| * The associated HistoryBrowserEvent event |
| */ |
| public void fireUndoPerformed(HistoryBrowserEvent event) { |
| Object[] listeners = eventListeners.getListenerList(); |
| int length = listeners.length; |
| for (int i = 0; i < length; i += 2) { |
| if (listeners[i] == HistoryBrowserListener.class) { |
| ((HistoryBrowserListener) listeners[i + 1]) |
| .undoPerformed(event); |
| } |
| } |
| } |
| |
| /** |
| * Fires the redoPerformed event. |
| * |
| * @param event |
| * The associated HistoryBrowserEvent event |
| */ |
| public void fireRedoPerformed(HistoryBrowserEvent event) { |
| Object[] listeners = eventListeners.getListenerList(); |
| int length = listeners.length; |
| for (int i = 0; i < length; i += 2) { |
| if (listeners[i] == HistoryBrowserListener.class) { |
| ((HistoryBrowserListener) listeners[i + 1]) |
| .redoPerformed(event); |
| } |
| } |
| } |
| |
| /** |
| * Fires the historyReset event. |
| * |
| * @param event |
| * The associated HistoryBrowserEvent event |
| */ |
| public void fireHistoryReset(HistoryBrowserEvent event) { |
| Object[] listeners = eventListeners.getListenerList(); |
| int length = listeners.length; |
| for (int i = 0; i < length; i += 2) { |
| if (listeners[i] == HistoryBrowserListener.class) { |
| ((HistoryBrowserListener) listeners[i + 1]) |
| .historyReset(event); |
| } |
| } |
| } |
| |
| /** |
| * Fires the doCompoundEdit event. |
| * |
| * @param event |
| * The associated HistoryBrowserEvent event |
| */ |
| public void fireDoCompoundEdit(HistoryBrowserEvent event) { |
| Object[] listeners = eventListeners.getListenerList(); |
| int length = listeners.length; |
| for (int i = 0; i < length; i += 2) { |
| if (listeners[i] == HistoryBrowserListener.class) { |
| ((HistoryBrowserListener) listeners[i + 1]) |
| .doCompoundEdit(event); |
| } |
| } |
| } |
| |
| /** |
| * Fires the compoundEditPerformed event. |
| * |
| * @param event |
| * The associated HistoryBrowserEvent event |
| */ |
| public void fireCompoundEditPerformed(HistoryBrowserEvent event) { |
| Object[] listeners = eventListeners.getListenerList(); |
| int length = listeners.length; |
| for (int i = 0; i < length; i += 2) { |
| if (listeners[i] == HistoryBrowserListener.class) { |
| ((HistoryBrowserListener) listeners[i + 1]) |
| .compoundEditPerformed(event); |
| } |
| } |
| } |
| |
| /** |
| * Contains the info on the command name being executed, undone or redone and |
| * last undoable and redoable command names. |
| */ |
| public static class CommandNamesInfo { |
| |
| /** |
| * The name of the last undoable command in the history. |
| */ |
| private String lastUndoableCommandName; |
| |
| /** |
| * The name of the last redoable command in the history. |
| */ |
| private String lastRedoableCommandName; |
| |
| /** |
| * The command name being executed, undone or redone. |
| */ |
| private String commandName; |
| |
| /** |
| * Constructor. |
| * |
| * @param commandName |
| * The current command name being executed/undone/redone |
| * @param lastUndoableCommandName |
| * The last undoable command name |
| * @param lastRedoableCommandName |
| * The last redoable command name |
| */ |
| public CommandNamesInfo(String commandName, |
| String lastUndoableCommandName, |
| String lastRedoableCommandName) { |
| this.lastUndoableCommandName = lastUndoableCommandName; |
| this.lastRedoableCommandName = lastRedoableCommandName; |
| this.commandName = commandName; |
| } |
| |
| /** |
| * Gets the name of the last undoable command. |
| * |
| * @return the lastUndoableCommandName |
| */ |
| public String getLastRedoableCommandName() { |
| return lastRedoableCommandName; |
| } |
| |
| /** |
| * Gets the name of the last redoable command. |
| * |
| * @return the lastRedoableCommandName |
| */ |
| public String getLastUndoableCommandName() { |
| return lastUndoableCommandName; |
| } |
| |
| /** |
| * Gets the command name. |
| * |
| * @return the command name |
| */ |
| public String getCommandName() { |
| return commandName; |
| } |
| } |
| |
| /** |
| * Wrapps the command's execute, undo and redo methods. |
| */ |
| public static interface CommandController { |
| |
| /** |
| * Wrapps the execute method. |
| */ |
| void execute(UndoableCommand command); |
| |
| /** |
| * Wrapps the undo method. |
| */ |
| void undo(UndoableCommand command); |
| |
| /** |
| * Wrapps the redo method. |
| */ |
| void redo(UndoableCommand command); |
| |
| /** |
| * Gets the state of the command controller. |
| * @return HistoryBrowserState |
| */ |
| int getState(); |
| } |
| |
| /** |
| * Lets the DOMViewerController wrap the commands. |
| */ |
| public static class DocumentCommandController implements CommandController { |
| |
| /** |
| * The DOMViewerController. |
| */ |
| protected DOMViewerController controller; |
| |
| /** |
| * The current state of the command controller. |
| */ |
| protected int state = HistoryBrowser.IDLE; |
| |
| /** |
| * The constructor. |
| * |
| * @param controller |
| * The DOMViewerController |
| */ |
| public DocumentCommandController(DOMViewerController controller) { |
| this.controller = controller; |
| } |
| |
| public void execute(final UndoableCommand command) { |
| Runnable r = new Runnable() { |
| public void run() { |
| state = HistoryBrowser.EXECUTING; |
| command.execute(); |
| state = HistoryBrowser.IDLE; |
| } |
| }; |
| controller.performUpdate(r); |
| } |
| |
| public void undo(final UndoableCommand command) { |
| Runnable r = new Runnable() { |
| public void run() { |
| state = HistoryBrowser.UNDOING; |
| command.undo(); |
| state = HistoryBrowser.IDLE; |
| } |
| }; |
| controller.performUpdate(r); |
| } |
| |
| public void redo(final UndoableCommand command) { |
| Runnable r = new Runnable() { |
| public void run() { |
| state = HistoryBrowser.REDOING; |
| command.redo(); |
| state = HistoryBrowser.IDLE; |
| } |
| }; |
| controller.performUpdate(r); |
| } |
| |
| public int getState() { |
| return state; |
| } |
| } |
| } |