| /******************************************************************************* |
| * Copyright (c) 2000, 2012 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Renaud Waldura <renaud+eclipse@waldura.com> |
| * IBM Corporation - updates |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.ui.text.correction.proposals; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.List; |
| |
| import org.eclipse.swt.widgets.Shell; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| |
| import org.eclipse.jface.layout.PixelConverter; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.jface.wizard.IWizardPage; |
| import org.eclipse.jface.wizard.WizardDialog; |
| |
| import org.eclipse.jface.text.IDocument; |
| |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IPackageFragment; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.dom.AST; |
| import org.eclipse.jdt.core.dom.ASTNode; |
| import org.eclipse.jdt.core.dom.CatchClause; |
| import org.eclipse.jdt.core.dom.ITypeBinding; |
| import org.eclipse.jdt.core.dom.MethodDeclaration; |
| import org.eclipse.jdt.core.dom.Name; |
| import org.eclipse.jdt.core.dom.ParameterizedType; |
| import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; |
| |
| import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility; |
| import org.eclipse.jdt.internal.corext.dom.ASTNodes; |
| import org.eclipse.jdt.internal.corext.dom.Bindings; |
| import org.eclipse.jdt.internal.corext.util.JavaModelUtil; |
| import org.eclipse.jdt.internal.corext.util.Messages; |
| |
| import org.eclipse.jdt.ui.JavaElementLabels; |
| import org.eclipse.jdt.ui.text.java.IInvocationContext; |
| import org.eclipse.jdt.ui.text.java.IProblemLocation; |
| import org.eclipse.jdt.ui.text.java.correction.ChangeCorrectionProposal; |
| import org.eclipse.jdt.ui.wizards.NewAnnotationWizardPage; |
| import org.eclipse.jdt.ui.wizards.NewClassWizardPage; |
| import org.eclipse.jdt.ui.wizards.NewEnumWizardPage; |
| import org.eclipse.jdt.ui.wizards.NewInterfaceWizardPage; |
| import org.eclipse.jdt.ui.wizards.NewTypeWizardPage; |
| |
| import org.eclipse.jdt.internal.ui.JavaPlugin; |
| import org.eclipse.jdt.internal.ui.JavaPluginImages; |
| import org.eclipse.jdt.internal.ui.text.correction.ASTResolving; |
| import org.eclipse.jdt.internal.ui.text.correction.CorrectionMessages; |
| import org.eclipse.jdt.internal.ui.text.correction.UnresolvedElementsSubProcessor; |
| import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels; |
| import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider; |
| import org.eclipse.jdt.internal.ui.wizards.NewAnnotationCreationWizard; |
| import org.eclipse.jdt.internal.ui.wizards.NewClassCreationWizard; |
| import org.eclipse.jdt.internal.ui.wizards.NewElementWizard; |
| import org.eclipse.jdt.internal.ui.wizards.NewEnumCreationWizard; |
| import org.eclipse.jdt.internal.ui.wizards.NewInterfaceCreationWizard; |
| |
| |
| /** |
| * This proposal is listed in the corrections list for a "type not found" problem. |
| * It offers to create a new type by running the class/interface wizard. |
| * If selected, this proposal will open a {@link NewClassCreationWizard}, |
| * {@link NewInterfaceCreationWizard}, {@link NewEnumCreationWizard} or {@link NewAnnotationCreationWizard}. |
| * |
| * @see UnresolvedElementsSubProcessor#getTypeProposals(IInvocationContext, IProblemLocation, Collection) |
| */ |
| public class NewCUUsingWizardProposal extends ChangeCorrectionProposal { |
| |
| public static final int K_CLASS= 1; |
| public static final int K_INTERFACE= 2; |
| public static final int K_ENUM= 3; |
| public static final int K_ANNOTATION= 4; |
| |
| private Name fNode; |
| private ICompilationUnit fCompilationUnit; |
| private int fTypeKind; |
| private IJavaElement fTypeContainer; // IType or IPackageFragment |
| private String fTypeNameWithParameters; |
| private IType fCreatedType; |
| |
| private boolean fShowDialog; |
| |
| public NewCUUsingWizardProposal(ICompilationUnit cu, Name node, int typeKind, IJavaElement typeContainer, int severity) { |
| super("", null, severity, null); //$NON-NLS-1$ |
| |
| fCompilationUnit= cu; |
| fNode= node; |
| fTypeKind= typeKind; |
| fTypeContainer= typeContainer; |
| fTypeNameWithParameters= getTypeName(typeKind, node); |
| |
| fCreatedType= null; |
| |
| String containerName= ASTNodes.getQualifier(node); |
| String typeName= fTypeNameWithParameters; |
| String containerLabel= BasicElementLabels.getJavaElementName(containerName); |
| String typeLabel= BasicElementLabels.getJavaElementName(typeName); |
| boolean isInnerType= typeContainer instanceof IType; |
| switch (typeKind) { |
| case K_CLASS: |
| setImage(JavaPluginImages.get(JavaPluginImages.IMG_OBJS_CLASS)); |
| if (isInnerType) { |
| if (containerName.length() == 0) { |
| setDisplayName(Messages.format(CorrectionMessages.NewCUCompletionUsingWizardProposal_createinnerclass_description, typeLabel)); |
| } else { |
| setDisplayName(Messages.format(CorrectionMessages.NewCUCompletionUsingWizardProposal_createinnerclass_intype_description, new String[] { typeLabel, containerLabel })); |
| } |
| } else { |
| if (containerName.length() == 0) { |
| setDisplayName(Messages.format(CorrectionMessages.NewCUCompletionUsingWizardProposal_createclass_description, typeLabel)); |
| } else { |
| setDisplayName(Messages.format(CorrectionMessages.NewCUCompletionUsingWizardProposal_createclass_inpackage_description, new String[] { typeLabel, containerLabel })); |
| } |
| } |
| break; |
| case K_INTERFACE: |
| setImage(JavaPluginImages.get(JavaPluginImages.IMG_OBJS_INTERFACE)); |
| if (isInnerType) { |
| if (containerName.length() == 0) { |
| setDisplayName(Messages.format(CorrectionMessages.NewCUCompletionUsingWizardProposal_createinnerinterface_description, typeLabel)); |
| } else { |
| setDisplayName(Messages.format(CorrectionMessages.NewCUCompletionUsingWizardProposal_createinnerinterface_intype_description, new String[] { typeLabel, containerLabel })); |
| } |
| } else { |
| if (containerName.length() == 0) { |
| setDisplayName(Messages.format(CorrectionMessages.NewCUCompletionUsingWizardProposal_createinterface_description, typeLabel)); |
| } else { |
| setDisplayName(Messages.format(CorrectionMessages.NewCUCompletionUsingWizardProposal_createinterface_inpackage_description, new String[] { typeLabel, containerLabel })); |
| } |
| } |
| break; |
| case K_ENUM: |
| setImage(JavaPluginImages.get(JavaPluginImages.IMG_OBJS_ENUM)); |
| if (isInnerType) { |
| if (containerName.length() == 0) { |
| setDisplayName(Messages.format(CorrectionMessages.NewCUCompletionUsingWizardProposal_createinnerenum_description, typeLabel)); |
| } else { |
| setDisplayName(Messages.format(CorrectionMessages.NewCUCompletionUsingWizardProposal_createinnerenum_intype_description, new String[] { typeLabel, containerLabel })); |
| } |
| } else { |
| if (containerName.length() == 0) { |
| setDisplayName(Messages.format(CorrectionMessages.NewCUCompletionUsingWizardProposal_createenum_description, typeLabel)); |
| } else { |
| setDisplayName(Messages.format(CorrectionMessages.NewCUCompletionUsingWizardProposal_createenum_inpackage_description, new String[] { typeLabel, containerLabel })); |
| } |
| } |
| break; |
| case K_ANNOTATION: |
| setImage(JavaPluginImages.get(JavaPluginImages.IMG_OBJS_ANNOTATION)); |
| if (isInnerType) { |
| if (containerName.length() == 0) { |
| setDisplayName(Messages.format(CorrectionMessages.NewCUCompletionUsingWizardProposal_createinnerannotation_description, typeLabel)); |
| } else { |
| setDisplayName(Messages.format(CorrectionMessages.NewCUCompletionUsingWizardProposal_createinnerannotation_intype_description, new String[] { typeLabel, containerLabel })); |
| } |
| } else { |
| if (containerName.length() == 0) { |
| setDisplayName(Messages.format(CorrectionMessages.NewCUCompletionUsingWizardProposal_createannotation_description, typeLabel)); |
| } else { |
| setDisplayName(Messages.format(CorrectionMessages.NewCUCompletionUsingWizardProposal_createannotation_inpackage_description, new String[] { typeLabel, containerLabel })); |
| } |
| } |
| break; |
| default: |
| throw new IllegalArgumentException("Unknown type kind"); //$NON-NLS-1$ |
| } |
| fShowDialog= true; |
| } |
| |
| private static String getTypeName(int typeKind, Name node) { |
| String name= ASTNodes.getSimpleNameIdentifier(node); |
| |
| if (typeKind == K_CLASS || typeKind == K_INTERFACE) { |
| ASTNode parent= node.getParent(); |
| if (parent.getLocationInParent() == ParameterizedType.TYPE_PROPERTY) { |
| String typeArgBaseName= name.startsWith(String.valueOf('T')) ? String.valueOf('S') : String.valueOf('T'); // use 'S' or 'T' |
| |
| int nTypeArgs= ((ParameterizedType) parent.getParent()).typeArguments().size(); |
| StringBuffer buf= new StringBuffer(name); |
| buf.append('<'); |
| if (nTypeArgs == 1) { |
| buf.append(typeArgBaseName); |
| } else { |
| for (int i= 0; i < nTypeArgs; i++) { |
| if (i != 0) |
| buf.append(", "); //$NON-NLS-1$ |
| buf.append(typeArgBaseName).append(i + 1); |
| } |
| } |
| buf.append('>'); |
| return buf.toString(); |
| } |
| } |
| return name; |
| } |
| |
| |
| @Override |
| public void apply(IDocument document) { |
| StructuredSelection selection= new StructuredSelection(fCompilationUnit); |
| NewElementWizard wizard= createWizard(selection); |
| wizard.init(JavaPlugin.getDefault().getWorkbench(), selection); |
| |
| IType createdType= null; |
| |
| if (fShowDialog) { |
| Shell shell= JavaPlugin.getActiveWorkbenchShell(); |
| WizardDialog dialog= new WizardDialog(shell, wizard); |
| |
| PixelConverter converter= new PixelConverter(JFaceResources.getDialogFont()); |
| dialog.setMinimumPageSize(converter.convertWidthInCharsToPixels(70), converter.convertHeightInCharsToPixels(20)); |
| dialog.create(); |
| dialog.getShell().setText(CorrectionMessages.NewCUCompletionUsingWizardProposal_dialogtitle); |
| |
| if (dialog.open() == Window.OK) { |
| createdType= (IType) wizard.getCreatedElement(); |
| } |
| } else { |
| wizard.addPages(); |
| try { |
| NewTypeWizardPage page= getPage(wizard); |
| page.createType(null); |
| createdType= page.getCreatedType(); |
| } catch (CoreException e) { |
| JavaPlugin.log(e); |
| } catch (InterruptedException e) { |
| } |
| } |
| |
| if (createdType != null) { |
| IJavaElement container= createdType.getParent(); |
| if (container instanceof ICompilationUnit) { |
| container= container.getParent(); |
| } |
| if (!container.equals(fTypeContainer)) { |
| // add import |
| try { |
| ImportRewrite rewrite= StubUtility.createImportRewrite(fCompilationUnit, true); |
| rewrite.addImport(createdType.getFullyQualifiedName('.')); |
| JavaModelUtil.applyEdit(fCompilationUnit, rewrite.rewriteImports(null), false, null); |
| } catch (CoreException e) { |
| } |
| } |
| fCreatedType= createdType; |
| } |
| |
| } |
| |
| private NewTypeWizardPage getPage(NewElementWizard wizard) { |
| IWizardPage[] pages= wizard.getPages(); |
| Assert.isTrue(pages.length > 0 && pages[0] instanceof NewTypeWizardPage); |
| return (NewTypeWizardPage) pages[0]; |
| } |
| |
| private NewElementWizard createWizard(StructuredSelection selection) { |
| switch (fTypeKind) { |
| case K_CLASS: { |
| NewClassWizardPage page= new NewClassWizardPage(); |
| page.init(selection); |
| configureWizardPage(page); |
| return new NewClassCreationWizard(page, true); |
| } |
| case K_INTERFACE: { |
| NewInterfaceWizardPage page= new NewInterfaceWizardPage(); |
| page.init(selection); |
| configureWizardPage(page); |
| return new NewInterfaceCreationWizard(page, true); |
| } |
| case K_ENUM: { |
| NewEnumWizardPage page= new NewEnumWizardPage(); |
| page.init(selection); |
| configureWizardPage(page); |
| return new NewEnumCreationWizard(page, true); |
| } |
| case K_ANNOTATION: { |
| NewAnnotationWizardPage page= new NewAnnotationWizardPage(); |
| page.init(selection); |
| configureWizardPage(page); |
| return new NewAnnotationCreationWizard(page, true); |
| } |
| } |
| throw new IllegalArgumentException(); |
| } |
| |
| private void configureWizardPage(NewTypeWizardPage page) { |
| fillInWizardPageName(page); |
| fillInWizardPageSuperTypes(page); |
| } |
| |
| /** |
| * Fill-in the "Package" and "Name" fields. |
| * @param page the wizard page. |
| */ |
| private void fillInWizardPageName(NewTypeWizardPage page) { |
| // allow to edit when there are type parameters |
| page.setTypeName(fTypeNameWithParameters, fTypeNameWithParameters.indexOf('<') != -1); |
| |
| boolean isInEnclosingType= fTypeContainer instanceof IType; |
| if (isInEnclosingType) { |
| page.setEnclosingType((IType) fTypeContainer, true); |
| } else { |
| page.setPackageFragment((IPackageFragment) fTypeContainer, true); |
| } |
| page.setEnclosingTypeSelection(isInEnclosingType, true); |
| } |
| |
| /** |
| * Fill-in the "Super Class" and "Super Interfaces" fields. |
| * @param page the wizard page. |
| */ |
| private void fillInWizardPageSuperTypes(NewTypeWizardPage page) { |
| ITypeBinding type= getPossibleSuperTypeBinding(fNode); |
| type= Bindings.normalizeTypeBinding(type); |
| if (type != null) { |
| if (type.isArray()) { |
| type= type.getElementType(); |
| } |
| if (type.isTopLevel() || type.isMember()) { |
| if (type.isClass() && (fTypeKind == K_CLASS)) { |
| page.setSuperClass(type.getQualifiedName(), true); |
| } else if (type.isInterface()) { |
| List<String> superInterfaces= new ArrayList<String>(); |
| superInterfaces.add(type.getQualifiedName()); |
| page.setSuperInterfaces(superInterfaces, true); |
| } |
| } |
| } |
| } |
| |
| private ITypeBinding getPossibleSuperTypeBinding(ASTNode node) { |
| if (fTypeKind == K_ANNOTATION) { |
| return null; |
| } |
| |
| AST ast= node.getAST(); |
| node= ASTNodes.getNormalizedNode(node); |
| ASTNode parent= node.getParent(); |
| switch (parent.getNodeType()) { |
| case ASTNode.METHOD_DECLARATION: |
| if (node.getLocationInParent() == MethodDeclaration.THROWN_EXCEPTIONS_PROPERTY) { |
| return ast.resolveWellKnownType("java.lang.Exception"); //$NON-NLS-1$ |
| } |
| break; |
| case ASTNode.THROW_STATEMENT : |
| return ast.resolveWellKnownType("java.lang.Exception"); //$NON-NLS-1$ |
| case ASTNode.SINGLE_VARIABLE_DECLARATION: |
| if (parent.getLocationInParent() == CatchClause.EXCEPTION_PROPERTY) { |
| return ast.resolveWellKnownType("java.lang.Exception"); //$NON-NLS-1$ |
| } |
| break; |
| case ASTNode.VARIABLE_DECLARATION_STATEMENT: |
| case ASTNode.FIELD_DECLARATION: |
| return null; // no guessing for LHS types, cannot be a supertype of a known type |
| case ASTNode.PARAMETERIZED_TYPE: |
| return null; // Inheritance doesn't help: A<X> z= new A<String>(); -> |
| } |
| ITypeBinding binding= ASTResolving.guessBindingForTypeReference(node); |
| if (binding != null && !binding.isRecovered()) { |
| return binding; |
| } |
| return null; |
| } |
| |
| /* |
| * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension5#getAdditionalProposalInfo(org.eclipse.core.runtime.IProgressMonitor) |
| * @since 3.5 |
| */ |
| @Override |
| public Object getAdditionalProposalInfo(IProgressMonitor monitor) { |
| StringBuffer buf= new StringBuffer(); |
| switch (fTypeKind) { |
| case K_CLASS: |
| buf.append(CorrectionMessages.NewCUCompletionUsingWizardProposal_createclass_info); |
| break; |
| case K_INTERFACE: |
| buf.append(CorrectionMessages.NewCUCompletionUsingWizardProposal_createinterface_info); |
| break; |
| case K_ENUM: |
| buf.append(CorrectionMessages.NewCUCompletionUsingWizardProposal_createenum_info); |
| break; |
| case K_ANNOTATION: |
| buf.append(CorrectionMessages.NewCUCompletionUsingWizardProposal_createannotation_info); |
| break; |
| } |
| buf.append("<br>"); //$NON-NLS-1$ |
| buf.append("<br>"); //$NON-NLS-1$ |
| if (fTypeContainer instanceof IType) { |
| buf.append(CorrectionMessages.NewCUCompletionUsingWizardProposal_tooltip_enclosingtype); |
| } else { |
| buf.append(CorrectionMessages.NewCUCompletionUsingWizardProposal_tooltip_package); |
| } |
| buf.append(" <b>"); //$NON-NLS-1$ |
| buf.append(JavaElementLabels.getElementLabel(fTypeContainer, JavaElementLabels.T_FULLY_QUALIFIED)); |
| buf.append("</b><br>"); //$NON-NLS-1$ |
| buf.append("public "); //$NON-NLS-1$ |
| |
| |
| switch (fTypeKind) { |
| case K_CLASS: |
| buf.append("class <b>"); //$NON-NLS-1$ |
| break; |
| case K_INTERFACE: |
| buf.append("interface <b>"); //$NON-NLS-1$ |
| break; |
| case K_ENUM: |
| buf.append("enum <b>"); //$NON-NLS-1$ |
| break; |
| case K_ANNOTATION: |
| buf.append("@interface <b>"); //$NON-NLS-1$ |
| break; |
| } |
| nameToHTML(fTypeNameWithParameters, buf); |
| |
| ITypeBinding superclass= getPossibleSuperTypeBinding(fNode); |
| if (superclass != null) { |
| if (superclass.isClass()) { |
| if (fTypeKind == K_CLASS) { |
| buf.append("</b> extends <b>"); //$NON-NLS-1$ |
| nameToHTML(BindingLabelProvider.getBindingLabel(superclass, BindingLabelProvider.DEFAULT_TEXTFLAGS), buf); |
| } |
| } else { |
| if (fTypeKind == K_INTERFACE) { |
| buf.append("</b> extends <b>"); //$NON-NLS-1$ |
| } else { |
| buf.append("</b> implements <b>"); //$NON-NLS-1$ |
| } |
| nameToHTML(BindingLabelProvider.getBindingLabel(superclass, BindingLabelProvider.DEFAULT_TEXTFLAGS), buf); |
| } |
| } |
| buf.append("</b> {<br>}<br>"); //$NON-NLS-1$ |
| return buf.toString(); |
| } |
| |
| private void nameToHTML(String name, StringBuffer buf) { |
| for (int i= 0; i < name.length(); i++) { |
| char ch= name.charAt(i); |
| if (ch == '>') { |
| buf.append(">"); //$NON-NLS-1$ |
| } else if (ch == '<') { |
| buf.append("<"); //$NON-NLS-1$ |
| } else { |
| buf.append(ch); |
| } |
| } |
| } |
| |
| /** |
| * Returns the showDialog. |
| * @return boolean |
| */ |
| public boolean isShowDialog() { |
| return fShowDialog; |
| } |
| |
| /** |
| * Sets the showDialog. |
| * @param showDialog The showDialog to set |
| */ |
| public void setShowDialog(boolean showDialog) { |
| fShowDialog= showDialog; |
| } |
| |
| public IType getCreatedType() { |
| return fCreatedType; |
| } |
| |
| |
| public int getTypeKind() { |
| return fTypeKind; |
| } |
| |
| } |