001: /*******************************************************************************
002: * Copyright (c) 2006, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.ide.undo;
011:
012: import org.eclipse.core.commands.ExecutionException;
013: import org.eclipse.core.commands.operations.AbstractOperation;
014: import org.eclipse.core.commands.operations.IAdvancedUndoableOperation;
015: import org.eclipse.core.commands.operations.IAdvancedUndoableOperation2;
016: import org.eclipse.core.commands.operations.OperationHistoryEvent;
017: import org.eclipse.core.commands.operations.OperationStatus;
018: import org.eclipse.core.resources.IResource;
019: import org.eclipse.core.resources.IResourceRuleFactory;
020: import org.eclipse.core.resources.IWorkspace;
021: import org.eclipse.core.resources.IWorkspaceRunnable;
022: import org.eclipse.core.resources.ResourcesPlugin;
023: import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
024: import org.eclipse.core.resources.mapping.ResourceChangeValidator;
025: import org.eclipse.core.runtime.CoreException;
026: import org.eclipse.core.runtime.IAdaptable;
027: import org.eclipse.core.runtime.IProgressMonitor;
028: import org.eclipse.core.runtime.IStatus;
029: import org.eclipse.core.runtime.Status;
030: import org.eclipse.core.runtime.jobs.ISchedulingRule;
031: import org.eclipse.jface.action.Action;
032: import org.eclipse.osgi.util.NLS;
033: import org.eclipse.swt.widgets.Shell;
034: import org.eclipse.ui.PlatformUI;
035: import org.eclipse.ui.ide.IDE;
036: import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
037: import org.eclipse.ui.internal.ide.undo.UndoMessages;
038:
039: /**
040: * An AbstractWorkspaceOperation represents an undoable operation that affects
041: * the workspace. It handles common workspace operation activities such as
042: * tracking which resources are affected by an operation, prompting the user
043: * when there are possible side effects of operations, building execution
044: * exceptions from core exceptions, etc. Clients may call the public API from a
045: * background thread.
046: *
047: * This class is not intended to be subclassed by clients.
048: *
049: * @since 3.3
050: *
051: */
052: public abstract class AbstractWorkspaceOperation extends
053: AbstractOperation implements IAdvancedUndoableOperation,
054: IAdvancedUndoableOperation2 {
055:
056: private static String ELLIPSIS = "..."; //$NON-NLS-1$
057:
058: protected static int EXECUTE = 1;
059:
060: protected static int UNDO = 2;
061:
062: protected static int REDO = 3;
063:
064: protected IResource[] resources;
065:
066: private boolean isValid = true;
067:
068: /*
069: * Specifies whether any user prompting is appropriate while computing
070: * status.
071: */
072: protected boolean quietCompute = false;
073:
074: String[] modelProviderIds;
075:
076: /**
077: * Create an AbstractWorkspaceOperation with the specified name.
078: *
079: * @param name
080: * the name used to describe the operation
081: */
082: AbstractWorkspaceOperation(String name) {
083: // Many operation names are based on the triggering action's name, so
084: // we strip out the any mnemonics that may be embedded in the name.
085: super (Action.removeMnemonics(name));
086:
087: // For the same reason, check for an ellipsis and strip out
088: String label = this .getLabel();
089: if (label.endsWith(ELLIPSIS)) {
090: this .setLabel(label.substring(0, label.length()
091: - ELLIPSIS.length()));
092: }
093: }
094:
095: /**
096: * Set the ids of any model providers for the resources involved.
097: *
098: * @param ids
099: * the array of String model provider ids that provide models
100: * associated with the resources involved in this operation
101: */
102: public void setModelProviderIds(String[] ids) {
103: modelProviderIds = ids;
104: }
105:
106: /**
107: * Set the resources which are affected by this operation
108: *
109: * @param resources
110: * an array of resources
111: */
112: protected void setTargetResources(IResource[] resources) {
113: this .resources = resources;
114: }
115:
116: /**
117: * Return the workspace manipulated by this operation.
118: *
119: * @return the IWorkspace used by this operation.
120: */
121: protected IWorkspace getWorkspace() {
122: return ResourcesPlugin.getWorkspace();
123: }
124:
125: /**
126: * Return the workspace rule factory associated with this operation.
127: *
128: * @return the IResourceRuleFactory associated with this operation.
129: */
130: protected IResourceRuleFactory getWorkspaceRuleFactory() {
131: return getWorkspace().getRuleFactory();
132: }
133:
134: /**
135: * Mark this operation invalid due to some external change. May be used by
136: * subclasses.
137: *
138: */
139: protected void markInvalid() {
140: isValid = false;
141: }
142:
143: /*
144: * (non-Javadoc)
145: *
146: * This implementation checks a validity flag.
147: *
148: * @see org.eclipse.core.commands.operations.IUndoableOperation#canExecute()
149: */
150: public boolean canExecute() {
151: return isValid();
152: }
153:
154: /*
155: * (non-Javadoc)
156: *
157: * This implementation checks a validity flag.
158: *
159: * @see org.eclipse.core.commands.operations.IUndoableOperation#canUndo()
160: */
161: public boolean canUndo() {
162: return isValid();
163: }
164:
165: /*
166: * (non-Javadoc)
167: *
168: * This implementation checks a validity flag.
169: *
170: * @see org.eclipse.core.commands.operations.IUndoableOperation#canRedo()
171: */
172: public boolean canRedo() {
173: return isValid();
174: }
175:
176: /**
177: * Execute the specified operation. This implementation executes the
178: * operation in a workspace runnable and catches any CoreExceptions
179: * resulting from the operation. Unhandled CoreExceptions are propagated as
180: * ExecutionExceptions.
181: *
182: * @param monitor
183: * the progress monitor to use for the operation
184: * @param uiInfo
185: * the IAdaptable (or <code>null</code>) provided by the
186: * caller in order to supply UI information for prompting the
187: * user if necessary. When this parameter is not
188: * <code>null</code>, it contains an adapter for the
189: * org.eclipse.swt.widgets.Shell.class
190: * @return the IStatus of the execution. The status severity should be set
191: * to <code>OK</code> if the operation was successful, and
192: * <code>ERROR</code> if it was not. Any other status is assumed
193: * to represent an incompletion of the execution.
194: * @throws ExecutionException
195: * if an exception occurred during execution.
196: *
197: * @see org.eclipse.core.commands.operations.IUndoableOperation#execute(org.eclipse.core.runtime.IProgressMonitor,
198: * org.eclipse.core.runtime.IAdaptable)
199: */
200: public IStatus execute(IProgressMonitor monitor,
201: final IAdaptable uiInfo) throws ExecutionException {
202: try {
203: getWorkspace().run(
204: new IWorkspaceRunnable() {
205: public void run(IProgressMonitor monitor)
206: throws CoreException {
207: doExecute(monitor, uiInfo);
208: }
209: }, getExecuteSchedulingRule(),
210: IWorkspace.AVOID_UPDATE,
211: monitor);
212: } catch (final CoreException e) {
213: throw new ExecutionException(
214: NLS
215: .bind(
216: UndoMessages.AbstractWorkspaceOperation_ExecuteErrorTitle,
217: getLabel()), e);
218: }
219: isValid = true;
220: return Status.OK_STATUS;
221: }
222:
223: /**
224: * Redo the specified operation. This implementation redoes the operation in
225: * a workspace runnable and catches any CoreExceptions resulting from the
226: * operation. Unhandled CoreExceptions are propagated as
227: * ExecutionExceptions.
228: *
229: * @param monitor
230: * the progress monitor to use for the operation
231: * @param uiInfo
232: * the IAdaptable (or <code>null</code>) provided by the
233: * caller in order to supply UI information for prompting the
234: * user if necessary. When this parameter is not
235: * <code>null</code>, it contains an adapter for the
236: * org.eclipse.swt.widgets.Shell.class
237: * @return the IStatus of the redo. The status severity should be set to
238: * <code>OK</code> if the operation was successful, and
239: * <code>ERROR</code> if it was not. Any other status is assumed
240: * to represent an incompletion of the redo.
241: * @throws ExecutionException
242: * if an exception occurred during execution.
243: * @see org.eclipse.core.commands.operations.IUndoableOperation#redo(org.eclipse.core.runtime.IProgressMonitor,
244: * org.eclipse.core.runtime.IAdaptable)
245: */
246: public IStatus redo(IProgressMonitor monitor,
247: final IAdaptable uiInfo) throws ExecutionException {
248: try {
249: getWorkspace().run(
250: new IWorkspaceRunnable() {
251: public void run(IProgressMonitor monitor)
252: throws CoreException {
253: doExecute(monitor, uiInfo);
254: }
255: }, getRedoSchedulingRule(),
256: IWorkspace.AVOID_UPDATE,
257: monitor);
258: } catch (final CoreException e) {
259: throw new ExecutionException(
260: NLS
261: .bind(
262: UndoMessages.AbstractWorkspaceOperation_RedoErrorTitle,
263: getLabel()), e);
264:
265: }
266: isValid = true;
267: return Status.OK_STATUS;
268: }
269:
270: /**
271: * Undo the specified operation. This implementation undoes the operation in
272: * a workspace runnable and catches any CoreExceptions resulting from the
273: * operation. Unhandled CoreExceptions are propagated as
274: * ExecutionExceptions.
275: *
276: * @param monitor
277: * the progress monitor to use for the operation
278: * @param uiInfo
279: * the IAdaptable (or <code>null</code>) provided by the
280: * caller in order to supply UI information for prompting the
281: * user if necessary. When this parameter is not
282: * <code>null</code>, it contains an adapter for the
283: * org.eclipse.swt.widgets.Shell.class
284: * @return the IStatus of the undo. The status severity should be set to
285: * <code>OK</code> if the operation was successful, and
286: * <code>ERROR</code> if it was not. Any other status is assumed
287: * to represent an incompletion of the undo. *
288: * @throws ExecutionException
289: * if an exception occurred during execution.
290: * @see org.eclipse.core.commands.operations.IUndoableOperation#undo(org.eclipse.core.runtime.IProgressMonitor,
291: * org.eclipse.core.runtime.IAdaptable)
292: */
293: public IStatus undo(IProgressMonitor monitor,
294: final IAdaptable uiInfo) throws ExecutionException {
295: try {
296: getWorkspace().run(
297: new IWorkspaceRunnable() {
298: public void run(IProgressMonitor monitor)
299: throws CoreException {
300: doUndo(monitor, uiInfo);
301: }
302: }, getUndoSchedulingRule(),
303: IWorkspace.AVOID_UPDATE,
304: monitor);
305: } catch (final CoreException e) {
306: throw new ExecutionException(
307: NLS
308: .bind(
309: UndoMessages.AbstractWorkspaceOperation_UndoErrorTitle,
310: getLabel()), e);
311:
312: }
313: isValid = true;
314: return Status.OK_STATUS;
315: }
316:
317: /**
318: * Perform the specific work involved in undoing this operation.
319: *
320: * @param monitor
321: * the progress monitor to use for the operation
322: * @param uiInfo
323: * the IAdaptable (or <code>null</code>) provided by the
324: * caller in order to supply UI information for prompting the
325: * user if necessary. When this parameter is not
326: * <code>null</code>, it contains an adapter for the
327: * org.eclipse.swt.widgets.Shell.class
328: * @throws CoreException
329: * propagates any CoreExceptions thrown from the resources API
330: */
331: protected abstract void doUndo(IProgressMonitor monitor,
332: IAdaptable uiInfo) throws CoreException;
333:
334: /**
335: * Perform the specific work involved in executing this operation.
336: *
337: * @param monitor
338: * the progress monitor to use for the operation
339: * @param uiInfo
340: * the IAdaptable (or <code>null</code>) provided by the
341: * caller in order to supply UI information for prompting the
342: * user if necessary. When this parameter is not
343: * <code>null</code>, it contains an adapter for the
344: * org.eclipse.swt.widgets.Shell.class
345: * @throws CoreException
346: * propagates any CoreExceptions thrown from the resources API
347: *
348: */
349: protected abstract void doExecute(IProgressMonitor monitor,
350: IAdaptable uiInfo) throws CoreException;
351:
352: /**
353: * Return whether the proposed operation is valid. The default
354: * implementation simply checks to see if the flag has been marked as
355: * invalid, relying on subclasses to mark the flag invalid when appropriate.
356: *
357: * @return the validity flag
358: */
359: protected boolean isValid() {
360: return isValid;
361: }
362:
363: /*
364: * (non-Javadoc)
365: *
366: * @see org.eclipse.core.commands.operations.IAdvancedUndoableOperation#aboutToNotify(org.eclipse.core.commands.operations.OperationHistoryEvent)
367: */
368: public void aboutToNotify(OperationHistoryEvent event) {
369: // do nothing
370: }
371:
372: /*
373: * (non-Javadoc)
374: *
375: * @see org.eclipse.core.commands.operations.IAdvancedUndoableOperation#getAffectedObjects()
376: */
377: public Object[] getAffectedObjects() {
378: return resources;
379: }
380:
381: /**
382: * Return a status indicating the projected outcome of executing the
383: * receiver. This method is not called by the operation history, but instead
384: * is used by clients (such as implementers of
385: * {@link org.eclipse.core.commands.operations.IOperationApprover2}) who
386: * wish to perform advanced validation of an operation before attempting to
387: * execute it.
388: *
389: * If an ERROR status is returned, the operation will not proceed and the
390: * user notified if deemed necessary by the caller. The validity flag on the
391: * operation should be marked as invalid. If an OK status is returned, the
392: * operation will proceed. The caller must interpret any other returned
393: * status severity, and may choose to prompt the user as to how to proceed.
394: *
395: * If there are multiple conditions that result in an ambiguous status
396: * severity, it is best for the implementor of this method to consult the
397: * user as to how to proceed for each one, and return an OK or ERROR status
398: * that accurately reflects the user's wishes, or to return a multi-status
399: * that accurately describes all of the issues at hand, so that the caller
400: * may potentially consult the user. (Note that the user should not be
401: * consulted at all if a client has called {@link #setQuietCompute(boolean)}
402: * with a value of <code>true</code>.)
403: *
404: * This implementation computes the validity of execution by computing the
405: * resource delta that would be generated on execution, and checking whether
406: * any registered model providers are affected by the operation.
407: *
408: * @param monitor
409: * the progress monitor to be used for computing the status
410: * @return the status indicating the projected outcome of executing the
411: * receiver
412: *
413: * @see org.eclipse.core.commands.operations.IAdvancedUndoableOperation#computeUndoableStatus(org.eclipse.core.runtime.IProgressMonitor)
414: * @see #setQuietCompute(boolean)
415: */
416: public IStatus computeExecutionStatus(IProgressMonitor monitor) {
417: IStatus status = Status.OK_STATUS;
418:
419: // If we are not to prompt the user, nothing to do.
420: if (quietCompute) {
421: return status;
422: }
423:
424: IResourceChangeDescriptionFactory factory = ResourceChangeValidator
425: .getValidator().createDeltaFactory();
426: if (updateResourceChangeDescriptionFactory(factory, EXECUTE)) {
427: boolean proceed = IDE
428: .promptToConfirm(
429: getShell(null),
430: UndoMessages.AbstractWorkspaceOperation_SideEffectsWarningTitle,
431: NLS
432: .bind(
433: UndoMessages.AbstractWorkspaceOperation_ExecuteSideEffectsWarningMessage,
434: getLabel()), factory
435: .getDelta(), modelProviderIds, true /* syncExec */);
436: if (!proceed) {
437: status = Status.CANCEL_STATUS;
438: }
439: }
440: return status;
441:
442: }
443:
444: /**
445: * Return a status indicating the projected outcome of undoing the receiver.
446: * This method is not called by the operation history, but instead is used
447: * by clients (such as implementers of
448: * {@link org.eclipse.core.commands.operations.IOperationApprover2}) who
449: * wish to perform advanced validation of an operation before attempting to
450: * undo it.
451: *
452: * If an ERROR status is returned, the undo will not proceed and the user
453: * notified if deemed necessary by the caller. The validity flag on the
454: * operation should be marked as invalid. If an OK status is returned, the
455: * undo will proceed. The caller must interpret any other returned status
456: * severity, and may choose to prompt the user as to how to proceed.
457: *
458: * If there are multiple conditions that result in an ambiguous status
459: * severity, it is best for the implementor of this method to consult the
460: * user as to how to proceed for each one, and return an OK or ERROR status
461: * that accurately reflects the user's wishes, or to return a multi-status
462: * that accurately describes all of the issues at hand, so that the caller
463: * may potentially consult the user. (Note that the user should not be
464: * consulted at all if a client has called {@link #setQuietCompute(boolean)}
465: * with a value of <code>true</code>.)
466: *
467: * This implementation computes the validity of undo by computing the
468: * resource delta that would be generated on undo, and checking whether any
469: * registered model providers are affected by the operation.
470: *
471: * @param monitor
472: * the progress monitor to be used for computing the status
473: * @return the status indicating the projected outcome of undoing the
474: * receiver
475: *
476: * @see org.eclipse.core.commands.operations.IAdvancedUndoableOperation#computeUndoableStatus(org.eclipse.core.runtime.IProgressMonitor)
477: * @see #setQuietCompute(boolean)
478: */
479: public IStatus computeUndoableStatus(IProgressMonitor monitor) {
480: IStatus status = Status.OK_STATUS;
481: // If we are not to prompt the user, nothing to do.
482: if (quietCompute) {
483: return status;
484: }
485:
486: IResourceChangeDescriptionFactory factory = ResourceChangeValidator
487: .getValidator().createDeltaFactory();
488: if (updateResourceChangeDescriptionFactory(factory, UNDO)) {
489: boolean proceed = IDE
490: .promptToConfirm(
491: getShell(null),
492: UndoMessages.AbstractWorkspaceOperation_SideEffectsWarningTitle,
493: NLS
494: .bind(
495: UndoMessages.AbstractWorkspaceOperation_UndoSideEffectsWarningMessage,
496: getLabel()), factory
497: .getDelta(), modelProviderIds, true /* syncExec */);
498: if (!proceed) {
499: status = Status.CANCEL_STATUS;
500: }
501: }
502: return status;
503:
504: }
505:
506: /**
507: * Return a status indicating the projected outcome of redoing the receiver.
508: * This method is not called by the operation history, but instead is used
509: * by clients (such as implementers of
510: * {@link org.eclipse.core.commands.operations.IOperationApprover2}) who
511: * wish to perform advanced validation of an operation before attempting to
512: * redo it.
513: *
514: * If an ERROR status is returned, the redo will not proceed and the user
515: * notified if deemed necessary by the caller. The validity flag on the
516: * operation should be marked as invalid. If an OK status is returned, the
517: * redo will proceed. The caller must interpret any other returned status
518: * severity, and may choose to prompt the user as to how to proceed.
519: *
520: * If there are multiple conditions that result in an ambiguous status
521: * severity, it is best for the implementor of this method to consult the
522: * user as to how to proceed for each one, and return an OK or ERROR status
523: * that accurately reflects the user's wishes, or to return a multi-status
524: * that accurately describes all of the issues at hand, so that the caller
525: * may potentially consult the user. (Note that the user should not be
526: * consulted at all if a client has called {@link #setQuietCompute(boolean)}
527: * with a value of <code>true</code>.)
528: *
529: * This implementation computes the validity of redo by computing the
530: * resource delta that would be generated on redo, and checking whether any
531: * registered model providers are affected by the operation.
532: *
533: * @param monitor
534: * the progress monitor to be used for computing the status
535: * @return the status indicating the projected outcome of redoing the
536: * receiver
537: *
538: * @see org.eclipse.core.commands.operations.IAdvancedUndoableOperation#computeUndoableStatus(org.eclipse.core.runtime.IProgressMonitor)
539: * @see #setQuietCompute(boolean)
540: */
541: public IStatus computeRedoableStatus(IProgressMonitor monitor) {
542: IStatus status = Status.OK_STATUS;
543: // If we are not to prompt the user, nothing to do.
544: if (quietCompute) {
545: return status;
546: }
547:
548: IResourceChangeDescriptionFactory factory = ResourceChangeValidator
549: .getValidator().createDeltaFactory();
550: if (updateResourceChangeDescriptionFactory(factory, REDO)) {
551: boolean proceed = IDE
552: .promptToConfirm(
553: getShell(null),
554: UndoMessages.AbstractWorkspaceOperation_SideEffectsWarningTitle,
555: NLS
556: .bind(
557: UndoMessages.AbstractWorkspaceOperation_RedoSideEffectsWarningMessage,
558: getLabel()), factory
559: .getDelta(), modelProviderIds, true /* syncExec */);
560: if (!proceed) {
561: status = Status.CANCEL_STATUS;
562: }
563: }
564: return status;
565: }
566:
567: /**
568: * Update the provided resource change description factory so it can
569: * generate a resource delta describing the result of an undo or redo.
570: * Return a boolean indicating whether any update was done. The default
571: * implementation does not update the factory. Subclasses are expected to
572: * override this method to more specifically describe their modifications to
573: * the workspace.
574: *
575: * @param factory
576: * the factory to update
577: * @param operation
578: * an integer indicating whether the change is part of an
579: * execute, undo, or redo
580: * @return a boolean indicating whether the factory was updated.
581: */
582: protected boolean updateResourceChangeDescriptionFactory(
583: IResourceChangeDescriptionFactory factory, int operation) {
584: return false;
585: }
586:
587: /**
588: * Return an error status describing an invalid operation using the provided
589: * message.
590: *
591: * @param message
592: * the message to be used in the status, or <code>null</code>
593: * if a generic message should be used
594: * @return the error status
595: */
596: protected IStatus getErrorStatus(String message) {
597: String statusMessage = message;
598: if (statusMessage == null) {
599: statusMessage = NLS
600: .bind(
601: UndoMessages.AbstractWorkspaceOperation_ErrorInvalidMessage,
602: getLabel());
603: }
604: return new Status(IStatus.ERROR,
605: IDEWorkbenchPlugin.IDE_WORKBENCH,
606: OperationStatus.OPERATION_INVALID, statusMessage, null);
607: }
608:
609: /**
610: * Return a warning status describing the warning state of an operation
611: * using the provided message and code.
612: *
613: * @param message
614: * the message to be used in the status, or <code>null</code>
615: * if a generic message should be used
616: * @param code
617: * the integer code to be assigned to the status
618: * @return the warning status
619: */
620: protected IStatus getWarningStatus(String message, int code) {
621: String statusMessage = message;
622: if (statusMessage == null) {
623: statusMessage = NLS
624: .bind(
625: UndoMessages.AbstractWorkspaceOperation_GenericWarningMessage,
626: getLabel());
627: }
628: return new Status(IStatus.WARNING,
629: IDEWorkbenchPlugin.IDE_WORKBENCH, code, statusMessage,
630: null);
631: }
632:
633: /**
634: * Return whether the resources known by this operation currently exist.
635: *
636: * @return <code>true</code> if there are existing resources and
637: * <code>false</code> if there are no known resources or any one
638: * of them does not exist
639: */
640: protected boolean resourcesExist() {
641: if (resources == null || resources.length == 0) {
642: return false;
643: }
644: for (int i = 0; i < resources.length; i++) {
645: if (!resources[i].exists()) {
646: return false;
647: }
648: }
649: return true;
650: }
651:
652: /**
653: * Return whether the resources known by this operation contain any
654: * projects.
655: *
656: * @return <code>true</code> if there is one or more projects known by
657: * this operation and false if there are no projects.
658: */
659: protected boolean resourcesIncludesProjects() {
660: if (resources == null || resources.length == 0) {
661: return false;
662: }
663: for (int i = 0; i < resources.length; i++) {
664: if (resources[i].getType() == IResource.PROJECT) {
665: return true;
666: }
667: }
668: return false;
669: }
670:
671: /**
672: * Return a scheduling rule appropriate for executing this operation.
673: *
674: * The default implementation is to return a rule that locks out the entire
675: * workspace. Subclasses are encouraged to provide more specific rules that
676: * affect only their resources.
677: *
678: * @return the scheduling rule to use when executing this operation, or
679: * <code>null</code> if there are no scheduling restrictions for
680: * this operation.
681: *
682: * @see IWorkspace#run(IWorkspaceRunnable, ISchedulingRule, int,
683: * IProgressMonitor)
684: */
685: protected ISchedulingRule getExecuteSchedulingRule() {
686: return getWorkspace().getRoot();
687: }
688:
689: /**
690: * Return a scheduling rule appropriate for undoing this operation.
691: *
692: * The default implementation is to return a rule that locks out the entire
693: * workspace. Subclasses are encouraged to provide more specific rules that
694: * affect only their resources.
695: *
696: * @return the scheduling rule to use when undoing this operation, or
697: * <code>null</code> if there are no scheduling restrictions for
698: * this operation.
699: *
700: * @see IWorkspace#run(IWorkspaceRunnable, ISchedulingRule, int,
701: * IProgressMonitor)
702: */
703: protected ISchedulingRule getUndoSchedulingRule() {
704: return getWorkspace().getRoot();
705: }
706:
707: /**
708: * Return a scheduling rule appropriate for redoing this operation.
709: *
710: * The default implementation considers the redo scheduling rule the same as
711: * the original execution scheduling rule.
712: *
713: * @return the scheduling rule to use when redoing this operation, or
714: * <code>null</code> if there are no scheduling restrictions for
715: * this operation.
716: *
717: * @see IWorkspace#run(IWorkspaceRunnable, ISchedulingRule, int,
718: * IProgressMonitor)
719: */
720: protected ISchedulingRule getRedoSchedulingRule() {
721: return getExecuteSchedulingRule();
722: }
723:
724: /*
725: * (non-Javadoc)
726: *
727: * @see org.eclipse.core.commands.operations.IAdvancedUndoableOperation2#setQuietCompute(boolean)
728: */
729: public void setQuietCompute(boolean quiet) {
730: quietCompute = quiet;
731: }
732:
733: /*
734: * @see java.lang.Object#toString()
735: */
736: public String toString() {
737: StringBuffer text = new StringBuffer(super .toString());
738: text.append("\n"); //$NON-NLS-1$
739: text.append(this .getClass().getName());
740: appendDescriptiveText(text);
741: return text.toString();
742: }
743:
744: /**
745: * Append any descriptive text to the specified string buffer to be shown in
746: * the receiver's {@link #toString()} text.
747: * <p>Note that this method is not intend to be subclassed by clients.
748: *
749: * @param text
750: * the StringBuffer on which to append the text
751: */
752: protected void appendDescriptiveText(StringBuffer text) {
753: text.append(" resources: "); //$NON-NLS-1$
754: text.append(resources);
755: text.append('\'');
756: }
757:
758: /**
759: * Return the shell described by the specified adaptable, or the active
760: * shell if no shell has been specified in the adaptable.
761: *
762: * @param uiInfo
763: * the IAdaptable (or <code>null</code>) provided by the
764: * caller in order to supply UI information for prompting the
765: * user if necessary. When this parameter is not
766: * <code>null</code>, it contains an adapter for the
767: * org.eclipse.swt.widgets.Shell.class
768: *
769: * @return the shell specified in the adaptable, or the active shell if no
770: * shell has been specified
771: *
772: */
773: protected Shell getShell(IAdaptable uiInfo) {
774: if (uiInfo != null) {
775: Shell shell = (Shell) uiInfo.getAdapter(Shell.class);
776: if (shell != null) {
777: return shell;
778: }
779: }
780: return PlatformUI.getWorkbench().getActiveWorkbenchWindow()
781: .getShell();
782: }
783:
784: /*
785: * (non-Javadoc)
786: *
787: * @see org.eclipse.core.commands.operations.IAdvancedUndoableOperation2#runInBackground()
788: */
789: public boolean runInBackground() {
790: return true;
791: }
792: }
|