package it.tref.eclipse.wicket.plugin.hyperlink;
import it.tref.eclipse.wicket.plugin.editors.WicketFunEditor;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jdt.core.ICodeAssist;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeHierarchy;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.NamedMember;
import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
import org.eclipse.jdt.internal.ui.text.JavaWordFinder;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
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.IEditorPart;
import org.eclipse.ui.PlatformUI;
/**
* Class that detect wicket id hyperlink on java files.
* <br>
* This class is a modification of the qwickie plugin class.
*
* @author Andrea Fantappi�
*
*/
@SuppressWarnings("restriction")
public class WicketFunJavaHyperlinkDetector extends AbstractHyperlinkDetector
{
@Override
public IHyperlink[] detectHyperlinks(final ITextViewer textViewer, final IRegion region, final boolean canShowMultipleHyperlinks)
{
IEditorPart editor;
try {
editor = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getActivePage()
.getActiveEditor();
} catch (Exception e) {
return null;
}
if ((region == null) || (textViewer == null) || !(editor instanceof WicketFunEditor)) {
return null;
}
final int offset = region.getOffset();
final IDocument document = textViewer.getDocument();
if (document == null) {
return null;
}
final JavaEditor javaEditor = (JavaEditor) getAdapter(JavaEditor.class);
Assert.isNotNull(javaEditor);
String wicketId = null;
String wcName = null;
/* java file region, html file region, properties file region */
final IRegion[] wicketRegions = findWicketRegions(javaEditor, textViewer, offset);
if (wicketRegions == null) {
return null;
}
final IRegion widRegion = wicketRegions[0];
final IRegion wcRegion = wicketRegions[1];
final IRegion wcPropertiesRegion = wicketRegions[2];
if (widRegion == null || wcRegion == null) {
return null;
}
try {
wicketId = document.get(widRegion.getOffset(), widRegion.getLength());
wcName = document.get(wcRegion.getOffset(), wcRegion.getLength());
if (wicketId == null || wcName == null) {
return null;
}
} catch (final Exception e) {
return null;
}
final IHyperlink wicketHyperlink = new WicketHyperlink(widRegion, wicketId, wcPropertiesRegion == null ? "html" : "properties");
return new IHyperlink[] { wicketHyperlink };
}
public static IRegion[] findWicketRegions(final IEditorPart editor, final ITextViewer textViewer, final int offset)
{
Assert.isNotNull(textViewer);
final IDocument document = textViewer.getDocument();
final IRegion[] regions = new IRegion[3];
try {
final IRegion wicketIdRegion = findStringArgumentRegion(document, offset);
if (wicketIdRegion == null) {
return null;
}
final IRegion wicketComponentRegion = findWicketComponentRegion(document, wicketIdRegion.getOffset());
if (wicketComponentRegion == null) {
return null;
}
final IRegion javaRegion = JavaWordFinder.findWord(document, wicketComponentRegion.getOffset());
final IJavaElement input = EditorUtility.getEditorInputJavaElement(editor, false);
final IJavaElement[] javaElements = ((ICodeAssist) input).codeSelect(javaRegion.getOffset(), javaRegion.getLength());
if (javaElements == null || javaElements.length == 0) {
return null;
}
for (final IJavaElement javaElement : javaElements)
{
// search for a string in a properties file
if ("getString".equals(javaElement.getElementName()) && "Component".equals(javaElement.getParent().getElementName())) {
regions[2] = findStringArgumentRegion(document, offset);
regions[1] = regions[2];
} else {
regions[1] = getRegionOfWicketComponent(textViewer, offset, wicketIdRegion, javaElement);
}
}
regions[0] = wicketIdRegion;
return regions;
} catch (final JavaModelException e) {
return null;
}
}
private static IRegion getRegionOfWicketComponent(final ITextViewer textViewer, final int offset, final IRegion wordRegion, final IJavaElement javaElement) throws JavaModelException
{
if (javaElement != null && javaElement instanceof NamedMember)
{
final NamedMember method = (NamedMember) javaElement;
final IType type = method.getDeclaringType();
if (type != null)
{
final ITypeHierarchy hierarchy = type.newSupertypeHierarchy(null);
if (hierarchy != null)
{
final IType[] supertypes = hierarchy.getAllSupertypes(type);
for (final IType iType : supertypes)
{
if (iType.getFullyQualifiedName().equals("org.apache.wicket.Component"))
{
try {
final IDocument document = textViewer.getDocument();
final IRegion lineInfo = document.getLineInformationOfOffset(offset);
final String line = document.get(lineInfo.getOffset(), lineInfo.getLength());
final int lineRelativeOffset = offset - lineInfo.getOffset();
final int index = line.indexOf(javaElement.getElementName());
return new Region(offset - lineRelativeOffset + index, javaElement.getElementName().length());
} catch (final Exception ex) {
return null;
}
}
}
}
}
}
return null;
}
/** finds an argument between "" */
private static IRegion findStringArgumentRegion(final IDocument document, final int offset)
{
try {
final IRegion lineInfo = document.getLineInformationOfOffset(offset);
final String line = document.get(lineInfo.getOffset(), lineInfo.getLength());
final int lineRelativeOffset = offset - lineInfo.getOffset();
int start = line.lastIndexOf("(", lineRelativeOffset) + 1;
start = line.indexOf('"', start) + 1;
if (start == 0)
return null;
final int end = line.indexOf('"', start);
return new Region(offset - (lineRelativeOffset - start), end - start);
} catch (final BadLocationException e) {
return null;
}
}
/** finds the JavaElement that is a subtype of org.apache.wicket.Component */
private static IRegion findWicketComponentRegion(final IDocument document, final int offset)
{
try {
final IRegion lineInfo = document.getLineInformationOfOffset(offset);
final String line = document.get(lineInfo.getOffset(), lineInfo.getLength());
final int lineRelativeOffset = offset - lineInfo.getOffset();
// first check for generics
int start = line.lastIndexOf('<', lineRelativeOffset);
if (start == -1) {
start = line.lastIndexOf('(', lineRelativeOffset);
}
if (start == -1) {
return null;
}
return new Region(offset - lineRelativeOffset + start, 1);
} catch (final BadLocationException e) {
return null;
}
}
}