Speichern von Annotationen unter Beachtung des Editiermodus

Anforderung

Oft ist ein "Annotationen speichern" Knopf in der Toolbar gewünscht. Grundsätzlich ist dies kein Problem. Man erstellt sich ein Command in dessen execute-Methode der Speichervorgang ausgelöst wird. Eine Beschreibung, wie der Speichervorgang von Annotationen implementiert werden kann findet sich unter Technische Annotationsdokumentation.
Dieses Beispiel beschäftigt sich im Schwerpunkt jedoch mit einer anderen Frage. Wie kann die Konsistenz der Annotationseigenschaften sichergestellt werden, wenn sich eine Annotation im Editiermodus befindet? Die ernüchternde Antwort lautet schlicht gar nicht! Durch die flexiblen Möglichkeiten, die die Annotationsprofile bieten unterschiedliche AnnotationWrangler und damit beliebige Annotationseditoren zu nutzen, gibt es keinen zuverlässigen Standardweg vor einem Speichervorgang noch nicht bestätigte Änderungen aus einem aktiven Editor in das zugehörige Annotationsobjekt zu übernehmen. Ebenso gibt es keine sichere Entscheidungsbasis, welche der unbestätigten Änderungen automatisch übernommen werden sollen. Ausschließlich vor und nach einem Editiervorgang sind Annotationen in einem konsistenten Zustand, der als Grundlage für einen Speichervorgang geeignet ist. 

Lösungsmöglichkeit

Für einen Anwender ist es nachvollziehbar, dass ein Speichern nur möglich ist, wenn alle Annotationen in einem definierten Zustand sind. Während des Editierens von Annotationen ist dieser Zustand nicht gewährleistet. Daher sollte zu diesen Zeitpunkt ein "Annotationen speichern" Command nicht aktiv sein. Nach dem Schließen des Annotationseditors ist die Annotation wieder in einen zugesicherten Zustand. In diesem Fall kann das  "Annotationen speichern" Command sich wieder aktivieren.

Das folgende Beispiel skizziert dieses suggestive Verhalten. Das Speichern-Command "beobachtet" dabei den Editierzustand der Annotationen im aktuellen Dokument. Auf Basis dessen aktiviert sich das Command nur dann, wenn die Annotationen in einem definierten Zustand sind.  

Beispiel

/**
 * This command requires jadice 5.1.0.4 or newer.
 **/
public class SaveAnnotationCommand extends AbstractDocumentCommand {

  /**
   * Observes the edit mode of annotations.
   * <p>
   * For consistency reasons and in order to finish the editing process before the annotation saving
   * process can be started, this watcher class observes the edit mode of annotations. If an
   * annotation is currently edited, the watcher disables the start of an annotation saving process.
   * When the editing of the annotation is finished, the watcher enables this commend again.
   */
  private class AnnoEditStateWatcher extends DocumentAdapter {
    @Override
    public void pageSegmentModified(PageSegmentEvent evt) {
      if (evt.getLayer() == DocumentLayer.ANNOTATIONS && evt instanceof AnnotationPageSegmentEvent) {
        final AnnotationPageSegmentEvent apse = (AnnotationPageSegmentEvent) evt;
        switch (apse.getEventType()){
          case ACTION_EDIT_ON :
            annnotationsSavable = false;
            propagateContextChange();
            break;

          case ACTION_EDIT_OFF :
            annnotationsSavable = true;
            propagateContextChange();
            break;

          default :
            break;
        }
      }
    }

  }

  private AnnoEditStateWatcher watcher = new AnnoEditStateWatcher();
  private boolean annnotationsSavable = true;


  @Override
  protected void execute() {
    // start anno saving task here...
    System.err.println("Do save annotations...");
    boolean saveAnnotationSuccessful = ...;
    if(saveAnnotationSuccessful) {
       // update command state
       propagateContextChange();
    }
  }

  @Override
  protected boolean canExecute() {
    PageView pv = getPageView();
    if (pv == null) {
      // if there is no page view, we clean up any listener registration of possibly referenced
      // document and remove the document reference as well
      unregisterListener(document);
      document = null;
      annnotationsSavable = false;
      return false;
    }

    Document doc = pv.getDocument();
    if (doc != document) {
      // if a document change happens, we have to unregister the listener of the old referenced
      // document, ...
      unregisterListener(document);
      // ...register it to the new document reference and ...
      registerListener(doc);
      document = doc;
      // ...(re-)init the "annotationsSavable" state
      annnotationsSavable = (document != null);
    }

    // finally return the enabled state of this command
    return document != null && annnotationsSavable && Annotations.isModified(document);
  }

  private void unregisterListener(Document doc) {
    if (doc != null)
      doc.removeDocumentListener(watcher);
  }

  private void registerListener(Document doc) {
    if (doc != null)
      doc.addDocumentListener(watcher);
  }

}