Mit FXDiagram Editoren der nächsten Generation entwickeln

Diagramme für User

Diagramme für User

Mit FXDiagram Editoren der nächsten Generation entwickeln

Diagramme für User


Die gängigen Eclipse-Frameworks für grafische Editoren sind darauf optimiert, dem Entwickler für möglichst wenig Aufwand möglichst viele Funktionen zu bieten. Stellt man aber statt des Entwicklers den Endbenutzer in den Mittelpunkt, kommt man auf ganz andere Anforderungen und zu einem neuen Framework.

Mit etablierten Eclipse-Frameworks wie GMF, Graphiti oder Sirius kann man relativ schnell einen Diagrammeditor implementieren oder zusammenklicken. Glücklich wird man damit aber nur, wenn man mit den Grundannahmen und Voreinstellungen des jeweiligen Frameworks einverstanden ist. Die oft sehr speziellen Anpassungswünsche der Endanwender sind dann nur mit viel Aufwand und nicht selten nur an den Kernabstraktionen der Frameworks vorbei realisierbar. Der anspruchsvolle Entwickler muss sich also zwangsläufig mit den zugrunde liegenden Basistechnologien auseinandersetzen.

Alle oben genannten grafischen Frameworks bauen auf GEF3 auf. GEF3 hat sich in den letzten zehn Jahren kaum verändert. Führt man sich vor Augen, dass in genau diesem Zeitraum Smartphones, Tablets, AJAX und Windows’ Metro-Oberfläche erfunden wurden, bedeutet das: In der Welt der Eclipse-Diagrammeditoren wurde eine Revolution der Benutzerinterfaces komplett verschlafen! Dabei geht es nicht nur um historisch bedingte technische Einschränkungen der GEF3-Plattform, sondern auch um Userinteraktion und Bedienbarkeit der Editoren. Will man an dieser Ecke ernsthaft etwas ändern, stößt man mit GEF3 und allen darauf basierenden Frameworks schnell an die Grenzen des Machbaren.

Mit JavaFX hat ein neuer Star die UI-Bühne betreten, der alle technischen Voraussetzungen mitbringt, um GEF3 als Basistechnologie abzulösen: ein konsequentes Szenengraph-API zum Definieren lokaler Koordinatensysteme, Animationen und Transitionen, Transparenz und Farbgradienten, Multi-Touch-Support, Hardware-Rendering etc. Natürlich ist JavaFX kein Diagrammframework. So entstand die Idee, eine dünne Abstraktionsschicht für Graphen (sprich Knoten und Kanten) zu bauen, und dann die restliche Funktionalität für einen grafischen Editor mit den Bordmitteln von JavaFX zu implementieren. Das Projekt FXDiagram war geboren.

FXDiagram ist ein Open-Source-Projekt, das seit Ende 2012 bei GitHub unter der Eclipse Public License entwickelt wird. Ein erster Prototyp wurde auf der EclipseCon Europe 2013 vorgestellt. Inzwischen befindet sich das Framework bei Kunden im Einsatz. FXDiagram ist vollständig in der Programmiersprache Xtend geschrieben, was die Entwicklung erheblich vereinfacht (Kasten: „JavaFX loves Xtend“). Das Framework kann aber selbstverständlich auch mit reinem Java verwendet werden. Wie fast alle JavaFX-Frameworks erfordert FXDiagram eine Java-8-Umgebung. Das Basisframework kann in reinen Java-Anwendungen auch ohne OSGi verwendet werden. Für Eclipse und IntelliJ IDEA werden zusätzliche Funktionen mitgeliefert.

JavaFX loves Xtend

Xtend ist eine bei Eclipse entwickelte Programmiersprache, die zu Java-Code kompiliert wird. Da auch Javas Typsystem eins zu eins übernommen wurde, kann Xtend-Code beliebig mit Java-Code im selben Projekt kombiniert werden. Xtend bietet eine kompaktere Syntax und viele zusätzliche Möglichkeiten, das Programmieren mit JavaFX erheblich zu erleichtern. Listing 1 zeigt einige davon:

  • Ein Setter-Aufruf kann einfach als Zuweisung geschrieben werden. Dadurch entsteht eine elegante Initialisierungssyntax für UI-Elemente.
  • Der with-Operator => bindet den linksseitigen Ausdruck an den impliziten Parameter it im darauffolgenden Lambda-Ausdruck. it kann wie this beim Dereferenzieren weggelassen werden.
  • Die Baumstruktur der UI-Elemente spiegelt sich in geschachtelten with-Ausdrücken im Code wider.
  • Dank eines so genannten Extension-Imports kann die statische Hilfsmethode Duration.millis(double) wie eine Methode auf einem double-Literal aufgerufen werden.
  • Mithilfe von Active Annotations kann man aufwändige Programmiermuster wie die in JavaFX üblichen Getter-Setter-Property-Kombinationen einfach vom Compiler erzeugen lassen.

