1 /*******************************************************************************
2  * Copyright (c) 2000, 2020 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *     John Kaplan, johnkaplantech@gmail.com - 108071 [code templates] template for body of newly created class
14  *     Microsoft Corporation - [templates][content assist] - Extract the UI related code - https://bugs.eclipse.org/549989
15  *******************************************************************************/
16 package org.eclipse.jdt.ui.wizards;
17 
18 import java.lang.reflect.InvocationTargetException;
19 import java.math.BigDecimal;
20 import java.net.URI;
21 import java.util.ArrayList;
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Set;
25 import java.util.regex.Matcher;
26 import java.util.regex.Pattern;
27 
28 import org.eclipse.equinox.bidi.StructuredTextTypeHandlerFactory;
29 
30 import org.eclipse.swt.SWT;
31 import org.eclipse.swt.events.KeyAdapter;
32 import org.eclipse.swt.events.KeyEvent;
33 import org.eclipse.swt.events.SelectionEvent;
34 import org.eclipse.swt.events.SelectionListener;
35 import org.eclipse.swt.events.VerifyEvent;
36 import org.eclipse.swt.events.VerifyListener;
37 import org.eclipse.swt.graphics.Image;
38 import org.eclipse.swt.layout.GridData;
39 import org.eclipse.swt.layout.GridLayout;
40 import org.eclipse.swt.widgets.Button;
41 import org.eclipse.swt.widgets.Composite;
42 import org.eclipse.swt.widgets.Control;
43 import org.eclipse.swt.widgets.Item;
44 import org.eclipse.swt.widgets.Link;
45 import org.eclipse.swt.widgets.Text;
46 
47 import org.eclipse.core.filesystem.EFS;
48 import org.eclipse.core.filesystem.IFileStore;
49 
50 import org.eclipse.core.runtime.CoreException;
51 import org.eclipse.core.runtime.IPath;
52 import org.eclipse.core.runtime.IProgressMonitor;
53 import org.eclipse.core.runtime.IStatus;
54 import org.eclipse.core.runtime.NullProgressMonitor;
55 import org.eclipse.core.runtime.SubProgressMonitor;
56 
57 import org.eclipse.core.resources.IResource;
58 import org.eclipse.core.resources.ResourcesPlugin;
59 
60 import org.eclipse.text.edits.TextEdit;
61 
62 import org.eclipse.jface.contentassist.SubjectControlContentAssistant;
63 import org.eclipse.jface.dialogs.MessageDialog;
64 import org.eclipse.jface.operation.IRunnableWithProgress;
65 import org.eclipse.jface.preference.PreferenceDialog;
66 import org.eclipse.jface.util.BidiUtils;
67 import org.eclipse.jface.viewers.CellEditor;
68 import org.eclipse.jface.viewers.ICellModifier;
69 import org.eclipse.jface.viewers.ISelection;
70 import org.eclipse.jface.viewers.IStructuredSelection;
71 import org.eclipse.jface.viewers.LabelProvider;
72 import org.eclipse.jface.viewers.TableViewer;
73 import org.eclipse.jface.window.Window;
74 
75 import org.eclipse.jface.text.BadLocationException;
76 import org.eclipse.jface.text.ITextSelection;
77 import org.eclipse.jface.text.templates.Template;
78 import org.eclipse.jface.text.templates.TemplateException;
79 
80 import org.eclipse.ui.contentassist.ContentAssistHandler;
81 import org.eclipse.ui.dialogs.ElementListSelectionDialog;
82 import org.eclipse.ui.dialogs.PreferencesUtil;
83 
84 import org.eclipse.jdt.core.Flags;
85 import org.eclipse.jdt.core.IBuffer;
86 import org.eclipse.jdt.core.ICompilationUnit;
87 import org.eclipse.jdt.core.IField;
88 import org.eclipse.jdt.core.IJavaElement;
89 import org.eclipse.jdt.core.IJavaProject;
90 import org.eclipse.jdt.core.IMethod;
91 import org.eclipse.jdt.core.IPackageFragment;
92 import org.eclipse.jdt.core.IPackageFragmentRoot;
93 import org.eclipse.jdt.core.ISourceRange;
94 import org.eclipse.jdt.core.IType;
95 import org.eclipse.jdt.core.JavaConventions;
96 import org.eclipse.jdt.core.JavaCore;
97 import org.eclipse.jdt.core.JavaModelException;
98 import org.eclipse.jdt.core.Signature;
99 import org.eclipse.jdt.core.ToolFactory;
100 import org.eclipse.jdt.core.compiler.IProblem;
101 import org.eclipse.jdt.core.compiler.IScanner;
102 import org.eclipse.jdt.core.compiler.ITerminalSymbols;
103 import org.eclipse.jdt.core.compiler.InvalidInputException;
104 import org.eclipse.jdt.core.dom.ASTNode;
105 import org.eclipse.jdt.core.dom.ASTParser;
106 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
107 import org.eclipse.jdt.core.dom.CompilationUnit;
108 import org.eclipse.jdt.core.dom.ITypeBinding;
109 import org.eclipse.jdt.core.dom.ImportDeclaration;
110 import org.eclipse.jdt.core.dom.ParameterizedType;
111 import org.eclipse.jdt.core.dom.Type;
112 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
113 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
114 import org.eclipse.jdt.core.formatter.CodeFormatter;
115 import org.eclipse.jdt.core.manipulation.CodeGeneration;
116 import org.eclipse.jdt.core.search.IJavaSearchConstants;
117 import org.eclipse.jdt.core.search.IJavaSearchScope;
118 import org.eclipse.jdt.core.search.SearchEngine;
119 
120 import org.eclipse.jdt.internal.core.manipulation.StubUtility;
121 import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
122 import org.eclipse.jdt.internal.core.manipulation.util.Strings;
123 import org.eclipse.jdt.internal.corext.codemanipulation.AddUnimplementedConstructorsOperation;
124 import org.eclipse.jdt.internal.corext.codemanipulation.AddUnimplementedMethodsOperation;
125 import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
126 import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
127 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
128 import org.eclipse.jdt.internal.corext.dom.IASTSharedValues;
129 import org.eclipse.jdt.internal.corext.dom.TokenScanner;
130 import org.eclipse.jdt.internal.corext.refactoring.StubTypeContext;
131 import org.eclipse.jdt.internal.corext.refactoring.TypeContextChecker;
132 import org.eclipse.jdt.internal.corext.template.java.TemplateUtils;
133 import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil;
134 import org.eclipse.jdt.internal.corext.util.JavaConventionsUtil;
135 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
136 import org.eclipse.jdt.internal.corext.util.Messages;
137 import org.eclipse.jdt.internal.corext.util.Resources;
138 
139 import org.eclipse.jdt.ui.JavaElementLabelProvider;
140 
141 import org.eclipse.jdt.internal.ui.JavaPlugin;
142 import org.eclipse.jdt.internal.ui.JavaPluginImages;
143 import org.eclipse.jdt.internal.ui.dialogs.FilteredTypesSelectionDialog;
144 import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
145 import org.eclipse.jdt.internal.ui.dialogs.TableTextCellEditor;
146 import org.eclipse.jdt.internal.ui.dialogs.TextFieldNavigationHandler;
147 import org.eclipse.jdt.internal.ui.preferences.CodeTemplatePreferencePage;
148 import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
149 import org.eclipse.jdt.internal.ui.preferences.formatter.FormatterProfileManager;
150 import org.eclipse.jdt.internal.ui.refactoring.contentassist.CompletionContextRequestor;
151 import org.eclipse.jdt.internal.ui.refactoring.contentassist.ControlContentAssistHelper;
152 import org.eclipse.jdt.internal.ui.refactoring.contentassist.JavaPackageCompletionProcessor;
153 import org.eclipse.jdt.internal.ui.refactoring.contentassist.JavaTypeCompletionProcessor;
154 import org.eclipse.jdt.internal.ui.text.correction.PreviewFeaturesSubProcessor;
155 import org.eclipse.jdt.internal.ui.util.SWTUtil;
156 import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages;
157 import org.eclipse.jdt.internal.ui.wizards.SuperInterfaceSelectionDialog;
158 import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField;
159 import org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
160 import org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter;
161 import org.eclipse.jdt.internal.ui.wizards.dialogfields.IStringButtonAdapter;
162 import org.eclipse.jdt.internal.ui.wizards.dialogfields.LayoutUtil;
163 import org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField;
164 import org.eclipse.jdt.internal.ui.wizards.dialogfields.SelectionButtonDialogField;
165 import org.eclipse.jdt.internal.ui.wizards.dialogfields.SelectionButtonDialogFieldGroup;
166 import org.eclipse.jdt.internal.ui.wizards.dialogfields.Separator;
167 import org.eclipse.jdt.internal.ui.wizards.dialogfields.StringButtonDialogField;
168 import org.eclipse.jdt.internal.ui.wizards.dialogfields.StringButtonStatusDialogField;
169 import org.eclipse.jdt.internal.ui.wizards.dialogfields.StringDialogField;
170 
171 /**
172  * The class <code>NewTypeWizardPage</code> contains controls and validation routines
173  * for a 'New Type WizardPage'. Implementors decide which components to add and to enable.
174  * Implementors can also customize the validation code. <code>NewTypeWizardPage</code>
175  * is intended to serve as base class of all wizards that create types like applets, servlets, classes,
176  * interfaces, etc.
177  * <p>
178  * See {@link NewClassWizardPage} or {@link NewInterfaceWizardPage} for an
179  * example usage of the <code>NewTypeWizardPage</code>.
180  * </p>
181  *
182  * @see org.eclipse.jdt.ui.wizards.NewClassWizardPage
183  * @see org.eclipse.jdt.ui.wizards.NewInterfaceWizardPage
184  * @see org.eclipse.jdt.ui.wizards.NewEnumWizardPage
185  * @see org.eclipse.jdt.ui.wizards.NewAnnotationWizardPage
186  *
187  * @since 2.0
188  */
189 public abstract class NewTypeWizardPage extends NewContainerWizardPage {
190 
191 	/**
192 	 * Class used in stub creation routines to add needed imports to a
193 	 * compilation unit.
194 	 */
195 	public static class ImportsManager {
196 
197 		private final CompilationUnit fAstRoot;
198 		private final ImportRewrite fImportsRewrite;
199 
ImportsManager(CompilationUnit astRoot)200 		/* package */ ImportsManager(CompilationUnit astRoot) {
201 			fAstRoot= astRoot;
202 			fImportsRewrite= StubUtility.createImportRewrite(astRoot, true);
203 		}
204 
getCompilationUnit()205 		/* package */ ICompilationUnit getCompilationUnit() {
206 			return fImportsRewrite.getCompilationUnit();
207 		}
208 
209 		/**
210 		 * Adds a new import declaration that is sorted in the existing imports.
211 		 * If an import already exists or the import would conflict with an import
212 		 * of an other type with the same simple name, the import is not added.
213 		 *
214 		 * @param qualifiedTypeName The fully qualified name of the type to import
215 		 * (dot separated).
216 		 * @return Returns the simple type name that can be used in the code or the
217 		 * fully qualified type name if an import conflict prevented the import.
218 		 */
addImport(String qualifiedTypeName)219 		public String addImport(String qualifiedTypeName) {
220 			return fImportsRewrite.addImport(qualifiedTypeName);
221 		}
222 
223 		/**
224 		 * Adds a new import declaration that is sorted in the existing imports.
225 		 * If an import already exists or the import would conflict with an import
226 		 * of an other type with the same simple name, the import is not added.
227 		 *
228 		 * @param qualifiedTypeName The fully qualified name of the type to import
229 		 * (dot separated).
230 		 * @param insertPosition the offset where the import will be used
231 		 * @return Returns the simple type name that can be used in the code or the
232 		 * fully qualified type name if an import conflict prevented the import.
233 		 *
234 		 * @since 3.8
235 		 */
addImport(String qualifiedTypeName, int insertPosition)236 		public String addImport(String qualifiedTypeName, int insertPosition) {
237 			ImportRewriteContext context= new ContextSensitiveImportRewriteContext(fAstRoot, insertPosition, fImportsRewrite);
238 			return fImportsRewrite.addImport(qualifiedTypeName, context);
239 		}
240 
241 		/**
242 		 * Adds a new import declaration that is sorted in the existing imports.
243 		 * If an import already exists or the import would conflict with an import
244 		 * of an other type with the same simple name, the import is not added.
245 		 *
246 		 * @param typeBinding the binding of the type to import
247 		 *
248 		 * @return Returns the simple type name that can be used in the code or the
249 		 * fully qualified type name if an import conflict prevented the import.
250 		 */
addImport(ITypeBinding typeBinding)251 		public String addImport(ITypeBinding typeBinding) {
252 			return fImportsRewrite.addImport(typeBinding);
253 		}
254 
255 		/**
256 		 * Adds a new import declaration that is sorted in the existing imports.
257 		 * If an import already exists or the import would conflict with an import
258 		 * of an other type with the same simple name, the import is not added.
259 		 *
260 		 * @param typeBinding the binding of the type to import
261 		 * @param insertPosition the offset where the import will be used
262 		 *
263 		 * @return Returns the simple type name that can be used in the code or the
264 		 * fully qualified type name if an import conflict prevented the import.
265 		 *
266 		 * @since 3.8
267 		 */
addImport(ITypeBinding typeBinding, int insertPosition)268 		public String addImport(ITypeBinding typeBinding, int insertPosition) {
269 			ImportRewriteContext context= new ContextSensitiveImportRewriteContext(fAstRoot, insertPosition, fImportsRewrite);
270 			return fImportsRewrite.addImport(typeBinding, context);
271 		}
272 
273 		/**
274 		 * Adds a new import declaration for a static type that is sorted in the existing imports.
275 		 * If an import already exists or the import would conflict with an import
276 		 * of an other static import with the same simple name, the import is not added.
277 		 *
278 		 * @param declaringTypeName The qualified name of the static's member declaring type
279 		 * @param simpleName the simple name of the member; either a field or a method name.
280 		 * @param isField <code>true</code> specifies that the member is a field, <code>false</code> if it is a
281 		 * method.
282 		 * @return returns either the simple member name if the import was successful or else the qualified name if
283 		 * an import conflict prevented the import.
284 		 *
285 		 * @since 3.2
286 		 */
addStaticImport(String declaringTypeName, String simpleName, boolean isField)287 		public String addStaticImport(String declaringTypeName, String simpleName, boolean isField) {
288 			return fImportsRewrite.addStaticImport(declaringTypeName, simpleName, isField);
289 		}
290 
create(boolean needsSave, IProgressMonitor monitor)291 		/* package */ void create(boolean needsSave, IProgressMonitor monitor) throws CoreException {
292 			TextEdit edit= fImportsRewrite.rewriteImports(monitor);
293 			JavaModelUtil.applyEdit(fImportsRewrite.getCompilationUnit(), edit, needsSave, null);
294 		}
295 
removeImport(String qualifiedName)296 		/* package */ void removeImport(String qualifiedName) {
297 			fImportsRewrite.removeImport(qualifiedName);
298 		}
299 
removeStaticImport(String qualifiedName)300 		/* package */ void removeStaticImport(String qualifiedName) {
301 			fImportsRewrite.removeStaticImport(qualifiedName);
302 		}
303 	}
304 
305 
306 	/** Public access flag. See The Java Virtual Machine Specification for more details. */
307 	public int F_PUBLIC = Flags.AccPublic;
308 	/** Private access flag. See The Java Virtual Machine Specification for more details. */
309 	public int F_PRIVATE = Flags.AccPrivate;
310 	/**  Protected access flag. See The Java Virtual Machine Specification for more details. */
311 	public int F_PROTECTED = Flags.AccProtected;
312 	/** Static access flag. See The Java Virtual Machine Specification for more details. */
313 	public int F_STATIC = Flags.AccStatic;
314 	/** Final access flag. See The Java Virtual Machine Specification for more details. */
315 	public int F_FINAL = Flags.AccFinal;
316 	/** Abstract property flag. See The Java Virtual Machine Specification for more details. */
317 	public int F_ABSTRACT = Flags.AccAbstract;
318 
319 	private final static String PAGE_NAME= "NewTypeWizardPage"; //$NON-NLS-1$
320 
321 	/** Field ID of the package input field. */
322 	protected final static String PACKAGE= PAGE_NAME + ".package";	 //$NON-NLS-1$
323 	/** Field ID of the enclosing type input field. */
324 	protected final static String ENCLOSING= PAGE_NAME + ".enclosing"; //$NON-NLS-1$
325 	/** Field ID of the enclosing type checkbox. */
326 	protected final static String ENCLOSINGSELECTION= ENCLOSING + ".selection"; //$NON-NLS-1$
327 	/** Field ID of the type name input field. */
328 	protected final static String TYPENAME= PAGE_NAME + ".typename"; //$NON-NLS-1$
329 	/** Field ID of the super type input field. */
330 	protected final static String SUPER= PAGE_NAME + ".superclass"; //$NON-NLS-1$
331 	/** Field ID of the super interfaces input field. */
332 	protected final static String INTERFACES= PAGE_NAME + ".interfaces"; //$NON-NLS-1$
333 	/** Field ID of the modifier check boxes. */
334 	protected final static String MODIFIERS= PAGE_NAME + ".modifiers"; //$NON-NLS-1$
335 	/** Field ID of the method stubs check boxes. */
336 	protected final static String METHODS= PAGE_NAME + ".methods"; //$NON-NLS-1$
337 
338 	private static class InterfaceWrapper {
339 		public String interfaceName;
340 
InterfaceWrapper(String interfaceName)341 		public InterfaceWrapper(String interfaceName) {
342 			this.interfaceName= interfaceName;
343 		}
344 
345 		@Override
hashCode()346 		public int hashCode() {
347 			return interfaceName.hashCode();
348 		}
349 
350 		@Override
equals(Object obj)351 		public boolean equals(Object obj) {
352 			return obj != null && getClass().equals(obj.getClass()) && ((InterfaceWrapper) obj).interfaceName.equals(interfaceName);
353 		}
354 	}
355 
356 	private static class InterfacesListLabelProvider extends LabelProvider {
357 		private Image fInterfaceImage;
358 
InterfacesListLabelProvider()359 		public InterfacesListLabelProvider() {
360 			fInterfaceImage= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_INTERFACE);
361 		}
362 
363 		@Override
getText(Object element)364 		public String getText(Object element) {
365 			return BasicElementLabels.getJavaElementName(((InterfaceWrapper) element).interfaceName);
366 		}
367 
368 		@Override
getImage(Object element)369 		public Image getImage(Object element) {
370 			return fInterfaceImage;
371 		}
372 	}
373 
374 	private StringButtonStatusDialogField fPackageDialogField;
375 
376 	private SelectionButtonDialogField fEnclosingTypeSelection;
377 	private StringButtonDialogField fEnclosingTypeDialogField;
378 
379 	private boolean fCanModifyPackage;
380 	private boolean fCanModifyEnclosingType;
381 
382 	private IPackageFragment fCurrPackage;
383 
384 	private IType fCurrEnclosingType;
385 	/**
386 	 * a handle to the type to be created (does usually not exist, can be null)
387 	 */
388 	private IType fCurrType;
389 	private StringDialogField fTypeNameDialogField;
390 
391 	private StringButtonDialogField fSuperClassDialogField;
392 	private ListDialogField<InterfaceWrapper> fSuperInterfacesDialogField;
393 
394 	private SelectionButtonDialogFieldGroup fAccMdfButtons;
395 	private SelectionButtonDialogFieldGroup fOtherMdfButtons;
396 
397 	/**
398 	 * @noreference This field is not intended to be referenced by clients.
399 	 */
400 	protected SelectionButtonDialogField fAddCommentButton;
401 	private boolean fUseAddCommentButtonValue; // used for compatibility: Wizards that don't show the comment button control
402 	// will use the preferences settings
403 
404 	private IType fCreatedType;
405 
406 	private JavaPackageCompletionProcessor fCurrPackageCompletionProcessor;
407 	private JavaTypeCompletionProcessor fEnclosingTypeCompletionProcessor;
408 	private StubTypeContext fSuperClassStubTypeContext;
409 	private StubTypeContext fSuperInterfaceStubTypeContext;
410 
411 	protected IStatus fEnclosingTypeStatus;
412 	protected IStatus fPackageStatus;
413 	protected IStatus fTypeNameStatus;
414 	protected IStatus fSuperClassStatus;
415 	protected IStatus fModifierStatus;
416 	protected IStatus fSuperInterfacesStatus;
417 
418 	private final int PUBLIC_INDEX= 0, DEFAULT_INDEX= 1, PRIVATE_INDEX= 2, PROTECTED_INDEX= 3;
419 	private final int ABSTRACT_INDEX= 0, FINAL_INDEX= 1, STATIC_INDEX= 2, ENUM_ANNOT_STATIC_INDEX= 1;
420 
421 	private int fTypeKind;
422 
423 	/**
424 	 * Constant to signal that the created type is a class.
425 	 * @since 3.1
426 	 */
427 	public static final int CLASS_TYPE = 1;
428 
429 	/**
430 	 * Constant to signal that the created type is a interface.
431 	 * @since 3.1
432 	 */
433 	public static final int INTERFACE_TYPE = 2;
434 
435 	/**
436 	 * Constant to signal that the created type is an enum.
437 	 * @since 3.1
438 	 */
439 	public static final int ENUM_TYPE = 3;
440 
441 	/**
442 	 * Constant to signal that the created type is an annotation.
443 	 * @since 3.1
444 	 */
445 	public static final int ANNOTATION_TYPE = 4;
446 
447 	/**
448 	 * Constant to signal that the created type is an record.
449 	 * @since 3.21
450 	 * @noreference This field is not intended to be referenced by clients.
451 	 */
452 	public static final int RECORD_TYPE = 5;
453 
454 	/**
455 	 * Creates a new <code>NewTypeWizardPage</code>.
456 	 *
457 	 * @param isClass <code>true</code> if a new class is to be created; otherwise
458 	 * an interface is to be created
459 	 * @param pageName the wizard page's name
460 	 */
NewTypeWizardPage(boolean isClass, String pageName)461 	public NewTypeWizardPage(boolean isClass, String pageName) {
462 		this(isClass ? CLASS_TYPE : INTERFACE_TYPE, pageName);
463 	}
464 
465 	/**
466 	 * Creates a new <code>NewTypeWizardPage</code>.
467 	 *
468 	 * @param typeKind Signals the kind of the type to be created. Valid kinds are
469 	 * {@link #CLASS_TYPE}, {@link #INTERFACE_TYPE}, {@link #ENUM_TYPE} and {@link #ANNOTATION_TYPE}
470 	 * @param pageName the wizard page's name
471 	 * @since 3.1
472 	 */
NewTypeWizardPage(int typeKind, String pageName)473 	public NewTypeWizardPage(int typeKind, String pageName) {
474 	    super(pageName);
475 	    fTypeKind= typeKind;
476 
477 	    fCreatedType= null;
478 
479 		TypeFieldsAdapter adapter= new TypeFieldsAdapter();
480 
481 		fPackageDialogField= new StringButtonStatusDialogField(adapter);
482 		fPackageDialogField.setDialogFieldListener(adapter);
483 		fPackageDialogField.setLabelText(getPackageLabel());
484 		fPackageDialogField.setButtonLabel(NewWizardMessages.NewTypeWizardPage_package_button);
485 		fPackageDialogField.setStatusWidthHint(NewWizardMessages.NewTypeWizardPage_default);
486 
487 		fEnclosingTypeSelection= new SelectionButtonDialogField(SWT.CHECK);
488 		fEnclosingTypeSelection.setDialogFieldListener(adapter);
489 		fEnclosingTypeSelection.setLabelText(getEnclosingTypeLabel());
490 
491 		fEnclosingTypeDialogField= new StringButtonDialogField(adapter);
492 		fEnclosingTypeDialogField.setDialogFieldListener(adapter);
493 		fEnclosingTypeDialogField.setButtonLabel(NewWizardMessages.NewTypeWizardPage_enclosing_button);
494 
495 		fTypeNameDialogField= new StringDialogField();
496 		fTypeNameDialogField.setDialogFieldListener(adapter);
497 		fTypeNameDialogField.setLabelText(getTypeNameLabel());
498 
499 		fSuperClassDialogField= new StringButtonDialogField(adapter);
500 		fSuperClassDialogField.setDialogFieldListener(adapter);
501 		fSuperClassDialogField.setLabelText(getSuperClassLabel());
502 		fSuperClassDialogField.setButtonLabel(NewWizardMessages.NewTypeWizardPage_superclass_button);
503 
504 		String[] addButtons= new String[] {
505 			NewWizardMessages.NewTypeWizardPage_interfaces_add,
506 			/* 1 */ null,
507 			NewWizardMessages.NewTypeWizardPage_interfaces_remove
508 		};
509 		fSuperInterfacesDialogField= new ListDialogField<>(adapter, addButtons, new InterfacesListLabelProvider());
510 		fSuperInterfacesDialogField.setDialogFieldListener(adapter);
511 		fSuperInterfacesDialogField.setTableColumns(new ListDialogField.ColumnsDescription(1, false));
512 		fSuperInterfacesDialogField.setLabelText(getSuperInterfacesLabel());
513 		fSuperInterfacesDialogField.setRemoveButtonIndex(2);
514 
515 		String[] buttonNames1= new String[] {
516 			NewWizardMessages.NewTypeWizardPage_modifiers_public,
517 			NewWizardMessages.NewTypeWizardPage_modifiers_default,
518 			NewWizardMessages.NewTypeWizardPage_modifiers_private,
519 			NewWizardMessages.NewTypeWizardPage_modifiers_protected
520 		};
521 		fAccMdfButtons= new SelectionButtonDialogFieldGroup(SWT.RADIO, buttonNames1, 4);
522 		fAccMdfButtons.setDialogFieldListener(adapter);
523 		fAccMdfButtons.setLabelText(getModifiersLabel());
524 		fAccMdfButtons.setSelection(0, true);
525 
526 		String[] buttonNames2;
527 		if (fTypeKind == CLASS_TYPE) {
528 			buttonNames2= new String[] {
529 				NewWizardMessages.NewTypeWizardPage_modifiers_abstract,
530 				NewWizardMessages.NewTypeWizardPage_modifiers_final,
531 				NewWizardMessages.NewTypeWizardPage_modifiers_static
532 			};
533 		} else {
534 		    if (fTypeKind == ENUM_TYPE || fTypeKind == ANNOTATION_TYPE) {
535 		        buttonNames2= new String[] {
536 					NewWizardMessages.NewTypeWizardPage_modifiers_abstract,
537 					NewWizardMessages.NewTypeWizardPage_modifiers_static
538 		        };
539 		    }
540 			else {
541 				if (fTypeKind == RECORD_TYPE) {
542 					buttonNames2= new String[] {NewWizardMessages.NewTypeWizardPage_modifiers_static};
543 				} else
544 					buttonNames2= new String[] {};
545 			}
546 		}
547 
548 		fOtherMdfButtons= new SelectionButtonDialogFieldGroup(SWT.CHECK, buttonNames2, 4);
549 		fOtherMdfButtons.setDialogFieldListener(adapter);
550 
551 		fAccMdfButtons.enableSelectionButton(PRIVATE_INDEX, false);
552 		fAccMdfButtons.enableSelectionButton(PROTECTED_INDEX, false);
553 		fOtherMdfButtons.enableSelectionButton(STATIC_INDEX, false);
554 
555 		if (fTypeKind == ENUM_TYPE || fTypeKind == ANNOTATION_TYPE) {
556 		    fOtherMdfButtons.enableSelectionButton(ABSTRACT_INDEX, false);
557 		    fOtherMdfButtons.enableSelectionButton(ENUM_ANNOT_STATIC_INDEX, false);
558 		}
559 
560 		fAddCommentButton= new SelectionButtonDialogField(SWT.CHECK);
561 		fAddCommentButton.setLabelText(NewWizardMessages.NewTypeWizardPage_addcomment_label);
562 
563 		fUseAddCommentButtonValue= false; // only used when enabled
564 
565 		fCurrPackageCompletionProcessor= new JavaPackageCompletionProcessor();
566 		fEnclosingTypeCompletionProcessor= new JavaTypeCompletionProcessor(false, false, true);
567 
568 		fPackageStatus= new StatusInfo();
569 		fEnclosingTypeStatus= new StatusInfo();
570 
571 		fCanModifyPackage= true;
572 		fCanModifyEnclosingType= true;
573 		updateEnableState();
574 
575 		fTypeNameStatus= new StatusInfo();
576 		fSuperClassStatus= new StatusInfo();
577 		fSuperInterfacesStatus= new StatusInfo();
578 		fModifierStatus= new StatusInfo();
579 	}
580 
581 	/**
582 	 * Initializes all fields provided by the page with a given selection.
583 	 *
584 	 * @param elem the selection used to initialize this page or <code>
585 	 * null</code> if no selection was available
586 	 */
initTypePage(IJavaElement elem)587 	protected void initTypePage(IJavaElement elem) {
588 		String initSuperclass= "java.lang.Object"; //$NON-NLS-1$
589 		ArrayList<String> initSuperinterfaces= new ArrayList<>(5);
590 
591 		IJavaProject project= null;
592 		IPackageFragment pack= null;
593 		IType enclosingType= null;
594 
595 		if (elem != null) {
596 			project= elem.getJavaProject();
597 			pack= (IPackageFragment) elem.getAncestor(IJavaElement.PACKAGE_FRAGMENT);
598 			if (pack == null && project != null) {
599 				pack= getPackage(project);
600 			}
601 			// evaluate the enclosing type
602 			IType typeInCU= (IType) elem.getAncestor(IJavaElement.TYPE);
603 			if (typeInCU != null) {
604 				if (typeInCU.getCompilationUnit() != null) {
605 					enclosingType= typeInCU;
606 				}
607 			} else {
608 				ICompilationUnit cu= (ICompilationUnit) elem.getAncestor(IJavaElement.COMPILATION_UNIT);
609 				if (cu != null) {
610 					enclosingType= cu.findPrimaryType();
611 				}
612 			}
613 
614 			try {
615 				IType type= null;
616 				if (elem.getElementType() == IJavaElement.TYPE) {
617 					type= (IType)elem;
618 					if (type.exists()) {
619 						String superName= SuperInterfaceSelectionDialog.getNameWithTypeParameters(type);
620 						if (type.isInterface()) {
621 							initSuperinterfaces.add(superName);
622 						} else {
623 							initSuperclass= superName;
624 						}
625 					}
626 				}
627 			} catch (JavaModelException e) {
628 				JavaPlugin.log(e);
629 				// ignore this exception now
630 			}
631 		}
632 
633 		String typeName= ""; //$NON-NLS-1$
634 
635 		ITextSelection selection= getCurrentTextSelection();
636 		if (selection != null) {
637 			String text= selection.getText();
638 			if (text != null && validateJavaTypeName(text, project).isOK()) {
639 				typeName= getUniqueJavaTypeName (pack, text);
640 			}
641 		}
642 
643 		setPackageFragment(pack, true);
644 		setEnclosingType(enclosingType, true);
645 		setEnclosingTypeSelection(false, true);
646 
647 		setTypeName(typeName, true);
648 		setSuperClass(initSuperclass, true);
649 		setSuperInterfaces(initSuperinterfaces, true);
650 
651 		setAddComments(StubUtility.doAddComments(project), true); // from project or workspace
652 	}
653 
654 	/**
655 	 * Generate a unique type name for some initially given name under the given package fragment.
656 	 *
657 	 * @param pack the package fragment under which to check for uniqueness
658 	 * @param name the type name to check for uniqueness
659 	 * @return a type name string that is unique under the given package fragment. If the initial
660 	 *         type name is not unique, it is suffixed with a number greater than or equal to 2.
661 	 * @since 3.17
662 	 */
getUniqueJavaTypeName(IPackageFragment pack, String name)663 	protected String getUniqueJavaTypeName(IPackageFragment pack, String name) {
664 		String typeName= name;
665 		if (pack != null) {
666 			IResource resource= null;
667 			boolean initial= true;
668 			while (resource == null || resource.exists()) {
669 				typeName= Signature.getSimpleName(typeName);
670 				Pattern p= Pattern.compile("[0-9]+$"); //$NON-NLS-1$
671 				Matcher m= p.matcher(typeName);
672 				if (m.find()) {
673 					// String ends with a number: increment it by 1
674 					BigDecimal newNumber= null;
675 					try {
676 						newNumber= new BigDecimal(m.group()).add(new BigDecimal(1));
677 						typeName= m.replaceFirst(newNumber.toPlainString());
678 					} catch (NumberFormatException e) {
679 						typeName= m.replaceFirst("2"); //$NON-NLS-1$
680 					}
681 				} else {
682 					typeName+= (initial ? "" : "2"); //$NON-NLS-1$ //$NON-NLS-2$
683 					initial= false;
684 				}
685 
686 				ICompilationUnit cu= pack.getCompilationUnit(getCompilationUnitName(typeName));
687 				resource= cu.getResource();
688 			}
689 		}
690 		return typeName;
691 	}
692 
693 	/**
694 	 * Checks if the package field has to be pre-filled in this page and returns the package
695 	 * fragment to be used for that. The package fragment has the name of the project if the source
696 	 * folder does not contain any package and if the project name is a valid package name. If the
697 	 * source folder contains exactly one package then the name of that package is used as the
698 	 * package fragment's name. <code>null</code> is returned if none of the above is applicable.
699 	 *
700 	 * @param javaProject the containing Java project of the selection used to initialize this page
701 	 *
702 	 * @return the package fragment to be pre-filled in this page or <code>null</code> if no
703 	 *         suitable package can be suggested for the given project
704 	 *
705 	 * @since 3.9
706 	 */
getPackage(IJavaProject javaProject)707 	private IPackageFragment getPackage(IJavaProject javaProject) {
708 		String packName= null;
709 		final IPackageFragmentRoot pkgFragmentRoot= getPackageFragmentRoot();
710 		IJavaElement[] packages= null;
711 		try {
712 			if (pkgFragmentRoot != null && pkgFragmentRoot.exists()) {
713 				packages= pkgFragmentRoot.getChildren();
714 				if (packages.length == 1) { // only default package -> use Project name
715 					packName= javaProject.getElementName();
716 					// validate package name
717 					IStatus status= validatePackageName(packName, javaProject);
718 					if (status.getSeverity() == IStatus.OK) {
719 						return pkgFragmentRoot.getPackageFragment(packName);
720 					}
721 				} else {
722 					int noOfPackages= 0;
723 					IPackageFragment thePackage= null;
724 					for (final IJavaElement pack : packages) {
725 						IPackageFragment pkg= (IPackageFragment) pack;
726 						// ignoring empty parent packages and default package
727 						if ((!pkg.hasSubpackages() || pkg.hasChildren()) && !pkg.isDefaultPackage()) {
728 							noOfPackages++;
729 							thePackage= pkg;
730 							if (noOfPackages > 1) {
731 								return null;
732 							}
733 						}
734 					}
735 					if (noOfPackages == 1) { // use package name
736 						packName= thePackage.getElementName();
737 						return pkgFragmentRoot.getPackageFragment(packName);
738 					}
739 				}
740 			}
741 		} catch (JavaModelException e) {
742 			// fall through
743 		}
744 		return null;
745 	}
746 
validateJavaTypeName(String text, IJavaProject project)747 	private static IStatus validateJavaTypeName(String text, IJavaProject project) {
748 		if (project == null || !project.exists()) {
749 			return JavaConventions.validateJavaTypeName(text, JavaCore.VERSION_1_3, JavaCore.VERSION_1_3, null);
750 		}
751 		return JavaConventionsUtil.validateJavaTypeName(text, project);
752 	}
753 
validatePackageName(String text, IJavaProject project)754 	private static IStatus validatePackageName(String text, IJavaProject project) {
755 		if (project == null || !project.exists()) {
756 			return JavaConventions.validatePackageName(text, JavaCore.VERSION_1_3, JavaCore.VERSION_1_3);
757 		}
758 		return JavaConventionsUtil.validatePackageName(text, project);
759 	}
760 
761 	// -------- UI Creation ---------
762 
763 	/**
764 	 * Returns the label that is used for the package input field.
765 	 *
766 	 * @return the label that is used for the package input field.
767 	 * @since 3.2
768 	 */
getPackageLabel()769 	protected String getPackageLabel() {
770 		return NewWizardMessages.NewTypeWizardPage_package_label;
771 	}
772 
773 	/**
774 	 * Returns the label that is used for the enclosing type input field.
775 	 *
776 	 * @return the label that is used for the enclosing type input field.
777 	 * @since 3.2
778 	 */
getEnclosingTypeLabel()779 	protected String getEnclosingTypeLabel() {
780 		return NewWizardMessages.NewTypeWizardPage_enclosing_selection_label;
781 	}
782 
783 	/**
784 	 * Returns the label that is used for the type name input field.
785 	 *
786 	 * @return the label that is used for the type name input field.
787 	 * @since 3.2
788 	 */
getTypeNameLabel()789 	protected String getTypeNameLabel() {
790 		return NewWizardMessages.NewTypeWizardPage_typename_label;
791 	}
792 
793 	/**
794 	 * Returns the label that is used for the modifiers input field.
795 	 *
796 	 * @return the label that is used for the modifiers input field
797 	 * @since 3.2
798 	 */
getModifiersLabel()799 	protected String getModifiersLabel() {
800 		return NewWizardMessages.NewTypeWizardPage_modifiers_acc_label;
801 	}
802 
803 	/**
804 	 * Returns the label that is used for the super class input field.
805 	 *
806 	 * @return the label that is used for the super class input field.
807 	 * @since 3.2
808 	 */
getSuperClassLabel()809 	protected String getSuperClassLabel() {
810 		return NewWizardMessages.NewTypeWizardPage_superclass_label;
811 	}
812 
813 	/**
814 	 * Returns the label that is used for the super interfaces input field.
815 	 *
816 	 * @return the label that is used for the super interfaces input field.
817 	 * @since 3.2
818 	 */
getSuperInterfacesLabel()819 	protected String getSuperInterfacesLabel() {
820 	    if (fTypeKind != INTERFACE_TYPE)
821 	        return NewWizardMessages.NewTypeWizardPage_interfaces_class_label;
822 	    return NewWizardMessages.NewTypeWizardPage_interfaces_ifc_label;
823 	}
824 
825 	/**
826 	 * Creates a separator line. Expects a <code>GridLayout</code> with at least 1 column.
827 	 *
828 	 * @param composite the parent composite
829 	 * @param nColumns number of columns to span
830 	 */
createSeparator(Composite composite, int nColumns)831 	protected void createSeparator(Composite composite, int nColumns) {
832 		(new Separator(SWT.SEPARATOR | SWT.HORIZONTAL)).doFillIntoGrid(composite, nColumns, convertHeightInCharsToPixels(1));
833 	}
834 
835 	/**
836 	 * Creates the controls for the package name field. Expects a <code>GridLayout</code> with at
837 	 * least 4 columns.
838 	 *
839 	 * @param composite the parent composite
840 	 * @param nColumns number of columns to span
841 	 */
createPackageControls(Composite composite, int nColumns)842 	protected void createPackageControls(Composite composite, int nColumns) {
843 		fPackageDialogField.doFillIntoGrid(composite, nColumns);
844 		Text text= fPackageDialogField.getTextControl(null);
845 		BidiUtils.applyBidiProcessing(text, StructuredTextTypeHandlerFactory.JAVA);
846 		LayoutUtil.setWidthHint(text, getMaxFieldWidth());
847 		LayoutUtil.setHorizontalGrabbing(text);
848 		ControlContentAssistHelper.createTextContentAssistant(text, fCurrPackageCompletionProcessor);
849 		TextFieldNavigationHandler.install(text);
850 	}
851 
852 	/**
853 	 * Creates the controls for the enclosing type name field. Expects a <code>GridLayout</code> with at
854 	 * least 4 columns.
855 	 *
856 	 * @param composite the parent composite
857 	 * @param nColumns number of columns to span
858 	 */
createEnclosingTypeControls(Composite composite, int nColumns)859 	protected void createEnclosingTypeControls(Composite composite, int nColumns) {
860 		// #6891
861 		Composite tabGroup= new Composite(composite, SWT.NONE);
862 		GridLayout layout= new GridLayout();
863 		layout.marginWidth= 0;
864 		layout.marginHeight= 0;
865  		tabGroup.setLayout(layout);
866 
867 		fEnclosingTypeSelection.doFillIntoGrid(tabGroup, 1);
868 
869 		Text text= fEnclosingTypeDialogField.getTextControl(composite);
870 		SWTUtil.setAccessibilityText(text, NewWizardMessages.NewTypeWizardPage_enclosing_field_description);
871 
872 		GridData gd= new GridData(GridData.FILL_HORIZONTAL);
873 		gd.widthHint= getMaxFieldWidth();
874 		gd.horizontalSpan= 2;
875 		text.setLayoutData(gd);
876 
877 		Button button= fEnclosingTypeDialogField.getChangeControl(composite);
878 		gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
879 		gd.widthHint = SWTUtil.getButtonWidthHint(button);
880 		button.setLayoutData(gd);
881 		ControlContentAssistHelper.createTextContentAssistant(text, fEnclosingTypeCompletionProcessor);
882 		TextFieldNavigationHandler.install(text);
883 	}
884 
885 	/**
886 	 * Creates the controls for the type name field. Expects a <code>GridLayout</code> with at
887 	 * least 2 columns.
888 	 *
889 	 * @param composite the parent composite
890 	 * @param nColumns number of columns to span
891 	 */
createTypeNameControls(Composite composite, int nColumns)892 	protected void createTypeNameControls(Composite composite, int nColumns) {
893 		fTypeNameDialogField.doFillIntoGrid(composite, nColumns - 1);
894 		DialogField.createEmptySpace(composite);
895 
896 		Text text= fTypeNameDialogField.getTextControl(null);
897 		LayoutUtil.setWidthHint(text, getMaxFieldWidth());
898 		TextFieldNavigationHandler.install(text);
899 
900 		text.addVerifyListener(new VerifyListener() {
901 			@Override
902 			public void verifyText(VerifyEvent e) {
903 				if (fCanModifyPackage && ! fEnclosingTypeSelection.isSelected() && e.start == 0 && e.end == ((Text) e.widget).getCharCount()) {
904 					String typeNameWithoutParameters= getTypeNameWithoutParameters(getTypeNameWithoutExtension(e.text));
905 					int lastDot= typeNameWithoutParameters.lastIndexOf('.');
906 					if (lastDot == -1 || lastDot == typeNameWithoutParameters.length() - 1)
907 						return;
908 
909 					String pack= typeNameWithoutParameters.substring(0, lastDot);
910 					if (validatePackageName(pack, null).getSeverity() == IStatus.ERROR)
911 						return;
912 
913 					fPackageDialogField.setText(pack);
914 					e.text= e.text.substring(lastDot + 1);
915 				}
916 			}
917 		});
918 	}
919 
920 	/**
921 	 * Creates the controls for the modifiers radio/checkbox buttons. Expects a
922 	 * <code>GridLayout</code> with at least 3 columns.
923 	 *
924 	 * @param composite the parent composite
925 	 * @param nColumns number of columns to span
926 	 */
createModifierControls(Composite composite, int nColumns)927 	protected void createModifierControls(Composite composite, int nColumns) {
928 		LayoutUtil.setHorizontalSpan(fAccMdfButtons.getLabelControl(composite), 1);
929 
930 		Control control= fAccMdfButtons.getSelectionButtonsGroup(composite);
931 		GridData gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
932 		gd.horizontalSpan= nColumns - 2;
933 		control.setLayoutData(gd);
934 
935 		DialogField.createEmptySpace(composite);
936 
937 		if (fTypeKind == CLASS_TYPE) {
938 			DialogField.createEmptySpace(composite);
939 
940 			control= fOtherMdfButtons.getSelectionButtonsGroup(composite);
941 			gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
942 			gd.horizontalSpan= nColumns - 2;
943 			control.setLayoutData(gd);
944 
945 			DialogField.createEmptySpace(composite);
946 		}
947 	}
948 
949 	/**
950 	 * Creates the controls for the superclass name field. Expects a <code>GridLayout</code>
951 	 * with at least 3 columns.
952 	 *
953 	 * @param composite the parent composite
954 	 * @param nColumns number of columns to span
955 	 */
createSuperClassControls(Composite composite, int nColumns)956 	protected void createSuperClassControls(Composite composite, int nColumns) {
957 		fSuperClassDialogField.doFillIntoGrid(composite, nColumns);
958 		Text text= fSuperClassDialogField.getTextControl(null);
959 		LayoutUtil.setWidthHint(text, getMaxFieldWidth());
960 		BidiUtils.applyBidiProcessing(text, StructuredTextTypeHandlerFactory.JAVA);
961 
962 		JavaTypeCompletionProcessor superClassCompletionProcessor= new JavaTypeCompletionProcessor(false, false, true);
963 		superClassCompletionProcessor.setCompletionContextRequestor(new CompletionContextRequestor() {
964 			@Override
965 			public StubTypeContext getStubTypeContext() {
966 				return getSuperClassStubTypeContext();
967 			}
968 		});
969 
970 		ControlContentAssistHelper.createTextContentAssistant(text, superClassCompletionProcessor);
971 		TextFieldNavigationHandler.install(text);
972 	}
973 
974 	/**
975 	 * Creates the controls for the superclass name field. Expects a <code>GridLayout</code> with
976 	 * at least 3 columns.
977 	 *
978 	 * @param composite the parent composite
979 	 * @param nColumns number of columns to span
980 	 */
createSuperInterfacesControls(Composite composite, int nColumns)981 	protected void createSuperInterfacesControls(Composite composite, int nColumns) {
982 		final String INTERFACE= "interface"; //$NON-NLS-1$
983 		fSuperInterfacesDialogField.doFillIntoGrid(composite, nColumns);
984 		final TableViewer tableViewer= fSuperInterfacesDialogField.getTableViewer();
985 		tableViewer.setColumnProperties(new String[] {INTERFACE});
986 
987 		TableTextCellEditor cellEditor= new TableTextCellEditor(tableViewer, 0) {
988 			@Override
989 			protected Control createControl(Composite parent) {
990 				Control control= super.createControl(parent);
991 				BidiUtils.applyBidiProcessing(text, StructuredTextTypeHandlerFactory.JAVA);
992 				return control;
993 			}
994 
995 		    @Override
996 			protected void doSetFocus() {
997 		        if (text != null) {
998 		            text.setFocus();
999 		            text.setSelection(text.getText().length());
1000 		            checkSelection();
1001 		            checkDeleteable();
1002 		            checkSelectable();
1003 		        }
1004 		    }
1005 		};
1006 		JavaTypeCompletionProcessor superInterfaceCompletionProcessor= new JavaTypeCompletionProcessor(false, false, true);
1007 		superInterfaceCompletionProcessor.setCompletionContextRequestor(new CompletionContextRequestor() {
1008 			@Override
1009 			public StubTypeContext getStubTypeContext() {
1010 				return getSuperInterfacesStubTypeContext();
1011 			}
1012 		});
1013 		SubjectControlContentAssistant contentAssistant= ControlContentAssistHelper.createJavaContentAssistant(superInterfaceCompletionProcessor);
1014 		Text cellEditorText= cellEditor.getText();
1015 		ContentAssistHandler.createHandlerForText(cellEditorText, contentAssistant);
1016 		TextFieldNavigationHandler.install(cellEditorText);
1017 		cellEditor.setContentAssistant(contentAssistant);
1018 
1019 		tableViewer.setCellEditors(new CellEditor[] { cellEditor });
1020 		tableViewer.setCellModifier(new ICellModifier() {
1021 			@Override
1022 			public void modify(Object element, String property, Object value) {
1023 				if (element instanceof Item)
1024 					element = ((Item) element).getData();
1025 
1026 				((InterfaceWrapper) element).interfaceName= (String) value;
1027 				fSuperInterfacesDialogField.elementChanged((InterfaceWrapper) element);
1028 			}
1029 			@Override
1030 			public Object getValue(Object element, String property) {
1031 				return ((InterfaceWrapper) element).interfaceName;
1032 			}
1033 			@Override
1034 			public boolean canModify(Object element, String property) {
1035 				return true;
1036 			}
1037 		});
1038 		tableViewer.getTable().addKeyListener(new KeyAdapter() {
1039 			@Override
1040 			public void keyPressed(KeyEvent event) {
1041 				if (event.keyCode == SWT.F2 && event.stateMask == 0) {
1042 					ISelection selection= tableViewer.getSelection();
1043 					if (! (selection instanceof IStructuredSelection))
1044 						return;
1045 					IStructuredSelection structuredSelection= (IStructuredSelection) selection;
1046 					tableViewer.editElement(structuredSelection.getFirstElement(), 0);
1047 				}
1048 			}
1049 		});
1050 		GridData gd= (GridData) fSuperInterfacesDialogField.getListControl(null).getLayoutData();
1051 		if (fTypeKind == CLASS_TYPE) {
1052 			gd.heightHint= convertHeightInCharsToPixels(3);
1053 		} else {
1054 			gd.heightHint= convertHeightInCharsToPixels(6);
1055 		}
1056 		gd.grabExcessVerticalSpace= false;
1057 		gd.widthHint= getMaxFieldWidth();
1058 	}
1059 
1060 	/**
1061 	 * Creates the controls for the preference page links. Expects a <code>GridLayout</code> with
1062 	 * at least 3 columns.
1063 	 *
1064 	 * @param composite the parent composite
1065 	 * @param nColumns number of columns to span
1066 	 *
1067 	 * @since 3.1
1068 	 */
createCommentControls(Composite composite, int nColumns)1069 	protected void createCommentControls(Composite composite, int nColumns) {
1070     	Link link= new Link(composite, SWT.NONE);
1071     	link.setText(NewWizardMessages.NewTypeWizardPage_addcomment_description);
1072     	link.addSelectionListener(new TypeFieldsAdapter());
1073     	link.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, false, false, nColumns, 1));
1074 		DialogField.createEmptySpace(composite);
1075 		fAddCommentButton.doFillIntoGrid(composite, nColumns - 1);
1076 	}
1077 	/**
1078 	  * Creates the comment and link in the single line for the preference page links. Expects a
1079 	  * <code>GridLayout</code> with at least 2 columns.
1080 	 *
1081 	 * @param composite the parent composite
1082 	 * @param nColumns number of columns to span
1083 	 * @param isModule if it is module or package
1084 	 * @return link is returned
1085 	 * @since 3.18
1086 	 */
createCommentWithLinkControls(Composite composite, int nColumns, boolean isModule)1087 	protected Link createCommentWithLinkControls(Composite composite, int nColumns, boolean isModule) {
1088 		if(isModule)
1089 			DialogField.createEmptySpace(composite);
1090 		fAddCommentButton.doFillIntoGridWithoutMargin(composite, nColumns, !isModule);
1091 		Link link= new Link(composite, SWT.NONE);
1092 		link.setText(NewWizardMessages.NewTypeWizardPage_addcomment_description2);
1093 		link.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, false, false));
1094 		if(!isModule) {
1095 			fAddCommentButton.setEnabled(false);
1096 		}
1097 		link.addSelectionListener(new TypeFieldsAdapter());
1098 		return link;
1099 	}
1100 
1101 
1102 
1103 	/**
1104 	 * Sets the focus on the type name input field.
1105 	 */
setFocus()1106 	protected void setFocus() {
1107 		if (fTypeNameDialogField.isEnabled()) {
1108 			fTypeNameDialogField.setFocus();
1109 		} else {
1110 			setFocusOnContainer();
1111 		}
1112 	}
1113 
1114 	// -------- TypeFieldsAdapter --------
1115 
1116 	private class TypeFieldsAdapter implements IStringButtonAdapter, IDialogFieldListener, IListAdapter<InterfaceWrapper>, SelectionListener {
1117 
1118 		// -------- IStringButtonAdapter
1119 		@Override
changeControlPressed(DialogField field)1120 		public void changeControlPressed(DialogField field) {
1121 			typePageChangeControlPressed(field);
1122 		}
1123 
1124 		// -------- IListAdapter
1125 		@Override
customButtonPressed(ListDialogField<InterfaceWrapper> field, int index)1126 		public void customButtonPressed(ListDialogField<InterfaceWrapper> field, int index) {
1127 			typePageCustomButtonPressed(field, index);
1128 		}
1129 
1130 		@Override
selectionChanged(ListDialogField<InterfaceWrapper> field)1131 		public void selectionChanged(ListDialogField<InterfaceWrapper> field) {}
1132 
1133 		// -------- IDialogFieldListener
1134 		@Override
dialogFieldChanged(DialogField field)1135 		public void dialogFieldChanged(DialogField field) {
1136 			typePageDialogFieldChanged(field);
1137 		}
1138 
1139 		@Override
doubleClicked(ListDialogField<InterfaceWrapper> field)1140 		public void doubleClicked(ListDialogField<InterfaceWrapper> field) {
1141 		}
1142 
1143 
1144 		@Override
widgetSelected(SelectionEvent e)1145 		public void widgetSelected(SelectionEvent e) {
1146 			typePageLinkActivated();
1147 		}
1148 
1149 		@Override
widgetDefaultSelected(SelectionEvent e)1150 		public void widgetDefaultSelected(SelectionEvent e) {
1151 			typePageLinkActivated();
1152 		}
1153 	}
1154 
typePageLinkActivated()1155 	private void typePageLinkActivated() {
1156 		IJavaProject project= getJavaProject();
1157 		if (project != null) {
1158 			PreferenceDialog dialog= PreferencesUtil.createPropertyDialogOn(getShell(), project.getProject(), CodeTemplatePreferencePage.PROP_ID, null, null);
1159 			dialog.open();
1160 		} else {
1161 			String title= NewWizardMessages.NewTypeWizardPage_configure_templates_title;
1162 			String message= NewWizardMessages.NewTypeWizardPage_configure_templates_message;
1163 			MessageDialog.openInformation(getShell(), title, message);
1164 		}
1165 	}
1166 
typePageChangeControlPressed(DialogField field)1167 	private void typePageChangeControlPressed(DialogField field) {
1168 		if (field == fPackageDialogField) {
1169 			IPackageFragment pack= choosePackage();
1170 			if (pack != null) {
1171 				fPackageDialogField.setText(pack.getElementName());
1172 			}
1173 		} else if (field == fEnclosingTypeDialogField) {
1174 			IType type= chooseEnclosingType();
1175 			if (type != null) {
1176 				fEnclosingTypeDialogField.setText(type.getFullyQualifiedName('.'));
1177 			}
1178 		} else if (field == fSuperClassDialogField) {
1179 			IType type= chooseSuperClass();
1180 			if (type != null) {
1181 				fSuperClassDialogField.setText(SuperInterfaceSelectionDialog.getNameWithTypeParameters(type));
1182 			}
1183 		}
1184 	}
1185 
typePageCustomButtonPressed(DialogField field, int index)1186 	private void typePageCustomButtonPressed(DialogField field, int index) {
1187 		if (field == fSuperInterfacesDialogField && index == 0) {
1188 			chooseSuperInterfaces();
1189 			List<InterfaceWrapper> interfaces= fSuperInterfacesDialogField.getElements();
1190 			if (!interfaces.isEmpty()) {
1191 				Object element= interfaces.get(interfaces.size() - 1);
1192 				fSuperInterfacesDialogField.editElement(element);
1193 			}
1194 		}
1195 	}
1196 
1197 	/*
1198 	 * A field on the type has changed. The fields' status and all dependent
1199 	 * status are updated.
1200 	 */
typePageDialogFieldChanged(DialogField field)1201 	private void typePageDialogFieldChanged(DialogField field) {
1202 		String fieldName= null;
1203 		if (field == fPackageDialogField) {
1204 			fPackageStatus= packageChanged();
1205 			updatePackageStatusLabel();
1206 			fTypeNameStatus= typeNameChanged();
1207 			fSuperClassStatus= superClassChanged();
1208 			fieldName= PACKAGE;
1209 		} else if (field == fEnclosingTypeDialogField) {
1210 			fEnclosingTypeStatus= enclosingTypeChanged();
1211 			fTypeNameStatus= typeNameChanged();
1212 			fSuperClassStatus= superClassChanged();
1213 			fieldName= ENCLOSING;
1214 		} else if (field == fEnclosingTypeSelection) {
1215 			updateEnableState();
1216 			boolean isEnclosedType= isEnclosingTypeSelected();
1217 			if (!isEnclosedType) {
1218 				if (fAccMdfButtons.isSelected(PRIVATE_INDEX) || fAccMdfButtons.isSelected(PROTECTED_INDEX)) {
1219 					fAccMdfButtons.setSelection(PRIVATE_INDEX, false);
1220 					fAccMdfButtons.setSelection(PROTECTED_INDEX, false);
1221 					fAccMdfButtons.setSelection(PUBLIC_INDEX, true);
1222 				}
1223 				if (fOtherMdfButtons.isSelected(STATIC_INDEX)) {
1224 					fOtherMdfButtons.setSelection(STATIC_INDEX, false);
1225 				}
1226 			}
1227 			fAccMdfButtons.enableSelectionButton(PRIVATE_INDEX, isEnclosedType);
1228 			fAccMdfButtons.enableSelectionButton(PROTECTED_INDEX, isEnclosedType);
1229 			fOtherMdfButtons.enableSelectionButton(STATIC_INDEX, isEnclosedType);
1230 			fTypeNameStatus= typeNameChanged();
1231 			fSuperClassStatus= superClassChanged();
1232 			fieldName= ENCLOSINGSELECTION;
1233 		} else if (field == fTypeNameDialogField) {
1234 			fTypeNameStatus= typeNameChanged();
1235 			fieldName= TYPENAME;
1236 		} else if (field == fSuperClassDialogField) {
1237 			fSuperClassStatus= superClassChanged();
1238 			fieldName= SUPER;
1239 		} else if (field == fSuperInterfacesDialogField) {
1240 			fSuperInterfacesStatus= superInterfacesChanged();
1241 			fieldName= INTERFACES;
1242 		} else if (field == fOtherMdfButtons || field == fAccMdfButtons) {
1243 			fModifierStatus= modifiersChanged();
1244 			fieldName= MODIFIERS;
1245 		} else {
1246 			fieldName= METHODS;
1247 		}
1248 		// tell all others
1249 		handleFieldChanged(fieldName);
1250 	}
1251 
1252 	// -------- update message ----------------
1253 
1254 	/*
1255 	 * @see org.eclipse.jdt.ui.wizards.NewContainerWizardPage#handleFieldChanged(String)
1256 	 */
1257 	@Override
handleFieldChanged(String fieldName)1258 	protected void handleFieldChanged(String fieldName) {
1259 		super.handleFieldChanged(fieldName);
1260 		if (CONTAINER.equals(fieldName)) {
1261 			fPackageStatus= packageChanged();
1262 			fEnclosingTypeStatus= enclosingTypeChanged();
1263 			fTypeNameStatus= typeNameChanged();
1264 			fSuperClassStatus= superClassChanged();
1265 			fSuperInterfacesStatus= superInterfacesChanged();
1266 		}
1267 	}
1268 
1269 	// ---- set / get ----------------
1270 
1271 	/**
1272 	 * Returns the text of the package input field.
1273 	 *
1274 	 * @return the text of the package input field
1275 	 */
getPackageText()1276 	public String getPackageText() {
1277 		return fPackageDialogField.getText();
1278 	}
1279 
1280 	/**
1281 	 * Returns the text of the enclosing type input field.
1282 	 *
1283 	 * @return the text of the enclosing type input field
1284 	 */
getEnclosingTypeText()1285 	public String getEnclosingTypeText() {
1286 		return fEnclosingTypeDialogField.getText();
1287 	}
1288 
1289 
1290 	/**
1291 	 * Returns the package fragment corresponding to the current input.
1292 	 *
1293 	 * @return a package fragment or <code>null</code> if the input
1294 	 * could not be resolved.
1295 	 */
getPackageFragment()1296 	public IPackageFragment getPackageFragment() {
1297 		if (!isEnclosingTypeSelected()) {
1298 			return fCurrPackage;
1299 		} else {
1300 			if (fCurrEnclosingType != null) {
1301 				return fCurrEnclosingType.getPackageFragment();
1302 			}
1303 		}
1304 		return null;
1305 	}
1306 
1307 	/**
1308 	 * Sets the package fragment to the given value. The method updates the model
1309 	 * and the text of the control.
1310 	 *
1311 	 * @param pack the package fragment to be set
1312 	 * @param canBeModified if <code>true</code> the package fragment is
1313 	 * editable; otherwise it is read-only.
1314 	 */
setPackageFragment(IPackageFragment pack, boolean canBeModified)1315 	public void setPackageFragment(IPackageFragment pack, boolean canBeModified) {
1316 		fCurrPackage= pack;
1317 		fCanModifyPackage= canBeModified;
1318 		String str= (pack == null) ? "" : pack.getElementName(); //$NON-NLS-1$
1319 		fPackageDialogField.setText(str);
1320 		updateEnableState();
1321 	}
1322 
1323 	/**
1324 	 * Returns the enclosing type corresponding to the current input.
1325 	 *
1326 	 * @return the enclosing type or <code>null</code> if the enclosing type is
1327 	 * not selected or the input could not be resolved
1328 	 */
getEnclosingType()1329 	public IType getEnclosingType() {
1330 		if (isEnclosingTypeSelected()) {
1331 			return fCurrEnclosingType;
1332 		}
1333 		return null;
1334 	}
1335 
1336 	/**
1337 	 * Sets the enclosing type. The method updates the underlying model
1338 	 * and the text of the control.
1339 	 *
1340 	 * @param type the enclosing type
1341 	 * @param canBeModified if <code>true</code> the enclosing type field is
1342 	 * editable; otherwise it is read-only.
1343 	 */
setEnclosingType(IType type, boolean canBeModified)1344 	public void setEnclosingType(IType type, boolean canBeModified) {
1345 		fCurrEnclosingType= type;
1346 		fCanModifyEnclosingType= canBeModified;
1347 		String str= (type == null) ? "" : type.getFullyQualifiedName('.'); //$NON-NLS-1$
1348 		fEnclosingTypeDialogField.setText(str);
1349 		updateEnableState();
1350 	}
1351 
1352 	/**
1353 	 * Returns the selection state of the enclosing type checkbox.
1354 	 *
1355 	 * @return the selection state of the enclosing type checkbox
1356 	 */
isEnclosingTypeSelected()1357 	public boolean isEnclosingTypeSelected() {
1358 		return fEnclosingTypeSelection.isSelected();
1359 	}
1360 
1361 	/**
1362 	 * Sets the enclosing type checkbox's selection state.
1363 	 *
1364 	 * @param isSelected the checkbox's selection state
1365 	 * @param canBeModified if <code>true</code> the enclosing type checkbox is
1366 	 * modifiable; otherwise it is read-only.
1367 	 */
setEnclosingTypeSelection(boolean isSelected, boolean canBeModified)1368 	public void setEnclosingTypeSelection(boolean isSelected, boolean canBeModified) {
1369 		fEnclosingTypeSelection.setSelection(isSelected);
1370 		fEnclosingTypeSelection.setEnabled(canBeModified);
1371 		updateEnableState();
1372 	}
1373 
1374 	/**
1375 	 * Returns the type name entered into the type input field (without the default file extension
1376 	 * <code>java</code>, if entered).
1377 	 *
1378 	 * @return the type name
1379 	 */
getTypeName()1380 	public String getTypeName() {
1381 		String typeNameWithExtension= fTypeNameDialogField.getText();
1382 		return getTypeNameWithoutExtension(typeNameWithExtension);
1383 	}
1384 
getTypeNameWithoutExtension(String typeNameWithExtension)1385 	private String getTypeNameWithoutExtension(String typeNameWithExtension) {
1386 		if (!typeNameWithExtension.endsWith(JavaModelUtil.DEFAULT_CU_SUFFIX)) {
1387 			return typeNameWithExtension;
1388 		} else {
1389 			int extensionOffset= typeNameWithExtension.lastIndexOf(JavaModelUtil.DEFAULT_CU_SUFFIX);
1390 			return typeNameWithExtension.substring(0, extensionOffset);
1391 		}
1392 	}
1393 
1394 	/**
1395 	 * Sets the type name input field's text to the given value. Method doesn't update
1396 	 * the model.
1397 	 *
1398 	 * @param name the new type name
1399 	 * @param canBeModified if <code>true</code> the type name field is
1400 	 * editable; otherwise it is read-only.
1401 	 */
setTypeName(String name, boolean canBeModified)1402 	public void setTypeName(String name, boolean canBeModified) {
1403 		fTypeNameDialogField.setText(name);
1404 		fTypeNameDialogField.setEnabled(canBeModified);
1405 	}
1406 
1407 	/**
1408 	 * Returns the selected modifiers.
1409 	 *
1410 	 * @return the selected modifiers
1411 	 * @see Flags
1412 	 */
getModifiers()1413 	public int getModifiers() {
1414 		int mdf= 0;
1415 		if (fAccMdfButtons.isSelected(PUBLIC_INDEX)) {
1416 			mdf+= F_PUBLIC;
1417 		} else if (fAccMdfButtons.isSelected(PRIVATE_INDEX)) {
1418 			mdf+= F_PRIVATE;
1419 		} else if (fAccMdfButtons.isSelected(PROTECTED_INDEX)) {
1420 			mdf+= F_PROTECTED;
1421 		}
1422 		if (fOtherMdfButtons.isSelected(ABSTRACT_INDEX)) {
1423 			mdf+= F_ABSTRACT;
1424 		}
1425 		if (fOtherMdfButtons.isSelected(FINAL_INDEX)) {
1426 			mdf+= F_FINAL;
1427 		}
1428 		if (fOtherMdfButtons.isSelected(STATIC_INDEX)) {
1429 			mdf+= F_STATIC;
1430 		}
1431 		return mdf;
1432 	}
1433 
1434 	/**
1435 	 * Sets the modifiers.
1436 	 *
1437 	 * @param modifiers <code>F_PUBLIC</code>, <code>F_PRIVATE</code>,
1438 	 * <code>F_PROTECTED</code>, <code>F_ABSTRACT</code>, <code>F_FINAL</code>
1439 	 * or <code>F_STATIC</code> or a valid combination.
1440 	 * @param canBeModified if <code>true</code> the modifier fields are
1441 	 * editable; otherwise they are read-only
1442 	 * @see Flags
1443 	 */
setModifiers(int modifiers, boolean canBeModified)1444 	public void setModifiers(int modifiers, boolean canBeModified) {
1445 		if (Flags.isPublic(modifiers)) {
1446 			fAccMdfButtons.setSelection(PUBLIC_INDEX, true);
1447 		} else if (Flags.isPrivate(modifiers)) {
1448 			fAccMdfButtons.setSelection(PRIVATE_INDEX, true);
1449 		} else if (Flags.isProtected(modifiers)) {
1450 			fAccMdfButtons.setSelection(PROTECTED_INDEX, true);
1451 		} else {
1452 			fAccMdfButtons.setSelection(DEFAULT_INDEX, true);
1453 		}
1454 		if (Flags.isAbstract(modifiers)) {
1455 			fOtherMdfButtons.setSelection(ABSTRACT_INDEX, true);
1456 		}
1457 		if (Flags.isFinal(modifiers)) {
1458 			fOtherMdfButtons.setSelection(FINAL_INDEX, true);
1459 		}
1460 		if (Flags.isStatic(modifiers)) {
1461 			fOtherMdfButtons.setSelection(STATIC_INDEX, true);
1462 		}
1463 
1464 		fAccMdfButtons.setEnabled(canBeModified);
1465 		fOtherMdfButtons.setEnabled(canBeModified);
1466 	}
1467 
1468 	/**
1469 	 * Returns the content of the superclass input field.
1470 	 *
1471 	 * @return the superclass name
1472 	 */
getSuperClass()1473 	public String getSuperClass() {
1474 		return fSuperClassDialogField.getText();
1475 	}
1476 
1477 	/**
1478 	 * Sets the super class name.
1479 	 *
1480 	 * @param name the new superclass name
1481 	 * @param canBeModified  if <code>true</code> the superclass name field is
1482 	 * editable; otherwise it is read-only.
1483 	 */
setSuperClass(String name, boolean canBeModified)1484 	public void setSuperClass(String name, boolean canBeModified) {
1485 		fSuperClassDialogField.setText(name);
1486 		fSuperClassDialogField.setEnabled(canBeModified);
1487 	}
1488 
1489 	/**
1490 	 * Returns the chosen super interfaces.
1491 	 *
1492 	 * @return a list of chosen super interfaces. The list's elements
1493 	 * are of type <code>String</code>
1494 	 */
getSuperInterfaces()1495 	public List<String> getSuperInterfaces() {
1496 		List<InterfaceWrapper> interfaces= fSuperInterfacesDialogField.getElements();
1497 		ArrayList<String> result= new ArrayList<>(interfaces.size());
1498 		for (InterfaceWrapper wrapper : interfaces) {
1499 			result.add(wrapper.interfaceName);
1500 		}
1501 		return result;
1502 	}
1503 
1504 	/**
1505 	 * Sets the super interfaces.
1506 	 *
1507 	 * @param interfacesNames a list of super interface. The method requires that
1508 	 * the list's elements are of type <code>String</code>
1509 	 * @param canBeModified if <code>true</code> the super interface field is
1510 	 * editable; otherwise it is read-only.
1511 	 */
setSuperInterfaces(List<String> interfacesNames, boolean canBeModified)1512 	public void setSuperInterfaces(List<String> interfacesNames, boolean canBeModified) {
1513 		ArrayList<InterfaceWrapper> interfaces= new ArrayList<>(interfacesNames.size());
1514 		for (String string : interfacesNames) {
1515 			interfaces.add(new InterfaceWrapper(string));
1516 		}
1517 		fSuperInterfacesDialogField.setElements(interfaces);
1518 		fSuperInterfacesDialogField.setEnabled(canBeModified);
1519 	}
1520 
1521 	/**
1522 	 * Adds a super interface to the end of the list and selects it if it is not in the list yet.
1523 	 *
1524 	 * @param superInterface the fully qualified type name of the interface.
1525 	 * @return returns <code>true</code>if the interfaces has been added, <code>false</code>
1526 	 * if the interface already is in the list.
1527 	 * @since 3.2
1528 	 */
addSuperInterface(String superInterface)1529 	public boolean addSuperInterface(String superInterface) {
1530 		return fSuperInterfacesDialogField.addElement(new InterfaceWrapper(superInterface));
1531 	}
1532 
1533 
1534 	/**
1535 	 * Sets 'Add comment' checkbox. The value set will only be used when creating source when
1536 	 * the comment control is enabled (see {@link #enableCommentControl(boolean)}
1537 	 *
1538 	 * @param doAddComments if <code>true</code>, comments are added.
1539 	 * @param canBeModified if <code>true</code> check box is
1540 	 * editable; otherwise it is read-only.
1541 	 * 	@since 3.1
1542 	 */
setAddComments(boolean doAddComments, boolean canBeModified)1543 	public void setAddComments(boolean doAddComments, boolean canBeModified) {
1544 		fAddCommentButton.setSelection(doAddComments);
1545 		fAddCommentButton.setEnabled(canBeModified);
1546 	}
1547 
1548 	/**
1549 	 * Sets to use the 'Add comment' checkbox value. Clients that use the 'Add comment' checkbox
1550 	 * additionally have to enable the control. This has been added for backwards compatibility.
1551 	 *
1552 	 * @param useAddCommentValue if <code>true</code>,
1553 	 * 	@since 3.1
1554 	 */
enableCommentControl(boolean useAddCommentValue)1555 	public void enableCommentControl(boolean useAddCommentValue) {
1556 		fUseAddCommentButtonValue= useAddCommentValue;
1557 	}
1558 
1559 
1560 	/**
1561 	 * Returns if comments are added. This method can be overridden by clients.
1562 	 * The selection of the comment control is taken if enabled (see {@link #enableCommentControl(boolean)}, otherwise
1563 	 * the settings as specified in the preferences is used.
1564 	 *
1565 	 * @return Returns <code>true</code> if comments can be added
1566 	 * @since 3.1
1567 	 */
isAddComments()1568 	public boolean isAddComments() {
1569 		if (fUseAddCommentButtonValue) {
1570 			return fAddCommentButton.isSelected();
1571 		}
1572 		return StubUtility.doAddComments(getJavaProject());
1573 	}
1574 
1575 	/**
1576 	 * Returns the resource handle that corresponds to the compilation unit to was or
1577 	 * will be created or modified.
1578 	 * @return A resource or null if the page contains illegal values.
1579 	 * @since 3.0
1580 	 */
getModifiedResource()1581 	public IResource getModifiedResource() {
1582 		IType enclosing= getEnclosingType();
1583 		if (enclosing != null) {
1584 			return enclosing.getResource();
1585 		}
1586 		IPackageFragment pack= getPackageFragment();
1587 		if (pack != null) {
1588 			String cuName= getCompilationUnitName(getTypeNameWithoutParameters());
1589 			return pack.getCompilationUnit(cuName).getResource();
1590 		}
1591 		return null;
1592 	}
1593 
1594 	// ----------- validation ----------
1595 
1596 	/*
1597 	 * @see org.eclipse.jdt.ui.wizards.NewContainerWizardPage#containerChanged()
1598 	 */
1599 	@Override
containerChanged()1600 	protected IStatus containerChanged() {
1601 		IStatus status= super.containerChanged();
1602 	    IPackageFragmentRoot root= getPackageFragmentRoot();
1603 		if ((fTypeKind == ANNOTATION_TYPE || fTypeKind == ENUM_TYPE) && !status.matches(IStatus.ERROR)) {
1604 	    	if (root != null && !JavaModelUtil.is50OrHigher(root.getJavaProject())) {
1605 	    		// error as createType will fail otherwise (bug 96928)
1606 	    		return new StatusInfo(IStatus.ERROR, Messages.format(NewWizardMessages.NewTypeWizardPage_warning_NotJDKCompliant, BasicElementLabels.getJavaElementName(root.getJavaProject().getElementName())));
1607 	    	}
1608 	    	if (fTypeKind == ENUM_TYPE) {
1609 		    	try {
1610 		    	    // if findType(...) == null then Enum is unavailable
1611 		    	    if (findType(root.getJavaProject(), "java.lang.Enum") == null) //$NON-NLS-1$
1612 		    	        return new StatusInfo(IStatus.WARNING, NewWizardMessages.NewTypeWizardPage_warning_EnumClassNotFound);
1613 		    	} catch (JavaModelException e) {
1614 		    	    JavaPlugin.log(e);
1615 		    	}
1616 	    	}
1617 	    }
1618 		if ((fTypeKind == RECORD_TYPE) && !status.matches(IStatus.ERROR)) {
1619 	    	if (root != null) {
1620 	    		if (!JavaModelUtil.is14OrHigher(root.getJavaProject())) {
1621 	    			return new StatusInfo(IStatus.ERROR, Messages.format(NewWizardMessages.NewTypeWizardPage_warning_NotJDKCompliant2, new String[] {BasicElementLabels.getJavaElementName(root.getJavaProject().getElementName()), "14" })); //$NON-NLS-1$
1622 	    		} else if (!PreviewFeaturesSubProcessor.isPreviewFeatureEnabled(root.getJavaProject())) {
1623 	    			return new StatusInfo(IStatus.ERROR, Messages.format(NewWizardMessages.NewTypeWizardPage_warning_PreviewFeatureNotEnabled, BasicElementLabels.getJavaElementName(root.getJavaProject().getElementName())));
1624 	    		}
1625 	    		try {
1626 		    	    // if findType(...) == null then Record is unavailable
1627 		    	    if (findType(root.getJavaProject(), "java.lang.Record") == null) //$NON-NLS-1$
1628 		    	        return new StatusInfo(IStatus.WARNING, NewWizardMessages.NewTypeWizardPage_warning_RecordClassNotFound);
1629 		    	} catch (JavaModelException e) {
1630 		    	    JavaPlugin.log(e);
1631 		    	}
1632 	    	} else {
1633 	    		return new StatusInfo(IStatus.WARNING, NewWizardMessages.NewTypeWizardPage_warning_RecordClassNotFound);
1634 	    	}
1635 	    }
1636 
1637 		fCurrPackageCompletionProcessor.setPackageFragmentRoot(root);
1638 		if (root != null) {
1639 			fEnclosingTypeCompletionProcessor.setPackageFragment(root.getPackageFragment("")); //$NON-NLS-1$
1640 		}
1641 		return status;
1642 	}
1643 
1644 	/**
1645 	 * A hook method that gets called when the package field has changed. The method
1646 	 * validates the package name and returns the status of the validation. The validation
1647 	 * also updates the package fragment model.
1648 	 * <p>
1649 	 * Subclasses may extend this method to perform their own validation.
1650 	 * </p>
1651 	 *
1652 	 * @return the status of the validation
1653 	 */
packageChanged()1654 	protected IStatus packageChanged() {
1655 		StatusInfo status= new StatusInfo();
1656 		IPackageFragmentRoot root= getPackageFragmentRoot();
1657 		fPackageDialogField.enableButton(root != null);
1658 
1659 		IJavaProject project= root != null ? root.getJavaProject() : null;
1660 
1661 		String packName= getPackageText();
1662 		if (packName.length() > 0) {
1663 			IStatus val= validatePackageName(packName, project);
1664 			if (val.getSeverity() == IStatus.ERROR) {
1665 				status.setError(Messages.format(NewWizardMessages.NewTypeWizardPage_error_InvalidPackageName, val.getMessage()));
1666 				return status;
1667 			} else if (val.getSeverity() == IStatus.WARNING) {
1668 				status.setWarning(Messages.format(NewWizardMessages.NewTypeWizardPage_warning_DiscouragedPackageName, val.getMessage()));
1669 				// continue
1670 			}
1671 		} else {
1672 			status.setWarning(NewWizardMessages.NewTypeWizardPage_warning_DefaultPackageDiscouraged);
1673 		}
1674 
1675 		if (project != null) {
1676 			if (project.exists() && packName.length() > 0) {
1677 				try {
1678 					IPath rootPath= root.getPath();
1679 					IPath outputPath= project.getOutputLocation();
1680 					if (rootPath.isPrefixOf(outputPath) && !rootPath.equals(outputPath)) {
1681 						// if the bin folder is inside of our root, don't allow to name a package
1682 						// like the bin folder
1683 						IPath packagePath= rootPath.append(packName.replace('.', '/'));
1684 						if (outputPath.isPrefixOf(packagePath)) {
1685 							status.setError(NewWizardMessages.NewTypeWizardPage_error_ClashOutputLocation);
1686 							return status;
1687 						}
1688 					}
1689 				} catch (JavaModelException e) {
1690 					JavaPlugin.log(e);
1691 					// let pass
1692 				}
1693 			}
1694 
1695 			fCurrPackage= root.getPackageFragment(packName);
1696 			IResource resource= fCurrPackage.getResource();
1697 			if (resource != null){
1698 				if (resource.isVirtual()){
1699 					status.setError(NewWizardMessages.NewTypeWizardPage_error_PackageIsVirtual);
1700 					return status;
1701 				}
1702 				if (!ResourcesPlugin.getWorkspace().validateFiltered(resource).isOK()) {
1703 					status.setError(NewWizardMessages.NewTypeWizardPage_error_PackageNameFiltered);
1704 					return status;
1705 				}
1706 			}
1707 		} else {
1708 			status.setError(""); //$NON-NLS-1$
1709 		}
1710 		return status;
1711 	}
1712 
1713 	/*
1714 	 * Updates the 'default' label next to the package field.
1715 	 */
updatePackageStatusLabel()1716 	private void updatePackageStatusLabel() {
1717 		String packName= getPackageText();
1718 
1719 		if (packName.length() == 0) {
1720 			fPackageDialogField.setStatus(NewWizardMessages.NewTypeWizardPage_default);
1721 		} else {
1722 			fPackageDialogField.setStatus(""); //$NON-NLS-1$
1723 		}
1724 	}
1725 
1726 	/*
1727 	 * Updates the enable state of buttons related to the enclosing type selection checkbox.
1728 	 */
updateEnableState()1729 	private void updateEnableState() {
1730 		boolean enclosing= isEnclosingTypeSelected();
1731 		fPackageDialogField.setEnabled(fCanModifyPackage && !enclosing);
1732 		fEnclosingTypeDialogField.setEnabled(fCanModifyEnclosingType && enclosing);
1733 		if (fTypeKind == ENUM_TYPE || fTypeKind == ANNOTATION_TYPE) {
1734 		    fOtherMdfButtons.enableSelectionButton(ABSTRACT_INDEX, enclosing);
1735 		    fOtherMdfButtons.enableSelectionButton(ENUM_ANNOT_STATIC_INDEX, enclosing);
1736 		}
1737 	}
1738 
1739 	/**
1740 	 * Hook method that gets called when the enclosing type name has changed. The method
1741 	 * validates the enclosing type and returns the status of the validation. It also updates the
1742 	 * enclosing type model.
1743 	 * <p>
1744 	 * Subclasses may extend this method to perform their own validation.
1745 	 * </p>
1746 	 *
1747 	 * @return the status of the validation
1748 	 */
enclosingTypeChanged()1749 	protected IStatus enclosingTypeChanged() {
1750 		StatusInfo status= new StatusInfo();
1751 		fCurrEnclosingType= null;
1752 
1753 		IPackageFragmentRoot root= getPackageFragmentRoot();
1754 
1755 		fEnclosingTypeDialogField.enableButton(root != null);
1756 		if (root == null) {
1757 			status.setError(""); //$NON-NLS-1$
1758 			return status;
1759 		}
1760 
1761 		String enclName= getEnclosingTypeText();
1762 		if (enclName.length() == 0) {
1763 			status.setError(NewWizardMessages.NewTypeWizardPage_error_EnclosingTypeEnterName);
1764 			return status;
1765 		}
1766 		try {
1767 			IType type= findType(root.getJavaProject(), enclName);
1768 			if (type == null) {
1769 				status.setError(NewWizardMessages.NewTypeWizardPage_error_EnclosingTypeNotExists);
1770 				return status;
1771 			}
1772 
1773 			if (type.getCompilationUnit() == null) {
1774 				status.setError(NewWizardMessages.NewTypeWizardPage_error_EnclosingNotInCU);
1775 				return status;
1776 			}
1777 			if (!JavaModelUtil.isEditable(type.getCompilationUnit())) {
1778 				status.setError(NewWizardMessages.NewTypeWizardPage_error_EnclosingNotEditable);
1779 				return status;
1780 			}
1781 
1782 			fCurrEnclosingType= type;
1783 			IPackageFragmentRoot enclosingRoot= JavaModelUtil.getPackageFragmentRoot(type);
1784 			if (!enclosingRoot.equals(root)) {
1785 				status.setWarning(NewWizardMessages.NewTypeWizardPage_warning_EnclosingNotInSourceFolder);
1786 			}
1787 			return status;
1788 		} catch (JavaModelException e) {
1789 			status.setError(NewWizardMessages.NewTypeWizardPage_error_EnclosingTypeNotExists);
1790 			JavaPlugin.log(e);
1791 			return status;
1792 		}
1793 	}
1794 
findType(IJavaProject project, String typeName)1795 	private IType findType(IJavaProject project, String typeName) throws JavaModelException {
1796 		if (project.exists()) {
1797 			return project.findType(typeName);
1798 		}
1799 		return null;
1800 	}
1801 
getTypeNameWithoutParameters()1802 	private String getTypeNameWithoutParameters() {
1803 		return getTypeNameWithoutParameters(getTypeName());
1804 	}
1805 
getTypeNameWithoutParameters(String typeNameWithParameters)1806 	private static String getTypeNameWithoutParameters(String typeNameWithParameters) {
1807 		int angleBracketOffset= typeNameWithParameters.indexOf('<');
1808 		if (angleBracketOffset == -1) {
1809 			return typeNameWithParameters;
1810 		} else {
1811 			return typeNameWithParameters.substring(0, angleBracketOffset);
1812 		}
1813 	}
1814 
1815 	/**
1816 	 * Hook method that is called when evaluating the name of the compilation unit to create. By default, a file extension
1817 	 * <code>java</code> is added to the given type name, but implementors can override this behavior.
1818 	 *
1819 	 * @param typeName the name of the type to create the compilation unit for.
1820 	 * @return the name of the compilation unit to be created for the given name
1821 	 *
1822 	 * @since 3.2
1823 	 */
getCompilationUnitName(String typeName)1824 	protected String getCompilationUnitName(String typeName) {
1825 		return typeName + JavaModelUtil.DEFAULT_CU_SUFFIX;
1826 	}
1827 
1828 
1829 	/**
1830 	 * Hook method that gets called when the type name has changed. The method validates the
1831 	 * type name and returns the status of the validation.
1832 	 * <p>
1833 	 * Subclasses may extend this method to perform their own validation.
1834 	 * </p>
1835 	 *
1836 	 * @return the status of the validation
1837 	 */
typeNameChanged()1838 	protected IStatus typeNameChanged() {
1839 		StatusInfo status= new StatusInfo();
1840 		fCurrType= null;
1841 
1842 		String typeNameWithExtension = fTypeNameDialogField.getText();
1843 		// must not be empty
1844 		if (typeNameWithExtension.length() == 0) {
1845 			status.setError(NewWizardMessages.NewTypeWizardPage_error_EnterTypeName);
1846 			return status;
1847 		}
1848 
1849 		if (typeNameWithExtension.endsWith(JavaModelUtil.DEFAULT_CU_SUFFIX)) {
1850 			status.setInfo(NewWizardMessages.NewTypeWizardPage_info_FileExtensionNotRequired);
1851 		}
1852 
1853 		String typeNameWithParameters= getTypeName();
1854 
1855 		String typeName= getTypeNameWithoutParameters();
1856 		if (typeName.indexOf('.') != -1) {
1857 			status.setError(NewWizardMessages.NewTypeWizardPage_error_QualifiedName);
1858 			return status;
1859 		}
1860 
1861 		IJavaProject project= getJavaProject();
1862 		IStatus val= validateJavaTypeName(typeName, project);
1863 		if (val.getSeverity() == IStatus.ERROR) {
1864 			status.setError(Messages.format(NewWizardMessages.NewTypeWizardPage_error_InvalidTypeName, val.getMessage()));
1865 			return status;
1866 		} else if (val.getSeverity() == IStatus.WARNING) {
1867 			status.setWarning(Messages.format(NewWizardMessages.NewTypeWizardPage_warning_TypeNameDiscouraged, val.getMessage()));
1868 			// continue checking
1869 		}
1870 
1871 		// must not exist
1872 		if (!isEnclosingTypeSelected()) {
1873 			IPackageFragment pack= getPackageFragment();
1874 			if (pack != null) {
1875 				ICompilationUnit cu= pack.getCompilationUnit(getCompilationUnitName(typeName));
1876 				fCurrType= cu.getType(typeName);
1877 				IResource resource= cu.getResource();
1878 
1879 				if (resource.exists()) {
1880 					status.setError(NewWizardMessages.NewTypeWizardPage_error_TypeNameExists);
1881 					return status;
1882 				}
1883 				if (!ResourcesPlugin.getWorkspace().validateFiltered(resource).isOK()) {
1884 					status.setError(NewWizardMessages.NewTypeWizardPage_error_TypeNameFiltered);
1885 					return status;
1886 				}
1887 				URI location= resource.getLocationURI();
1888 				if (location != null) {
1889 					try {
1890 						IFileStore store= EFS.getStore(location);
1891 						if (store.fetchInfo().exists()) {
1892 							status.setError(NewWizardMessages.NewTypeWizardPage_error_TypeNameExistsDifferentCase);
1893 							return status;
1894 						}
1895 					} catch (CoreException e) {
1896 						status.setError(Messages.format(
1897 							NewWizardMessages.NewTypeWizardPage_error_uri_location_unkown,
1898 							BasicElementLabels.getURLPart(Resources.getLocationString(resource))));
1899 					}
1900 				}
1901 			}
1902 		} else {
1903 			IType type= getEnclosingType();
1904 			if (type != null) {
1905 				fCurrType= type.getType(typeName);
1906 				if (fCurrType.exists()) {
1907 					status.setError(NewWizardMessages.NewTypeWizardPage_error_TypeNameExists);
1908 					return status;
1909 				}
1910 			}
1911 		}
1912 
1913 		if (!typeNameWithParameters.equals(typeName) && project != null) {
1914 			if (!JavaModelUtil.is50OrHigher(project)) {
1915 				status.setError(NewWizardMessages.NewTypeWizardPage_error_TypeParameters);
1916 				return status;
1917 			}
1918 			String typeDeclaration= "class " + typeNameWithParameters + " {}"; //$NON-NLS-1$//$NON-NLS-2$
1919 			ASTParser parser= ASTParser.newParser(IASTSharedValues.SHARED_AST_LEVEL);
1920 			parser.setSource(typeDeclaration.toCharArray());
1921 			parser.setProject(project);
1922 			CompilationUnit compilationUnit= (CompilationUnit) parser.createAST(null);
1923 			IProblem[] problems= compilationUnit.getProblems();
1924 			if (problems.length > 0) {
1925 				status.setError(Messages.format(NewWizardMessages.NewTypeWizardPage_error_InvalidTypeName, problems[0].getMessage()));
1926 				return status;
1927 			}
1928 		}
1929 		return status;
1930 	}
1931 
1932 	/**
1933 	 * Hook method that gets called when the superclass name has changed. The method
1934 	 * validates the superclass name and returns the status of the validation.
1935 	 * <p>
1936 	 * Subclasses may extend this method to perform their own validation.
1937 	 * </p>
1938 	 *
1939 	 * @return the status of the validation
1940 	 */
superClassChanged()1941 	protected IStatus superClassChanged() {
1942 		StatusInfo status= new StatusInfo();
1943 		IPackageFragmentRoot root= getPackageFragmentRoot();
1944 		fSuperClassDialogField.enableButton(root != null);
1945 
1946 		fSuperClassStubTypeContext= null;
1947 
1948 		String sclassName= getSuperClass();
1949 		if (sclassName.length() == 0) {
1950 			// accept the empty field (stands for java.lang.Object)
1951 			return status;
1952 		}
1953 
1954 		if (root != null) {
1955 			Type type= TypeContextChecker.parseSuperClass(sclassName);
1956 			if (type == null) {
1957 				status.setError(NewWizardMessages.NewTypeWizardPage_error_InvalidSuperClassName);
1958 				return status;
1959 			}
1960 			if (type instanceof ParameterizedType && ! JavaModelUtil.is50OrHigher(root.getJavaProject())) {
1961 				status.setError(NewWizardMessages.NewTypeWizardPage_error_SuperClassNotParameterized);
1962 				return status;
1963 			}
1964 		} else {
1965 			status.setError(""); //$NON-NLS-1$
1966 		}
1967 		return status;
1968 	}
1969 
getSuperClassStubTypeContext()1970 	private StubTypeContext getSuperClassStubTypeContext() {
1971 		if (fSuperClassStubTypeContext == null) {
1972 			String typeName;
1973 			if (fCurrType != null) {
1974 				typeName= getTypeName();
1975 			} else {
1976 				typeName= JavaTypeCompletionProcessor.DUMMY_CLASS_NAME;
1977 			}
1978 			fSuperClassStubTypeContext= TypeContextChecker.createSuperClassStubTypeContext(typeName, getEnclosingType(), getPackageFragment());
1979 		}
1980 		return fSuperClassStubTypeContext;
1981 	}
1982 
1983 	/**
1984 	 * Hook method that gets called when the list of super interface has changed. The method
1985 	 * validates the super interfaces and returns the status of the validation.
1986 	 * <p>
1987 	 * Subclasses may extend this method to perform their own validation.
1988 	 * </p>
1989 	 *
1990 	 * @return the status of the validation
1991 	 */
superInterfacesChanged()1992 	protected IStatus superInterfacesChanged() {
1993 		StatusInfo status= new StatusInfo();
1994 
1995 		IPackageFragmentRoot root= getPackageFragmentRoot();
1996 		fSuperInterfacesDialogField.enableButton(0, root != null);
1997 
1998 		if (root != null) {
1999 			List<InterfaceWrapper> elements= fSuperInterfacesDialogField.getElements();
2000 			for (InterfaceWrapper element : elements) {
2001 				String intfname= element.interfaceName;
2002 				Type type= TypeContextChecker.parseSuperInterface(intfname);
2003 				if (type == null) {
2004 					status.setError(Messages.format(NewWizardMessages.NewTypeWizardPage_error_InvalidSuperInterfaceName, BasicElementLabels.getJavaElementName(intfname)));
2005 					return status;
2006 				}
2007 				if (type instanceof ParameterizedType && ! JavaModelUtil.is50OrHigher(root.getJavaProject())) {
2008 					status.setError(Messages.format(NewWizardMessages.NewTypeWizardPage_error_SuperInterfaceNotParameterized, BasicElementLabels.getJavaElementName(intfname)));
2009 					return status;
2010 				}
2011 			}
2012 		}
2013 		return status;
2014 	}
2015 
getSuperInterfacesStubTypeContext()2016 	private StubTypeContext getSuperInterfacesStubTypeContext() {
2017 		if (fSuperInterfaceStubTypeContext == null) {
2018 			String typeName;
2019 			if (fCurrType != null) {
2020 				typeName= getTypeName();
2021 			} else {
2022 				typeName= JavaTypeCompletionProcessor.DUMMY_CLASS_NAME;
2023 			}
2024 			fSuperInterfaceStubTypeContext= TypeContextChecker.createSuperInterfaceStubTypeContext(typeName, getEnclosingType(), getPackageFragment());
2025 		}
2026 		return fSuperInterfaceStubTypeContext;
2027 	}
2028 
2029 	/**
2030 	 * Hook method that gets called when the modifiers have changed. The method validates
2031 	 * the modifiers and returns the status of the validation.
2032 	 * <p>
2033 	 * Subclasses may extend this method to perform their own validation.
2034 	 * </p>
2035 	 *
2036 	 * @return the status of the validation
2037 	 */
modifiersChanged()2038 	protected IStatus modifiersChanged() {
2039 		StatusInfo status= new StatusInfo();
2040 		int modifiers= getModifiers();
2041 		if (Flags.isFinal(modifiers) && Flags.isAbstract(modifiers)) {
2042 			status.setError(NewWizardMessages.NewTypeWizardPage_error_ModifiersFinalAndAbstract);
2043 		}
2044 		return status;
2045 	}
2046 
2047 	// selection dialogs
2048 
2049 	/**
2050 	 * Opens a selection dialog that allows to select a package.
2051 	 *
2052 	 * @return returns the selected package or <code>null</code> if the dialog has been canceled.
2053 	 * The caller typically sets the result to the package input field.
2054 	 * <p>
2055 	 * Clients can override this method if they want to offer a different dialog.
2056 	 * </p>
2057 	 *
2058 	 * @since 3.2
2059 	 */
choosePackage()2060 	protected IPackageFragment choosePackage() {
2061 		IPackageFragmentRoot froot= getPackageFragmentRoot();
2062 		IJavaElement[] packages= null;
2063 		try {
2064 			if (froot != null && froot.exists()) {
2065 				packages= froot.getChildren();
2066 			}
2067 		} catch (JavaModelException e) {
2068 			JavaPlugin.log(e);
2069 		}
2070 		if (packages == null) {
2071 			packages= new IJavaElement[0];
2072 		}
2073 
2074 		ElementListSelectionDialog dialog= new ElementListSelectionDialog(getShell(), new JavaElementLabelProvider(JavaElementLabelProvider.SHOW_DEFAULT));
2075 		dialog.setIgnoreCase(false);
2076 		dialog.setTitle(NewWizardMessages.NewTypeWizardPage_ChoosePackageDialog_title);
2077 		dialog.setMessage(NewWizardMessages.NewTypeWizardPage_ChoosePackageDialog_description);
2078 		dialog.setEmptyListMessage(NewWizardMessages.NewTypeWizardPage_ChoosePackageDialog_empty);
2079 		dialog.setElements(packages);
2080 		dialog.setHelpAvailable(false);
2081 
2082 		IPackageFragment pack= getPackageFragment();
2083 		if (pack != null) {
2084 			dialog.setInitialSelections(pack);
2085 		}
2086 
2087 		if (dialog.open() == Window.OK) {
2088 			return (IPackageFragment) dialog.getFirstResult();
2089 		}
2090 		return null;
2091 	}
2092 
2093 	/**
2094 	 * Opens a selection dialog that allows to select an enclosing type.
2095 	 *
2096 	 * @return returns the selected type or <code>null</code> if the dialog has been canceled.
2097 	 * The caller typically sets the result to the enclosing type input field.
2098 	 * <p>
2099 	 * Clients can override this method if they want to offer a different dialog.
2100 	 * </p>
2101 	 *
2102 	 * @since 3.2
2103 	 */
chooseEnclosingType()2104 	protected IType chooseEnclosingType() {
2105 		IPackageFragmentRoot root= getPackageFragmentRoot();
2106 		if (root == null) {
2107 			return null;
2108 		}
2109 
2110 		IJavaSearchScope scope= SearchEngine.createJavaSearchScope(new IJavaElement[] { root });
2111 
2112 		FilteredTypesSelectionDialog dialog= new FilteredTypesSelectionDialog(getShell(),
2113 			false, getWizard().getContainer(), scope, IJavaSearchConstants.TYPE);
2114 		dialog.setTitle(NewWizardMessages.NewTypeWizardPage_ChooseEnclosingTypeDialog_title);
2115 		dialog.setMessage(NewWizardMessages.NewTypeWizardPage_ChooseEnclosingTypeDialog_description);
2116 		dialog.setInitialPattern(Signature.getSimpleName(getEnclosingTypeText()));
2117 
2118 		if (dialog.open() == Window.OK) {
2119 			return (IType) dialog.getFirstResult();
2120 		}
2121 		return null;
2122 	}
2123 
2124 	/**
2125 	 * Opens a selection dialog that allows to select a super class.
2126 	 *
2127 	 * @return returns the selected type or <code>null</code> if the dialog has been canceled.
2128 	 * The caller typically sets the result to the super class input field.
2129 	 * 	<p>
2130 	 * Clients can override this method if they want to offer a different dialog.
2131 	 * </p>
2132 	 *
2133 	 * @since 3.2
2134 	 */
chooseSuperClass()2135 	protected IType chooseSuperClass() {
2136 		IJavaProject project= getJavaProject();
2137 		if (project == null) {
2138 			return null;
2139 		}
2140 
2141 		IJavaElement[] elements= new IJavaElement[] { project };
2142 		IJavaSearchScope scope= SearchEngine.createJavaSearchScope(elements);
2143 
2144 		FilteredTypesSelectionDialog dialog= new FilteredTypesSelectionDialog(getShell(), false,
2145 			getWizard().getContainer(), scope, IJavaSearchConstants.CLASS);
2146 		dialog.setTitle(NewWizardMessages.NewTypeWizardPage_SuperClassDialog_title);
2147 		dialog.setMessage(NewWizardMessages.NewTypeWizardPage_SuperClassDialog_message);
2148 		dialog.setInitialPattern(getSuperClass());
2149 
2150 		if (dialog.open() == Window.OK) {
2151 			return (IType) dialog.getFirstResult();
2152 		}
2153 		return null;
2154 	}
2155 
2156 	/**
2157 	 * Opens a selection dialog that allows to select the super interfaces. The selected interfaces are
2158 	 * directly added to the wizard page using {@link #addSuperInterface(String)}.
2159 	 *
2160 	 * 	<p>
2161 	 * Clients can override this method if they want to offer a different dialog.
2162 	 * </p>
2163 	 *
2164 	 * @since 3.2
2165 	 */
chooseSuperInterfaces()2166 	protected void chooseSuperInterfaces() {
2167 		IJavaProject project= getJavaProject();
2168 		if (project == null) {
2169 			return;
2170 		}
2171 
2172 		SuperInterfaceSelectionDialog dialog= new SuperInterfaceSelectionDialog(getShell(), getWizard().getContainer(), this, project);
2173 		dialog.setTitle(getInterfaceDialogTitle());
2174 		dialog.setMessage(NewWizardMessages.NewTypeWizardPage_InterfacesDialog_message);
2175 		dialog.open();
2176 	}
2177 
getInterfaceDialogTitle()2178 	private String getInterfaceDialogTitle() {
2179 	    if (fTypeKind == INTERFACE_TYPE)
2180 	        return NewWizardMessages.NewTypeWizardPage_InterfacesDialog_interface_title;
2181 	    return NewWizardMessages.NewTypeWizardPage_InterfacesDialog_class_title;
2182 	}
2183 
2184 
2185 	// ---- creation ----------------
2186 
2187 	/**
2188 	 * Creates the new type using the entered field values.
2189 	 *
2190 	 * @param monitor a progress monitor to report progress.
2191 	 * @throws CoreException Thrown when the creation failed.
2192 	 * @throws InterruptedException Thrown when the operation was canceled.
2193 	 */
createType(IProgressMonitor monitor)2194 	public void createType(IProgressMonitor monitor) throws CoreException, InterruptedException {
2195 		if (monitor == null) {
2196 			monitor= new NullProgressMonitor();
2197 		}
2198 
2199 		monitor.beginTask(NewWizardMessages.NewTypeWizardPage_operationdesc, 8);
2200 
2201 		IPackageFragmentRoot root= getPackageFragmentRoot();
2202 		IPackageFragment pack= getPackageFragment();
2203 		if (pack == null) {
2204 			pack= root.getPackageFragment(""); //$NON-NLS-1$
2205 		}
2206 
2207 		if (!pack.exists()) {
2208 			String packName= pack.getElementName();
2209 			pack= root.createPackageFragment(packName, true, new SubProgressMonitor(monitor, 1));
2210 		} else {
2211 			monitor.worked(1);
2212 		}
2213 
2214 		boolean needsSave;
2215 		ICompilationUnit connectedCU= null;
2216 
2217 		try {
2218 			String typeName= getTypeNameWithoutParameters();
2219 
2220 			boolean isInnerClass= isEnclosingTypeSelected();
2221 
2222 			IType createdType;
2223 			ImportsManager imports;
2224 			int indent= 0;
2225 
2226 			Set<String> existingImports;
2227 
2228 			String lineDelimiter= null;
2229 			if (!isInnerClass) {
2230 				lineDelimiter= StubUtility.getLineDelimiterUsed(pack.getJavaProject());
2231 
2232 				String cuName= getCompilationUnitName(typeName);
2233 				ICompilationUnit parentCU= pack.createCompilationUnit(cuName, "", false, new SubProgressMonitor(monitor, 2)); //$NON-NLS-1$
2234 				// create a working copy with a new owner
2235 
2236 				needsSave= true;
2237 				parentCU.becomeWorkingCopy(new SubProgressMonitor(monitor, 1)); // cu is now a (primary) working copy
2238 				connectedCU= parentCU;
2239 
2240 				IBuffer buffer= parentCU.getBuffer();
2241 
2242 				String simpleTypeStub= constructSimpleTypeStub();
2243 				String cuContent= constructCUContent(parentCU, simpleTypeStub, lineDelimiter);
2244 				buffer.setContents(cuContent);
2245 
2246 				CompilationUnit astRoot= createASTForImports(parentCU);
2247 				existingImports= getExistingImports(astRoot);
2248 
2249 				imports= new ImportsManager(astRoot);
2250 				// add an import that will be removed again. Having this import solves 14661
2251 				imports.addImport(JavaModelUtil.concatenateName(pack.getElementName(), typeName));
2252 
2253 				String typeContent= constructTypeStub(parentCU, imports, lineDelimiter);
2254 
2255 				int index= cuContent.lastIndexOf(simpleTypeStub);
2256 				if (index == -1) {
2257 					AbstractTypeDeclaration typeNode= (AbstractTypeDeclaration) astRoot.types().get(0);
2258 					int start= ((ASTNode) typeNode.modifiers().get(0)).getStartPosition();
2259 					int end= typeNode.getStartPosition() + typeNode.getLength();
2260 					buffer.replace(start, end - start, typeContent);
2261 				} else {
2262 					buffer.replace(index, simpleTypeStub.length(), typeContent);
2263 				}
2264 
2265 				createdType= parentCU.getType(typeName);
2266 			} else {
2267 				IType enclosingType= getEnclosingType();
2268 
2269 				ICompilationUnit parentCU= enclosingType.getCompilationUnit();
2270 
2271 				needsSave= !parentCU.isWorkingCopy();
2272 				parentCU.becomeWorkingCopy(new SubProgressMonitor(monitor, 1)); // cu is now for sure (primary) a working copy
2273 				connectedCU= parentCU;
2274 
2275 				CompilationUnit astRoot= createASTForImports(parentCU);
2276 				imports= new ImportsManager(astRoot);
2277 				existingImports= getExistingImports(astRoot);
2278 
2279 
2280 				// add imports that will be removed again. Having the imports solves 14661
2281 				for (IType topLevelType : parentCU.getTypes()) {
2282 					imports.addImport(topLevelType.getFullyQualifiedName('.'));
2283 				}
2284 
2285 				lineDelimiter= StubUtility.getLineDelimiterUsed(enclosingType);
2286 				StringBuilder content= new StringBuilder();
2287 
2288 				String comment= getTypeComment(parentCU, lineDelimiter);
2289 				if (comment != null) {
2290 					content.append(comment);
2291 					content.append(lineDelimiter);
2292 				}
2293 
2294 				content.append(constructTypeStub(parentCU, imports, lineDelimiter));
2295 				IJavaElement sibling= null;
2296 				if (enclosingType.isEnum()) {
2297 					IField[] fields = enclosingType.getFields();
2298 					if (fields.length > 0) {
2299 						for (IField field : fields) {
2300 							if (!field.isEnumConstant()) {
2301 								sibling = field;
2302 								break;
2303 							}
2304 						}
2305 					}
2306 				} else {
2307 					IJavaElement[] elems= enclosingType.getChildren();
2308 					sibling = elems.length > 0 ? elems[0] : null;
2309 				}
2310 
2311 				createdType= enclosingType.createType(content.toString(), sibling, false, new SubProgressMonitor(monitor, 2));
2312 
2313 				indent= StubUtility.getIndentUsed(enclosingType) + 1;
2314 			}
2315 			if (monitor.isCanceled()) {
2316 				throw new InterruptedException();
2317 			}
2318 
2319 			// add imports for superclass/interfaces, so types can be resolved correctly
2320 
2321 			ICompilationUnit cu= createdType.getCompilationUnit();
2322 
2323 			imports.create(false, new SubProgressMonitor(monitor, 1));
2324 
2325 			JavaModelUtil.reconcile(cu);
2326 
2327 			if (monitor.isCanceled()) {
2328 				throw new InterruptedException();
2329 			}
2330 
2331 			// set up again
2332 			CompilationUnit astRoot= createASTForImports(imports.getCompilationUnit());
2333 			imports= new ImportsManager(astRoot);
2334 
2335 			createTypeMembers(createdType, imports, new SubProgressMonitor(monitor, 1));
2336 
2337 			// add imports
2338 			imports.create(false, new SubProgressMonitor(monitor, 1));
2339 
2340 			removeUnusedImports(cu, existingImports, false);
2341 
2342 			JavaModelUtil.reconcile(cu);
2343 
2344 			ISourceRange range= createdType.getSourceRange();
2345 
2346 			IBuffer buf= cu.getBuffer();
2347 			String originalContent= buf.getText(range.getOffset(), range.getLength());
2348 
2349 			String formattedContent= CodeFormatterUtil.format(CodeFormatter.K_CLASS_BODY_DECLARATIONS, originalContent, indent, lineDelimiter,
2350 					FormatterProfileManager.getProjectSettings(pack.getJavaProject()));
2351 			formattedContent= Strings.trimLeadingTabsAndSpaces(formattedContent);
2352 			buf.replace(range.getOffset(), range.getLength(), formattedContent);
2353 			if (!isInnerClass) {
2354 				String fileComment= getFileComment(cu);
2355 				if (fileComment != null && fileComment.length() > 0) {
2356 					buf.replace(0, 0, fileComment + lineDelimiter);
2357 				}
2358 			}
2359 			fCreatedType= createdType;
2360 
2361 			if (needsSave) {
2362 				cu.commitWorkingCopy(true, new SubProgressMonitor(monitor, 1));
2363 			} else {
2364 				monitor.worked(1);
2365 			}
2366 
2367 		} finally {
2368 			if (connectedCU != null) {
2369 				connectedCU.discardWorkingCopy();
2370 			}
2371 			monitor.done();
2372 		}
2373 	}
2374 
createASTForImports(ICompilationUnit cu)2375 	private CompilationUnit createASTForImports(ICompilationUnit cu) {
2376 		ASTParser parser= ASTParser.newParser(IASTSharedValues.SHARED_AST_LEVEL);
2377 		parser.setSource(cu);
2378 		parser.setResolveBindings(true);
2379 		parser.setFocalPosition(0);
2380 		return (CompilationUnit) parser.createAST(null);
2381 	}
2382 
2383 
getExistingImports(CompilationUnit root)2384 	private Set<String> getExistingImports(CompilationUnit root) {
2385 		List<ImportDeclaration> imports= root.imports();
2386 		Set<String> res= new HashSet<>(imports.size());
2387 		for (ImportDeclaration import1 : imports) {
2388 			res.add(ASTNodes.asString(import1));
2389 		}
2390 		return res;
2391 	}
2392 
removeUnusedImports(ICompilationUnit cu, Set<String> existingImports, boolean needsSave)2393 	private void removeUnusedImports(ICompilationUnit cu, Set<String> existingImports, boolean needsSave) throws CoreException {
2394 		ASTParser parser= ASTParser.newParser(IASTSharedValues.SHARED_AST_LEVEL);
2395 		parser.setSource(cu);
2396 		parser.setResolveBindings(true);
2397 
2398 		CompilationUnit root= (CompilationUnit) parser.createAST(null);
2399 		if (root.getProblems().length == 0) {
2400 			return;
2401 		}
2402 
2403 		List<ImportDeclaration> importsDecls= root.imports();
2404 		if (importsDecls.isEmpty()) {
2405 			return;
2406 		}
2407 		ImportsManager imports= new ImportsManager(root);
2408 
2409 		int importsEnd= ASTNodes.getExclusiveEnd(importsDecls.get(importsDecls.size() - 1));
2410 		for (IProblem curr : root.getProblems()) {
2411 			if (curr.getSourceEnd() < importsEnd) {
2412 				int id= curr.getID();
2413 				if (id == IProblem.UnusedImport || id == IProblem.NotVisibleType) { // not visible problems hide unused -> remove both
2414 					int pos= curr.getSourceStart();
2415 					for (ImportDeclaration decl : importsDecls) {
2416 						if (decl.getStartPosition() <= pos && pos < decl.getStartPosition() + decl.getLength()) {
2417 							if (existingImports.isEmpty() || !existingImports.contains(ASTNodes.asString(decl))) {
2418 								String name= decl.getName().getFullyQualifiedName();
2419 								if (decl.isOnDemand()) {
2420 									name += ".*"; //$NON-NLS-1$
2421 								}
2422 								if (decl.isStatic()) {
2423 									imports.removeStaticImport(name);
2424 								} else {
2425 									imports.removeImport(name);
2426 								}
2427 							}
2428 							break;
2429 						}
2430 					}
2431 				}
2432 			}
2433 		}
2434 		imports.create(needsSave, null);
2435 	}
2436 
2437 	/**
2438 	 * Uses the New Java file template from the code template page to generate a
2439 	 * compilation unit with the given type content.
2440 	 *
2441 	 * @param cu The new created compilation unit
2442 	 * @param typeContent The content of the type, including signature and type
2443 	 * body.
2444 	 * @param lineDelimiter The line delimiter to be used.
2445 	 * @return String Returns the result of evaluating the new file template
2446 	 * with the given type content.
2447 	 * @throws CoreException when fetching the file comment fails or fetching the content for the
2448 	 *             new compilation unit fails
2449 	 * @since 2.1
2450 	 */
constructCUContent(ICompilationUnit cu, String typeContent, String lineDelimiter)2451 	protected String constructCUContent(ICompilationUnit cu, String typeContent, String lineDelimiter) throws CoreException {
2452 		String fileComment= getFileComment(cu, lineDelimiter);
2453 		String typeComment= getTypeComment(cu, lineDelimiter);
2454 		IPackageFragment pack= (IPackageFragment) cu.getParent();
2455 		String content= CodeGeneration.getCompilationUnitContent(cu, fileComment, typeComment, typeContent, lineDelimiter);
2456 		if (content != null) {
2457 			ASTParser parser= ASTParser.newParser(IASTSharedValues.SHARED_AST_LEVEL);
2458 			parser.setProject(cu.getJavaProject());
2459 			parser.setSource(content.toCharArray());
2460 			CompilationUnit unit= (CompilationUnit) parser.createAST(null);
2461 			if ((pack.isDefaultPackage() || unit.getPackage() != null) && !unit.types().isEmpty()) {
2462 				return content;
2463 			}
2464 		}
2465 		StringBuilder buf= new StringBuilder();
2466 		if (!pack.isDefaultPackage()) {
2467 			buf.append("package ").append(pack.getElementName()).append(';'); //$NON-NLS-1$
2468 		}
2469 		buf.append(lineDelimiter).append(lineDelimiter);
2470 		if (typeComment != null) {
2471 			buf.append(typeComment).append(lineDelimiter);
2472 		}
2473 		buf.append(typeContent);
2474 		return buf.toString();
2475 	}
2476 
2477 
2478 	/**
2479 	 * Returns the created type or <code>null</code> is the type has not been created yet. The method
2480 	 * only returns a valid type after <code>createType</code> has been called.
2481 	 *
2482 	 * @return the created type
2483 	 * @see #createType(IProgressMonitor)
2484 	 */
getCreatedType()2485 	public IType getCreatedType() {
2486 		return fCreatedType;
2487 	}
2488 
2489 	// ---- construct CU body----------------
2490 
writeSuperClass(StringBuffer buf, ImportsManager imports)2491 	private void writeSuperClass(StringBuffer buf, ImportsManager imports) {
2492 		String superclass= getSuperClass();
2493 		if (fTypeKind == CLASS_TYPE && superclass.length() > 0 && !"java.lang.Object".equals(superclass)) { //$NON-NLS-1$
2494 			buf.append(" extends "); //$NON-NLS-1$
2495 
2496 			ITypeBinding binding= null;
2497 			if (fCurrType != null) {
2498 				binding= TypeContextChecker.resolveSuperClass(superclass, fCurrType, getSuperClassStubTypeContext());
2499 			}
2500 			if (binding != null) {
2501 				buf.append(imports.addImport(binding));
2502 			} else {
2503 				buf.append(imports.addImport(superclass));
2504 			}
2505 		}
2506 	}
2507 
writeSuperInterfaces(StringBuffer buf, ImportsManager imports)2508 	private void writeSuperInterfaces(StringBuffer buf, ImportsManager imports) {
2509 		List<String> interfaces= getSuperInterfaces();
2510 		int last= interfaces.size() - 1;
2511 		if (last >= 0) {
2512 		    if (fTypeKind != INTERFACE_TYPE) {
2513 				buf.append(" implements "); //$NON-NLS-1$
2514 			} else {
2515 				buf.append(" extends "); //$NON-NLS-1$
2516 			}
2517 			String[] intfs= interfaces.toArray(new String[interfaces.size()]);
2518 			ITypeBinding[] bindings;
2519 			if (fCurrType != null) {
2520 				bindings= TypeContextChecker.resolveSuperInterfaces(intfs, fCurrType, getSuperInterfacesStubTypeContext());
2521 			} else {
2522 				bindings= new ITypeBinding[intfs.length];
2523 			}
2524 			for (int i= 0; i <= last; i++) {
2525 				ITypeBinding binding= bindings[i];
2526 				if (binding != null) {
2527 					buf.append(imports.addImport(binding));
2528 				} else {
2529 					buf.append(imports.addImport(intfs[i]));
2530 				}
2531 				if (i < last) {
2532 					buf.append(',');
2533 				}
2534 			}
2535 		}
2536 	}
2537 
2538 
constructSimpleTypeStub()2539 	private String constructSimpleTypeStub() {
2540 		StringBuilder buf= new StringBuilder("public class "); //$NON-NLS-1$
2541 		buf.append(getTypeName());
2542 		buf.append("{ }"); //$NON-NLS-1$
2543 		return buf.toString();
2544 	}
2545 
2546 	/*
2547 	 * Called from createType to construct the source for this type
2548 	 */
constructTypeStub(ICompilationUnit parentCU, ImportsManager imports, String lineDelimiter)2549 	private String constructTypeStub(ICompilationUnit parentCU, ImportsManager imports, String lineDelimiter) throws CoreException {
2550 		StringBuffer buf= new StringBuffer();
2551 
2552 		int modifiers= getModifiers();
2553 		buf.append(Flags.toString(modifiers));
2554 		if (modifiers != 0) {
2555 			buf.append(' ');
2556 		}
2557 		String type= ""; //$NON-NLS-1$
2558 		String templateID= ""; //$NON-NLS-1$
2559 		switch (fTypeKind) {
2560 			case CLASS_TYPE:
2561 				type= "class ";  //$NON-NLS-1$
2562 				templateID= CodeGeneration.CLASS_BODY_TEMPLATE_ID;
2563 				break;
2564 			case INTERFACE_TYPE:
2565 				type= "interface "; //$NON-NLS-1$
2566 				templateID= CodeGeneration.INTERFACE_BODY_TEMPLATE_ID;
2567 				break;
2568 			case ENUM_TYPE:
2569 				type= "enum "; //$NON-NLS-1$
2570 				templateID= CodeGeneration.ENUM_BODY_TEMPLATE_ID;
2571 				break;
2572 			case ANNOTATION_TYPE:
2573 				type= "@interface "; //$NON-NLS-1$
2574 				templateID= CodeGeneration.ANNOTATION_BODY_TEMPLATE_ID;
2575 				break;
2576 			case RECORD_TYPE:
2577 				type= "record "; //$NON-NLS-1$
2578 				templateID= CodeGeneration.RECORD_BODY_TEMPLATE_ID;
2579 				break;
2580 		}
2581 		buf.append(type);
2582 		buf.append(getTypeName());
2583 		if (fTypeKind == RECORD_TYPE) {
2584 			buf.append("()"); //$NON-NLS-1$
2585 		}
2586 		writeSuperClass(buf, imports);
2587 		writeSuperInterfaces(buf, imports);
2588 
2589 		buf.append(" {").append(lineDelimiter); //$NON-NLS-1$
2590 		String typeBody= CodeGeneration.getTypeBody(templateID, parentCU, getTypeName(), lineDelimiter);
2591 		if (typeBody != null) {
2592 			buf.append(typeBody);
2593 		} else {
2594 			buf.append(lineDelimiter);
2595 		}
2596 		buf.append('}').append(lineDelimiter);
2597 		return buf.toString();
2598 	}
2599 
2600 	/**
2601 	 * Hook method that gets called from <code>createType</code> to support adding of
2602 	 * unanticipated methods, fields, and inner types to the created type.
2603 	 * <p>
2604 	 * Implementers can use any methods defined on <code>IType</code> to manipulate the
2605 	 * new type.
2606 	 * </p>
2607 	 * <p>
2608 	 * The source code of the new type will be formatted using the platform's formatter. Needed
2609 	 * imports are added by the wizard at the end of the type creation process using the given
2610 	 * import manager.
2611 	 * </p>
2612 	 *
2613 	 * @param newType the new type created via <code>createType</code>
2614 	 * @param imports an import manager which can be used to add new imports
2615 	 * @param monitor a progress monitor to report progress. Must not be <code>null</code>
2616 	 * @throws CoreException thrown when creation of the type members failed
2617 	 *
2618 	 * @see #createType(IProgressMonitor)
2619 	 */
createTypeMembers(IType newType, final ImportsManager imports, IProgressMonitor monitor)2620 	protected void createTypeMembers(IType newType, final ImportsManager imports, IProgressMonitor monitor) throws CoreException {
2621 		// default implementation does nothing
2622 		// example would be
2623 		// String mainMathod= "public void foo(Vector vec) {}"
2624 		// createdType.createMethod(main, null, false, null);
2625 		// imports.addImport("java.lang.Vector");
2626 	}
2627 
2628 
2629 	/**
2630 	 * @param parentCU the current compilation unit
2631 	 * @return returns the file template or <code>null</code>
2632 	 * @deprecated Instead of file templates, the new type code template
2633 	 * specifies the stub for a compilation unit.
2634 	 */
2635 	@Deprecated
getFileComment(ICompilationUnit parentCU)2636 	protected String getFileComment(ICompilationUnit parentCU) {
2637 		return null;
2638 	}
2639 
2640 	/**
2641 	 * Hook method that gets called from <code>createType</code> to retrieve
2642 	 * a file comment. This default implementation returns the content of the
2643 	 * 'file comment' template or <code>null</code> if no comment should be created.
2644 	 *
2645 	 * @param parentCU the parent compilation unit
2646 	 * @param lineDelimiter the line delimiter to use
2647 	 * @return the file comment or <code>null</code> if a file comment
2648 	 * is not desired
2649 	 * @throws CoreException when fetching the file comment fails
2650      *
2651      * @since 3.1
2652 	 */
getFileComment(ICompilationUnit parentCU, String lineDelimiter)2653 	protected String getFileComment(ICompilationUnit parentCU, String lineDelimiter) throws CoreException {
2654 		if (isAddComments()) {
2655 			return CodeGeneration.getFileComment(parentCU, lineDelimiter);
2656 		}
2657 		return null;
2658 
2659 	}
2660 
isValidComment(String template)2661 	private boolean isValidComment(String template) {
2662 		IScanner scanner= ToolFactory.createScanner(true, false, false, false);
2663 		scanner.setSource(template.toCharArray());
2664 		try {
2665 			int next= scanner.getNextToken();
2666 			while (TokenScanner.isComment(next)) {
2667 				next= scanner.getNextToken();
2668 			}
2669 			return next == ITerminalSymbols.TokenNameEOF;
2670 		} catch (InvalidInputException e) {
2671 		}
2672 		return false;
2673 	}
2674 
2675 	/**
2676 	 * Hook method that gets called from <code>createType</code> to retrieve
2677 	 * a type comment. This default implementation returns the content of the
2678 	 * 'type comment' template.
2679 	 *
2680 	 * @param parentCU the parent compilation unit
2681 	 * @param lineDelimiter the line delimiter to use
2682 	 * @return the type comment or <code>null</code> if a type comment
2683 	 * is not desired
2684      *
2685      * @since 3.0
2686 	 */
getTypeComment(ICompilationUnit parentCU, String lineDelimiter)2687 	protected String getTypeComment(ICompilationUnit parentCU, String lineDelimiter) {
2688 		if (isAddComments()) {
2689 			try {
2690 				StringBuilder typeName= new StringBuilder();
2691 				if (isEnclosingTypeSelected()) {
2692 					typeName.append(getEnclosingType().getTypeQualifiedName('.')).append('.');
2693 				}
2694 				typeName.append(getTypeNameWithoutParameters());
2695 				String[] typeParamNames= new String[0];
2696 				String comment= CodeGeneration.getTypeComment(parentCU, typeName.toString(), typeParamNames, lineDelimiter);
2697 				if (comment != null && isValidComment(comment)) {
2698 					return comment;
2699 				}
2700 			} catch (CoreException e) {
2701 				JavaPlugin.log(e);
2702 			}
2703 		}
2704 		return null;
2705 	}
2706 
2707 	/**
2708 	 * @param parentCU the current compilation unit
2709 	 * @return returns the template or <code>null</code>
2710 	 * @deprecated Use getTypeComment(ICompilationUnit, String)
2711 	 */
2712 	@Deprecated
getTypeComment(ICompilationUnit parentCU)2713 	protected String getTypeComment(ICompilationUnit parentCU) {
2714 		if (StubUtility.doAddComments(parentCU.getJavaProject()))
2715 			return getTypeComment(parentCU, StubUtility.getLineDelimiterUsed(parentCU));
2716 		return null;
2717 	}
2718 
2719 	/**
2720 	 * @param name the name of the template
2721 	 * @param parentCU the current compilation unit
2722 	 * @return returns the template or <code>null</code>
2723 	 * @deprecated Use getTemplate(String,ICompilationUnit,int)
2724 	 */
2725 	@Deprecated
getTemplate(String name, ICompilationUnit parentCU)2726 	protected String getTemplate(String name, ICompilationUnit parentCU) {
2727 		return getTemplate(name, parentCU, 0);
2728 	}
2729 
2730 
2731 	/**
2732 	 * Returns the string resulting from evaluation the given template in
2733 	 * the context of the given compilation unit. This accesses the normal
2734 	 * template page, not the code templates. To use code templates use
2735 	 * <code>constructCUContent</code> to construct a compilation unit stub or
2736 	 * getTypeComment for the comment of the type.
2737 	 *
2738 	 * @param name the template to be evaluated
2739 	 * @param parentCU the templates evaluation context
2740 	 * @param pos a source offset into the parent compilation unit. The
2741 	 * template is evaluated at the given source offset
2742 	 * @return return the template with the given name or <code>null</code> if the template could not be found.
2743 	 */
getTemplate(String name, ICompilationUnit parentCU, int pos)2744 	protected String getTemplate(String name, ICompilationUnit parentCU, int pos) {
2745 		try {
2746 			Template template= JavaPlugin.getDefault().getTemplateStore().findTemplate(name);
2747 			if (template != null) {
2748 				return TemplateUtils.evaluateTemplate(template, parentCU, pos);
2749 			}
2750 		} catch (CoreException e) {
2751 			JavaPlugin.log(e);
2752 		} catch (BadLocationException e) {
2753 			JavaPlugin.log(e);
2754 		} catch (TemplateException e) {
2755 			JavaPlugin.log(e);
2756 		}
2757 		return null;
2758 	}
2759 
2760 
2761 	/**
2762 	 * Creates the bodies of all unimplemented methods and constructors and adds them to the type.
2763 	 * Method is typically called by implementers of <code>NewTypeWizardPage</code> to add
2764 	 * needed method and constructors.
2765 	 *
2766 	 * @param type the type for which the new methods and constructor are to be created
2767 	 * @param doConstructors if <code>true</code> unimplemented constructors are created
2768 	 * @param doUnimplementedMethods if <code>true</code> unimplemented methods are created
2769 	 * @param imports an import manager to add all needed import statements
2770 	 * @param monitor a progress monitor to report progress
2771 	 * @return the created methods.
2772 	 * @throws CoreException thrown when the creation fails.
2773 	 */
createInheritedMethods(IType type, boolean doConstructors, boolean doUnimplementedMethods, ImportsManager imports, IProgressMonitor monitor)2774 	protected IMethod[] createInheritedMethods(IType type, boolean doConstructors, boolean doUnimplementedMethods, ImportsManager imports, IProgressMonitor monitor) throws CoreException {
2775 		final ICompilationUnit cu= type.getCompilationUnit();
2776 		JavaModelUtil.reconcile(cu);
2777 		IMethod[] typeMethods= type.getMethods();
2778 		Set<String> handleIds= new HashSet<>(typeMethods.length);
2779 		for (IMethod typeMethod : typeMethods) {
2780 			handleIds.add(typeMethod.getHandleIdentifier());
2781 		}
2782 		ArrayList<IMethod> newMethods= new ArrayList<>();
2783 		CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(type.getJavaProject());
2784 		settings.createComments= isAddComments();
2785 		ASTParser parser= ASTParser.newParser(IASTSharedValues.SHARED_AST_LEVEL);
2786 		parser.setResolveBindings(true);
2787 		parser.setSource(cu);
2788 		CompilationUnit unit= (CompilationUnit) parser.createAST(new SubProgressMonitor(monitor, 1));
2789 		final ITypeBinding binding= ASTNodes.getTypeBinding(unit, type);
2790 		if (binding != null) {
2791 			if (doUnimplementedMethods) {
2792 				AddUnimplementedMethodsOperation operation= new AddUnimplementedMethodsOperation(unit, binding, null, -1, false, true, false);
2793 				operation.setCreateComments(isAddComments());
2794 				operation.run(monitor);
2795 				createImports(imports, operation.getCreatedImports());
2796 			}
2797 			if (doConstructors) {
2798 				AddUnimplementedConstructorsOperation operation= new AddUnimplementedConstructorsOperation(unit, binding, null, -1, false, true, false, FormatterProfileManager.getProjectSettings(type.getJavaProject()));
2799 				operation.setOmitSuper(true);
2800 				operation.setCreateComments(isAddComments());
2801 				operation.run(monitor);
2802 				createImports(imports, operation.getCreatedImports());
2803 			}
2804 		}
2805 		JavaModelUtil.reconcile(cu);
2806 		for (IMethod typeMethod : type.getMethods()) {
2807 			if (!handleIds.contains(typeMethod.getHandleIdentifier())) {
2808 				newMethods.add(typeMethod);
2809 			}
2810 		}
2811 		IMethod[] methods= new IMethod[newMethods.size()];
2812 		newMethods.toArray(methods);
2813 		return methods;
2814 	}
2815 
createImports(ImportsManager imports, String[] createdImports)2816 	private void createImports(ImportsManager imports, String[] createdImports) {
2817 		for (String createdImport : createdImports) {
2818 			imports.addImport(createdImport);
2819 		}
2820 	}
2821 
2822 
2823 	// ---- creation ----------------
2824 
2825 	/**
2826 	 * Returns the runnable that creates the type using the current settings.
2827 	 * The returned runnable must be executed in the UI thread.
2828 	 *
2829 	 * @return the runnable to create the new type
2830 	 */
getRunnable()2831 	public IRunnableWithProgress getRunnable() {
2832 		return new IRunnableWithProgress() {
2833 			@Override
2834 			public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
2835 				try {
2836 					if (monitor == null) {
2837 						monitor= new NullProgressMonitor();
2838 					}
2839 					createType(monitor);
2840 				} catch (CoreException e) {
2841 					throw new InvocationTargetException(e);
2842 				}
2843 			}
2844 		};
2845 	}
2846 }
2847