diff --git a/org.openmbee.mpspi/src/org/openmbee/mpspi/MPAdapter.java b/org.openmbee.mpspi/src/org/openmbee/mpspi/MPAdapter.java index 56eddf1..7f16f2e 100644 --- a/org.openmbee.mpspi/src/org/openmbee/mpspi/MPAdapter.java +++ b/org.openmbee.mpspi/src/org/openmbee/mpspi/MPAdapter.java @@ -62,19 +62,17 @@ public enum ReloadResult { NEED_REACTIVATE } + public enum DoResult implements UndoResult, RedoResult { + UNSUPPORTED, DONE, ERROR, NEED_REACTIVATE, EMPTY_STACK + } + /** * reload the model * @throws MPException */ ReloadResult reload() throws MPException; - - public enum UndoResult { - UNSUPPORTED, - DONE, - ERROR, - NEED_REACTIVATE, - EMPTY_STACK - } + + public interface UndoResult {} /** * reload the last modification @@ -87,6 +85,14 @@ public enum UndoResult { * */ void storeTransaction() throws MPException; + public interface RedoResult {} + + + /** + * Revert the last undo transaction + * */ + RedoResult redo() throws MPException; + /** * Return the resource that has been loaded. * diff --git a/org.openmbee.mpspi/src/org/openmbee/mpspi/exceptions/MPRedoException.java b/org.openmbee.mpspi/src/org/openmbee/mpspi/exceptions/MPRedoException.java new file mode 100644 index 0000000..b02615b --- /dev/null +++ b/org.openmbee.mpspi/src/org/openmbee/mpspi/exceptions/MPRedoException.java @@ -0,0 +1,24 @@ +/** + * + */ +package org.openmbee.mpspi.exceptions; + +/** + * @author mzeshan + * + */ +public class MPRedoException extends MPFatalException { + /** + * + */ + private static final long serialVersionUID = 6684692097946706048L; + + public MPRedoException(String message) { + super(message); + } + + public MPRedoException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/org.openmbee.mpspi/src/org/openmbee/mpspi/svc/MPBaseAdapter.java b/org.openmbee.mpspi/src/org/openmbee/mpspi/svc/MPBaseAdapter.java index 0ced61c..96a1090 100644 --- a/org.openmbee.mpspi/src/org/openmbee/mpspi/svc/MPBaseAdapter.java +++ b/org.openmbee.mpspi/src/org/openmbee/mpspi/svc/MPBaseAdapter.java @@ -14,6 +14,7 @@ import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.resource.Resource; import org.openmbee.mpspi.exceptions.MPException; +import org.openmbee.mpspi.exceptions.MPRedoException; import org.openmbee.mpspi.exceptions.MPUndoException; import org.openmbee.mpspi.exceptions.MPUnsupportedOperationException; import org.openmbee.mpspi.modifier.MPModifier; @@ -45,7 +46,7 @@ private boolean isTransactionEnabled() { protected void setTransaction(boolean flag) { if (flag) { - mpCommandLog = new ArrayList(); + mpCommandLog = new ArrayList(); undoCommandLog = new Stack>(); } else { mpCommandLog = null; @@ -97,28 +98,71 @@ protected void commit() throws MPException { for (MPCommand mpc : mpCommandLog) { mpc.execute(); } + redoStack.clear(); } + @SuppressWarnings({ "unchecked", "rawtypes" }) public UndoResult undo() throws MPException { if (undoLogs.isEmpty()) - return UndoResult.EMPTY_STACK; + return DoResult.EMPTY_STACK; try { Stack> undoLog = undoLogs.pop(); + Object redoObject = undoLog.clone(); while (!undoLog.isEmpty()) { List undo = undoLog.pop(); for (MPCommand mpCommand : undo) { mpCommand.undo(); } } - return UndoResult.DONE; + redoStack.add((Stack) redoObject); + return DoResult.DONE; } catch (Exception e) { // clear the undo stack and throw exception clearUndoStack(); - throw new MPUndoException("Unable to revert, Please reload the model without saving." , e); + throw new MPUndoException("Unable to revert, Please reload the model without saving.", e); } } + private Stack>> redoStack = new Stack>>();; + + @Override + public RedoResult redo() throws MPException { + if (redoStack.isEmpty()) + return DoResult.EMPTY_STACK; + try { + Stack> redoLog = redoStack.pop(); + Object tmp = redoLog.clone(); + Stack> undoObject = null; + if (tmp instanceof Stack) { + @SuppressWarnings("unchecked") + // This cast is safe as it keeps the same type used internally + Stack> tmp2 = (Stack>) tmp; + undoObject = tmp2; + } + + if (undoObject == null) + throw new IllegalStateException(); + + while (!redoLog.isEmpty()) { + List redo = redoLog.pop(); + for (MPCommand mpCommand : redo) { + mpCommand.execute(); + } + } + undoLogs.push(undoObject); + return DoResult.DONE; + } catch (Exception e) { + // clear the redo stack and throw exception + clearRedoStack(); + throw new MPRedoException("Unable to perform redo operation, Please reload the model without saving.", e); + } + } + + private void clearRedoStack() { + redoStack.clear(); + } + public void doSet(EObject target, EStructuralFeature feature, Object value, Object oldValue) { if (isTransactionEnabled()) { mpCommandLog.add(new MPCommand.Set(target, feature, value, oldValue, false)); @@ -263,12 +307,12 @@ public void removeByIdx(EObject eObj, EStructuralFeature feature, int index) thr public void set(EObject eObj, EStructuralFeature feature, Object value) throws MPException { MPModifier m = mpModifierMap.get(feature); if (m != null) { - Object oldValue = get(eObj, feature); + Object oldValue = get(eObj, feature); m.set(eObj, feature, value, oldValue); } else { if (MPUtil.isVirtual(feature)) return; - Object oldValue = get(eObj, feature); + Object oldValue = get(eObj, feature); doSet(eObj, feature, value, oldValue); } }