Basisfeatures

Bei FXDiagram stehen der Benutzer und die Interaktion im Mittelpunkt. Diagramme sind für Menschen und müssen daher ansprechend aussehen und mit wenigen eingängigen Aktionen erzeugbar sein. Gutes Design und angenehme intuitive Bedienbarkeit sind also Pflicht.
Wenn möglich, werden in FXDiagram Metaphern aus der realen Welt verwendet (Abb. 1), z. B. sind selektierte Elemente ein bisschen größer und werfen einen Schatten, um ein Schweben über der Arbeitsfläche zu simulieren. Für einen organischen Look werden sanfte Spline-Kurven anstelle von eckigen Polygonzügen verwendet. Die Kontrollpunkte von Bézier-Kurven ziehen diese wie ein Magnet an und werden als solche visualisiert. Solche Metaphern ersparen in vielen Fällen eine Dokumentation im Benutzerhandbuch und machen den Editor „menschlicher“.

Abb. 1: Selektion und Spline-Kurven

Abb. 1: Selektion und Spline-Kurven

Besitzt man einen Laptop mit Trackpad, lässt sich das Diagramm mit Multi-Touch-Gesten scrollen, zoomen und rotieren. Dadurch entsteht eine Haptik, die richtig Spaß macht.

Die Bildschirmfläche soll so weit wie möglich durch das Diagramm ausgefüllt werden. Daher gibt es neben den Magneten noch eine Reihe anderer flüchtiger grafischer Kontrollelemente: Buttons, die nur erscheinen, wenn man mit dem Mauszeiger über einem Knoten verweilt, das grafische Kontextmenü aus dem Projekt Enzo, Hilfslinien zum Ausrichten von Nodes etc.

Um die im Diagramm dargestellten Domänenelemente auszuwählen, setzen viele Frameworks auf komplizierte Dialogfenster. FXDiagram bietet dafür verschiedene grafische Chooser direkt im Diagramm, beispielsweise einen an Mac OS X angelehnten, gestensensitiven CoverFlowChooser (Abb. 2). Mit diesem kann das Diagramm von einem Knoten ausgehend explorativ erweitert werden.

Abb. 2: CoverFlow

Abb. 2: CoverFlow

Da Diagramme häufig zur Dokumentation verwendet werden, können sie als druckfreundliche, skalierbare Vektorgrafiken exportiert werden.

Animationen

Der Benutzer sollte zu jeder Zeit verstehen, was gerade passiert. In herkömmlichen Eclipse-Frameworks gelingt dies nicht immer, beispielsweise erscheint wie aus dem Nichts ein neues Editorfenster, wenn man sich den Inhalt eines Containerknotens ansehen will (drill-down). Da verliert man als Benutzer schnell einmal die Übersicht. FXDiagram vermeidet solch unnötiges Flackern mithilfe von Animationen: Das enthaltene Diagramm erscheint erst verkleinert im Containerknoten, dann wird herangezoomt, während der Container verschwindet. Animationslänge und Effekt sind dabei so justiert, dass der Benutzer nicht genervt wird. Animationen werden auch beim Fokussieren auf ein Element durch ZOOM TO FIT (CMD/STRG-F) oder CENTER (CMD/STRG-C) sowie beim automatischen LAYOUT (CMD/STRG-L) eingesetzt.

Undo- und Redo-Aktionen sind ebenfalls animiert. Dabei wird in jedem Schritt der ursprüngliche Bildausschnitt wiederhergestellt, sodass der Benutzer einfacher den Zeitpunkt identifizieren kann, zu dem die ungewünschte Änderung passiert ist. Als kleines Bonbon kann man mit dem Undo-Redo-Player (CMD/STRG-P) die Entstehung des Diagramms wie einen Film vorwärts und rückwärts ablaufen lassen.

Modelle

Statt neue Konzepte zu definieren, bietet FXDiagram dem Entwickler an vielen Stellen einfach die JavaFX-Schnittstellen an. So erben alle grafischen Elemente von der JavaFX-Basisklasse javafx.scene.Node, auf deren Grundlage fast beliebige Verhaltensmuster implementiert werden können. Mit wenigen Zeilen Xtend-Code kann man etwa einen selektierten Node ähnlich wie in iOS vibrieren lassen (Listing 1). Das einzig FXDiagram-spezifische an diesem Beispiel ist übrigens die JavaFX-Property selectedProperty.

Listing 1

