1 /*******************************************************************************
2 * Copyright (c) 2000, 2009 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.ui.refactoring;
13 import java.lang.reflect.InvocationTargetException;
15 import org.eclipse.swt.custom.BusyIndicator;
16 import org.eclipse.swt.widgets.Display;
17 import org.eclipse.swt.widgets.Shell;
19 import org.eclipse.core.runtime.Assert;
20 import org.eclipse.core.runtime.CoreException;
21 import org.eclipse.core.runtime.IProgressMonitor;
22 import org.eclipse.core.runtime.OperationCanceledException;
23 import org.eclipse.core.runtime.SubProgressMonitor;
24 import org.eclipse.core.runtime.jobs.IJobManager;
25 import org.eclipse.core.runtime.jobs.ISchedulingRule;
26 import org.eclipse.core.runtime.jobs.Job;
28 import org.eclipse.core.resources.IWorkspaceRunnable;
29 import org.eclipse.core.resources.ResourcesPlugin;
31 import org.eclipse.jface.dialogs.Dialog;
32 import org.eclipse.jface.dialogs.IDialogConstants;
33 import org.eclipse.jface.dialogs.MessageDialog;
34 import org.eclipse.jface.operation.IRunnableContext;
36 import org.eclipse.ltk.core.refactoring.Change;
37 import org.eclipse.ltk.core.refactoring.PerformChangeOperation;
38 import org.eclipse.ltk.core.refactoring.Refactoring;
39 import org.eclipse.ltk.core.refactoring.RefactoringCore;
40 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
41 import org.eclipse.ltk.ui.refactoring.RefactoringUI;
43 import org.eclipse.jdt.internal.corext.util.Messages;
45 import org.eclipse.jdt.ui.refactoring.RefactoringSaveHelper;
47 import org.eclipse.jdt.internal.ui.actions.WorkbenchRunnableAdapter;
52 * A helper class to execute a refactoring. The class takes care of pushing the
53 * undo change onto the undo stack and folding editor edits into one editor
56 public class RefactoringExecutionHelper {
58 private final Refactoring fRefactoring;
59 private final Shell fParent;
60 private final IRunnableContext fExecContext;
61 private final int fStopSeverity;
62 private final int fSaveMode;
64 private class Operation implements IWorkspaceRunnable {
65 public Change fChange;
66 public PerformChangeOperation fPerformChangeOperation;
67 private final boolean fForked;
68 private final boolean fForkChangeExecution;
70 public Operation(boolean forked, boolean forkChangeExecution) {
72 fForkChangeExecution= forkChangeExecution;
75 public void run(IProgressMonitor pm) throws CoreException {
77 pm.beginTask("", fForked && !fForkChangeExecution ? 7 : 11); //$NON-NLS-1$
78 pm.subTask(""); //$NON-NLS-1$
80 final RefactoringStatus status= fRefactoring.checkAllConditions(new SubProgressMonitor(pm, 4, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
81 if (status.getSeverity() >= fStopSeverity) {
82 final boolean[] canceled= { false };
84 fParent.getDisplay().syncExec(new Runnable() {
86 canceled[0]= showStatusDialog(status);
90 canceled[0]= showStatusDialog(status);
93 throw new OperationCanceledException();
97 fChange= fRefactoring.createChange(new SubProgressMonitor(pm, 2, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
98 fChange.initializeValidationData(new SubProgressMonitor(pm, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
100 fPerformChangeOperation= new PerformChangeOperation(fChange);//RefactoringUI.createUIAwareChangeOperation(fChange);
101 fPerformChangeOperation.setUndoManager(RefactoringCore.getUndoManager(), fRefactoring.getName());
102 if (fRefactoring instanceof IScheduledRefactoring)
103 fPerformChangeOperation.setSchedulingRule(((IScheduledRefactoring)fRefactoring).getSchedulingRule());
105 if (!fForked || fForkChangeExecution)
106 fPerformChangeOperation.run(new SubProgressMonitor(pm, 4, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
113 * @param status the status to show
114 * @return <code>true</code> iff the operation should be cancelled
116 private boolean showStatusDialog(RefactoringStatus status) {
117 Dialog dialog= RefactoringUI.createRefactoringStatusDialog(status, fParent, fRefactoring.getName(), false);
118 return dialog.open() == IDialogConstants.CANCEL_ID;
123 * Creates a new refactoring execution helper.
125 * @param refactoring the refactoring
126 * @param stopSeverity a refactoring status constant from {@link RefactoringStatus}
127 * @param saveMode a save mode from {@link RefactoringSaveHelper}
128 * @param parent the parent shell
129 * @param context the runnable context
131 public RefactoringExecutionHelper(Refactoring refactoring, int stopSeverity, int saveMode, Shell parent, IRunnableContext context) {
133 Assert.isNotNull(refactoring);
134 Assert.isNotNull(parent);
135 Assert.isNotNull(context);
136 fRefactoring= refactoring;
137 fStopSeverity= stopSeverity;
139 fExecContext= context;
144 * Must be called in the UI thread.
145 * @param fork if set, the operation will be forked
146 * @param cancelable if set, the operation will be cancelable
147 * @throws InterruptedException thrown when the operation is cancelled
148 * @throws InvocationTargetException thrown when the operation failed to execute
150 public void perform(boolean fork, boolean cancelable) throws InterruptedException, InvocationTargetException {
151 perform(fork, false, cancelable);
155 * Must be called in the UI thread.<br>
156 * <strong>Use {@link #perform(boolean, boolean)} unless you know exactly what you are doing!</strong>
158 * @param fork if set, the operation will be forked
159 * @param forkChangeExecution if the change should not be executed in the UI thread: This may not work in any case
160 * @param cancelable if set, the operation will be cancelable
161 * @throws InterruptedException thrown when the operation is cancelled
162 * @throws InvocationTargetException thrown when the operation failed to execute
164 public void perform(boolean fork, boolean forkChangeExecution, boolean cancelable) throws InterruptedException, InvocationTargetException {
165 Assert.isTrue(Display.getCurrent() != null);
166 final IJobManager manager= Job.getJobManager();
167 final ISchedulingRule rule;
168 if (fRefactoring instanceof IScheduledRefactoring) {
169 rule= ((IScheduledRefactoring)fRefactoring).getSchedulingRule();
171 rule= ResourcesPlugin.getWorkspace().getRoot();
175 Runnable r= new Runnable() {
177 manager.beginRule(rule, null);
180 BusyIndicator.showWhile(fParent.getDisplay(), r);
181 } catch (OperationCanceledException e) {
182 throw new InterruptedException(e.getMessage());
185 RefactoringSaveHelper saveHelper= new RefactoringSaveHelper(fSaveMode);
186 if (!saveHelper.saveEditors(fParent))
187 throw new InterruptedException();
188 final Operation op= new Operation(fork, forkChangeExecution);
189 fRefactoring.setValidationContext(fParent);
191 fExecContext.run(fork, cancelable, new WorkbenchRunnableAdapter(op, rule, true));
192 if (fork && !forkChangeExecution && op.fPerformChangeOperation != null)
193 fExecContext.run(false, false, new WorkbenchRunnableAdapter(op.fPerformChangeOperation, rule, true));
195 if (op.fPerformChangeOperation != null) {
196 RefactoringStatus validationStatus= op.fPerformChangeOperation.getValidationStatus();
197 if (validationStatus != null && validationStatus.hasFatalError()) {
198 MessageDialog.openError(fParent, fRefactoring.getName(),
200 RefactoringMessages.RefactoringExecutionHelper_cannot_execute,
201 validationStatus.getMessageMatchingSeverity(RefactoringStatus.FATAL)));
202 throw new InterruptedException();
205 } catch (InvocationTargetException e) {
206 PerformChangeOperation pco= op.fPerformChangeOperation;
207 if (pco != null && pco.changeExecutionFailed()) {
208 ChangeExceptionHandler handler= new ChangeExceptionHandler(fParent, fRefactoring);
209 Throwable inner= e.getTargetException();
210 if (inner instanceof RuntimeException) {
211 handler.handle(pco.getChange(), (RuntimeException)inner);
212 } else if (inner instanceof CoreException) {
213 handler.handle(pco.getChange(), (CoreException)inner);
220 } catch (OperationCanceledException e) {
221 throw new InterruptedException(e.getMessage());
223 saveHelper.triggerIncrementalBuild();
226 manager.endRule(rule);
227 fRefactoring.setValidationContext(null);