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 command link 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.

Vertical ruler

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.

Vertical overview ruler in Java Editor

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.  

Squiggly mark in Java Editor

We'll look again at the creation of the source viewer in AbstractDecoratedTextEditor.

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 AbstractDecoratedTextEditor 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.