myNode.selectedProperty.addListener [ property, oldVal, newVal |
  if(newVal) {
    node.effect = new RotateTransition => [
      fromAngle = -3
      toAngle = 3
      node = myNode
      duration = 100.millis
      autoReverse = true
      cycleCount = INDEFINITE
    ]
  } else {
    node.effect = null
    node.rotate = 0
  }
]

Vorgefertigte komplexere Funktionen werden als Basisklassen bereitgestellt. So ist zum Beispiel das oben beschriebene Drill-down-Verhalten für Containerknoten in der Klasse BaseDiagramNode gekapselt.

Auch ein separates Diagrammmodell sucht man in FXDiagram vergebens: Der Szenengraph ist das Diagrammmodell. Dadurch fällt nicht nur die fehlerträchtige Synchronisation zwischen den beiden Modellen weg, auch werden keine zusätzlichen Restriktionen an die Diagrammelemente einführt. Eigene Knotenimplementierungen, beispielsweise mit zusätzlichem Animationsverhalten, werden so möglich. Zum Speichern wird der Szenengraph selbst mittels Reflection in ein JSON-Format serialisiert.

In FXDiagram kann das zu visualisierende Domänenmodell in einer beliebigen Technologie vorliegen. Die Anbindung wird in einem technologie- und eventuell auch modellspezifischen DomainObjectDescriptor gekapselt. Statt fester Referenzen auf ein Domänenelement speichert dieser alle Informationen, die notwendig sind, um das Element bei Bedarf wiederherzustellen. Falls dazu eine Transaktion notwendig ist, kann man sie in einer eigenen Implementierung des DomainDescriptorProviders öffnen und schließen. Außerdem sind die Deskriptoren serialisierbar. FXDiagram liefert Deskriptoren für EMF-, Xtext- und IntelliJ-PSI-Modelle bereits mit aus.

Views, Mapping und Eclipse

Nicht für alle Arten von Modellen ist es eine gute Idee, grafische Editoren zu entwickeln. Besonders dann, wenn die Modelle gleichzeitig in einer weiteren Notation editierbar sein sollen – beispielsweise in Xtext –, entstehen in der Benutzung Konflikte, die sich nicht ohne für den Endbenutzer sichtbare Effekte lösen lassen. Der Schweregrad solcher „Usability Glitches“ reicht von kleinen Überraschungen über kryptische Dialoge bis hin zum Datenverlust.

FXDiagram macht daher hier einen klaren Schnitt: Diagramme sind nur in der Hinsicht editierbar, dass die anzuzeigenden Daten gewählt und arrangiert werden können. Auf das zugrunde liegende Domänenmodell wird ausschließlich lesend zugegriffen. Diese zunächst hart anmutende Einschränkung reicht vollkommen aus, wenn man wie mit Xtext oder JDT bereits ein mächtiges Tool zur Änderung der Modelle besitzt.

FXDiagram bietet ein deklaratives Mapping-API, mit dem die Abbildung der Domänenmodellelemente auf die grafischen Konzepte beschrieben wird. Listing 2 zeigt eine XDiagramConfiguration für die Xtext-Beispielsprache State Machine: Die Klasse erbt von AbstractXtextDiagramConfig die Xtext-Anbindung. Die einzelnen Mappings werden als Attribute angelegt: States werden auf Nodes und Transitions auf Connections abgebildet. Durch das Überschreiben der Methode calls() wird für jeden stateNode automatisch der Name des States als Label eingesetzt und je eine transitionConnection für alle ausgehenden Transitions erzeugt. Durch die Methode entryCalls() stellt das Framework im Kontextmenü des Xtext-Editors auf einem State die Aktion ADD TO FXDIAGRAM AS STATE bereit. Die StatemachineDiagramConfig muss nun noch über den Extension Point de.fxdiagram.mapping.fxDiagramConfig angemeldet werden. Weitere Elemente des Mapping-API sind in der Dokumentation auf der Website von FXDiagram beschrieben.

Listing 2

class StatemachineDiagramConfig extends AbstractXtextDiagramConfig {
  val stateNode = new NodeMapping<State>(this, 'stateNode', 'State') {
    override protected calls() {
      stateLabel.labelFor[it] transitionConn.outConnectionForEach[transitions]
    }
  }

  val stateLabel = new NodeHeadingMapping<State>(this, NODE_HEADING) {
    override getText(State it) {
      name
    }
  }

  val transitionConn = new ConnectionMapping<Transition>(this, 'transitionConn', 'Transition') {
    override protected calls() {
      stateNode.source[eContainer as State]
      stateNode.target[state]
    }
  }

  override protected <ARG> entryCalls(ARG domainArgument, MappingAcceptor<ARG> acceptor) {
    if(domainArgument instance State)
      acceptor.add(stateNode, [domainArgument])
  }
}

