/*******************************************************************************
* Copyright (c) 2012 VMware, Inc.
* 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:
* VMware, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.quickfix.processors;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.ClassFile;
import org.eclipse.jdt.internal.core.CompilationUnit;
import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
import org.eclipse.jdt.internal.core.PackageFragment;
import org.eclipse.jdt.internal.ui.text.correction.NameMatcher;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
import org.springframework.ide.eclipse.quickfix.Activator;
import org.springframework.ide.eclipse.quickfix.proposals.CreateNewClassQuickFixProposal;
import org.springframework.ide.eclipse.quickfix.proposals.RenameToSimilarNameQuickFixProposal;
import org.springsource.ide.eclipse.commons.core.StatusHandler;
/**
* Quick assist processor for bean class attribute in beans XML editor.
* @author Terry Denney
* @author Leo Dos Santos
* @author Christian Dupuis
* @since 2.0
*/
public class ClassAttributeQuickAssistProcessor extends BeanQuickAssistProcessor {
private class SimilarCUFindingVisitor implements IResourceVisitor {
private final Set<String> suggestedClassNames = new HashSet<String>();
private final String toMatch;
private SimilarCUFindingVisitor(String toMatch) {
this.toMatch = toMatch;
}
public List<String> getSuggestedClassNames() {
List<String> result = new ArrayList<String>(suggestedClassNames);
Collections.sort(result, new NameSuggestionComparator(toMatch));
return result;
}
public boolean visit(IResource resource) throws CoreException {
if (resource instanceof IFile) {
IFile file = (IFile) resource;
String fileExtension = file.getFullPath().getFileExtension();
if (fileExtension == null) {
return false;
}
if (fileExtension.equals("java")) {
ICompilationUnit cu = JavaCore.createCompilationUnitFrom(file);
if (cu instanceof CompilationUnit) {
CompilationUnit c = (CompilationUnit) cu;
IType[] types = c.getAllTypes();
for (IType type : types) {
if (NameMatcher.isSimilarName(type.getElementName(), toMatch)) {
suggestedClassNames.add(type.getFullyQualifiedName());
}
}
}
return false;
}
else if (fileExtension.equals("class")) {
IClassFile classFile = JavaCore.createClassFileFrom(file);
IType type = classFile.getType();
if (type != null) {
if (NameMatcher.isSimilarName(type.getElementName(), toMatch)) {
suggestedClassNames.add(type.getFullyQualifiedName());
}
}
return false;
}
return true;
}
return true;
}
public void visitJar(JarPackageFragmentRoot jarRoot) throws CoreException {
IJavaElement[] children = jarRoot.getChildren();
for (IJavaElement child : children) {
if (child instanceof PackageFragment) {
visitPackageFragment((PackageFragment) child);
}
}
}
public void visitPackageFragment(PackageFragment fragment) throws JavaModelException {
IJavaElement[] grandChildren = fragment.getChildren();
for (IJavaElement grandChild : grandChildren) {
if (grandChild instanceof ClassFile) {
ClassFile classFile = (ClassFile) grandChild;
IType type = classFile.getType();
if (NameMatcher.isSimilarName(type.getElementName(), toMatch)) {
suggestedClassNames.add(type.getFullyQualifiedName());
}
}
}
}
}
private final Set<String> propertyNames;
private final int numConstructorArgs;
private final IJavaProject javaProject;
public ClassAttributeQuickAssistProcessor(int offset, int length, String text, IProject project,
boolean missingEndQuote, Set<String> propertyNames, int numConstructorArgs) {
super(offset, length, text, missingEndQuote);
this.propertyNames = propertyNames;
this.numConstructorArgs = numConstructorArgs;
this.javaProject = JavaCore.create(project).getJavaProject();
}
public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationContext invocationContext) {
List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
// find similar classes and add as proposals
String className;
int lastDotPos = text.lastIndexOf(".");
if (lastDotPos < 0) {
className = text;
}
else {
className = text.substring(lastDotPos + 1);
}
try {
SimilarCUFindingVisitor visitor = new SimilarCUFindingVisitor(className);
IPackageFragmentRoot[] fragmentRoots = javaProject.getAllPackageFragmentRoots();
for (IPackageFragmentRoot fragmentRoot : fragmentRoots) {
if (fragmentRoot instanceof JarPackageFragmentRoot) {
visitor.visitJar((JarPackageFragmentRoot) fragmentRoot);
}
IResource resource = fragmentRoot.getResource();
if (resource != null) {
resource.accept(visitor);
}
}
List<String> suggestedClassNames = visitor.getSuggestedClassNames();
for (String suggestedClassName : suggestedClassNames) {
proposals.add(new RenameToSimilarNameQuickFixProposal(suggestedClassName, offset, length,
missingEndQuote));
}
proposals.add(new CreateNewClassQuickFixProposal(offset, length, text, missingEndQuote, javaProject,
propertyNames, numConstructorArgs));
return proposals.toArray(new ICompletionProposal[proposals.size()]);
}
catch (CoreException e1) {
StatusHandler.log(new Status(Status.ERROR, Activator.PLUGIN_ID, "Cound not compute proposals."));
}
return new ICompletionProposal[0];
}
}