@Override
 public void addAnnotationModelListener(IAnnotationModelListener listener) {
   if (!annotationModelListeners.contains(listener)) {
     annotationModelListeners.add(listener);
     fireModelChanged(new AnnotationModelEvent(this, true));
   }
 }
  /** Removes all annotations. */
  private void clear() {
    AnnotationModelEvent event = new AnnotationModelEvent(this);
    for (final ColorAnnotation ca : annotations) {
      event.annotationRemoved(ca, ca.getPosition());
    }
    annotations.clear();

    fireModelChanged(event);
  }
  /**
   * This method is called, when the document is changed, but the number of lines stays the same.
   *
   * <p>It updates the offset and length of annotations, with an offset greater than the "change
   * offset".
   *
   * @param offset the change offset
   * @param newLength the length of the changed document
   */
  private void changeAnnotations(int offset, int newLength) {
    AnnotationModelEvent modelEvent = new AnnotationModelEvent(this);

    for (ColorAnnotation annotation : annotations) {
      Position pos = annotation.getPosition();
      if (pos.getOffset() > offset) {
        annotation.updateOffset(newLength - docLength);
        modelEvent.annotationChanged(annotation);
      } else if (pos.includes(offset)) {
        annotation.updateLength(newLength - docLength);
        modelEvent.annotationChanged(annotation);
      }
    }
    docLength = newLength;

    fireModelChanged(modelEvent);
  }
  /** Creates the color annotations from the FSTDirectives. */
  private void createAnnotations() {
    AnnotationModelEvent event = new AnnotationModelEvent(this);

    Iterator<FSTDirective> it = validDirectiveList.descendingIterator();
    while (it.hasNext()) {
      FSTDirective dir = it.next();
      try {
        int startline = dir.getStartLine();
        int endline = dir.getEndLine();
        for (int i = startline; i <= endline; i++) {
          if (i < endline || dir.getEndLength() > 0) {
            int lineLength = document.getLineLength(i);
            int lineOffset = document.getLineOffset(i);

            if (i == endline) {
              lineLength = dir.getEndLength();
            }
            if (i == startline) {
              lineOffset += dir.getStartOffset();
              lineLength -= dir.getStartOffset();
            }

            Position newPos = new Position(lineOffset, lineLength);

            if (!annotatedPositions.containsKey(i)) {
              if (!ColorList.isValidColor(dir.getColor())) break;
              ColorAnnotation ca =
                  new ColorAnnotation(
                      dir.getColor(),
                      new Position(lineOffset, lineLength),
                      ColorAnnotation.TYPE_IMAGE);
              annotations.add(ca);
              event.annotationAdded(ca);

              if (highlighting) {
                ca =
                    new ColorAnnotation(
                        dir.getColor(),
                        newPos,
                        i == startline
                            ? ColorAnnotation.TYPE_HIGHLIGHT_OVERVIEW
                            : ColorAnnotation.TYPE_HIGHLIGHT);
                annotations.add(ca);
                event.annotationAdded(ca);
              } else if (i == startline) {
                ca = new ColorAnnotation(dir.getColor(), newPos, ColorAnnotation.TYPE_OVERVIEW);
                annotations.add(ca);
                event.annotationAdded(ca);
              }

              annotatedPositions.put(i, newPos);
            } else if (highlighting) {
              Position oldPos = annotatedPositions.get(i);
              int oldOffset = oldPos.getOffset();
              int oldLength = oldPos.getLength();
              int wholeOffset = oldOffset;
              int wholeLength = oldLength;

              if (oldOffset > lineOffset) {
                ColorAnnotation ca =
                    new ColorAnnotation(
                        dir.getColor(),
                        new Position(lineOffset, oldOffset - lineOffset),
                        ColorAnnotation.TYPE_HIGHLIGHT);
                annotations.add(ca);
                event.annotationAdded(ca);
                wholeOffset = lineOffset;
                wholeLength += oldOffset - lineOffset;
              }
              int newOffset = oldOffset + oldLength;
              int newLength = lineLength - (newOffset - lineOffset);
              if (newLength > 0) {
                newPos.setOffset(newOffset);
                newPos.setLength(newLength);

                ColorAnnotation ca =
                    new ColorAnnotation(dir.getColor(), newPos, ColorAnnotation.TYPE_HIGHLIGHT);
                annotations.add(ca);
                event.annotationAdded(ca);

                wholeLength += newLength;
              }
              annotatedPositions.put(i, new Position(wholeOffset, wholeLength));
            }
          }
        }
      } catch (BadLocationException e) {
        UIPlugin.getDefault().logError(e);
      }
    }

    fireModelChanged(event);
  }
  /** Creates the color annotations from the FSTDirectives. */
  private void createAnnotations() {
    AnnotationModelEvent event = new AnnotationModelEvent(this);

    for (FSTDirective directive : validDirectiveList) {
      if (directive == null) {
        continue;
      }
      try {
        int startline = directive.getStartLine();
        int endline = getLastChildLine(directive, directive.getEndLine());
        final int color = directive.getColor();
        int overViewStartOffset = document.getLineOffset(startline);
        int overViewLength = 0;
        for (int line = startline; line <= endline; line++) {
          int length = document.getLineLength(line);
          if (line < endline || directive.getEndLength() > 0) {
            int lineOffset = document.getLineOffset(line);

            if (line == directive.getEndLine()) {
              length = directive.getEndLength();
            }
            if (line == startline) {
              lineOffset += directive.getStartOffset();
              length -= directive.getStartOffset();
            }

            if (hasChildAtLine(directive, line)) {
              length = 1;
            }

            if (overViewStartOffset != -1 && hasChildAtLineWithColor(directive, line)) {
              Position overViewPos = new Position(overViewStartOffset, overViewLength);
              createOverViewRuler(event, directive, color, overViewPos);
              overViewStartOffset = -1;
              overViewLength = 0;
            } else if (!hasChildAtLineWithColor(directive, line)) {
              if (overViewStartOffset == -1) {
                overViewStartOffset = document.getLineOffset(line);
              }
              overViewLength += document.getLineLength(line);
            }

            FSTDirective parent = directive.getParent();
            while (parent != null) {
              lineOffset++;
              if (length > 1) {
                length--;
              }
              parent = parent.getParent();
            }
            Position newPos = new Position(lineOffset, length);

            if (!hasChildAtLine(directive, line)) {
              // bar at the left of the editor
              ColorAnnotation ca = new ColorAnnotation(color, newPos, ColorAnnotation.TYPE_IMAGE);
              ca.setText(directive.toString());
              annotations.add(ca);
              event.annotationAdded(ca);
            }
            if (!hasChildAtLine(directive, line)) {
              // bar at the right of the editor

            }
            if (highlighting) {
              // background colors
              ColorAnnotation ca =
                  new ColorAnnotation(color, newPos, ColorAnnotation.TYPE_HIGHLIGHT);
              ca.setText(directive.toDependencyString());
              annotations.add(ca);
              event.annotationAdded(ca);
            }
          }
        }
        if (overViewStartOffset != -1) {
          Position overViewPos = new Position(overViewStartOffset, overViewLength);
          createOverViewRuler(event, directive, color, overViewPos);
          overViewStartOffset = -1;
          overViewLength = 0;
        }
      } catch (BadLocationException e) {
        LogService.getInstance().log(LogLevel.DEBUG, e.getMessage());
      }
    }

    fireModelChanged(event);
  }