Wählt der Benutzer in Eclipse eine Aktion ADD TO FXDIAGRAM AS … aus, wird die FXDiagram View geöffnet und ein neues Diagramm initialisiert bzw. es werden die entsprechenden Elemente in ein bereits geöffnetes Diagramm eingefügt. Die View erlaubt auch das Umschalten zwischen mehreren aktiven Diagrammen. Durch Doppelklick im Diagramm wird im Editor das entsprechende Modellelement selektiert und angezeigt.

In der aktuellen Version von FXDiagram gibt es Beispielkonfigurationen für die Xtext-Sprachen Domain Model und State Machine, für PDE Bundle Dependencies, für Java-/Xtend-/Xbase-Klassendiagramme sowie für Ecore-Modelle. Ein ähnliches Tooling existiert für IntelliJ IDEA, wo allerdings bisher nur ein Klassendiagrammeditor für Java realisiert wurde.

Diagram Repair

Ein neues Feature von FXDiagram ist das Reparieren existierender Diagramme, wenn sich das zugrunde liegende Modell geändert hat (Abb. 3). Auf eine automatische Synchronisation wurde aus guten Gründen verzichtet. Die Gefahr ist zu groß, dass dadurch Layoutinformationen verloren gehen, weil das Modell temporär korrupt ist (z. B. beim Editieren eines Xtext-Modells) oder weil Domänenelemente nicht mehr eindeutig zugeordnet werden können (z. B. nach Kopieren und Umbenennen). Stattdessen wählt der Benutzer selbst den Zeitpunkt, zu dem das Diagramm nachgezogen wird. In der Zwischenzeit signalisiert ihm der Editor, welche Elemente sich verändert haben und korrigiert werden können (blinkend), und welche nicht wiederhergestellt werden können (transparent). Dabei kommt die Xtext-Integration sogar mit geänderten Reihenfolgen und unbenannten Elementen klar.

Abb. 3: Diagram Repair: Der im Modell auskommentierte State würde beim nächsten Repair gelöscht

Abb. 3: Diagram Repair: Der im Modell auskommentierte State würde beim nächsten Repair gelöscht

Fazit

Nach über zehn Jahren GEF3 war es Zeit, die Welt der Diagramme auf neue Füße zu stellen. FXDiagram benutzt JavaFX und stellt die Benutzbarkeit der Editoren für den Endnutzer in den Mittelpunkt. Dem Entwickler werden statt schwergewichtiger Abstraktionen reine JavaFX-Schnittstellen bereitgestellt, mit denen er den Editor bis zur Produktreife anpassen kann.

Im Gegensatz zu den meisten anderen Diagrammframeworks konzentriert sich FXDiagram auf das reine Lesen des visualisierten Modells und vermeidet so eine ganze Menge merkwürdiger Effekte. FXDiagram integriert sich sehr gut in Eclipse und erlaubt, Xtext-Sprachen mit zusätzlichen grafischen Views auszustatten.

Obwohl FXDiagram noch in einer 0.x-Version vorliegt, ist es durchaus für die Benutzung bereit, allerdings ist das API noch nicht 100 Prozent auskonvergiert. In Zukunft werden noch einige Features verbessert und hinzugefügt werden, wie die Unterstützung weiterer Container-Nodes oder Ports. Anregungen, Erlebnisberichte und Bugreports sind jederzeit sehr willkommen.

Riskiert man einen Blick über den Tellerrand, sollte man noch zwei weitere neuere Frameworks erwähnen: GEF4 und KLighD. Um einige Entscheidungen aus der Vergangenheit zu korrigieren, bricht GEF4 die Kompatibilität zu GEF3 und basiert jetzt auch auf JavaFX. Im Gegensatz zu FXDiagram liegt der Fokus auf grafischen Modelleditoren; zudem sind die Usabilityaspekte schwächer ausgeprägt und weniger innovativ. KLighD aus dem KIELER-Projekt der Universität Kiel ist ein reines View-Framework. Da die Entwickler an automatischen Layoutalgorithmen forschen, tritt KLighD mit dem Anspruch an, dass die in einem Skript spezifizierten Diagramme nicht von Hand bearbeitet werden müssen. Bei jeder Modelländerung wird daher das gesamte Diagramm neu gezeichnet, und Animationen sorgen für weiche Übergänge.

Aufmacherbild: Shiny color bar graph von Shutterstock / Urheberrecht: Supertrooper

Dr. Jan Köhnlein ist Geschäftsführer von TypeFox, einem Kieler Unternehmen das auf die Entwicklung von Programmierwerkzeugen für Entwicklern und Fachexperten spezialisiert ist. Jan ist der Kopf hinter FXDiagram und Committer in den Open-Source-Projekten Xtext und Xtend.


Weitere Artikel zu diesem Thema