Customizing
a Text Editor
'JavaEditorKit' Plug-in Shows How It's Done
NOTE:
This article was written before the release of Swing 1.1 Beta
3 and JDKTM 1.2 RC1, a set of
APIs that introduced the package names now used in Swing.
To
compile and run the example program under current versions of the
JFCTM software, you must use an
alternative version of the example that is contained in zipped form
a downloadable jar file named javakit.zip.
When you unzip the file, the sample it produces is in a jar file
named javakit.jar. This newer example uses the lexical scanner that
is part of the java compiler found in JDK 1.1, which you can download
from the JFC
Web page. (If you use the JavaTM
2 SDK or another JVM implementation, the compiler may not be included.
With Java 2, the old compiler classes can be found in the tools.jar
file, which must be included in your classpath when running under
Java 2.)
In upcoming issues of The Swing Connection, this article will
be replaced by newer articles illustrating other approaches for
creating an EditorKit implementation and an editor that uses it.
This article shows how
to add customized features to the ready-made text-editor kits that
are supplied with Swing.
More specifically, it shows how to create a "plug-in"
for JEditorPane that can handle different kinds of content are not
handled by default.
To show you how to create plug-ins
for Swing text-editor kits, we supply all the source files you'll
need to create, compile, and execute a plug-in that adds color highlighting
capabilities to a text editor.
Once you know how to do that,
you can use similar techniques to provide text editors with other
kinds of custom capabilities.
This article is designed to accompany a longer and
more comprehensive article, titled "The
Swing Text Package," that is also presented in this
issue. Before you start working with the sample program we'll be
presenting here, we recommend that you read "The Swing Text
Package."
Once you learn the techniques
outlined in this article, you can use them to add any kind of special
capabilities you like to any text editor that's compatible with
the Swing text API.
The major topics we'll be covering are:
Introducing the JavaEditorKit
To create the customized source-code editor demonstrated
in this article, we created a customized implementation of the Swing
EditorKit
class and used it to add color highlighting to the Swing JEditorPane
class.
The new editor kit that we created is designed for
editing source code written in the Java programming language, so
we've named it the JavaEditorKit.
Later in this article, you find links to the all source-code
files that we used to create the JavaEditorKit. You can download
the source code, study it, and modify it to create any kind of customized
text editor you'd like to build.
The JEditorPane class
JEditorPane -- the foundation
class for the customized editor that we'll create in this article
-- separates the management of look-and-feel features from the management
of document content.
By default, JEditorPane supports
plain text, HTML text, and RTF text. To create the JavaEditorKit
that we built for this article, we added some specialized support
for text written in the JavaTM
programming language.
When you learn how the JavaEditorKit
example works, you know all you need to know to add just about any
kind of support for new kinds of content to a Swing text editor.
A preview of the JavaEditorKit
program
When you complete the JavaEditorKit example and execute
it, the program displays a window like the one shown below. As you
can see, the JavaEditorKit provides color text highlighting that
is specially designed for use with the Java programming language.
Planning a strategy
When you want to customize a Swing text editor, the
first thing you should do is plan a strategy for the kind of support
that your new editor kit will provide. In the example that we'll
present in this article, we'' provide the bare bones of what a programmer
would need to edit code written in the Java programming language.
At this level, we wont be dealing with the overall
environment of an IDE; that would be, a higher-level task. Instead,
we'll just create a plug-in that provides some basic services. By
building on that foundation, we could easily create a higher-level
environment. There are many directions we could go in, but for now,
we'll keep it simple by dealing primarily with syntax highlighting.
To perform the task of syntax highlighting, it might
be tempting to use the styled-text support that Swing provides.
But we'll be building a source-code editor, and in terms of modeling,
source code is really oriented more towards plain text than towards
styled text. Furthermore, different programmers may want to view
the documents using different style settings.
Also, if the syntax of a program gets too broken it
can always be treated as plain text. So embedding styles in documents
is not very desirable -- at least not in the kind of editor we are
building.
The JavaEditorKit example extends a plain-text document,
forming semi-styled views (in color) over it. To accomplish this
task, we could use a model that maintains a lexical structure of
the program in addition to the line-mapping services already provided
by the PlainDocument
class. The lexical structure provided by PlainDocument is designed
primarily to provide a beautification service that is nice but not
essential, so we could build and store a lexical structure on a
separate lower-priority thread in such a way that it would not get
in the way of any editing or text viewing. If an application opened
a large document, it could be used as soon as the plain-text part
Became available. This strategy would free the user from having
to wait for the scanner to finish -- an operation that could take
a while if the region to be "lexed"
was a large one.
Alternatively, we could "lex"
the region being displayed and not store any lexical information.
This is the approach we have taken --because it reduces the complexity
of the example and avoids storing a lot of extra information that
we do not use in our JavaEditorKit example.
Implementation
As noted in the article title "The
Swing Text Package," the EditorKit
class is the primary mechanism for extending Swing text components.
To create an EditorKit, you register it with a JEditorPane
object.
When you start building a new editor kit, the first
thing you need to do is create an EditorKit implementation -- which,
in turn, forms the plug-in for whatever new type of content you
want to support.
In the JavaEditorKit example, we create a content
type named TEXT/JAVA -- and, as noted previously, we call our EditorKit
implementation JavaEditorKit. So JavaEditorKit is the class
name that we register with JEditorPane, and is also the class name
that we use for all requests that we issue to edit Java text.
The two primary duties of the EditorKit class (beyond
the duties provided by the superclass) are to hand out Java programming
language documents that model the text with optional lexical information,
and to produce views that display those models.
The class that we use to model text is called JavaDocument.
It extends the PlainDocument class because it fundamentally deals
with plain text. In the JavaEditorKit example, we add to the PlainDocument
class the ability to produce lexical tokens for some given range
of the document.
To produce lexical information, the JavaEditorKit
example simply uses the freely available scanner found in the JDK.
To feed the scanner, we implement a simple nested class DocumentInputStream
to give the scanner a stream-based access to the content storage
of the model. The document also provides a crude mechanism for marking
multi-line comment areas so scanning can start at a reasonable location.
This mechanism would not be robust enough for use
in a real-world application, but it serves well as an example. The
comment marking is performed in the insertUpdate method, which gives
the document an opportunity to update its structure after an insertion
takes place. Because the insertUpdate method occurs under the protection
of a write lock, attributes can be freely modified.
One other fundamental class is used in the JavaEditorKit
example: a view object that highlights in color the various tokens
used in the Java programming language.
The view object used in JavaEditorKit is an implementation
of the View class. The Swing text package provides a PlainView class
that can be used to represent a PlainDocument. In the JavaEditorKit
example, we extend PlainDocument's rendering methods to take into
account the lexical structure of the document.
JavaEditorKit produces views for Swing text using
an implementation of the ViewFactory interface. This interface is
implemented by the JavaContext class to produce a nested class JavaView.
The rendering method uses the scan codes of the lexical tokens to
reference into a lookup table for the color to use for the token.
Making the JavaView class a nested class ensures it easy access
to the style information it will use for its rendering operations.
To manage styles conveniently, the JavaContext class
extends the StyleContext class, mapping a policy over the set of
styles contained. The JavaEditorKit provides a pair of methods to
set and get the JavaContext to use for building the views. This
capabilities enables the developer to use serialization for saving
and restoring the settings, and to have this set of settings shared
for all of the views produced by it.
The names of the styles are based upon the categories
of lexical tokens and actual lexical token names. This convention
allows attributes to be set for different categories of tokens,
and allows specific settings for particular tokens. In other words,
you can use it to build an independent customization interface to
configure the EditorKit. To perform this class properly, one would
create a BeanInfo class for the appropriate Bean and name the customization
class. Those kinds of operations are beyond the scope of this particular
article, but may be examined in more detail in a future article
in The Swing Connection.
The JavaContext can also serve other purposes. For
example, you can use it to produce a styled document. In that case,
you could export the styled views (using style preferences specified
in the JavaContext) into other formats such as HTML and RTF.
The Token class represents the various possible token
types that can be produced by the lexical process. These are implemented
as the set of possible scan codes produced by the freely available
scanner in the JDK, along with a couple of additional values. The
Token class wraps up set of possible tokens as objects so that additional
things can be done with them -- for example, to make the lexical
information more useful. This feature makes tokens easier to manage
when styles are being set up, and allows them to be used as attributes.
Using the JavaEditorKit Example
These are the source files that implement the JavaEditorKit
application. Just click on their links to download them:
When
you have compiled the application, you can execute it using a helper
program named JavaKitTest, which you can download by clicking
this link.
The JavaKitTest program creates a JEditorPane component
and installs the JavaEditorKit into it. The component is then used
to load a file named as an argument to the method EditorKitTest.main().
The example plugs some values into the JavaContext to illustrate
color highlighting.
-- Tim Prinzing
|