blob: 5bfc7d0607cca162c3b5501b0376df3b66d408a1 [file] [log] [blame]
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
= NetBeans Hyperlink Navigation Tutorial
:jbake-type: platform_tutorial
:jbake-tags: tutorials
:jbake-status: published
:syntax: true
:source-highlighter: pygments
:toc: left
:toc-title:
:icons: font
:experimental:
:description: NetBeans Hyperlink Navigation Tutorial - Apache NetBeans
:keywords: Apache NetBeans Platform, Platform Tutorials, NetBeans Hyperlink Navigation Tutorial
In this tutorial, you learn how to programmatically define hyperlinks in HTML files. You will do this by implementing the NetBeans API link:https://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib/org/netbeans/lib/editor/hyperlink/spi/HyperlinkProvider.html[HyperlinkProvider] class. The hyperlink will be visible when the user holds down the Ctrl key and then uses the mouse to move over a predefined identifier in an HTML document, as shown here:
image::images/hyperlink_hyperlink-69-1.png[]
When the hyperlink is clicked, something happens relevant to the identifier, for example, a related file can open or a message can be displayed.
Though the focus of this tutorial is on hyperlinking in an HTML file, the principles shown here could equally be applied to other types of files, such as to Java source files, XML files, JSP files, Properties files, or Manifest files.
NOTE: This document is applicable to NetBeans IDE 7.2 and NetBeans Platform 7.2. If you are using an earlier version, see link:71/nbm-hyperlink.html[the previous version of this document].
== Getting Started
In this section, we use a wizard to create a module project. We declare dependencies on modules that provide the NetBeans API classes needed by our hyperlink module.
[start=1]
1. Choose File > New Project. In the New Project wizard, choose NetBeans Modules under Categories and Module under Projects. Click Next.
[start=2]
1. Type ``MySpecialHyperlink`` in Project Name and set Project Location to an appropriate folder on your disk. Click Next.
[start=3]
1. Type ``org.netbeans.modules.myspecialhyperlink`` in Code Name Base. Click Finish.
[start=4]
1.
In the Projects window, expand the project, right-click the Libraries node, and click Add Module Dependency. Add dependencies on the following APIs:
* Dialogs API
* Editor Library
* Editor Library 2
* HTML Lexer
* Lexer
* MIME Lookup API
You should now see the following:
image::images/hyperlink_72_add-libs.png[]
== Implementing the HyperlinkProvider Class
The link:https://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib/org/netbeans/lib/editor/hyperlink/spi/HyperlinkProvider.html[HyperlinkProvider] class implements three methods, each of which is discussed in detail below, accompanied by a practical example in the context of our module.
An alternative approach, which lets you define a tooltip on your hyperlink, is provided by the link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib/org/netbeans/lib/editor/hyperlink/spi/HyperlinkProviderExt.html[HyperlinkProviderExt] class, which is discussed link:https://blogs.oracle.com/geertjan/entry/hyperlink_for_freemarker[here] and link:https://blogs.oracle.com/geertjan/entry/jump_to_declaration_for_freemarker[here].
Below, we first we set up the class and then we implement each of the three methods in turn.
=== Setting Up the HyperlinkProvider Class
Setting up our class means implementing link:https://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib/org/netbeans/lib/editor/hyperlink/spi/HyperlinkProvider.html[HyperlinkProvider] and initializing the values we will need in our implementation.
[start=1]
1. Create a Java class in ``org.netbeans.modules.myspecialhyperlink`` , and name it ``MySpecialHyperlinkProvider`` .
[start=2]
1. Change the class signature so that `` link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib/org/netbeans/lib/editor/hyperlink/spi/HyperlinkProvider.html[org.netbeans.lib.editor.hyperlink.spi.HyperlinkProvider]`` is implemented.
[start=3]
1. Note that the following import statements will be needed in this tutorial:
[source,java]
----
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.text.Document;
import org.netbeans.api.editor.mimelookup.MimeRegistration;
import org.netbeans.api.html.lexer.HTMLTokenId;
import org.netbeans.api.lexer.Token;
import org.netbeans.api.lexer.TokenHierarchy;
import org.netbeans.api.lexer.TokenSequence;
import org.netbeans.lib.editor.hyperlink.spi.HyperlinkProvider;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
----
[start=4]
1. Add the following initial values at the top of the class:
[source,java]
----
public static final Pattern MY_SPECIAL_PATTERN =
Pattern.compile(".*\\[myspecial:(.*?):myspecial\\].*");
private String target;
private int targetStart;
private int targetEnd;
----
=== isHyperlinkPoint(Document doc, int offset)
`` link:https://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib/org/netbeans/lib/editor/hyperlink/spi/HyperlinkProvider.html#isHyperlinkPoint(javax.swing.text.Document,%20int)[isHyperlinkPoint(Document doc, int offset)]`` determines whether there should be a hyperlink at the given offset within the given document.
[source,java]
----
@Override
public boolean isHyperlinkPoint(Document doc, int offset) {
return verifyState(doc, offset);
}
public boolean verifyState(Document doc, int offset) {
TokenHierarchy hi = TokenHierarchy.get(doc);
TokenSequence<HTMLTokenId> ts = hi.tokenSequence(HTMLTokenId.language());
if (ts != null) {
ts.move(offset);
ts.moveNext();
Token<HTMLTokenId> tok = ts.token();
int newOffset = ts.offset();
String matcherText = tok.text().toString();
Matcher m = MY_SPECIAL_PATTERN.matcher(matcherText);
if (m.matches()) {
target = m.group(1);
int idx = matcherText.indexOf(target);
targetStart = newOffset + idx;
targetEnd = targetStart + target.length();
return true;
}
}
return false;
}
----
=== getHyperlinkSpan(Document doc, int offset)
`` link:https://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib/org/netbeans/lib/editor/hyperlink/spi/HyperlinkProvider.html#getHyperlinkSpan(javax.swing.text.Document,%20int)[getHyperlinkSpan(Document doc, int offset)]`` determines the length of the hyperlink.
[source,java]
----
@Override
public int[] getHyperlinkSpan(Document document, int offset) {
if (verifyState(document, offset)) {
return new int[]{targetStart, targetEnd};
} else {
return null;
}
}
----
=== performClickAction(Document doc, int offset)
`` link:https://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib/org/netbeans/lib/editor/hyperlink/spi/HyperlinkProvider.html#performClickAction(javax.swing.text.Document,%20int)[performClickAction(Document doc, int offset)]`` determines what happens when the hyperlink is clicked. In general, a document should open, the cursor should move to a certain place in a document, or both. Here a simple message is displayed with the identified special content:
[source,java]
----
@Override
public void performClickAction(Document document, int offset) {
if (verifyState(document, offset)) {
NotifyDescriptor.Message msg = new NotifyDescriptor.Message(target);
DialogDisplayer.getDefault().notify(msg);
}
}
----
== Registering the HyperlinkProvider Implementation Class
Finally, you need to register the hyperlink provider implementation class. Do this via the class-level annotation shown in the highlighted line in the completed Java source below:
[source,java]
----
package org.netbeans.modules.myspecialhyperlink;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.text.Document;
import org.netbeans.api.editor.mimelookup.MimeRegistration;
import org.netbeans.api.html.lexer.HTMLTokenId;
import org.netbeans.api.lexer.Token;
import org.netbeans.api.lexer.TokenHierarchy;
import org.netbeans.api.lexer.TokenSequence;
import org.netbeans.lib.editor.hyperlink.spi.HyperlinkProvider;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
*@MimeRegistration(mimeType = "text/html", service = HyperlinkProvider.class)*
public class MySpecialHyperlinkProvider implements HyperlinkProvider {
public static final Pattern MY_SPECIAL_PATTERN =
Pattern.compile(".*\\[myspecial:(.*?):myspecial\\].*");
private String target;
private int targetStart;
private int targetEnd;
@Override
public boolean isHyperlinkPoint(Document doc, int offset) {
return verifyState(doc, offset);
}
public boolean verifyState(Document doc, int offset) {
TokenHierarchy hi = TokenHierarchy.get(doc);
TokenSequence<HTMLTokenId> ts = hi.tokenSequence(HTMLTokenId.language());
if (ts != null) {
ts.move(offset);
ts.moveNext();
Token<HTMLTokenId> tok = ts.token();
int newOffset = ts.offset();
String matcherText = tok.text().toString();
Matcher m = MY_SPECIAL_PATTERN.matcher(matcherText);
if (m.matches()) {
target = m.group(1);
int idx = matcherText.indexOf(target);
targetStart = newOffset + idx;
targetEnd = targetStart + target.length();
return true;
}
}
return false;
}
@Override
public int[] getHyperlinkSpan(Document document, int offset) {
if (verifyState(document, offset)) {
return new int[]{targetStart, targetEnd};
} else {
return null;
}
}
@Override
public void performClickAction(Document document, int offset) {
if (verifyState(document, offset)) {
NotifyDescriptor.Message msg = new NotifyDescriptor.Message(target);
DialogDisplayer.getDefault().notify(msg);
}
}
}
----
If you create a hyperlink for a different MIME type, you need to change the ``text/html`` folder in the annotation above to the appropriate MIME type. Read link:http://blogs.oracle.com/geertjan/entry/hyperlink_in_a_plain_text[Hyperlink in a Plain Text File] to learn about a different implementation of the above class.
Now that the HyperlinkProvider is registered, you can run the module and try out your new hyperlinks, with this result:
image::images/hyperlink_hyperlink-69-1.png[]
link:http://netbeans.apache.org/community/mailing-lists.html[Send Us Your Feedback]