/******************************************************************************* * Copyright (c) 2013 Arapiki Solutions Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * psmith - initial API and * implementation and/or initial documentation *******************************************************************************/ package com.buildml.model.undo; import com.buildml.model.IActionMgr; import com.buildml.model.IActionMgr.OperationType; import com.buildml.model.IBuildStore; import com.buildml.model.IPackageMemberMgr; /** * An undo/redo operation for any change that is made to an Action. This object records the * details of the changes necessary to the IBuildStore so they can be undone or redone later. * * @author Peter Smith <psmith@arapiki.com> */ public class ActionUndoOp implements IUndoOp { /*=====================================================================================* * FIELDS/TYPES *=====================================================================================*/ /** * Bitmap of all the parts of the action that have changed, and will need to be changed * back on an undo/redo operation. */ private final static int CHANGED_PACKAGE = 1; private final static int CHANGED_LOCATION = 2; private final static int CHANGED_SLOT = 4; private final static int REMOVED_SLOT = 8; private final static int MOVED_TO_TRASH = 16; private final static int NEW_ACTION = 32; private final static int CHANGED_PARENT = 64; private final static int ADD_PATH_ACCESS = 128; private final static int REMOVE_PATH_ACCESS = 256; /** The IBuildStore we're operating on */ private IBuildStore buildStore; /** The ID of the action being changed */ private int actionId; /** The fields of this operation that have changed - see above bitmap */ private int changedFields = 0; /** if CHANGED_PACKAGE set, what is the original package ID? */ private int oldPackage; /** if CHANGED_PACKAGE set, what is the new package ID? */ private int newPackage; /** if CHANGED_COMMAND set, what is the original command string? */ private String oldCommand; /** if CHANGED_COMMAND set, what is the new command string? */ private String newCommand; /** if CHANGED_LOCATION, what is the old (x, y) location */ private int oldX, oldY; /** if CHANGED_LOCATION, what is the new (x, y) location */ private int newX, newY; /** if CHANGED_SLOT | REMOVED_SLOT, what is the ID of the slot that's changing */ private int slotId; /** if CHANGED_SLOT | REMOVED_SLOT, what is the old value in the slot */ private Object oldSlotValue; /** if CHANGED_SLOT, what is the new value in the slot */ private Object newSlotValue; /** if CHANGED_PARENT, the old parent ID */ private int oldParentId; /** if CHANGED_PARENT, the new parent ID */ private int newParentId; /** if ADD_PATH_ACCESS | REMOVE_PATH_ACCESS what is the sequence number? */ private int accessSeqno; /** If ADD_PATH_ACCESS | REMOVE_PATH_ACCESS what is the ID of the path being accessed? */ private int accessPathId; /** If ADD_PATH_ACCESS | REMOVE_PATH_ACCESS what is the type of access? */ private OperationType accessOpType; /*=====================================================================================* * CONSTRUCTORS *=====================================================================================*/ /** * Create a new {@link ActionUndoOp} object, representing a single entry on the * undo/redo stack. * * @param buildStore The IBuildStore we're operating on. * @param actionId The actionMgr ID of the action being changed. */ public ActionUndoOp(IBuildStore buildStore, int actionId) { this.buildStore = buildStore; this.actionId = actionId; } /*=====================================================================================* * PUBLIC METHODS *=====================================================================================*/ /** * Records the fact that the action's package has changed. If there is no change in the * packageId, this method does nothing. * * @param prevPackageId The action's current package ID. * @param nextPackageId The action's future package ID. */ public void recordPackageChange(int prevPackageId, int nextPackageId) { if (prevPackageId != nextPackageId) { changedFields |= CHANGED_PACKAGE; oldPackage = prevPackageId; newPackage = nextPackageId; } } /*-------------------------------------------------------------------------------------*/ /** * Records the fact that the action's pictogram (icon) has been moved to a new location * on the diagram. * @param oldX The existing x location * @param oldY The existing y location * @param newX The new x location (must be >= 0) * @param newY The new y location (must be >= 0) */ public void recordLocationChange(int oldX, int oldY, int newX, int newY) { if ((oldX != newX) || (oldY != newY)) { changedFields |= CHANGED_LOCATION; this.oldX = oldX; this.oldY = oldY; this.newX = newX; this.newY = newY; } } /*-------------------------------------------------------------------------------------*/ /** * Records the fact that a file group has been inserted into an action's slot. * * @param slotId The slot being modified. * @param oldValue The current value in the slot. * @param newValue The new value in the slot. */ public void recordSlotChange(int slotId, Object oldValue, Object newValue) { if (((oldValue == null) && (newValue != null)) || (!oldValue.equals(newValue))) { changedFields |= CHANGED_SLOT; this.slotId = slotId; this.oldSlotValue = oldValue; this.newSlotValue = newValue; } } /*-------------------------------------------------------------------------------------*/ /** * Records the fact that a slot value has been deleted (will revert to default value). * * @param slotId The slot being deleted. * @param oldValue The current value in the slot. */ public void recordSlotRemove(int slotId, Object oldValue) { changedFields |= REMOVED_SLOT; this.slotId = slotId; this.oldSlotValue = oldValue; } /*-------------------------------------------------------------------------------------*/ /** * Records the fact that this action has been deleted */ public void recordMoveToTrash() { changedFields |= MOVED_TO_TRASH; } /*-------------------------------------------------------------------------------------*/ /** * Records the fact that this action has been deleted */ public void recordNewAction() { changedFields |= NEW_ACTION; } /*-------------------------------------------------------------------------------------*/ /** * Records a change to an action's parent. * @param oldParentId The action's current parent ID. * @param newParentId The action's new parent ID. */ public void recordParentChange(int oldParentId, int newParentId) { if (oldParentId != newParentId) { changedFields |= CHANGED_PARENT; this.oldParentId = oldParentId; this.newParentId = newParentId; } } /*-------------------------------------------------------------------------------------*/ /** * Record the removal of a file access for this action. * * @param seqno The sequence number of this access (to retain ordering). * @param pathId The path being accessed. * @param opType The type of access (OP_READ, OP_WRITE, etc). */ public void recordRemovePathAccess(int seqno, int pathId, OperationType opType) { changedFields |= REMOVE_PATH_ACCESS; this.accessSeqno = seqno; this.accessPathId = pathId; this.accessOpType = opType; } /*-------------------------------------------------------------------------------------*/ /** * Record the addition of a file access for this action. * * @param seqno The sequence number of this access (to retain ordering). * @param pathId The path being accessed. * @param opType The type of access (OP_READ, OP_WRITE, etc). */ public void recordAddPathAccess(int seqno, int pathId, OperationType opType) { changedFields |= ADD_PATH_ACCESS; this.accessSeqno = seqno; this.accessPathId = pathId; this.accessOpType = opType; } /*-------------------------------------------------------------------------------------*/ /* (non-Javadoc) * @see com.buildml.eclipse.utils.BmlAbstractOperation#undo() */ @Override public boolean undo() { IPackageMemberMgr pkgMemberMgr = buildStore.getPackageMemberMgr(); IActionMgr actionMgr = buildStore.getActionMgr(); /* if the action's package needs to change... */ if ((changedFields & CHANGED_PACKAGE) != 0) { pkgMemberMgr.setPackageOfMember(IPackageMemberMgr.TYPE_ACTION, actionId, oldPackage); } /* if the action's location needs to change... */ if ((changedFields & CHANGED_LOCATION) != 0){ pkgMemberMgr.setMemberLocation(IPackageMemberMgr.TYPE_ACTION, actionId, oldX, oldY); } /* if one of the action's slots needs to change... */ if ((changedFields & (CHANGED_SLOT | REMOVED_SLOT)) != 0){ actionMgr.setSlotValue(actionId, slotId, oldSlotValue); } /* if the action has been moved to the trash... */ if ((changedFields & MOVED_TO_TRASH) != 0) { actionMgr.reviveActionFromTrash(actionId); } /* if the action has been newly created */ if ((changedFields & NEW_ACTION) != 0) { actionMgr.moveActionToTrash(actionId); } /* if the action's parent has changed */ if ((changedFields & CHANGED_PARENT) != 0) { actionMgr.setParent(actionId, oldParentId); } /* if this action is now accessing a new path */ if ((changedFields & ADD_PATH_ACCESS) != 0) { actionMgr.removeFileAccess(actionId, accessPathId); } /* if this action is no longer accessing a path */ if ((changedFields & REMOVE_PATH_ACCESS) != 0) { actionMgr.addSequencedFileAccess(accessSeqno, actionId, accessPathId, accessOpType); } return (changedFields != 0); } /*-------------------------------------------------------------------------------------*/ /* (non-Javadoc) * @see com.buildml.eclipse.utils.BmlAbstractOperation#redo() */ @Override public boolean redo() { IPackageMemberMgr pkgMemberMgr = buildStore.getPackageMemberMgr(); IActionMgr actionMgr = buildStore.getActionMgr(); /* if the action's package needs to change... */ if ((changedFields & CHANGED_PACKAGE) != 0) { pkgMemberMgr.setPackageOfMember(IPackageMemberMgr.TYPE_ACTION, actionId, newPackage); } /* if the action's location needs to change... */ if ((changedFields & CHANGED_LOCATION) != 0){ pkgMemberMgr.setMemberLocation(IPackageMemberMgr.TYPE_ACTION, actionId, newX, newY); } /* if one of the action's slots needs to change... */ if ((changedFields & CHANGED_SLOT) != 0){ actionMgr.setSlotValue(actionId, slotId, newSlotValue); } /* if one of the action's slots needs to be deleted... */ if ((changedFields & REMOVED_SLOT) != 0){ actionMgr.clearSlotValue(actionId, slotId); } /* if the action has been moved to the trash... */ if ((changedFields & MOVED_TO_TRASH) != 0) { actionMgr.moveActionToTrash(actionId); } /* if the action has been newly created */ if ((changedFields & NEW_ACTION) != 0) { actionMgr.reviveActionFromTrash(actionId); } /* if the action's parent has changed */ if ((changedFields & CHANGED_PARENT) != 0) { actionMgr.setParent(actionId, newParentId); } /* if this action is now accessing a new path */ if ((changedFields & ADD_PATH_ACCESS) != 0) { actionMgr.addSequencedFileAccess(accessSeqno, actionId, accessPathId, accessOpType); } /* if this action is no longer accessing a new path */ if ((changedFields & REMOVE_PATH_ACCESS) != 0) { actionMgr.removeFileAccess(actionId, accessPathId); } return (changedFields != 0); } /*-------------------------------------------------------------------------------------*/ }