NetBeans Mark Occurrences Module Tutorial
This tutorial needs a review. You can edit it in GitHub following these contribution guidelines. |
This tutorial demonstrates how to create a NetBeans module that highlights all instances of a selected word in an HTML file, as shown below:
For troubleshooting purposes, you are welcome to download the completed tutorial source code.
Introduction to Highlight Layers
In this tutorial, you implement several classes provided by the NetBeans Highlighting SPI. The two principle classes in this context are as follows:
-
* Highlight Layer*. Defines a set of highlights used for rendering a document.
-
* Highlight Layer Factory*. Defines a MIME-specific factory for creating highlight layers.
The above two classes need to be registered in the module’s layer.xml
file, within the editor folder of the relevant MIME-type.
Setting up the Module Project
Before you start writing the module, you have to make sure you that your project is set up correctly. The IDE provides a wizard that sets up all the basic files needed for a module.
-
Choose File > New Project (Ctrl+Shift+N). Under Categories, select NetBeans Modules. Under Projects, select Module. Click Next.
-
In the Name and Location panel, type
MarkHTMLOccurrences
in the Project Name field. Change the Project Location to any directory on your computer. Click Next.
-
In the Basic Module Configuration panel, type
org.netbeans.modules.markhtmloccurrences
in Code Name Base. Click Finish.
The IDE creates the MarkHTMLOccurrences
project. The project contains all of your sources and project metadata, such as the project’s Ant build script. The project opens in the IDE. You can view its logical structure in the Projects window (Ctrl-1) and its file structure in the Files window (Ctrl-2).
Creating the Highlight Layer and Factory
Next, we will implement the Highlighting SPI. The SPI’s classes are as follows:
Class | Description |
---|---|
Defines the factory for creating highlight layers. |
|
Defines the context passed to the factory when the factory is asked to create highlight layers. |
|
Defines the container of highlighted areas and related attributes. |
|
Defines the highlight layer, consisting of attributes. |
|
Defines position of highlight layer in relation to other highlight layers. |
|
Defines a set of highlighted areas specified by their offsets in the document. |
Specifying the Module’s Dependencies
You will need to subclass several classes that belong to NetBeans APIs. Each has to be declared as a Module dependency. Use the Project Properties dialog box for this purpose.
-
In the Projects window, right-click the Libraries node in the
MarkHTMLOccurrences
project and choose Add Module Dependency.
-
For each of the following APIs, select the name from the Module list, and then click OK to confirm that you want to depend on it:
-
Datasystems API
-
Editor
-
Editor Library 2
-
Editor Settings
-
File System API
-
Lookup API
-
MIME Lookup API
-
Nodes API
-
Text API
-
UI Utilities API
-
Utilities API
-
You should now see the following:
-
In the Projects window, expand the Important Files node, double-click the Project Metadata node, and note the long list of APIs that you selected have been declared as module dependencies. When the module is built, the dependencies will be registered in the manifest file.
Creating the Highlight Layer Factory
Highlight layer factories are defined by the Highlighting SPI.
To use the Highlighting SPI to create the palette in this tutorial, take the following steps:
-
Right-click the
MarkHTMLOccurrences
project node and choose New > Java Class. Create a Java file calledMarkHTMLOccurrencesHighlightsLayerFactory
.
-
Replace the default content of the
MarkHTMLOccurrencesHighlightsLayerFactory.java
file with the following:
import javax.swing.text.Document;
import org.netbeans.api.editor.mimelookup.MimeRegistration;
import org.netbeans.api.editor.mimelookup.MimeRegistrations;
import org.netbeans.spi.editor.highlighting.HighlightsLayer;
import org.netbeans.spi.editor.highlighting.HighlightsLayerFactory;
import org.netbeans.spi.editor.highlighting.ZOrder;
@MimeRegistrations({
@MimeRegistration(mimeType = "text/html", service = HighlightsLayerFactory.class),
@MimeRegistration(mimeType = "text/xml", service = HighlightsLayerFactory.class)
})
public class MarkHTMLOccurrencesHighlightsLayerFactory implements HighlightsLayerFactory {
public static MarkHTMLOccurrencesHighlighter getMarkOccurrencesHighlighter(Document doc) {
MarkHTMLOccurrencesHighlighter highlighter =
(MarkHTMLOccurrencesHighlighter) doc.getProperty(MarkHTMLOccurrencesHighlighter.class);
if (highlighter == null) {
doc.putProperty(MarkHTMLOccurrencesHighlighter.class,
highlighter = new MarkHTMLOccurrencesHighlighter(doc));
}
return highlighter;
}
@Override
public HighlightsLayer[] createLayers( Context context) {
return new HighlightsLayer[]{
HighlightsLayer.create(
MarkHTMLOccurrencesHighlighter.class.getName(),
ZOrder.CARET_RACK.forPosition(2000),
true,
getMarkOccurrencesHighlighter(context.getDocument()).getHighlightsBag())
};
}
}
Several statements remain underlined in red because they refer to the "MarkHTMLOccurrencesHighlighter" class, which we will create in the next section.
Creating the Highlight Layer
In this section, we create the highlight layer. Create a new Java class named MarkHTMLOccurrencesHighlighter
, with the content below.
import java.awt.Color;
import java.lang.ref.WeakReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JEditorPane;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.text.StyleConstants;
import org.netbeans.api.editor.settings.AttributesUtilities;
import org.netbeans.modules.editor.NbEditorUtilities;
import org.netbeans.spi.editor.highlighting.support.OffsetsBag;
import org.openide.cookies.EditorCookie;
import org.openide.loaders.DataObject;
import org.openide.util.RequestProcessor;
public class MarkHTMLOccurrencesHighlighter implements CaretListener {
private static final AttributeSet defaultColors =
AttributesUtilities.createImmutable(StyleConstants.Background,
new Color(236, 235, 163));
private final OffsetsBag bag;
private JTextComponent comp;
private final WeakReference<Document> weakDoc;
private final RequestProcessor rp;
private final static int REFRESH_DELAY = 100;
private RequestProcessor.Task lastRefreshTask;
public MarkHTMLOccurrencesHighlighter(Document doc) {
rp = new RequestProcessor(MarkHTMLOccurrencesHighlighter.class);
bag = new OffsetsBag(doc);
weakDoc = new WeakReference<Document>Document) doc); DataObject dobj = NbEditorUtilities.getDataObject(weakDoc.get(;
if (dobj != null) {
EditorCookie pane = dobj.getLookup().lookup(EditorCookie.class);
JEditorPane[] panes = pane.getOpenedPanes();
if (panes != null && panes.length > 0) {
comp = panes[0];
comp.addCaretListener(this);
}
}
}
@Override
public void caretUpdate(CaretEvent e) {
bag.clear();
setupAutoRefresh();
}
public void setupAutoRefresh() {
if (lastRefreshTask == null) {
lastRefreshTask = rp.create(new Runnable() {
@Override
public void run() {
String selection = comp.getSelectedText();
if (selection != null) {
Pattern p = Pattern.compile(selection);
Matcher m = p.matcher(comp.getText());
while (m.find() == true) {
int startOffset = m.start();
int endOffset = m.end();
bag.addHighlight(startOffset, endOffset, defaultColors);
}
}
}
});
}
lastRefreshTask.schedule(REFRESH_DELAY);
}
public OffsetsBag getHighlightsBag() {
return bag;
}
}
Building and Installing the Module
The IDE uses an Ant build script to build and install your module. The build script is created for you when you create the module project.
-
In the Projects window, right-click the
MarkHTMLOccurrences
project and choose Run.
-
The module is built and installed in a new instance of the IDE. Open an HTML file or an XML file, double-click on a word, and notice that all matching words are automatically highlighted:
-
Navigate from one matching word to the next via Ctrl-F3. Send Us Your Feedback
Next Steps
For more information about creating and developing NetBeans modules, see the following resources: