blob: b2a4b7639bc06ea8f0b4754af8cbfd2eb5cfda3d [file] [log] [blame]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<!-- -*- xhtml -*- -->
<title>NetBeans Code Completion Tutorial for NetBeans Platform 6.5</title>
<link rel="stylesheet" type="text/css" href="https://netbeans.org/netbeans.css"/>
<meta name="AUDIENCE" content="NBUSER"/>
<meta name="TYPE" content="ARTICLE"/>
<meta name="EXPIRES" content="N"/>
<meta name="developer" content="gwielenga@netbeans.org"/>
<meta name="indexed" content="y"/>
<meta name="description"
content="A short guide to using the Editor Code Completion API."/>
<!-- Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. -->
<!-- Use is subject to license terms.-->
</head>
<body>
<h1>NetBeans Code Completion Tutorial</h1>
<p>This tutorial shows you how to implement the <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/overview-summary.html">Editor
Code Completion API</a>. You will be shown how to implement the API
in the context of HTML files. When the user invokes the
code completion feature, a code completion box will appear,
displaying words that can complete the text typed in the editor. At the
end of this tutorial, HTML files will have a code completion
box as follows:</p>
<p><img src="../images/tutorials/cc/65-result-of-cc.png" alt="Code completion in text file"/></p>
<p>The content of the code completion box will come from
country names retrieved from the JDK's
<tt>java.util.Locale</tt> package.</p>
<p><b>Contents</b></p>
<p><img src="../images/articles/68/netbeans-stamp-65-67-68.gif" class="stamp" width="114" height="114" alt="Content on this page applies to NetBeans IDE 6.5, 6.7, 6.8" title="Content on this page applies to NetBeans IDE 6.5, 6.7, 6.8"/></p>
<ul class="toc">
<li><a href="#intro">Introduction to Code Completion Integration</a></li>
<li><a href="#creating-the-module-project">Creating the Module Project</a></li>
<li><a href="#implementing-the-code-completion-provider">Implementing the Completion Provider Class</a>
<ul>
<li><a href="#completiontask">Implementing the createTask Method</a></li>
<li><a href="#autoquerytype">Implementing the getAutoQueryTypes Method</a></li>
</ul></li>
<li><a href="#implementing-the-code-completion-item">Implementing the Completion Item Class</a>
<ul>
<li><a href="#defining-the-action">Implementing the Action</a></li>
<li><a href="#defining-the-filter">Implementing the Filter</a></li>
<li><a href="#defining-the-tooltip-documentation">Implementing the Tooltip and Documentation Task</a></li>
</ul></li>
</ul>
<p><b>To follow this tutorial, you need the software and resources listed in the following
table.</b></p>
<table>
<tbody>
<tr>
<th class="tblheader" scope="col">Software or Resource</th>
<th class="tblheader" scope="col">Version Required</th>
</tr>
<tr>
<td class="tbltd1"><a href="https://netbeans.org/downloads/index.html">NetBeans IDE</a></td>
<td class="tbltd1">version 6.5 or above</td>
</tr>
<tr>
<td class="tbltd1"><a href="http://java.sun.com/javase/downloads/index.jsp">Java Developer Kit (JDK)</a></td>
<td class="tbltd1">Version 6 or <br/>version 5</td>
</tr>
</tbody>
</table>
<p class="tips">Optionally, for troubleshooting purposes, you can <a href="http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=11981">download the
completed sample</a> and inspect the sources.</p>
<h2 class="tutorial"><a name="intro"></a>Introduction to Code Completion Integration</h2>
<p>Two classes apply to code completion and these will be developed in this tutorial:</p>
<ul>
<li><a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/CompletionItem.html">CompletionItem</a></li>
<li><a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/CompletionProvider.html">CompletionProvider</a></li>
</ul>
<p>Both of these come from the
<a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/overview-summary.html">Editor
Code Completion API</a> and are implemented in this tutorial's module as
CountriesCompletionItem and CountriesCompletionProvider.</p>
<p>When this tutorial is complete, the Projects window will
contain the files shown in the illustration below:</p>
<p><img src="../images/tutorials/cc/65-final-projects-window.png" alt="Final Projects window"/></p>
<!-- ===================================================================================== -->
<h2 class="tutorial"><a name="creating"></a>Creating the Module Project</h2>
<p>In this section, we use a wizard to create the source structure that every NetBeans module requires. The
source structure consists of certain folders in specific places and a set of files that are
always needed. For example, every NetBeans module requires a <tt>nbproject</tt> folder, which holds
the project's metadata, and a <tt>layer.xml</tt> file, for declarative registration of items
such as toolbar buttons and windows.</p>
<ol>
<li>Choose File &gt; New Project (Ctrl-Shift-N). Under Categories, select NetBeans Modules. Under Projects,
select Module and click Next.</li>
<li>In the Name and Location panel, type <tt>CountryCodeCompleter</tt> in Project Name.
Change the
Project Location to any directory on your computer, such as <tt>c:\mymodules</tt>. Leave the Standalone Module radiobutton
selected. Click Next.</li>
<li>In the Basic Module Configuration panel, type <tt>org.netbeans.modules.countries</tt>
as the Code Name Base.
Select the "Generate XML Layer" checkbox and
leave the location of the localizing bundle and XML layer as they are,
so that they will be stored in a
package with the name <tt>org/netbeans/modules/countries</tt>. Click Finish.</li></ol>
<p> The IDE creates the <tt>CountriesCodeCompleter</tt>
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).</p>
<!-- ===================================================================================== -->
<h2><a name="implementing-the-code-completion-provider"></a>Implementing the Completion Provider Class</h2>
<p>The first class we will deal with when creating a code completion feature
for HTML files is the <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/CompletionProvider.html">CompletionProvider</a>.
As the user types in an editor, the code completion infrastructure asks all code
completion providers registered in the XML layer file to create <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/CompletionTask.html">CompletionTasks</a>.
The tasks are created by the <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/CompletionProvider.html#createTask(int,%20javax.swing.text.JTextComponent)">CompletionProvider.createTask</a>
method. What <i>happens</i> when the method is invoked is up to the implementation. In <i>our</i>
implementation, we will create a <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/CompletionItem.html">CompletionItem</a>
for a list of countries.
</p>
<ol>
<li>Right-click the <tt>CountryCodeCompleter</tt> project and choose New &gt; Java Class.</li>
<li>In Class Name, type CountriesCompletionProvider. In Package, choose <tt>org.netbeans.modules.countries</tt>.
Click Finish.</li>
<li>Before coding the CompletionProvider class, let's register it in the XML layer file.
Open the XML layer file, and right below the opening <tt>&lt;filesystem&gt;</tt> tag, add the following tags:
<pre class="examplecode">&lt;folder name="Editors"&gt;
&lt;folder name="text"&gt;
&lt;folder name="html"&gt;
&lt;folder name="CompletionProviders"&gt;
&lt;file name="org-netbeans-modules-countries-CountriesCompletionProvider.instance"/&gt;
&lt;/folder&gt;
&lt;/folder&gt;
&lt;/folder&gt;
&lt;/folder&gt;</pre>
<p><b>Note:</b> As explained earlier, because of the entries specified above,
whenever the user types a character of any kind in a file with
a MIME type of <tt>text/html</tt>, the
code completion infrastructure will ask the CountriesCompletionProvider
to create its CompletionTask. In the next steps we will define our CompletionTask.</p></li>
<li>Right-click the <tt>CountryCodeCompleter</tt> project and choose Properties.
In the Project Properties dialog box, click Libraries. Click Add next to the
Module Dependencies list. Scroll to "Editor Code Completion" and click OK. Click
OK again to exit the Project Properties dialog box.</li>
<li>In the CountriesCompletionProvider class, change the signature so that
the class <tt>implements CompletionProvider</tt>. Place the cursor on the line
that defines the signature. A lightbulb appears. Click it and the
IDE adds an import statement for <tt>org.netbeans.spi.editor.completion.CompletionProvider</tt>.
The lightbulb appears again. Click it again and the IDE creates
skeleton methods for the two methods required by the CompletionProvider class.
<p>You should now see this:</p>
<pre class="examplecode">package org.netbeans.modules.CountryCodeCompleter;
import javax.swing.text.JTextComponent;
import org.netbeans.spi.editor.completion.CompletionProvider;
import org.netbeans.spi.editor.completion.CompletionTask;
public class CountriesCompletionProvider implements <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/CompletionProvider.html">CompletionProvider</a> {
public CountriesCompletionProvider() {
}
public <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/CompletionTask.html">CompletionTask</a> <a href="http://www.netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/CompletionProvider.html#createTask(int,%20javax.swing.text.JTextComponent)">createTask(int i,at JTextComponent jTextComponent)</a> {
}
public int <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/CompletionProvider.html#getAutoQueryTypes(javax.swing.text.JTextComponent,%20java.lang.String)">getAutoQueryTypes(JTextComponent jTextComponent, String string)</a> {
}
}
</pre>
<p>Click the links above to find out more about the classes and methods. Note that you
will see a few red error markings. Don't worry about these yet, they're just there to
tell you that the methods need to return something. We will work on this in the following steps.</p>
</li>
</ol>
<div class="indent">
<h3 class="tutorial"><a name="completiontask"></a>Implementing the createTask Method</h3>
<p>In this section we create a skeleton implementation of
<a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/support/AsyncCompletionTask.html">AsyncCompletionTask</a>.
In the next sections, we will fill this skeleton method out.</p>
<ol>
<li>In the createTask method,
below the code from the previous section, add the following lines:
<pre class="examplecode">return new AsyncCompletionTask(new AsyncCompletionQuery() {
});
</pre>
<p>Here, we're returning <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/support/AsyncCompletionTask.html">AsyncCompletionTask</a>,
which will allow for the asynchronous creation of our task. The class
comes from the <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/support/package-summary.html">org.netbeans.spi.editor.completion.support</a> package,
which provides several useful supporting classes for code completion implementations. We will
use several of
them in this tutorial.</p></li>
<li>Place the cursor on the line. Click the lightbulb that appears and let
the IDE add import statements. Also let it create a skeleton method for the
<a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/support/AsyncCompletionTask.html#query(org.netbeans.spi.editor.completion.CompletionResultSet)">query</a> method.</li>
<li>Next, we need to specify which code completion type we are working with. When
the user clicks Ctrl-Space, or an alternative key combination defined by the user,
our code completion entries should appear. This is the COMPLETION_QUERY_TYPE. Alternative
query types exist, such as DOCUMENTATION_QUERY_TYPE and TOOLTIP_QUERY_TYPE. We need to test
whether the user pressed the keys applicable to the COMPLETION_QUERY_TYPE. Therefore add
the following test to the start of the <tt>createTask</tt> method:
<pre class="examplecode">if (i != CompletionProvider.COMPLETION_QUERY_TYPE)
return null;</pre>
<p>At this stage, the <tt>createTask</tt> method should look as follows:</p>
<pre class="examplecode">public CompletionTask createTask(int i, JTextComponent jTextComponent) {
if (i != CompletionProvider.COMPLETION_QUERY_TYPE)
return null;
return new AsyncCompletionTask(new AsyncCompletionQuery() {
protected void query(CompletionResultSet completionResultSet, Document document, int caretOffset) {
}
});
}
</pre>
</li>
</ol>
</div>
<div class="indent">
<h3 class="tutorial"><a name="autoquerytype"></a>Implementing the getAutoQueryTypes Method</h3>
<p>In this section we return 0 as our AutoQueryType, so that
the code completion box does not appear automatically, but only
when requested by the user.</p>
<ol>
<li>Change the name "i" in the createTask method
signature to "type". Do this to make your code
more readable. The name "i" does not mean anything.
By changing it to "type" you will later be able
to see more clearly that the AutoQueryType is
being referred to here.</li>
<li>Before filling out the query method, let's look at the <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/CompletionProvider.html#getAutoQueryTypes(javax.swing.text.JTextComponent,%20java.lang.String)">getAutoQueryTypes(JTextComponent jTextComponent, String string)</a>
method. This method determines whether the code completion box appears <i>automatically</i>
or not. For now, let's return 0. This means that the code completion box
will never appear unless the user explicitly asks for it. So, this method should
now look as follows:
<pre class="examplecode">public int getAutoQueryTypes(JTextComponent jTextComponent, String string) {
return 0;
}
</pre>
<p>By default, the
user would press Ctrl-Space to make the code completion box appear. Later, we
can add a new option to our Options window extension, such as a checkbox which
will change the int returned in this method from 0 to 1, so that the code completion
box appears automatically. (There are also other types of queries, as
shown <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/constant-values.html#org.netbeans.spi.editor.completion.CompletionProvider.COMPLETION_QUERY_TYPE">here</a>.)
</p></li>
</ol>
</div>
<!-- ===================================================================================== -->
<h2><a name="implementing-the-code-completion-item"></a>Implementing the Completion Item Class</h2>
<p>In this section
we will create a class that implements <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/CompletionItem.html">CompletionItem</a>.
Once we have defined this class, we will fill out the query method in the
CompletionProvider class. The CompletionProvider will create instances of
our CompletionItem.</p>
<ol><li>Right-click the
<tt>CountryCodeCompleter</tt> project and choose New &gt; Java Class.
In Class Name, type CountriesCompletionItem. In Package, choose
<tt>org.netbeans.modules.countries</tt>. Click Finish.</li>
<li>We will return to this class in later steps. For now, we
will fill out the query method that we defined in the CompletionProvider class.
Fill out the AsyncCompletionTask as follows, and note
the explanatory comments in the code:
<pre class="examplecode">return new AsyncCompletionTask(new AsyncCompletionQuery() {
@Override
protected void query(CompletionResultSet completionResultSet, Document document, int caretOffset) {
//Iterate through the available locales
//and assign each country display name
//to a CompletionResultSet:
Locale[] locales = Locale.getAvailableLocales();
for (int i = 0; i < locales.length; i++) {
final Locale locale = locales[i];
final String country = locale.getDisplayCountry();
if (!country.equals("")) {
completionResultSet.addItem(new CountriesCompletionItem(country, caretOffset));
}
}
completionResultSet.finish();
}
}, jTextComponent);</pre>
<p><b>Note:</b> A red underline remains, after you let the IDE add various import statements.
The error underline tells you that the CompletionItem's constructor does not expect the
values that you are passing to it. In the next step, we will fill out the CompletionItem
so that it meets the requirements of the CompletionProvider.</p></li>
<li>In the CountriesCompletionItem class, change the signature so that
the class <tt>implements CompletionItem</tt>. Let the IDE create import statements and skeleton
implementations for
the class's required methods.
Read the entry in the NetBeans Javadoc for
<a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/CompletionItem.html">CompletionItem</a>
to begin to understand what each of the methods is for. For now, we will implement a
minimal completion item, just enough to
be able to compile the module and see the code completion box.</li>
<li>In the CountriesCompletionItem class, define the constructor as follows:
<pre class="examplecode">private String text;
private static ImageIcon fieldIcon =
new ImageIcon(Utilities.loadImage("org/netbeans/modules/countries/icon.png"));
private static Color fieldColor = Color.decode("0x0000B2");
private int caretOffset;
public CountriesCompletionItem(String text, int caretOffset) {
this.text = text;
this.caretOffset = caretOffset;
}</pre>
<p>Note that here we're referencing an icon. This is the icon that will
appear next to each entry represented by the CompletionItem in the
code completion box. The icon can be any icon with a dimension of 16x16 pixels.
For example, you could make use of this icon:</p>
<p><img src="../images/tutorials/cc/icon.png" alt="icon"/></p>
<p>If you like, you can right-click the image above and save it to the location
specified in the ImageIcon definition above.</p></li>
<li>Next define the <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/CompletionItem.html#getPreferredWidth(java.awt.Graphics,%20java.awt.Font)">getPreferredWidth()</a>
and <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/CompletionItem.html#render(java.awt.Graphics,%20java.awt.Font,%20java.awt.Color,%20java.awt.Color,%20int,%20int,%20boolean)">render()</a>
methods as follows:
<pre class="examplecode">public int getPreferredWidth(Graphics graphics, Font font) {
return CompletionUtilities.getPreferredWidth(text, null, graphics, font);
}
public void render(Graphics g, Font defaultFont, Color defaultColor,
Color backgroundColor, int width, int height, boolean selected) {
CompletionUtilities.renderHtml(fieldIcon, text, null, g, defaultFont,
(selected ? Color.white : fieldColor), width, height, selected);
}
</pre>
<p>Define the <tt><a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/CompletionItem.html#getSortText()">getSortText()</a></tt> method as follows:</p>
<pre class="examplecode">public CharSequence getSortText() {
return text;
}
</pre>
<p>Next, define the <tt><a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/CompletionItem.html#getInsertPrefix()">getInsertPrefix()</a></tt> method:</p>
<pre class="examplecode">public CharSequence getInsertPrefix() {
return text;
}</pre>
<p>Finally, create dummy implementations of the remaining methods. So,
return <tt>null</tt> for <tt>createDocumentationTask()</tt>, <tt>createToolTipTask()</tt>,
and <tt>getInsertPrefix()</tt>. Then return <tt>false</tt> for
<tt>instantSubstitution()</tt> and return <tt>0</tt> for <tt>getSortPriority()</tt>.</p></li>
<li>Right-click the module and choose Run.
A new instance of the IDE starts up and installs your module. Open an HTML file in
the IDE. Type something and press Ctrl-Space.
<p>You should now see the following:</p>
<p><img src="../images/tutorials/cc/65-result-of-cc1.png" alt="icon"/></p>
<p><b>Note:</b> When you press Enter, nothing happens. That is because
we have not defined the <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-completion/org/netbeans/spi/editor/completion/CompletionItem.html#defaultAction(javax.swing.text.JTextComponent)">defaultAction()</a>
method yet. We will do so in the next section. Also note that the list does not narrow while you are typing. That
is because we have not created a filter yet. The filter will detect
what we are typing and adjust the entries in the list accordingly. We will create
a filter in a later section.</p></li>
</ol>
<div class="indent">
<h3 class="tutorial"><a name="defining-the-action"></a>Implementing the Action</h3>
<p>In this section we specify what happens when the user
presses the Enter key or clicks the mouse over an entry in the
code completion box.</p>
<ol>
<li>Fill out the <tt>defaultAction()</tt> method
as follows:
<pre class="examplecode">public void defaultAction(JTextComponent jTextComponent) {
StyledDocument doc = (StyledDocument) jTextComponent.getDocument();
doc.insertString(caretOffset, text, null);
//This statement will close the code completion box:
Completion.get().hideAll();
}
</pre> </li>
<li>Install the module again. Notice that when
you press Enter or click the mouse over an entry
in the code completion box, the selected text is added at the cursor
in your HTML file. However, the text that you typed
prior to calling up the code completion box is
not removed. Below, the "V" should be removed, because "Vietnam"
was selected from the code completion box:
<p><img src="../images/tutorials/cc/65-result-of-cc2.png" alt="icon"/></p>
<p>In the next section, we will add functionality to detect the number of
characters that have been typed and remove them when the selected country
is inserted into the document.</p></li>
</ol>
</div>
<div class="indent">
<h3 class="tutorial"><a name="defining-the-filter"></a>Implementing the Filter</h3>
<p>In this section we enable the code completion box
to narrow while the user is typing. In this way, when the user types
'hel', only words that begin with those letters are
shown in the code completion box. The filter is defined
in the CountriesCompletionProvider class.</p>
<ol>
<li>In the CountriesCompletionProvider class,
rewrite the <tt>AsyncCompletionTask()</tt> method by
adding the statements highlighted in bold below:
<pre class="examplecode">return new AsyncCompletionTask(new AsyncCompletionQuery() {
@Override
protected void query(CompletionResultSet completionResultSet, Document document, int caretOffset) {
<b>String filter = null;
int startOffset = caretOffset - 1;
try {
final StyledDocument bDoc = (StyledDocument) document;
final int lineStartOffset = getRowFirstNonWhite(bDoc, caretOffset);
final char[] line = bDoc.getText(lineStartOffset, caretOffset - lineStartOffset).toCharArray();
final int whiteOffset = indexOfWhite(line);
filter = new String(line, whiteOffset + 1, line.length - whiteOffset - 1);
if (whiteOffset > 0) {
startOffset = lineStartOffset + whiteOffset + 1;
} else {
startOffset = lineStartOffset;
}
} catch (BadLocationException ex) {
Exceptions.printStackTrace(ex);
}</b>
//Iterate through the available locales
//and assign each country display name
//to a CompletionResultSet:
Locale[] locales = Locale.getAvailableLocales();
for (int i = 0; i < locales.length; i++) {
final Locale locale = locales[i];
final String country = locale.getDisplayCountry();
<b>//Here we test whether the country starts with the filter defined above:</b>
if (!country.equals("") <b>&& country.startsWith(filter)</b>) {
<b>//Here we include the start offset, so that we'll be able to figure out
//the number of characters that we'll need to remove:</b>
completionResultSet.addItem(new CountriesCompletionItem(country, <b>startOffset,</b> caretOffset));
}
}
completionResultSet.finish();
}
}, jTextComponent);</pre> </li>
<li>Right at the end of the CountriesCompletionProvider, add the
following two methods:
<pre class="examplecode">static int getRowFirstNonWhite(StyledDocument doc, int offset)
throws BadLocationException {
Element lineElement = doc.getParagraphElement(offset);
int start = lineElement.getStartOffset();
while (start + 1 < lineElement.getEndOffset()) {
try {
if (doc.getText(start, 1).charAt(0) != ' ') {
break;
}
} catch (BadLocationException ex) {
throw (BadLocationException)new BadLocationException(
"calling getText(" + start + ", " + (start + 1) +
") on doc of length: " + doc.getLength(), start
).initCause(ex);
}
start++;
}
return start;
}</pre>
<pre class="examplecode">static int indexOfWhite(char[] line){
int i = line.length;
while(--i > -1){
final char c = line[i];
if(Character.isWhitespace(c)){
return i;
}
}
return -1;
}
</pre> </li>
<li>Change the constructor of the CountriesCompletionItem to receive the start offset.
Then change the <tt>defaultAction</tt> so that the start offset will be used in
determining the characters that will be removed when the selected country is inserted.
Below, the statements highlighted in bold are those that should be added:
<pre class="examplecode"><b>private int dotOffset;</b>
public CountriesCompletionItem(String text, <b>int dotOffset,</b> int caretOffset) {
this.text = text;
<b>this.dotOffset = dotOffset;</b>
this.caretOffset = caretOffset;
}
public void defaultAction(JTextComponent jTextComponent) {
try {
StyledDocument doc = (StyledDocument) jTextComponent.getDocument();
<b>//Here we remove the characters starting at the start offset
//and ending at the point where the caret is currently found:
doc.remove(dotOffset, caretOffset-dotOffset);</b>
doc.insertString(<b>dotOffset,</b> text, null);
Completion.get().hideAll();
} catch (BadLocationException ex) {
Exceptions.printStackTrace(ex);
}
}
...
...
...</pre></li>
<li>Install the module again and notice that this time the list of
words narrows while you are typing:
<p><img src="../images/tutorials/cc/65-result-of-cc.png" alt="Code completion in text file"/></p>
<p>When you press Enter, the characters that you typed are removed and replaced by
the country selected from the code completion box.</p></li>
</ol>
</div>
<div class="indent">
<h3 class="tutorial"><a name="defining-the-tooltip-documentation"></a>Implementing the Tooltip and Documentation Task</h3>
<p>Some optional features can also be added, as described below.</p>
<ol>
<li>Optionally, you can implement the createToolTipTask method in the CountriesCompletionItem, with
this result when Ctrl-P is pressed:
<p><img src="../images/tutorials/cc/65-result-of-cc3.png" alt="Code completion in text file"/></p>
<p>Here is the code that will achieve the result shown in the screenshot above:</p>
<pre class="examplecode">
public CompletionTask createToolTipTask() {
return new AsyncCompletionTask(new AsyncCompletionQuery() {
protected void query(CompletionResultSet completionResultSet, Document document, int i) {
JToolTip toolTip = new JToolTip();
toolTip.setTipText("Press Enter to insert \"" + text + "\"");
completionResultSet.setToolTip(toolTip);
completionResultSet.finish();
}
});
}</pre>
</li>
<li>Optionally, you can provide documentation for the entries in the code completion box:
<p><img src="../images/tutorials/cc/65-result-of-cc4.png" alt="Code completion in text file"/></p>
<p>Make use of the documentation box like this, by implementing the createDocumentationTask method
in the CountriesCompletionItem class:</p>
<pre class="examplecode">public CompletionTask createDocumentationTask() {
return new AsyncCompletionTask(new AsyncCompletionQuery() {
protected void query(CompletionResultSet completionResultSet, Document document, int i) {
completionResultSet.setDocumentation(new CountriesCompletionDocumentation(CountriesCompletionItem.this));
completionResultSet.finish();
}
});
}</pre>
<p>In the code above, the reference to the CountriesCompletionDocumentation class could be implemented as follows:</p>
<pre class="examplecode">public class CountriesCompletionDocumentation implements CompletionDocumentation {
private CountriesCompletionItem item;
public CountriesCompletionDocumentation(CountriesCompletionItem item) {
this.item = item;
}
public String getText() {
return "Information about " + item.getText();
}
public URL getURL() {
return null;
}
public CompletionDocumentation resolveLink(String string) {
return null;
}
public Action getGotoSourceAction() {
return null;
}
}</pre>
<p>By implementing the <tt>getURL()</tt> in the code above, you can enable
the URL button, as shown below:</p>
<p><img src="../images/tutorials/cc/65-result-of-cc5.png" alt="Code completion in text file"/></p>
<p>When the user clicks the URL button, the browser set in the IDE will open, displaying
the content provided by the specified URL.</p>
</li>
</ol>
</div>
<p>Congratulations, you have now completed a simple implementation of a code completion
integration module.</p>
</body>
</html>