]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-after/ui/org/eclipse/jdt/ui/actions/GenerateMethodAbstractAction.java
Some talks, mostly identical.
[ifi-stolz-refaktor.git] / case-study / jdt-after / ui / org / eclipse / jdt / ui / actions / GenerateMethodAbstractAction.java
CommitLineData
1b2798f6
EK
1/*******************************************************************************
2 * Copyright (c) 2008, 2011 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
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Mateusz Matela <mateusz.matela@gmail.com> - [code manipulation] [dcr] toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=26070
11 * Mateusz Matela <mateusz.matela@gmail.com> - [toString] toString() generator: Fields in declaration order - https://bugs.eclipse.org/bugs/show_bug.cgi?id=279924
12 *******************************************************************************/
13package org.eclipse.jdt.ui.actions;
14
15
16import java.lang.reflect.InvocationTargetException;
17
18import org.eclipse.swt.widgets.Shell;
19
20import org.eclipse.core.runtime.CoreException;
21import org.eclipse.core.runtime.jobs.ISchedulingRule;
22
23import org.eclipse.core.resources.IWorkspaceRunnable;
24import org.eclipse.core.resources.ResourcesPlugin;
25
26import org.eclipse.jface.dialogs.Dialog;
27import org.eclipse.jface.dialogs.MessageDialog;
28import org.eclipse.jface.operation.IRunnableContext;
29import org.eclipse.jface.viewers.IStructuredSelection;
30import org.eclipse.jface.window.Window;
31
32import org.eclipse.jface.text.IRewriteTarget;
33import org.eclipse.jface.text.ITextSelection;
34
35import org.eclipse.ui.IEditorPart;
36import org.eclipse.ui.IWorkbenchSite;
37import org.eclipse.ui.PlatformUI;
38
39import org.eclipse.ltk.core.refactoring.RefactoringStatus;
40import org.eclipse.ltk.core.refactoring.RefactoringStatusContext;
41import org.eclipse.ltk.ui.refactoring.RefactoringUI;
42
43import org.eclipse.jdt.core.IClassFile;
44import org.eclipse.jdt.core.ICompilationUnit;
45import org.eclipse.jdt.core.IJavaElement;
46import org.eclipse.jdt.core.IJavaProject;
47import org.eclipse.jdt.core.IMember;
48import org.eclipse.jdt.core.IOpenable;
49import org.eclipse.jdt.core.ISourceReference;
50import org.eclipse.jdt.core.IType;
51import org.eclipse.jdt.core.JavaModelException;
52import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
53import org.eclipse.jdt.core.dom.CompilationUnit;
54import org.eclipse.jdt.core.dom.ITypeBinding;
55import org.eclipse.jdt.core.dom.NodeFinder;
56
57import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
58import org.eclipse.jdt.internal.corext.dom.ASTNodes;
59import org.eclipse.jdt.internal.corext.fix.CleanUpConstants;
60import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
61import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
62import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
63import org.eclipse.jdt.internal.corext.util.Messages;
64
65import org.eclipse.jdt.ui.JavaUI;
66import org.eclipse.jdt.ui.PreferenceConstants;
67import org.eclipse.jdt.ui.cleanup.CleanUpOptions;
68
69import org.eclipse.jdt.internal.ui.JavaPlugin;
70import org.eclipse.jdt.internal.ui.actions.ActionMessages;
71import org.eclipse.jdt.internal.ui.actions.ActionUtil;
72import org.eclipse.jdt.internal.ui.actions.SelectionConverter;
73import org.eclipse.jdt.internal.ui.actions.WorkbenchRunnableAdapter;
74import org.eclipse.jdt.internal.ui.dialogs.SourceActionDialog;
75import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
76import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
77import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
78import org.eclipse.jdt.internal.ui.util.BusyIndicatorRunnableContext;
79import org.eclipse.jdt.internal.ui.util.ElementValidator;
80import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
81import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
82
83/**
84 * An abstract class containing elements common for <code>GenerateHashCodeEqualsAction</code> and
85 * <code>GenerateToStringAction</code>
86 *
87 * since 3.5
88 */
89public abstract class GenerateMethodAbstractAction extends SelectionDispatchAction {
90
91
92 CompilationUnitEditor fEditor;
93 CompilationUnit fUnit;
94 ITypeBinding fTypeBinding;
95
96 protected GenerateMethodAbstractAction(IWorkbenchSite site) {
97 super(site);
98 }
99
100 static RefactoringStatusContext createRefactoringStatusContext(IJavaElement element) {
101 if (element instanceof IMember) {
102 return JavaStatusContext.create((IMember) element);
103 }
104 if (element instanceof ISourceReference) {
105 IOpenable openable= element.getOpenable();
106 try {
107 if (openable instanceof ICompilationUnit) {
108 return JavaStatusContext.create((ICompilationUnit) openable, ((ISourceReference) element).getSourceRange());
109 } else if (openable instanceof IClassFile) {
110 return JavaStatusContext.create((IClassFile) openable, ((ISourceReference) element).getSourceRange());
111 }
112 } catch (JavaModelException e) {
113 // ignore
114 }
115 }
116 return null;
117 }
118
119 /**
120 * Can this action be enabled on the specified selection?
121 *
122 * @param selection the selection to test
123 * @return <code>true</code> if it can be enabled, <code>false</code>
124 * otherwise
125 * @throws JavaModelException if the kind of the selection cannot be
126 * determined
127 */
128 boolean canEnable(final IStructuredSelection selection) throws JavaModelException {
129 if (selection.size() == 1) {
130 final Object element= selection.getFirstElement();
131 if (element instanceof IType) {
132 final IType type= (IType) element;
133 return type.getCompilationUnit() != null && type.isClass();
134 }
135 if (element instanceof ICompilationUnit)
136 return true;
137 }
138 return false;
139 }
140
141 /**
142 * Returns the single selected type from the specified selection.
143 *
144 * @param selection the selection
145 * @return a single selected type, or <code>null</code>
146 * @throws JavaModelException if the kind of the selection cannot be
147 * determined
148 */
149 IType getSelectedType(final IStructuredSelection selection) throws JavaModelException {
150 if (selection.size() == 1 && selection.getFirstElement() instanceof IType) {
151 final IType type= (IType) selection.getFirstElement();
152 if (type.getCompilationUnit() != null && type.isClass())
153 return type;
154 } else if (selection.getFirstElement() instanceof ICompilationUnit) {
155 final ICompilationUnit unit= (ICompilationUnit) selection.getFirstElement();
156 final IType type= unit.findPrimaryType();
157 if (type != null && type.isClass())
158 return type;
159 }
160 return null;
161 }
162
163 @Override
164 public void run(IStructuredSelection selection) {
165 try {
166 checkAndRun(getSelectedType(selection));
167 } catch (CoreException exception) {
168 ExceptionHandler.handle(exception, getShell(), getErrorCaption(), ActionMessages.GenerateMethodAbstractAction_error_cannot_create);
169 }
170 }
171
172
173 @Override
174 public void run(ITextSelection selection) {
175 try {
176 checkAndRun(SelectionConverter.getTypeAtOffset(fEditor));
177 } catch (CoreException e) {
178 ExceptionHandler.handle(e, getShell(), getErrorCaption(), ActionMessages.GenerateMethodAbstractAction_error_cannot_create);
179 }
180 }
181
182 void checkAndRun(IType type) throws CoreException {
183 if (type == null) {
184 MessageDialog.openInformation(getShell(), getErrorCaption(),
185 ActionMessages.GenerateMethodAbstractAction_error_not_applicable);
186 notifyResult(false);
187 }
188 if (!ElementValidator.check(type, getShell(), getErrorCaption(), false)
189 || ! ActionUtil.isEditable(fEditor, getShell(), type)) {
190 notifyResult(false);
191 return;
192 }
193 if (type == null) {
194 MessageDialog.openError(getShell(), getErrorCaption(), ActionMessages.GenerateMethodAbstractAction_error_removed_type);
195 notifyResult(false);
196 return;
197 }
198 if (type.isAnnotation()) {
199 MessageDialog.openInformation(getShell(), getErrorCaption(), ActionMessages.GenerateMethodAbstractAction_annotation_not_applicable);
200 notifyResult(false);
201 return;
202 }
203 if (type.isInterface()) {
204 MessageDialog.openInformation(getShell(), getErrorCaption(), ActionMessages.GenerateMethodAbstractAction_interface_not_applicable);
205 notifyResult(false);
206 return;
207 }
208 if (type.isEnum()) {
209 MessageDialog.openInformation(getShell(), getErrorCaption(), ActionMessages.GenerateMethodAbstractAction_enum_not_applicable);
210 notifyResult(false);
211 return;
212 }
213 if (type.isAnonymous()) {
214 MessageDialog.openError(getShell(), getErrorCaption(), ActionMessages.GenerateMethodAbstractAction_anonymous_type_not_applicable);
215 notifyResult(false);
216 return;
217 }
218 run(getShell(), type);
219 }
220
221 /**
222 * Runs the action.
223 *
224 * @param shell the shell to use
225 * @param type the type to generate stubs for
226 * @throws CoreException if an error occurs
227 */
228 void run(Shell shell, IType type) throws CoreException {
229
230 initialize(type);
231
232 boolean regenerate= false;
233 if (isMethodAlreadyImplemented(fTypeBinding)) {
234 regenerate= MessageDialog.openQuestion(getShell(), getErrorCaption(), Messages.format(ActionMessages.GenerateMethodAbstractAction_already_has_this_method_error, new String[] {
235 BasicElementLabels.getJavaElementName(fTypeBinding.getQualifiedName()), getAlreadyImplementedErrorMethodName() }));
236 if (!regenerate) {
237 notifyResult(false);
238 return;
239 }
240 }
241
242 if (!generateCandidates()) {
243 MessageDialog.openInformation(getShell(), getErrorCaption(),
244 getNoMembersError());
245 notifyResult(false);
246 return;
247 }
248
249 final SourceActionDialog dialog= createDialog(shell, type);
250 final int dialogResult= dialog.open();
251
252 if (dialogResult == Window.OK) {
253
254 final Object[] selected= dialog.getResult();
255 if (selected == null) {
256 notifyResult(false);
257 return;
258 }
259 final CodeGenerationSettings settings= createSettings(type, dialog);
260 final IWorkspaceRunnable operation= createOperation(selected, settings, regenerate, type, dialog.getElementPosition());
261
262 ITypeBinding superclass= fTypeBinding.getSuperclass();
263 RefactoringStatus status= new RefactoringStatus();
264
265 status.merge(checkGeneralConditions(type, settings, selected));
266
267 if (!"java.lang.Object".equals(superclass.getQualifiedName())) { //$NON-NLS-1$
268 status.merge(checkSuperClass(superclass));
269 }
270
271 for (int i= 0; i < selected.length; i++) {
272 status.merge(checkMember(selected[i]));
273 }
274
275 if (status.hasEntries()) {
276 Dialog d= RefactoringUI.createLightWeightStatusDialog(status, getShell(), getErrorCaption());
277 if (d.open() != Window.OK) {
278 notifyResult(false);
279 return;
280 }
281 }
282
283 final IEditorPart editor= JavaUI.openInEditor(type.getCompilationUnit());
284 final IRewriteTarget target= editor != null ? (IRewriteTarget) editor.getAdapter(IRewriteTarget.class) : null;
285
286 if (target != null)
287 target.beginCompoundChange();
288 try {
289 IRunnableContext context= JavaPlugin.getActiveWorkbenchWindow();
290 if (context == null)
291 context= new BusyIndicatorRunnableContext();
292 ISchedulingRule schedulingRule= ResourcesPlugin.getWorkspace().getRoot();
293 PlatformUI.getWorkbench().getProgressService().runInUI(context, new WorkbenchRunnableAdapter(operation, schedulingRule), schedulingRule);
294 } catch (InvocationTargetException exception) {
295 ExceptionHandler.handle(exception, shell, getErrorCaption(), null);
296 } catch (InterruptedException exception) {
297 // Do nothing. Operation has been canceled by user.
298 } finally {
299 if (target != null)
300 target.endCompoundChange();
301 }
302 }
303 notifyResult(dialogResult == Window.OK);
304 }
305
306
307 /**
308 *
309 * @param type the type for which a method is created
310 * @param dialog the dialog box where the user has defined his preferences
311 * @return settings applicable for this action
312 */
313 CodeGenerationSettings createSettings(IType type, SourceActionDialog dialog) {
314 CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(type.getJavaProject());
315 return settings.generated_9083001889753781598(dialog, this);
316 }
317
318 /**
319 * @return Message to be shown when a method cannot be generated due to lack of appropriate members
320 */
321 abstract String getNoMembersError();
322
323 /**
324 * @return Caption for a dialog with error message
325 */
326 abstract String getErrorCaption();
327
328 abstract IWorkspaceRunnable createOperation(Object[] selectedBindings, CodeGenerationSettings settings, boolean regenerate, IJavaElement type, IJavaElement elementPosition);
329
330 /**
331 * Checks whether general requirements are fulfilled
332 *
333 * @param type the type for which a method is created
334 * @param settings preferences define by the user
335 * @param selected the type's members selected to be used in generated method
336 * @return RefactoringStatus containing information about eventual problems
337 */
338 abstract RefactoringStatus checkGeneralConditions(IType type, CodeGenerationSettings settings, Object[] selected);
339
340 /**
341 * Checks whether a member fulfills requirements expected by method generator
342 *
343 * @param object member binding to be checked
344 * @return RefactoringStatus containing information about eventual problems
345 */
346 abstract RefactoringStatus checkMember(Object object);
347
348 /**
349 * Checks whether the superclass fulfills requirements expected by method generator
350 * @param superclass superclass type binding to be checked
351 * @return RefactoringStatus containing information about eventual problems
352 */
353 abstract RefactoringStatus checkSuperClass(ITypeBinding superclass);
354
355 /**
356 * Creates the action's main dialog.
357 *
358 * @param shell the shell to use
359 * @param type the type to generate stubs for
360 * @return a dialog with generator-specific options
361 * @throws JavaModelException if creation of the dialog fails
362 */
363 abstract SourceActionDialog createDialog(Shell shell, IType type) throws JavaModelException;
364
365 /**
366 * Chooses type members that can be used in generated method.
367 * Returns false, if there are no such members and the method cannot
368 * be generated
369 * @return true, if the method can be generated (i.e. there are appropriate member fields)
370 * @throws JavaModelException if an error in java model occurs
371 */
372 abstract boolean generateCandidates() throws JavaModelException;
373
374 /**
375 *
376 * @return The message displayed when the method is already implemented in the type.
377 */
378 abstract String getAlreadyImplementedErrorMethodName();
379
380 /**
381 *
382 * @param typeBinding Type to be checked
383 * @return true if given type already contains the method to be generated
384 */
385 abstract boolean isMethodAlreadyImplemented(ITypeBinding typeBinding);
386
387 boolean useBlocks(IJavaProject project) {
388 if (CleanUpOptions.TRUE.equals(PreferenceConstants.getPreference(CleanUpConstants.CONTROL_STATEMENTS_USE_BLOCKS, project))) {
389 return CleanUpOptions.TRUE.equals(PreferenceConstants.getPreference(CleanUpConstants.CONTROL_STATMENTS_USE_BLOCKS_ALWAYS, project))
390 || CleanUpOptions.TRUE.equals(PreferenceConstants.getPreference(CleanUpConstants.CONTROL_STATMENTS_USE_BLOCKS_NO_FOR_RETURN_AND_THROW, project));
391 }
392 return false;
393 }
394
395 void initialize(IType type) throws JavaModelException {
396 RefactoringASTParser parser= new RefactoringASTParser(ASTProvider.SHARED_AST_LEVEL);
397 fUnit= parser.parse(type.getCompilationUnit(), true);
398 fTypeBinding= null;
399 // type cannot be anonymous
400 final AbstractTypeDeclaration declaration= (AbstractTypeDeclaration) ASTNodes.getParent(NodeFinder.perform(fUnit, type.getNameRange()),
401 AbstractTypeDeclaration.class);
402 if (declaration != null)
403 fTypeBinding= declaration.resolveBinding();
404 }
405
406 @Override
407 public void selectionChanged(IStructuredSelection selection) {
408 try {
409 setEnabled(canEnable(selection));
410 } catch (JavaModelException exception) {
411 if (JavaModelUtil.isExceptionToBeLogged(exception))
412 JavaPlugin.log(exception);
413 setEnabled(false);
414 }
415 }
416
417 @Override
418 public void selectionChanged(ITextSelection selection) {
419 // Do nothing
420 }
421
422}