@Override public void add(IUndoableOperation operation) { Assert.isNotNull(operation); /* * If we are in the middle of executing an open batching operation, and * this is not that operation, then we need only add the context of the * new operation to the batch. The operation itself is disposed since we * will never undo or redo it. We consider it to be triggered by the * batching operation and assume that its undo will be triggered by the * batching operation undo. */ synchronized (openCompositeLock) { if (openComposite != null && openComposite != operation) { openComposite.add(operation); return; } } if (checkUndoLimit(operation)) { synchronized (undoRedoHistoryLock) { undoList.add(operation); } notifyAdd(operation); // flush redo stack for related contexts IUndoContext[] contexts = operation.getContexts(); for (int i = 0; i < contexts.length; i++) { flushRedo(contexts[i]); } } else { // Dispose the operation since we will not have a reference to it. operation.dispose(); } }
/** * Perform the redo. All validity checks have already occurred. * * @param monitor * @param operation */ private IStatus doRedo(IProgressMonitor monitor, IAdaptable info, IUndoableOperation operation) throws ExecutionException { IStatus status = getRedoApproval(operation, info); if (status.isOK()) { notifyAboutToRedo(operation); try { status = operation.redo(monitor, info); } catch (OperationCanceledException e) { status = Status.CANCEL_STATUS; } catch (ExecutionException e) { notifyNotOK(operation); if (DEBUG_OPERATION_HISTORY_UNEXPECTED) { Tracing.printTrace( "OPERATIONHISTORY", //$NON-NLS-1$ "ExecutionException while redoing " + operation); // $NON-NLS-1$ } throw e; } catch (Exception e) { notifyNotOK(operation); if (DEBUG_OPERATION_HISTORY_UNEXPECTED) { Tracing.printTrace( "OPERATIONHISTORY", //$NON-NLS-1$ "Exception while redoing " + operation); // $NON-NLS-1$ } throw new ExecutionException( "While redoing the operation, an exception occurred", e); // $NON-NLS-1$ } } // if successful, the operation is removed from the redo history and // placed back in the undo history. if (status.isOK()) { boolean addedToUndo = true; synchronized (undoRedoHistoryLock) { redoList.remove(operation); if (checkUndoLimit(operation)) { undoList.add(operation); } else { addedToUndo = false; } } // dispose the operation since we could not add it to the // stack and will no longer have a reference to it. if (!addedToUndo) { operation.dispose(); } // notify listeners must happen after history is updated notifyRedone(operation); } else { notifyNotOK(operation, status); } return status; }
/* * Remove the operation by disposing it and notifying listeners. */ private void internalRemove(IUndoableOperation operation) { operation.dispose(); notifyRemoved(operation); }
@Override public IStatus execute(IUndoableOperation operation, IProgressMonitor monitor, IAdaptable info) throws ExecutionException { Assert.isNotNull(operation); // error if operation is invalid if (!operation.canExecute()) { return IOperationHistory.OPERATION_INVALID_STATUS; } // check with the operation approvers IStatus status = getExecuteApproval(operation, info); if (!status.isOK()) { // not approved. No notifications are sent, just return the status. return status; } /* * If we are in the middle of an open composite, then we will add this * operation to the open operation rather than add the operation to the * history. We will still execute it. */ boolean merging = false; synchronized (openCompositeLock) { if (openComposite != null) { // the composite shouldn't be executed explicitly while it is // still // open if (openComposite == operation) { return IOperationHistory.OPERATION_INVALID_STATUS; } openComposite.add(operation); merging = true; } } /* * Execute the operation */ if (!merging) { notifyAboutToExecute(operation); } try { status = operation.execute(monitor, info); } catch (OperationCanceledException e) { status = Status.CANCEL_STATUS; } catch (ExecutionException e) { notifyNotOK(operation); throw e; } catch (Exception e) { notifyNotOK(operation); throw new ExecutionException( "While executing the operation, an exception occurred", e); // $NON-NLS-1$ } // if successful, the notify listeners are notified and the operation is // added to the history if (!merging) { if (status.isOK()) { notifyDone(operation); add(operation); } else { notifyNotOK(operation, status); // dispose the operation since we did not add it to the stack // and will no longer have a reference to it. operation.dispose(); } } // all other severities are not interpreted. Simply return the status. return status; }