Source viewers and annotations
The editor and its corresponding text viewer are largely responsible for the
implementation of the document's presentation and the configuration of any needed
helper classes. (See
Viewers if you are not familiar with the
concept of a viewer.)
A
TextViewer
handles all of the low level details of mapping the document model and its
partitions into the colored and formatted text that a user sees. For source code style editors, a
SourceViewer
is provided. A source viewer introduces the notion of source code
annotations. These annotations can be shown in a vertical ruler on the left side of
the text, an overview ruler on the right side of the text, or as colored
squigglies underneath text.
SourceViewer
and its helper classes are used
throughout the
AbstractTextEditor
hierarchy. The package
org.eclipse.jface.text.source
defines this viewer and the other classes supporting annotation presentation.
Annotations and rulers
Annotations, like partitions, are largely dependent on the kind of document being edited.
The
IAnnotationModel
for a document is what holds the annotations, enumerates them on request, and listens for text
changes in order to keep the annotations up to date with the text. Annotation models are registered
in the
org.eclipse.core.filebuffers.annotationModelCreation
extension. This extension point allows plug-ins to register a class that will create an annotation model
appropriate for a given file extension. The Java Editor example does not use this extension point, so it
inherits the annotation model defined by the platform.
<extension
point="org.eclipse.core.filebuffers.annotationModelCreation">
<factory
extensions="*"
class="org.eclipse.ui.texteditor.ResourceMarkerAnnotationModelFactory">
</factory>
</extension>
The supplied factory class will create a
ResourceMarkerAnnotationModel
for files with any extension. This class displays annotations that represent a marker on a resource in the
workspace. (See
Resource markers for more
information on markers.) It assigns an image and description to each marker and monitors its resource for changes in the markers.
To see how an annotation model is displayed in a text editor, we'll examine
the platform text editor and its use of rulers and annotations. The
specifics of how different annotations are shown in the rulers and text can be
controlled by the user in the
General > Editors > Text Editors > Annotations
preferences.
Vertical ruler
A vertical ruler to the left of the editing area is used by platform text
editors to show text ranges and line-based annotations adjacent to their text line.
These annotations are described in the supplied
ResourceMarkerAnnotationModel
.
This model is set into the
SourceViewer
when the source viewer is initialized by the editor. The following snippet
from
AbstractTextEditor
shows how the document and the annotation model are associated with
the viewer.
private void initializeSourceViewer(IEditorInput input) {
IAnnotationModel model= getDocumentProvider().getAnnotationModel(input);
IDocument document= getDocumentProvider().getDocument(input);
if (document != null) {
fSourceViewer.setDocument(document, model);
...
Once the source viewer is configured with the proper document and annotation
model, it has enough information to present the document and ensure the correct
annotations are shown in the vertical ruler to the left. The model is
associated with the ruler when the document is set. The following snippet
shows what happens when a document is set into the source viewer. It has
been simplified from the actual code in
SourceViewer
for clarity:
public void setDocument(IDocument document, IAnnotationModel annotationModel) {
...
// create visual annotation model from the supplied model and store
// in fVisualAnnotationModel
...
if (fVerticalRuler != null)
fVerticalRuler.setModel(fVisualAnnotationModel);
In this way, the ruler is associated with the appropriate annotation
model.
Let's look at the ruler itself. It is created by the text editor and
then connected with the editor's viewer. Since the Java editor example
does not define any special behavior for rulers, it inherits the ruler as defined
in
TextEditor.
protected IVerticalRuler createVerticalRuler() {
CompositeRuler ruler= new CompositeRuler();
ruler.addDecorator(0, new AnnotationRulerColumn(VERTICAL_RULER_WIDTH));
if (isLineNumberRulerVisible())
ruler.addDecorator(1, createLineNumberRulerColumn());
return ruler;
}
The text editor uses a CompositeRuler. This ruler does not have a visual presentation
of its own. The presentation is provided by a list of decorators that
show columns (
IVerticalRulerColumn
)
in the ruler. In this example, a ruler column that shows annotations (
AnnotationRulerColumn
)
is always added, and a line number ruler column is added based on user preferences.
The annotation ruler column handles the particulars of displaying the annotation
images in the proper locations.
Despite all the classes involved in showing a ruler, note that the example
editor needed only to subclass framework classes to get ruler
behavior. JavaDocumentProvider inherits an appropriate
marker annotation model from
FileDocumentProvider
.
The JavaTextEditor inherits the ruler presentation from
TextEditor.
Overview ruler
An overview ruler on the right hand side of the editing area is used to show
annotations concerning the entire document. These annotations are shown
relative to their position in the document and do not move as the user scrolls
the document. There usually is a corresponding annotation on the
vertical ruler when that portion of the document is visible.
The vertical ruler below shows that there are two tasks in the document and
one bookmark. Since the bookmarked text is visible, its annotation is also
shown on the left.
The user can navigate to the location of the annotation in the code by
clicking on the annotation itself.
The types of annotations shown in the overview ruler are determined by adding
annotation types to the ruler. In the following snippet from
SourceViewerDecorationSupport,
annotation types are dynamically added to the ruler. (See next section for more
information about
SourceViewerDecorationSupport.)
private void showAnnotationOverview(Object annotationType) {
if (fOverviewRuler != null) {
Color c= getAnnotationTypeColor(annotationType);
fOverviewRuler.setAnnotationTypeColor(annotationType, c);
int l= getAnnotationTypeLayer(annotationType);
fOverviewRuler.setAnnotationTypeLayer(annotationType, l);
fOverviewRuler.addAnnotationType(annotationType);
fOverviewRuler.update();
}
}
The overview ruler is also supplied with an
IAnnotationAccess
that is used to provide information about a particular annotation, such as its
type and how it is to be displayed. The
TextEditor
uses a
DefaultMarkerAnnotationAccess
which interprets annotations according to their marker types and consults the
user preferences to see which marker types should be shown in the overview
ruler.
protected IAnnotationAccess createAnnotationAccess() {
return new DefaultMarkerAnnotationAccess(fAnnotationPreferences);
}
Consult the implementation of
DefaultMarkerAnnotationAccess
and
MarkerAnnotation
for more detail about presenting markers in the overview ruler.
Text annotations
In addition to showing annotations in the rulers, a source viewer can show
annotations as colored squiggly marks in the text.
We'll look again at the creation of the source viewer in
TextEditor.
protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
...
ISourceViewer sourceViewer= new SourceViewer(parent, ruler, fOverviewRuler, isOverviewRulerVisible(), styles);
fSourceViewerDecorationSupport= new SourceViewerDecorationSupport(sourceViewer, fOverviewRuler, fAnnotationAccess, sharedColors);
configureSourceViewerDecorationSupport();
return sourceViewer;
}
The class
SourceViewerDecorationSupport
handles many of the decorations shown in a source viewer, including text
annotations, colored margins, colored cursor lines, and the like. It is
configured with the user preferences so that it can respond to dynamic updates
of user preference changes. Most editors need not be concerned with the
details of how these decorations are painted. (See
SourceViewerDecorationSupport
and related classes such as
AnnotationPainter
if you must!). The important thing to know is what decorations are
available so that the
SourceViewer
and its supporting
SourceViewerDecorationSupport
are configured correctly.
Configuring a SourceViewerDecorationSupport
Let's look at the configuration used by
TextEditor
for the decoration support.
protected void configureSourceViewerDecorationSupport() {
Iterator e= fAnnotationPreferences.getAnnotationPreferences().iterator();
while (e.hasNext())
fSourceViewerDecorationSupport.setAnnotationPreference((AnnotationPreference) e.next());
fSourceViewerDecorationSupport.setAnnotationPainterPreferenceKeys(DefaultMarkerAnnotationAccess.UNKNOWN, UNKNOWN_INDICATION_COLOR, UNKNOWN_INDICATION, UNKNOWN_INDICATION_IN_OVERVIEW_RULER, 0);
fSourceViewerDecorationSupport.setCursorLinePainterPreferenceKeys(CURRENT_LINE, CURRENT_LINE_COLOR);
fSourceViewerDecorationSupport.setMarginPainterPreferenceKeys(PRINT_MARGIN, PRINT_MARGIN_COLOR, PRINT_MARGIN_COLUMN);
fSourceViewerDecorationSupport.setSymbolicFontName(getFontPropertyPreferenceKey());
}
Note that the annotation preferences are used to define annotation types for
all of the annotations shown in the user preferences. This includes annotations
contributed by any plug-in and is not limited to the workbench-supplied annotations.
If you do not wish to show all available annotations in your editor, you should
override this method and set up the
SourceViewerDecorationSupport
with only those types you want to show.