blob: d6178b3866d3e2c1a67fd4d4ac09d5f213bf5940 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.core.commands.operations;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.internal.commands.operations.GlobalUndoContext;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
/**
* <p>
* IOperationHistory tracks a history of operations that can be undone or
* redone. Operations are added to the history once they have been initially
* executed. Clients may choose whether to have the operations history perform
* the initial execution or to simply add an already-executed operation to the
* history.
* </p>
* <p>
* Once operations are added to the history, the methods
* {@link #canRedo(IUndoContext)} and {@link #canUndo(IUndoContext)} are used to
* determine whether there is an operation available for undo and redo in a
* given undo context. The context-based protocol implies that there is only one
* operation that can be undone or redone at a given time in a given context.
* This is typical of a linear undo model, when only the most recently executed
* operation is available for undo. When this protocol is used, a linear model
* is enforced by the history.
* </p>
* <p>
* It is up to clients to determine how to maintain a history that is invalid or
* stale. For example, when the most recent operation for a context cannot be
* performed, clients may wish to dispose the history for that context.
* </p>
* <p>
* Additional protocol allows direct undo and redo of a specified operation,
* regardless of its position in the history. When a more flexible undo model is
* supported, these methods can be implemented to undo and redo directly
* specified operations. If an implementer of IOperationHistory does not allow
* direct undo and redo, these methods can return a status indicating that it is
* not allowed.
* </p>
* <p>
* Listeners ({@link IOperationHistoryListener}) can listen for notifications
* about changes in the history (operations added or removed), and for
* notification before and after any operation is executed, undone or redone.
* Notification of operation execution only occurs when clients direct the
* history to execute the operation. If the operation is added after it is
* executed, there can be no notification of its execution.
* </p>
* <p>
* {@link IOperationApprover} defines an interface for approving an undo or redo
* before it occurs. This is useful for injecting policy-decisions into the undo
* model - whether direct undo and redo are supported, or warning the user about
* certain kinds of operations. It can also be used when clients maintain state
* related to an operation and need to determine whether an undo or redo will
* cause any conflicts with their local state.
* </p>
*
* @since 3.1
*/
public interface IOperationHistory {
/**
* An operation is to be opened or closed for execution. (value is 1).
*/
public static final int EXECUTE = 1;
/**
* An operation is to be opened for undo. (value is 2).
*/
public static final int UNDO = 2;
/**
* An operation is to be opened for redo. (value is 3).
*/
public static final int REDO = 3;
/**
* An undo context that can be used to refer to the global undo history.
* This context is not intended to be assigned to operations. Instead, it is
* used for querying the history or performing an undo or redo on the entire
* history, regardless of each operation's undo contexts.
*/
public static final IUndoContext GLOBAL_UNDO_CONTEXT = new GlobalUndoContext();
/**
* An operation info status describing the condition that there is no
* available operation for redo.
*/
public static final IStatus NOTHING_TO_REDO_STATUS = new OperationStatus(
IStatus.INFO, OperationStatus.DEFAULT_PLUGIN_ID,
OperationStatus.NOTHING_TO_REDO, "No operation to redo", null); //$NON-NLS-1$
/**
* An operation info status describing the condition that there is no
* available operation for undo.
*/
public static final IStatus NOTHING_TO_UNDO_STATUS = new OperationStatus(
IStatus.INFO, OperationStatus.DEFAULT_PLUGIN_ID,
OperationStatus.NOTHING_TO_UNDO, "No operation to undo", null); //$NON-NLS-1$
/**
* An operation error status describing the condition that the operation
* available for execution, undo or redo is not in a valid state for the
* action to be performed.
*/
public static final IStatus OPERATION_INVALID_STATUS = new OperationStatus(
IStatus.ERROR, OperationStatus.DEFAULT_PLUGIN_ID,
OperationStatus.OPERATION_INVALID, "Operation is not valid", null); //$NON-NLS-1$
/**
* <p>
* Add the specified operation to the history without executing it. The
* operation should have already been executed by the time it is added to
* the history. Listeners will be notified that the operation was added to
* the history (<code>OPERATION_ADDED</code>).
* </p>
*
* @param operation
* the operation to be added to the history
*/
void add(IUndoableOperation operation);
/**
* <p>
* Add the specified approver to the list of operation approvers consulted
* by the operation history before an undo or redo is allowed to proceed.
* </p>
*
* @param approver
* the IOperationApprover to be added as an approver.the instance
* to remove. Must not be <code>null</code>. If an attempt is
* made to register an instance which is already registered with
* this instance, this method has no effect.
*
* @see org.eclipse.core.commands.operations.IOperationApprover
*/
void addOperationApprover(IOperationApprover approver);
/**
* <p>
* Add the specified listener to the list of operation history listeners
* that are notified about changes in the history or operations that are
* executed, undone, or redone.
* </p>
*
* @param listener
* the IOperationHistoryListener to be added as a listener. Must
* not be <code>null</code>. If an attempt is made to register
* an instance which is already registered with this instance, this
* method has no effect.
*
* @see org.eclipse.core.commands.operations.IOperationHistoryListener
* @see org.eclipse.core.commands.operations.OperationHistoryEvent
*/
void addOperationHistoryListener(IOperationHistoryListener listener);
/**
* <p>
* Close the current operation. If the operation has successfully completed,
* send listeners a <code>DONE</code>, <code>UNDONE</code>, or
* <code>REDONE</code> notification, depending on the mode. Otherwise send
* an <code>OPERATION_NOT_OK</code> notification. Add the operation to the
* history if specified and send an <code>OPERATION_ADDED</code>
* notification.
* </p>
* <p>
* Any operations that are executed and added after this operation is closed
* will no longer be considered part of this operation.
* </p>
* <p>
* This method has no effect if the caller has not previously called
* {@link #openOperation}.
* </p>
*
* @param operationOK
* <code>true</code> if the operation successfully completed.
* Listeners should be notified with <code>DONE</code>,
* <code>UNDONE</code>, or <code>REDONE</code>.
* <code>false</code> if the operation did not successfully
* complete. Listeners should be notified with
* <code>OPERATION_NOT_OK</code>.
* @param addToHistory
* <code>true</code> if the operation should be added to the
* history, <code>false</code> if it should not. If the
* <code>operationOK</code> parameter is <code>false</code>,
* the operation will never be added to the history.
* @param mode
* the mode the operation was opened in. Can be one of
* <code>EXECUTE</code>, <code>UNDO</code>, or
* <code>REDO</code>. This determines what notifications are
* sent.
*/
void closeOperation(boolean operationOK, boolean addToHistory, int mode);
/**
* <p>
* Return whether there is a valid redoable operation available in the given
* context.
* </p>
*
* @param context
* the context to be checked
* @return <code>true</code> if there is a redoable operation,
* <code>false</code> otherwise.
*/
boolean canRedo(IUndoContext context);
/**
* <p>
* Return whether there is a valid undoable operation available in the given
* context
* </p>
*
* @param context
* the context to be checked
* @return <code>true</code> if there is an undoable operation,
* <code>false</code> otherwise.
*/
boolean canUndo(IUndoContext context);
/**
* <p>
* Dispose of the specified context in the history. All operations that have
* only the given context will be disposed. References to the context in
* operations that have more than one context will also be removed. A
* history notification for the removal of each operation being disposed
* will be sent.
* </p>
*
* @param context
* the context to be disposed
* @param flushUndo
* <code>true</code> if the context should be flushed from the
* undo history, <code>false</code> if it should not
* @param flushRedo
* <code>true</code> if the context should be flushed from the
* redo history, <code>false</code> if it should not.
* @param flushContext
* <code>true</code> if the context is no longer in use and
* references to it should be flushed.
*/
void dispose(IUndoContext context, boolean flushUndo, boolean flushRedo,
boolean flushContext);
/**
* <p>
* Execute the specified operation and add it to the operations history if
* successful. This method is used by clients who wish operation history
* listeners to receive notifications before and after the execution of the
* operation. Listeners will be notified before (
* <code>ABOUT_TO_EXECUTE</code>) and after (<code>DONE</code> or
* <code>OPERATION_NOT_OK</code>).
* </p>
* <p>
* If the operation successfully executes, an additional notification that
* the operation has been added to the history (<code>OPERATION_ADDED</code>)
* will be sent.
* </p>
*
* @param operation
* the operation to be executed and then added to the history
*
* @param monitor
* the progress monitor to be used (or <code>null</code>)
* during the operation.
*
* @param info
* the IAdaptable (or <code>null</code>) provided by the
* caller in order to supply UI information for prompting the
* user if necessary. When this parameter is not
* <code>null</code>, it should minimally contain an adapter
* for the org.eclipse.swt.widgets.Shell.class.
*
* @return the IStatus indicating whether the execution succeeded.
*
* <p>
* The severity code in the returned status describes whether the operation
* succeeded and whether it was added to the history. <code>OK</code>
* severity indicates that the execute operation was successful and that the
* operation has been added to the history. Listeners will receive
* notifications about the operation's success (<code>DONE</code>) and
* about the operation being added to the history (<code>OPERATION_ADDED</code>).
* </p>
* <p>
* <code>CANCEL</code> severity indicates that the user cancelled the
* operation and that the operation was not added to the history.
* <code>ERROR</code> severity indicates that the operation did not
* successfully execute and that it was not added to the history. Any other
* severity code is not specifically interpreted by the history, and the
* operation will not be added to the history. For all severities other than
* <code>OK</code>, listeners will receive the
* <code>OPERATION_NOT_OK</code> notification instead of the
* <code>DONE</code> notification.
* </p>
*
* @throws ExecutionException
* if an exception occurred during execution.
*
*/
IStatus execute(IUndoableOperation operation, IProgressMonitor monitor,
IAdaptable info) throws ExecutionException;
/**
* <p>
* Return the limit on the undo and redo history for a particular context.
* </p>
*
* @param context
* the context whose limit is requested
*
* @return the undo and redo history limit for the specified context.
*/
int getLimit(IUndoContext context);
/**
* <p>
* Get the array of operations in the redo history for a the specified undo
* context. The operations are in the order that they were added to the
* history, with the most recently undone operation appearing last in the
* array. This history is used LIFO (last in, first out) when successive
* "Redo" commands are invoked.
*
* </p>
*
* @param context
* the context for the redo
* @return the array of operations in the history
*/
IUndoableOperation[] getRedoHistory(IUndoContext context);
/**
* <p>
* Get the operation that will next be redone in the given undo context.
* </p>
*
* @param context
* the context for the redo
* @return the operation to be redone or <code>null</code> if there is no
* operation available. There is no guarantee that the returned
* operation is valid for redo.
*/
IUndoableOperation getRedoOperation(IUndoContext context);
/**
* <p>
* Get the array of operations in the undo history for the specified undo
* context. The operations are in the order that they were added to the
* history, with the most recently added operation appearing last in the
* array. This history is used LIFO (last in, first out) when successive
* "Undo" commands are invoked.
* </p>
*
* @param context
* the context for the undo
* @return the array of operations in the history
*/
IUndoableOperation[] getUndoHistory(IUndoContext context);
/**
* <p>
* Open this composite operation and consider it an operation that contains
* other related operations. Consider all operations that are subsequently
* executed or added to be part of this operation. When an operation is
* opened, listeners will immediately receive a notification for the opened
* operation. The specific notification depends on the mode in which the
* operation is opened (<code>ABOUT_TO_EXECUTE</code>,
* <code>ABOUT_TO_UNDO</code>, <code>ABOUT_TO_REDO</code>).
* Notifications for any other execute or add while this operation is open
* will not occur. Instead, those operations will be added to the current
* operation.
* </p>
* <p>
* Note: This method is intended to be used by legacy undo frameworks that
* do not expect related undo operations to appear in the same undo history
* as the triggering undo operation. When an operation is open, any
* subsequent requests to execute, add, undo, or redo another operation will
* result in that operation being added to the open operation. Once the
* operation is closed, the composite will be considered an atomic
* operation. Clients should not modify the composite directly (by adding
* and removing children) while it is open.
* </p>
* <p>
* When a composite is open, operations that are added to the history will
* be considered part of the open operation instead. Operations that are
* executed while a composite is open will first be executed and then added
* to the composite.
* </p>
* <p>
* Open operations cannot be nested. If this method is called when a
* different operation is open, it is presumed to be an application coding
* error and this method will throw an IllegalStateException.
* </p>
*
* @param operation
* the composite operation to be considered as the parent for all
* subsequent operations.
* @param mode
* the mode the operation is executing in. Can be one of
* <code>EXECUTE</code>, <code>UNDO</code>, or
* <code>REDO</code>. This determines what notifications are
* sent.
*/
void openOperation(ICompositeOperation operation, int mode);
/**
* <p>
* The specified operation has changed in some way since it was added to the
* operation history. Notify listeners with an OPERATION_CHANGED event.
* </p>
*
* @param operation
* the operation that has changed.
*
*/
void operationChanged(IUndoableOperation operation);
/**
* <p>
* Get the operation that will next be undone in the given undo context.
* </p>
*
* @param context
* the context for the undo
* @return the operation to be undone or <code>null</code> if there is no
* operation available. There is no guarantee that the available
* operation is valid for the undo.
*/
IUndoableOperation getUndoOperation(IUndoContext context);
/**
* <p>
* Redo the most recently undone operation in the given context
* </p>
*
* @param context
* the context to be redone
* @param monitor
* the progress monitor to be used for the redo, or
* <code>null</code> if no progress monitor is provided.
* @param info
* the IAdaptable (or <code>null</code>) provided by the
* caller in order to supply UI information for prompting the
* user if necessary. When this parameter is not
* <code>null</code>, it should minimally contain an adapter
* for the org.eclipse.swt.widgets.Shell.class.
* @return the IStatus indicating whether the redo succeeded.
*
* <p>
* The severity code in the returned status describes whether the operation
* succeeded and whether it remains in the history. <code>OK</code>
* severity indicates that the redo operation was successful. The operation
* will be placed on the undo history, provided it can be undone (answers
* <code>true</code> to {@link IUndoableOperation#canUndo()}). Listeners
* will receive the <code>REDONE</code> notification.
* </p>
* <p>
* Other severity codes (<code>CANCEL</code>, <code>ERROR</code>, <code>INFO</code>,
* etc.) are not specifically interpreted by the history. The operation will remain
* in the history and the returned status is simply passed back to the
* caller. For all severities other than <code>OK</code>, listeners
* will receive the <code>OPERATION_NOT_OK</code> notification
* instead of the <code>REDONE</code> notification.
* </p>
*
* @throws ExecutionException
* if an exception occurred during redo.
*
*/
IStatus redo(IUndoContext context, IProgressMonitor monitor, IAdaptable info)
throws ExecutionException;
/**
* <p>
* Redo the specified operation
* </p>
*
* @param operation
* the operation to be redone
* @param monitor
* the progress monitor to be used for the redo, or code>null</code>
* if no progress monitor is provided
* @param info
* the IAdaptable (or <code>null</code>) provided by the
* caller in order to supply UI information for prompting the
* user if necessary. When this parameter is not <code>null</code>,
* it should minimally contain an adapter for the
* org.eclipse.swt.widgets.Shell.class.
*
* @return the IStatus indicating whether the redo succeeded.
*
* <p>
* The severity code in the returned status describes whether the operation
* succeeded and whether it remains in the history. <code>OK</code>
* severity indicates that the redo operation was successful. The operation
* will be placed on the undo history, provided it can be undone (answers
* <code>true</code> to {@link IUndoableOperation#canUndo()}). Listeners
* will receive the <code>REDONE</code> notification.
* </p>
* <p>
* Other severity codes (<code>CANCEL</code>, <code>ERROR</code>,
* <code>INFO</code>, etc.) are not specifically interpreted by the
* history. The operation will remain in the history and the returned status
* is simply passed back to the caller. For all severities other than
* <code>OK</code>, listeners will receive the
* <code>OPERATION_NOT_OK</code> notification instead of the
* <code>REDONE</code> notification.
* </p>
*
* @throws ExecutionException
* if an exception occurred during redo.
*/
IStatus redoOperation(IUndoableOperation operation,
IProgressMonitor monitor, IAdaptable info)
throws ExecutionException;
/**
* <p>
* Remove the specified operation approver from the list of operation
* approvers that are consulted before an operation is undone or redone.
* </p>
*
* @param approver
* the IOperationApprover to be removed. Must not be
* <code>null</code>. If an attempt is made to remove an
* instance which is not already registered with this instance,
* this method has no effect.
*/
void removeOperationApprover(IOperationApprover approver);
/**
* <p>
* Remove the specified listener from the list of operation history
* listeners.
* </p>
*
* @param listener
* The IOperationHistoryListener to be removed. Must not be
* <code>null</code>. If an attempt is made to remove an
* instance which is not already registered with this instance,
* this method has no effect.
*/
void removeOperationHistoryListener(IOperationHistoryListener listener);
/**
* <p>
* Replace the specified operation in the undo or redo history with the
* provided list of replacements. This protocol is typically used when a
* composite is broken up into its atomic parts. The replacements will be
* inserted so that the first replacement will be the first of the
* replacements to be undone or redone. Listeners will be notified about the
* removal of the replaced element and the addition of each replacement.
* </p>
*
* @param operation
* The IUndoableOperation to be replaced
* @param replacements
* the array of IUndoableOperation to replace the first operation
*/
void replaceOperation(IUndoableOperation operation,
IUndoableOperation[] replacements);
/**
* <p>
* Set the limit on the undo and redo history for a particular context.
* </p>
*
* @param context
* the context whose limit is being set.
*
* @param limit
* the maximum number of operations that should be kept in the
* undo or redo history for the specified context. Must not be
* negative.
*/
void setLimit(IUndoContext context, int limit);
/**
* <p>
* Undo the most recently executed operation in the given context
* </p>
*
* @param context
* the context to be undone
* @param monitor
* the progress monitor to be used for the undo, or
* <code>null</code> if no progress monitor is provided.
* @param info
* the IAdaptable (or <code>null</code>) provided by the
* caller in order to supply UI information for prompting the
* user if necessary. When this parameter is not
* <code>null</code>, it should minimally contain an adapter
* for the org.eclipse.swt.widgets.Shell.class.
*
* @return the IStatus indicating whether the undo succeeded.
*
* <p>
* The severity code in the returned status describes whether the operation
* succeeded and whether it remains in the history. <code>OK</code>
* severity indicates that the undo operation was successful. The operation
* will be placed on the redo history, provided it can be redone (answers
* <code>true</code> to {@link IUndoableOperation#canRedo()}). Listeners
* will receive the <code>UNDONE</code> notification.
* </p>
* <p>
* Other severity codes (<code>CANCEL</code>, <code>ERROR</code>, <code>INFO</code>,
* etc.) are not specifically interpreted by the history. The operation will remain
* in the history and the returned status is simply passed back to the
* caller. For all severities other than <code>OK</code>, listeners
* will receive the <code>OPERATION_NOT_OK</code> notification
* instead of the <code>UNDONE</code> notification.
* </p>
*
* @throws ExecutionException
* if an exception occurred during undo.
*/
IStatus undo(IUndoContext context, IProgressMonitor monitor, IAdaptable info)
throws ExecutionException;
/**
* <p>
* Undo the specified operation
* </p>
*
* @param operation
* the operation to be undone
* @param monitor
* the progress monitor to be used for the undo, or
* <code>null</code> if no progress monitor is provided
* @param info
* the IAdaptable (or <code>null</code>) provided by the
* caller in order to supply UI information for prompting the
* user if necessary. When this parameter is not
* <code>null</code>, it should minimally contain an adapter
* for the org.eclipse.swt.widgets.Shell.class.
*
* @return the IStatus indicating whether the undo succeeded.
*
* <p>
* The severity code in the returned status describes whether the operation
* succeeded and whether it remains in the history. <code>OK</code>
* severity indicates that the undo operation was successful. The operation
* will be placed on the redo history, provided it can be redone (answers
* <code>true</code> to {@link IUndoableOperation#canRedo()}). Listeners
* will receive the <code>UNDONE</code> notification.
* </p>
* <p>
* Other severity codes (<code>CANCEL</code>, <code>ERROR</code>, <code>INFO</code>,
* etc.) are not specifically interpreted by the history. The operation will remain
* in the history and the returned status is simply passed back to the
* caller. For all severities other than <code>OK</code>, listeners
* will receive the <code>OPERATION_NOT_OK</code> notification
* instead of the <code>UNDONE</code> notification.
* </p>
*
* @throws ExecutionException
* if an exception occurred during undo.
*/
IStatus undoOperation(IUndoableOperation operation,
IProgressMonitor monitor, IAdaptable info)
throws ExecutionException;
}