package com.baselet.plugin;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IParent;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import com.baselet.plugin.builder.UmletNature;
import com.baselet.plugin.refactoring.ImageReference;
import com.baselet.plugin.refactoring.JavaDocParser;
import com.baselet.plugin.refactoring.JavaDocParser.HtmlTagAttr;
import com.baselet.plugin.refactoring.JavaDocParser.HtmlTagStartNode;
import com.baselet.plugin.refactoring.JavaDocParser.JavaDocCommentNode;
public class UmletPluginUtils {
public static IPath getPackageFragmentRootRelativePath(IJavaProject project, IResource resource) throws JavaModelException {
return getPackageFragmentRootRelativePath(project, resource.getProjectRelativePath());
}
public static IPath getPackageFragmentRootRelativePath(IJavaProject project, IPath projectRelativePath) throws JavaModelException {
for (IPackageFragmentRoot root : project.getAllPackageFragmentRoots()) {
IResource rootResource = root.getResource();
if (rootResource != null) {
if (rootResource.getProjectRelativePath().isPrefixOf(projectRelativePath)) {
return projectRelativePath.makeRelativeTo(rootResource.getProjectRelativePath());
}
}
}
return projectRelativePath;
}
/**
* Return the path of the parent of the given compilation unit, relative to the PackageFragmentRoot
*/
public static IPath getCompilationUnitParentPath(ICompilationUnit compilationUnit) throws JavaModelException {
final IContainer parent = getCompilationUnitParent(compilationUnit);
if (parent == null) {
return null;
}
return getPackageFragmentRootRelativePath(compilationUnit.getJavaProject(), parent);
}
/**
* Return the parent resource of the given compilation unit
*/
public static IContainer getCompilationUnitParent(ICompilationUnit compilationUnit) {
IResource javaResource = compilationUnit.getResource();
if (javaResource == null) {
return null;
}
final IContainer parent = javaResource.getParent();
if (parent == null) {
return null;
}
return parent;
}
/**
* Tests if a reference in a javadoc comment is absolute
*/
public static boolean isAbsoluteImageRef(String src) {
return src.startsWith("{@docRoot}");
}
/**
* Returns the package fragment root relative path for the given image reference src attribute value
*/
public static IPath getRootRelativePath(ICompilationUnit unit, String src) throws JavaModelException {
if (isAbsoluteImageRef(src)) {
return new Path(src.substring("{@docRoot}".length()));
}
else {
return getCompilationUnitParentPath(unit).append(src);
}
}
/**
* Return the image file referenced by a src attribute value in a compilation unit. The returned file
* might not exist.
* @throws JavaModelException
*/
public static IFile getReferencedImgFile(ICompilationUnit cu, String src) throws JavaModelException {
return getFile(getPackageFragmentRoot(cu), getRootRelativePath(cu, src));
}
public static IFile getFile(IPackageFragmentRoot root, IPath rootRelativePath) throws JavaModelException {
IResource res = root.getCorrespondingResource();
if (!(res instanceof IFolder)) {
return null;
}
return ((IFolder) res).getFile(rootRelativePath);
}
/**
* Return the umlet diagram referenced by the given src attribute value in the given compilation unit.
*
* @return the corresponding umlet diagram corresponding or null, if no diagram could be found
*/
public static IFile findUmletDiagram(ICompilationUnit unit, String src) throws JavaModelException {
IPath imgRef = getRootRelativePath(unit, src);
IFile pngFile = getFile(getPackageFragmentRoot(unit), imgRef);
IFile uxfFile = getUxfDiagramForImgFile(pngFile);
if (uxfFile.exists()) {
return uxfFile;
}
return null;
}
/**
* Calculate the image reference for the given java resource path and the image path.
* Both paths need to be relative to the package fragment root.
*/
public static String calculateImageRef(final IPath javaResourceParentPath, IPath imagePath) {
IPath relativePath = imagePath.makeRelativeTo(javaResourceParentPath);
int parentCount = 0;
while (parentCount < relativePath.segmentCount() && "..".equals(relativePath.segment(parentCount))) {
parentCount++;
}
String path;
if (parentCount > 1) {
path = "{@docRoot}/" + imagePath;
}
else {
path = relativePath.toString();
}
return path;
}
public static List<ISourceRange> collectJavadocRanges(ICompilationUnit unit) throws JavaModelException {
List<ISourceRange> result = new ArrayList<ISourceRange>();
collectJavadocRanges(unit, result);
return result;
}
private static void collectJavadocRanges(IJavaElement element, List<ISourceRange> javadocRanges) throws JavaModelException {
if (element instanceof IParent) {
for (IJavaElement child : ((IParent) element).getChildren()) {
collectJavadocRanges(child, javadocRanges);
}
}
if (element instanceof IMember) {
ISourceRange range = ((IMember) element).getJavadocRange();
if (range != null) {
javadocRanges.add(range);
}
}
}
public static List<ICompilationUnit> collectCompilationUnits(IJavaProject project) throws JavaModelException {
List<ICompilationUnit> compilationUnits = new ArrayList<ICompilationUnit>();
for (IPackageFragmentRoot root : getSourcePackageFragmentRoots(project)) {
collectCompilationUnits(root, compilationUnits);
}
return compilationUnits;
}
public static List<IPackageFragmentRoot> getSourcePackageFragmentRoots(IJavaProject project) throws JavaModelException {
List<IPackageFragmentRoot> roots = new ArrayList<IPackageFragmentRoot>();
for (IClasspathEntry entry : project.getResolvedClasspath(true)) {
if (entry.getEntryKind() != IClasspathEntry.CPE_SOURCE) {
continue;
}
roots.addAll(Arrays.asList(project.findPackageFragmentRoots(entry)));
}
return roots;
}
private static void collectCompilationUnits(IJavaElement element, List<ICompilationUnit> compilationUnits) throws JavaModelException {
if (element instanceof ICompilationUnit) {
compilationUnits.add((ICompilationUnit) element);
// don't process children of compilation units
return;
}
if (element instanceof IParent) {
for (IJavaElement child : ((IParent) element).getChildren()) {
collectCompilationUnits(child, compilationUnits);
}
}
}
public static IJavaProject getJavaProject(IProject project) {
try {
if (!project.hasNature(JavaCore.NATURE_ID)) {
return null;
}
} catch (CoreException e) {
return null;
}
return JavaCore.create(project);
}
public static IPackageFragmentRoot getPackageFragmentRoot(IJavaElement element) {
if (element == null) {
return null;
}
if (element instanceof IPackageFragmentRoot) {
return (IPackageFragmentRoot) element;
}
return getPackageFragmentRoot(element.getParent());
}
public static IFile getUxfDiagramForImgFile(IFile img) {
return img.getProject().getFile(img.getProjectRelativePath().removeFileExtension().addFileExtension("uxf"));
}
public static IFile getImageForUxfPath(IFile uxf) {
return uxf.getProject().getFile(uxf.getProjectRelativePath().removeFileExtension().addFileExtension("png"));
}
/**
* Search for image references with a corresponding .uxf diagram
*/
public static List<ImageReference> collectUxfImgRefs(ICompilationUnit cu) throws JavaModelException {
ArrayList<ImageReference> refs = collectAllImageRefs(cu);
// search for corresponding .uxf diagrams
ArrayList<ImageReference> result = new ArrayList<ImageReference>();
for (ImageReference ref : refs) {
IPath rootRelativePath = getRootRelativePath(cu, ref.srcAttr.value.getValue());
IFile imgFile = getFile(getPackageFragmentRoot(cu), rootRelativePath);
IFile uxf = getUxfDiagramForImgFile(imgFile);
if (uxf.exists()) {
result.add(ref);
}
}
return result;
}
/**
* Collect all image references, even those without .uxf diagrams
*/
public static ArrayList<ImageReference> collectAllImageRefs(ICompilationUnit cu) throws JavaModelException {
ArrayList<ImageReference> refs = new ArrayList<ImageReference>();
// collect javadocs
List<ISourceRange> javadocRanges = UmletPluginUtils.collectJavadocRanges(cu);
String source = cu.getBuffer().getContents();
// parse javadocs and collect image references
for (ISourceRange javadocRange : javadocRanges) {
collectImgRefsImpl(refs, source, javadocRange);
}
return refs;
}
private static void collectImgRefsImpl(ArrayList<ImageReference> result, String source, ISourceRange javadocRange) {
JavaDocCommentNode comment = new JavaDocParser(source, javadocRange.getOffset(), javadocRange.getOffset() + javadocRange.getLength()).comment();
for (HtmlTagStartNode tag : comment.ofType(HtmlTagStartNode.class)) {
if (!"img".equals(tag.tagName.getValue())) {
continue;
}
HtmlTagAttr srcAttr = tag.getAttr("src");
if (srcAttr == null) {
continue;
}
result.add(new ImageReference(tag, srcAttr));
}
}
public static boolean hasUmletNature(IJavaProject project) throws CoreException {
IProjectDescription description = project.getProject().getDescription();
for (String nature : description.getNatureIds()) {
if (UmletNature.NATURE_ID.equals(nature)) {
return true;
}
}
return false;
}
}