blob: 66c010c5955956c1569623b3bfb208c795bef1d0 [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 Mark Occurrences Module 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 Mark Occurrences Module Tutorial - Apache NetBeans
:keywords: Apache NetBeans Platform, Platform Tutorials, NetBeans Mark Occurrences Module Tutorial
This tutorial demonstrates how to create a NetBeans module that highlights all instances of a selected word in an HTML file, as shown below:
image::images/mark-occs_72_result-3.png[]
For troubleshooting purposes, you are welcome to download the link:http://web.archive.org/web/20170409072842/http://java.net/projects/nb-api-samples/show/versions/8.0/tutorials/MarkHTMLOccurrences[completed tutorial source code].
== Introduction to Highlight Layers
In this tutorial, you implement several classes provided by the link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/package-summary.html[NetBeans Highlighting SPI]. The two principle classes in this context are as follows:
* * link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/HighlightsLayer.html[Highlight Layer]*. Defines a set of highlights used for rendering a document.
* * link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/HighlightsLayerFactory.html[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.
[start=1]
1. Choose File > New Project (Ctrl+Shift+N). Under Categories, select NetBeans Modules. Under Projects, select Module. Click Next.
[start=2]
1. 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.
[start=3]
1. 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
| link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/HighlightsLayerFactory.html[HighlightsLayerFactory] |Defines the factory for creating highlight layers.
| link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/HighlightsLayerFactory.Context.html[HighlightsLayerFactory.Context] |Defines the context passed to the factory when the factory is asked to create highlight layers.
| link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/HighlightsContainer.html[HighlightsContainer] |Defines the container of highlighted areas and related attributes.
| link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/HighlightsLayer.html[HighlightsLayer] |Defines the highlight layer, consisting of attributes.
| link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/ZOrder.html[ZOrder] |Defines position of highlight layer in relation to other highlight layers.
| link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/support/OffsetsBag.html[OffsetsBag] |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 link:http://bits.netbeans.org/dev/javadoc/index.html[NetBeans APIs]. Each has to be declared as a Module dependency. Use the Project Properties dialog box for this purpose.
[start=1]
1. In the Projects window, right-click the Libraries node in the ``MarkHTMLOccurrences`` project and choose Add Module Dependency.
[start=2]
1. 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:
image::images/mark-occs_72_project-1.png[]
[start=3]
1. 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 link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/package-summary.html[Highlighting SPI].
To use the Highlighting SPI to create the palette in this tutorial, take the following steps:
[start=1]
1. Right-click the ``MarkHTMLOccurrences`` project node and choose New > Java Class. Create a Java file called ``MarkHTMLOccurrencesHighlightsLayerFactory`` .
[start=2]
1. Replace the default content of the ``MarkHTMLOccurrencesHighlightsLayerFactory.java`` file with the following:
[source,java]
----
import javax.swing.text.Document;
import org.netbeans.api.editor.mimelookup.MimeRegistration;
import org.netbeans.api.editor.mimelookup.MimeRegistrations;
import link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/HighlightsLayer.html[org.netbeans.spi.editor.highlighting.HighlightsLayer];
import link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/HighlightsLayerFactory.html[org.netbeans.spi.editor.highlighting.HighlightsLayerFactory];
import link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/ZOrder.html[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 link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/HighlightsLayerFactory.html[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[] link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/HighlightsLayerFactory.html#createLayers(org.netbeans.spi.editor.highlighting.HighlightsLayerFactory.Context)[createLayers]( link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/HighlightsLayerFactory.Context.html[Context] context) {
return new HighlightsLayer[]{
link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/HighlightsLayer.html#create(java.lang.String,%20org.netbeans.spi.editor.highlighting.ZOrder,%20boolean,%20org.netbeans.spi.editor.highlighting.HighlightsContainer)[HighlightsLayer.create](
MarkHTMLOccurrencesHighlighter.class.getName(),
link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/ZOrder.html[ZOrder.CARET_RACK.forPosition(2000)],
true,
link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/HighlightsContainer.html[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.
[source,java]
----
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 link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-settings/org/netbeans/api/editor/settings/AttributesUtilities.html[org.netbeans.api.editor.settings.AttributesUtilities];
import link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor/org/netbeans/modules/editor/NbEditorUtilities.html[org.netbeans.modules.editor.NbEditorUtilities];
import link:http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-editor-lib2/org/netbeans/spi/editor/highlighting/support/OffsetsBag.html[org.netbeans.spi.editor.highlighting.support.OffsetsBag];
import link:http://bits.netbeans.org/dev/javadoc/org-openide-text/org/openide/cookies/EditorCookie.html[org.openide.cookies.EditorCookie];
import link:http://bits.netbeans.org/dev/javadoc/org-openide-loaders/org/openide/loaders/DataObject.html[org.openide.loaders.DataObject];
import link:http://bits.netbeans.org/dev/javadoc/org-openide-util/org/openide/util/RequestProcessor.html[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 &amp;&amp; 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.
[start=1]
1. In the Projects window, right-click the ``MarkHTMLOccurrences`` project and choose Run.
[start=2]
1. 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:
image::images/mark-occs_72_result-3.png[]
[start=3]
1. Navigate from one matching word to the next via Ctrl-F3.
link:http://netbeans.apache.org/community/mailing-lists.html[Send Us Your Feedback]
== Next Steps
For more information about creating and developing NetBeans modules, see the following resources:
* link:https://netbeans.apache.org/kb/docs/platform.html[Other Related Tutorials]
* link:http://bits.netbeans.org/dev/javadoc/index.html[NetBeans API Javadoc]