package com.baselet.plugin.hyperlink; import java.util.ArrayList; import java.util.List; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IParent; import org.eclipse.jdt.core.ISourceRange; import org.eclipse.jdt.core.ITypeRoot; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.ui.JavaUI; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector; import org.eclipse.jface.text.hyperlink.IHyperlink; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.texteditor.ITextEditor; import com.baselet.plugin.UmletPluginUtils; 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; import com.baselet.plugin.refactoring.JavaDocParser.JavaDocNodeBase; /** * Detector for hyperlinks for image references in javadoc comments. Clicking * the link opens the umlet editor. */ public class ImageRefHyperlinkDetector extends AbstractHyperlinkDetector { @Override public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) { List<IHyperlink> result = new ArrayList<IHyperlink>(); ITextEditor textEditor = (ITextEditor) getAdapter(ITextEditor.class); if (region == null || textEditor == null) { return null; } IEditorSite site = textEditor.getEditorSite(); if (site == null) { return null; } ICompilationUnit compilationUnit; { ITypeRoot typeRoot = JavaUI.getEditorInputTypeRoot(textEditor.getEditorInput()); if (!(typeRoot instanceof ICompilationUnit)) { return null; } compilationUnit = (ICompilationUnit) typeRoot; } try { if (!UmletPluginUtils.hasUmletNature(compilationUnit.getJavaProject())) { return null; } // get all javadocs List<ISourceRange> ranges = new ArrayList<ISourceRange>(); collectIntersectingJavadocRanges(compilationUnit, region, ranges); String source = textViewer.getDocument().get(); for (ISourceRange range : ranges) { JavaDocCommentNode comment = new JavaDocParser(source, range.getOffset(), range.getOffset() + range.getLength()).comment(); for (JavaDocNodeBase child : comment.children) { if (!(child instanceof HtmlTagStartNode)) { continue; } final HtmlTagStartNode tag = (HtmlTagStartNode) child; if (!"img".equals(tag.tagName.getValue())) { continue; } final Region hyperlinkRegion = new Region(tag.start, tag.length()); if (!doIntersect(hyperlinkRegion, region)) { continue; } final HtmlTagAttr srcAttr = tag.getAttr("src"); if (srcAttr == null) { continue; } String src = srcAttr.value.getValue(); final IFile diagram = UmletPluginUtils.findUmletDiagram(compilationUnit, src); if (diagram != null) { final String linkText = "Go to " + src; result.add(new IHyperlink() { @Override public void open() { IWorkbenchWindow wnd = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); if (wnd == null) { return; } IWorkbenchPage page = wnd.getActivePage(); if (page == null) { return; } try { IDE.openEditor(page, diagram); } catch (PartInitException e) { throw new RuntimeException(e); } } @Override public String getTypeLabel() { return linkText; } @Override public String getHyperlinkText() { return linkText; } @Override public IRegion getHyperlinkRegion() { return hyperlinkRegion; } }); } } } } catch (CoreException e) { throw new RuntimeException(e); } if (result.isEmpty()) { return null; } return result.toArray(new IHyperlink[] {}); } private boolean doIntersect(Region a, IRegion b) { return a.getOffset() <= b.getOffset() + b.getLength() && b.getOffset() <= a.getOffset() + a.getLength(); } private void collectIntersectingJavadocRanges(IJavaElement element, IRegion region, List<ISourceRange> elements) throws JavaModelException { if (element instanceof IParent) { for (IJavaElement child : ((IParent) element).getChildren()) { collectIntersectingJavadocRanges(child, region, elements); } } if (element instanceof IMember) { ISourceRange range = ((IMember) element).getJavadocRange(); if (range != null) { if (range.getOffset() <= region.getOffset() + region.getLength() && range.getOffset() + range.getLength() >= region.getOffset()) { elements.add(range); } } } } }