/* JWildfire - an image and animation processor written in Java Copyright (C) 1995-2012 Andreas Maschke This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this software; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jwildfire.create.tina.edit; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class UndoManager<T extends Assignable<T>> { private final Map<T, List<UndoItem<T>>> undoStack = new HashMap<T, List<UndoItem<T>>>(); private final Map<T, Integer> undoStackPosition = new HashMap<T, Integer>(); private boolean enabled = true; public void initUndoStack(T pInitialState) { if (undoStack.get(pInitialState) == null) { List<UndoItem<T>> items = new ArrayList<UndoItem<T>>(); items.add(new UndoItem<T>(pInitialState.makeCopy())); undoStack.put(pInitialState, items); undoStackPosition.put(pInitialState, 0); } } private List<UndoItem<T>> getUndoStack(T pInitialState) { List<UndoItem<T>> items = undoStack.get(pInitialState); if (items == null) throw new RuntimeException("initUndoStack was not called"); return items; } public Integer getUndoStackPosition(T pInitialState) { Integer pos = undoStackPosition.get(pInitialState); if (pos == null) throw new RuntimeException("initUndoStack was not called"); return pos; } public Integer getUndoStackSize(T pInitialState) { List<UndoItem<T>> items = undoStack.get(pInitialState); return items != null ? items.size() : 0; } public void saveUndoPoint(T pState) { if (enabled) { List<UndoItem<T>> stack = getUndoStack(pState); Integer pos = getUndoStackPosition(pState); UndoItem<T> prevState = stack.get(pos); if (!prevState.getData().isEqual(pState)) { UndoItem<T> currState = new UndoItem<T>(pState.makeCopy()); stack.add(currState); undoStackPosition.put(pState, stack.size() - 1); } } } public void undo(T pInitialState) { List<UndoItem<T>> stack = getUndoStack(pInitialState); if (stack.size() > 0) { Integer pos = getUndoStackPosition(pInitialState); if (pos == stack.size() - 1) { UndoItem<T> prevState = stack.get(stack.size() - 1); if (!prevState.getData().isEqual(pInitialState)) { UndoItem<T> currState = new UndoItem<T>(pInitialState.makeCopy()); stack.add(currState); } else { pos--; } } else { pos--; } undoStackPosition.put(pInitialState, pos); if (pos >= 0 && pos < stack.size()) { pInitialState.assign(stack.get(pos).getData()); } } } public void redo(T pInitialState) { List<UndoItem<T>> stack = getUndoStack(pInitialState); Integer pos = getUndoStackPosition(pInitialState); pos++; undoStackPosition.put(pInitialState, pos); if (pos >= 0 && pos < stack.size()) { pInitialState.assign(stack.get(pos).getData()); } } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } }