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