Here's how:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.text.StyledDocument;
import org.netbeans.api.editor.EditorRegistry;
import org.netbeans.lib.editor.hyperlink.spi.HyperlinkProvider;
import org.openide.util.Exceptions;
public class RoutesHyperlinkProvider implements HyperlinkProvider {
private static String ROUTES_IDENTIFIER = "Application.index";
private int startOffset;
private int endOffset;
@Override
public boolean isHyperlinkPoint(Document doc, int offset) {
Pattern p = Pattern.compile(ROUTES_IDENTIFIER);
try {
Matcher m = p.matcher(doc.getText(0, doc.getLength()));
while (m.find() == true){
startOffset = m.start();
endOffset = m.end();
return true;
}
} catch (BadLocationException ex) {
Exceptions.printStackTrace(ex);
}
return false;
}
@Override
public int[] getHyperlinkSpan(Document dcmnt, int i) {
JTextComponent target = EditorRegistry.lastFocusedComponent();
final StyledDocument styledDoc = (StyledDocument) target.getDocument();
if (styledDoc == null) {
return null;
}
// Return the position which was set in the isHyperlink method:
return new int[]{startOffset, endOffset};
}
@Override
public void performClickAction(Document dcmnt, int i) {
//do something when the user clicks the hyperlink
}
}
It seems you code only supports a single ROUTES_IDENTIFIER in the document -- what happens if there are more ?
If it's only one, then the 'while' in 'isHyperlinkPoint' might as well be replaced with an 'if'.
Also, not sure why you are using 'EditorRegistry.lastFocusedComponent()' in 'getHyperlinkSpan' when it seems you are given a 'Document dcmnt' argument.
You are also given an 'offset' which you never use and should probably make matching faster if you just get a substring from the document and not the whole text. Another trick might be to cache the compiled pattern.
Well, that was my code review so far :-)
That's exactly the problem I have, i.e., I only support a single ROUTES_IDENITIFIER. Can someone give me a tip what I should do to support more?
This could be a prototype for a more general implementation:
public abstract class AbstractHyperlinkProvider implements HyperlinkProvider {
private transient int startOffset, endOffset;
private transient final String identifier;
@Override
public abstract void performClickAction(Document document, int i);
public AbstractHyperlinkProvider(String identifier) {
this.identifier = identifier;
}
@Override
public boolean isHyperlinkPoint(Document document, int offset) {
boolean result = false;
Matcher matcher = null;
try {
matcher = Pattern.compile(identifier).matcher(document.getText(0, document.getLength()));
} catch (BadLocationException ex) {
Exceptions.printStackTrace(ex);
}
while (matcher.find()) {
startOffset = matcher.start();
endOffset = matcher.end();
result = true;
break;
}
return result;
}
@Override
public int[] getHyperlinkSpan(Document document, int i) {
int[] result = null;
if ((StyledDocument) EditorRegistry.lastFocusedComponent().getDocument() != null) {
// Return the position which was set in the isHyperlink method:
result = new int[]{startOffset, endOffset};
}
return result;
}