package org.enhydra.jawe; import java.util.ArrayList; import java.util.List; import java.util.Stack; import org.enhydra.jawe.base.controller.JaWEController; import org.enhydra.shark.xpdl.XMLCollection; import org.enhydra.shark.xpdl.XMLComplexChoice; import org.enhydra.shark.xpdl.XMLElement; public class UndoHistoryManagerImpl implements UndoHistoryManager { private static boolean isUndoOrRedoInProgress = false; private static Stack undo; private static Stack redo; private int max; private static JaWEController jc; public UndoHistoryManagerImpl() { undo = new Stack(); redo = new Stack(); jc = JaWEManager.getInstance().getJaWEController(); } public void init(int max) { this.max = max; } public void registerEvents(List xpdlInfoList, XPDLElementChangeInfo selectedEvent) { if (max <= 0) { return; } if (xpdlInfoList != null && xpdlInfoList.size() > 0) { freeStackSpace("undo"); List undoChangedList = new ArrayList(xpdlInfoList); //add selected event as last event in list undoChangedList.add(selectedEvent); undo.push(undoChangedList); redo.clear(); } } public void undo() { if (!undo.isEmpty()) { isUndoOrRedoInProgress = true; //Get last event and changed list from undo stack List undoChangedList = (List) undo.pop(); XPDLElementChangeInfo lastEvent = (XPDLElementChangeInfo) undoChangedList.remove(undoChangedList.size() - 1); //Put current event and the changed list to redo stack freeStackSpace("redo"); XPDLElementChangeInfo selectEventForRedo = jc.getCurrentSelectionEvent(); List redoChangedList = new ArrayList(undoChangedList); redoChangedList.add(selectEventForRedo); redo.push(redoChangedList); //revert the undo changed list undoChangedList = revertChangedList(undoChangedList); //Apply change for (Object obj : undoChangedList) { XPDLElementChangeInfo info = (XPDLElementChangeInfo) obj; changeModel(info); } isUndoOrRedoInProgress = false; updateJaWEController(lastEvent, undoChangedList, XPDLElementChangeInfo.UNDO); } } public void redo() { if (!redo.isEmpty()) { isUndoOrRedoInProgress = true; //Get last event and changed list from redo stack List redoChangedList = (List) redo.pop(); XPDLElementChangeInfo lastEvent = (XPDLElementChangeInfo) redoChangedList.remove(redoChangedList.size() - 1); //Put event and the changed list to undo stack freeStackSpace("undo"); XPDLElementChangeInfo selectEventForRedo = jc.getCurrentSelectionEvent(); List undoChangedList = new ArrayList(redoChangedList); undoChangedList.add(selectEventForRedo); undo.push(undoChangedList); //Apply change for (Object obj : redoChangedList) { XPDLElementChangeInfo info = (XPDLElementChangeInfo) obj; changeModel(info); } isUndoOrRedoInProgress = false; updateJaWEController(lastEvent, redoChangedList, XPDLElementChangeInfo.REDO); } } public boolean canUndo() { if (undo.isEmpty()) { return false; } else { return true; } } public boolean canRedo() { if (redo.isEmpty()) { return false; } else { return true; } } public boolean isUndoOrRedoInProgress() { return isUndoOrRedoInProgress; } public void cleanHistory() { undo.clear(); redo.clear(); } protected List revertChangedList(List lst) { List changed = new ArrayList(); for (int i = lst.size() - 1; i >= 0; i--) { XPDLElementChangeInfo ch = (XPDLElementChangeInfo) lst.get(i); XPDLElementChangeInfo chNew = new XPDLElementChangeInfo(jc, ch); if (chNew.getAction() == XPDLElementChangeInfo.INSERTED) { chNew.setAction(XPDLElementChangeInfo.REMOVED); } else if (chNew.getAction() == XPDLElementChangeInfo.REMOVED) { chNew.setAction(XPDLElementChangeInfo.INSERTED); } else if (chNew.getAction() == XPDLElementChangeInfo.UPDATED || chNew.getAction() == XPDLElementChangeInfo.REPOSITIONED) { chNew.setNewValue(ch.getOldValue()); chNew.setOldValue(ch.getNewValue()); } changed.add(chNew); } return changed; } protected void freeStackSpace(String type) { if (type.equals("undo")) { if (undo.size() >= max) { undo.remove(0); } } else { if (redo.size() >= max) { redo.remove(0); } } } protected void changeModel(XPDLElementChangeInfo info) { try { if (info.getAction() == XPDLElementChangeInfo.INSERTED) { if (info.getChangedElement() instanceof XMLCollection) { XMLCollection col = (XMLCollection) info.getChangedElement(); List lst = info.getChangedSubElements(); for (int i = 0; i < lst.size(); i++) { col.add((XMLElement) lst.get(i)); } } } else if (info.getAction() == XPDLElementChangeInfo.REMOVED) { if (info.getChangedElement() instanceof XMLCollection) { XMLCollection col = (XMLCollection) info.getChangedElement(); List lst = info.getChangedSubElements(); for (int i = 0; i < lst.size(); i++) { col.remove((XMLElement) lst.get(i)); } } } else if (info.getAction() == XPDLElementChangeInfo.UPDATED) { XMLElement el = info.getChangedElement(); if (el instanceof XMLComplexChoice) { ((XMLComplexChoice) el).setChoosen((XMLElement) info.getNewValue()); } else { el.setValue(info.getNewValue().toString()); } } else if (info.getAction() == XPDLElementChangeInfo.REPOSITIONED) { XMLCollection col = (XMLCollection) info.getChangedElement(); List lst = info.getChangedSubElements(); List newPositions = (List) info.getNewValue(); for (int i = 0; i < lst.size(); i++) { col.reposition((XMLElement) lst.get(i), ((Integer) newPositions.get(i)).intValue()); } } } catch (Exception e) { //ignore } } protected void updateJaWEController(XPDLElementChangeInfo lastEvent, List changedList, int action) { jc.setUpdateInProgress(true); XPDLElementChangeInfo ucInfo = jc.createInfo(jc.getMainPackage(), action); ucInfo.setChangedSubElements(changedList); jc.sendEvent(ucInfo); jc.setUpdateInProgress(false); if (lastEvent.getChangedSubElements().size() > 0) { jc.getSelectionManager().setSelection(lastEvent.getChangedSubElements(), true); } else { jc.getSelectionManager().setSelection(lastEvent.getChangedElement(), true); } } }