001: /*******************************************************************************
002: * Copyright (c) 2000, 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.jdt.internal.ui.refactoring;
011:
012: import java.lang.reflect.InvocationTargetException;
013:
014: import org.eclipse.core.runtime.Assert;
015: import org.eclipse.core.runtime.CoreException;
016: import org.eclipse.core.runtime.IProgressMonitor;
017: import org.eclipse.core.runtime.OperationCanceledException;
018: import org.eclipse.core.runtime.SubProgressMonitor;
019: import org.eclipse.core.runtime.jobs.IJobManager;
020: import org.eclipse.core.runtime.jobs.ISchedulingRule;
021: import org.eclipse.core.runtime.jobs.Job;
022:
023: import org.eclipse.core.resources.IWorkspaceRunnable;
024: import org.eclipse.core.resources.ResourcesPlugin;
025:
026: import org.eclipse.swt.custom.BusyIndicator;
027: import org.eclipse.swt.widgets.Display;
028: import org.eclipse.swt.widgets.Shell;
029:
030: import org.eclipse.jface.dialogs.Dialog;
031: import org.eclipse.jface.dialogs.IDialogConstants;
032: import org.eclipse.jface.dialogs.MessageDialog;
033: import org.eclipse.jface.operation.IRunnableContext;
034: import org.eclipse.jface.operation.IThreadListener;
035:
036: import org.eclipse.ltk.core.refactoring.Change;
037: import org.eclipse.ltk.core.refactoring.PerformChangeOperation;
038: import org.eclipse.ltk.core.refactoring.Refactoring;
039: import org.eclipse.ltk.core.refactoring.RefactoringCore;
040: import org.eclipse.ltk.core.refactoring.RefactoringStatus;
041: import org.eclipse.ltk.ui.refactoring.RefactoringUI;
042:
043: import org.eclipse.jdt.internal.corext.util.Messages;
044:
045: import org.eclipse.jdt.internal.ui.actions.WorkbenchRunnableAdapter;
046:
047: /**
048: * A helper class to execute a refactoring. The class takes care of pushing the
049: * undo change onto the undo stack and folding editor edits into one editor
050: * undo object.
051: */
052: public class RefactoringExecutionHelper {
053:
054: private final Refactoring fRefactoring;
055: private final Shell fParent;
056: private final IRunnableContext fExecContext;
057: private final int fStopSeverity;
058: private final int fSaveMode;
059:
060: private class Operation implements IWorkspaceRunnable {
061: public Change fChange;
062: public PerformChangeOperation fPerformChangeOperation;
063: private final boolean fForked;
064:
065: public Operation(boolean forked) {
066: fForked = forked;
067: }
068:
069: public void run(IProgressMonitor pm) throws CoreException {
070: try {
071: pm.beginTask("", fForked ? 7 : 11); //$NON-NLS-1$
072: pm.subTask(""); //$NON-NLS-1$
073:
074: final RefactoringStatus status = fRefactoring
075: .checkAllConditions(new SubProgressMonitor(
076: pm,
077: 4,
078: SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
079: if (status.getSeverity() >= fStopSeverity) {
080: final boolean[] canceled = { false };
081: if (fForked) {
082: fParent.getDisplay().syncExec(new Runnable() {
083: public void run() {
084: canceled[0] = showStatusDialog(status);
085: }
086: });
087: } else {
088: canceled[0] = showStatusDialog(status);
089: }
090: if (canceled[0]) {
091: throw new OperationCanceledException();
092: }
093: }
094:
095: fChange = fRefactoring
096: .createChange(new SubProgressMonitor(
097: pm,
098: 2,
099: SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
100: fChange
101: .initializeValidationData(new SubProgressMonitor(
102: pm,
103: 1,
104: SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
105:
106: fPerformChangeOperation = RefactoringUI
107: .createUIAwareChangeOperation(fChange);
108: fPerformChangeOperation.setUndoManager(RefactoringCore
109: .getUndoManager(), fRefactoring.getName());
110: if (fRefactoring instanceof IScheduledRefactoring)
111: fPerformChangeOperation
112: .setSchedulingRule(((IScheduledRefactoring) fRefactoring)
113: .getSchedulingRule());
114:
115: if (!fForked)
116: fPerformChangeOperation
117: .run(new SubProgressMonitor(
118: pm,
119: 4,
120: SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
121: } finally {
122: pm.done();
123: }
124: }
125:
126: /**
127: * @param status the status to show
128: * @return <code>true</code> iff the operation should be cancelled
129: */
130: private boolean showStatusDialog(RefactoringStatus status) {
131: Dialog dialog = RefactoringUI
132: .createRefactoringStatusDialog(status, fParent,
133: fRefactoring.getName(), false);
134: return dialog.open() == IDialogConstants.CANCEL_ID;
135: }
136: }
137:
138: /**
139: * @param refactoring
140: * @param stopSeverity a refactoring status constant from {@link RefactoringStatus}
141: * @param saveMode a save mode from {@link RefactoringSaveHelper}
142: * @param parent
143: * @param context
144: */
145: public RefactoringExecutionHelper(Refactoring refactoring,
146: int stopSeverity, int saveMode, Shell parent,
147: IRunnableContext context) {
148: super ();
149: Assert.isNotNull(refactoring);
150: Assert.isNotNull(parent);
151: Assert.isNotNull(context);
152: fRefactoring = refactoring;
153: fStopSeverity = stopSeverity;
154: fParent = parent;
155: fExecContext = context;
156: fSaveMode = saveMode;
157: }
158:
159: /**
160: * Must be called in the UI thread.
161: * @param fork if set, the operation will be forked
162: * @param cancelable if set, the operation will be cancellable
163: * @throws InterruptedException thrown when the operation is cancelled
164: * @throws InvocationTargetException thrown when the operation failed to execute
165: */
166: public void perform(boolean fork, boolean cancelable)
167: throws InterruptedException, InvocationTargetException {
168: Assert.isTrue(Display.getCurrent() != null);
169: final IJobManager manager = Job.getJobManager();
170: final ISchedulingRule rule;
171: if (fRefactoring instanceof IScheduledRefactoring) {
172: rule = ((IScheduledRefactoring) fRefactoring)
173: .getSchedulingRule();
174: } else {
175: rule = ResourcesPlugin.getWorkspace().getRoot();
176: }
177: class OperationRunner extends WorkbenchRunnableAdapter
178: implements IThreadListener {
179: public OperationRunner(IWorkspaceRunnable runnable,
180: ISchedulingRule schedulingRule) {
181: super (runnable, schedulingRule);
182: }
183:
184: public void threadChange(Thread thread) {
185: manager.transferRule(getSchedulingRule(), thread);
186: }
187: }
188: try {
189: try {
190: Runnable r = new Runnable() {
191: public void run() {
192: manager.beginRule(rule, null);
193: }
194: };
195: BusyIndicator.showWhile(fParent.getDisplay(), r);
196: } catch (OperationCanceledException e) {
197: throw new InterruptedException(e.getMessage());
198: }
199:
200: RefactoringSaveHelper saveHelper = new RefactoringSaveHelper(
201: fSaveMode);
202: if (!saveHelper.saveEditors(fParent))
203: throw new InterruptedException();
204: final Operation op = new Operation(fork);
205: fRefactoring.setValidationContext(fParent);
206: try {
207: fExecContext.run(fork, cancelable, new OperationRunner(
208: op, rule));
209: if (fork && op.fPerformChangeOperation != null)
210: fExecContext.run(false, false, new OperationRunner(
211: op.fPerformChangeOperation, rule));
212:
213: if (op.fPerformChangeOperation != null) {
214: RefactoringStatus validationStatus = op.fPerformChangeOperation
215: .getValidationStatus();
216: if (validationStatus != null
217: && validationStatus.hasFatalError()) {
218: MessageDialog
219: .openError(
220: fParent,
221: fRefactoring.getName(),
222: Messages
223: .format(
224: RefactoringMessages.RefactoringExecutionHelper_cannot_execute,
225: validationStatus
226: .getMessageMatchingSeverity(RefactoringStatus.FATAL)));
227: return;
228: }
229: }
230: } catch (InvocationTargetException e) {
231: PerformChangeOperation pco = op.fPerformChangeOperation;
232: if (pco != null && pco.changeExecutionFailed()) {
233: ChangeExceptionHandler handler = new ChangeExceptionHandler(
234: fParent, fRefactoring);
235: Throwable inner = e.getTargetException();
236: if (inner instanceof RuntimeException) {
237: handler.handle(pco.getChange(),
238: (RuntimeException) inner);
239: } else if (inner instanceof CoreException) {
240: handler.handle(pco.getChange(),
241: (CoreException) inner);
242: } else {
243: throw e;
244: }
245: } else {
246: throw e;
247: }
248: } catch (OperationCanceledException e) {
249: throw new InterruptedException(e.getMessage());
250: } finally {
251: saveHelper.triggerBuild();
252: }
253: } finally {
254: manager.endRule(rule);
255: fRefactoring.setValidationContext(null);
256: }
257: }
258: }
|