/** * Check the undo limit before adding an operation. Return a boolean indicating whether the undo * should proceed. */ private boolean checkUndoLimit(IUndoableOperation operation) { IUndoContext[] contexts = operation.getContexts(); for (int i = 0; i < contexts.length; i++) { int limit = getLimit(contexts[i]); if (limit > 0) { forceUndoLimit(contexts[i], limit - 1); } else { // this context has a 0 limit operation.removeContext(contexts[i]); } } return operation.getContexts().length > 0; }
@Override public void setLimit(IUndoContext context, int limit) { Assert.isTrue(limit >= 0); /* * The limit checking methods interpret a null context as a global limit * to be enforced. We do not wish to support a global limit in this * implementation, so we throw an exception for a null context. The rest * of the implementation can handle a null context, so subclasses can * override this if a global limit is desired. */ Assert.isNotNull(context); limits.put(context, new Integer(limit)); synchronized (undoRedoHistoryLock) { forceUndoLimit(context, limit); forceRedoLimit(context, limit); } }
@Override public void replaceOperation(IUndoableOperation operation, IUndoableOperation[] replacements) { // check the undo history first. boolean inUndo = false; synchronized (undoRedoHistoryLock) { int index = undoList.indexOf(operation); if (index > -1) { inUndo = true; undoList.remove(operation); // notify listeners after the lock on undoList is released ArrayList<IUndoContext> allContexts = new ArrayList<>(replacements.length); for (int i = 0; i < replacements.length; i++) { IUndoContext[] opContexts = replacements[i].getContexts(); for (int j = 0; j < opContexts.length; j++) { allContexts.add(opContexts[j]); } undoList.add(index, replacements[i]); // notify listeners after the lock on the history is // released } // recheck all the limits. We do this at the end so the index // doesn't change during replacement for (int i = 0; i < allContexts.size(); i++) { IUndoContext context = allContexts.get(i); forceUndoLimit(context, getLimit(context)); } } } if (inUndo) { // notify listeners of operations added and removed internalRemove(operation); for (int i = 0; i < replacements.length; i++) { notifyAdd(replacements[i]); } return; } // operation was not in the undo history. Check the redo history. synchronized (undoRedoHistoryLock) { int index = redoList.indexOf(operation); if (index == -1) { return; } ArrayList<IUndoContext> allContexts = new ArrayList<>(replacements.length); redoList.remove(operation); // notify listeners after we release the lock on redoList for (int i = 0; i < replacements.length; i++) { IUndoContext[] opContexts = replacements[i].getContexts(); for (int j = 0; j < opContexts.length; j++) { allContexts.add(opContexts[j]); } redoList.add(index, replacements[i]); // notify listeners after we release the lock on redoList } // recheck all the limits. We do this at the end so the index // doesn't change during replacement for (int i = 0; i < allContexts.size(); i++) { IUndoContext context = allContexts.get(i); forceRedoLimit(context, getLimit(context)); } } // send listener notifications after we release the lock on the history internalRemove(operation); for (int i = 0; i < replacements.length; i++) { notifyAdd(replacements[i]); } }