Handbuch
Version 8.0.1 |
Das Graphical Editing Framework (GEF) besteht
aus mehreren Eclipse Plugins, mit deren Hilfe graphische Editoren erstellt werden
können, um damit beliebige Datenmodelle zu visualisieren. Diese Bibliothek ist sehr
populär, so dass QF-Test die Aufnahme und Wiedergabe von GEF Elementen bereits seit
Version 2.2 unterstützt. Dies ist auch ein gutes Beispiel für die Stärke des
ItemResolver
Konzepts (siehe Abschnitt 53.4), denn
das gef
Jython Modul enthält eine Implementierung genau dieser
Schnittstelle.
Das gef
Modul unterstützt GEF-Editoren in generischer Weise und kann
sogar mit mehreren Editoren gleichzeitig umgehen. Zwar werden auch für GMF-Anwendungen
brauchbare Namen für Unterelemente vergeben, doch nicht immer sind diese hinreichend
gut. Je nachdem, wie die zugrunde liegenden Modell-Klassen aussehen, bleibt noch etwas
Arbeit zu tun, nämlich die Implementierung eigener Resolver, die brauchbare Namen und
Werte für die Unterelemente liefern.
Die eigentliche GEF Komponente ist der FigureCanvas
. Dieser stellt
Figures
dar, die EditParts
repräsentieren. Nimmt man einen
Mausklick auf solch ein Element auf, registriert QF-Test nicht bloß ein
'Mausevent' für den Canvas mit entsprechenden (x,y) Werten für die Position,
sondern versucht, das Objekt unter dem Mauscursor zu erkennen. Die aufgenommene
'QF-Test ID der Komponente' sieht zum Beispiel so aus:
canvas@/Diagram/My ship/ShipLargeCargo (wine)
canvas@Connection-2
canvas@/Diagram/Rectangle 16329001
wobei "canvas" die 'QF-Test ID' der FigureCanvas
Komponente ist, gefolgt vom
Element-Index des erkannten EditPart
Objekts (siehe Abschnitt 5.9). EditParts
sind in einer Baumstruktur
organisiert, erkennbar am Pfadtrenner '/'. Die Namen der einzelnen Elemente werden
folgendermaßen abgeleitet:
Man kann sich denken, dass die generierten Namen nicht immer sinnvoll sind. Elemente könnten gelöscht werden und aufgezeichnete Indizes damit ihre Gültigkeit verlieren. Oder der Elementname ist instabil wie bei "Rectangle 16329001" aus dem GEF Shapes Beispiel: Die Zahl ist rein zufällig und wird bei einem Neustart der Anwendung neu ermittelt. Drei Möglichkeiten gibt es, um solche Probleme zu lösen:
/0/1
sagt nichts über das Element aus.
toString()
für das
Datenmodell eines Elements zu liefern. Das würde Ihnen das Leben leicht machen,
aber eben nur, wenn die Entwickler kooperativ sind.
ItemNameResolver2
Schnittstelle. Das ist nicht
ganz einfach, doch leider oft unumgänglich. Dieses Thema wird im nächsten
Abschnitt behandelt.
Wie in Abschnitt 53.1 ausgeführt, ist
ItemNameResolver2
die Schnittstelle, um Namen für Elemente zu ändern
oder überhaupt erst zu definieren. Ein erster Ansatz zur Implementierung ist das
folgende Jython 'SUT-Skript', das unter 'Extrasequenzen'
eingefügt werden kann:
| ||||
Beispiel 53.35: Ein erster GEF ItemNameResolver2 |
Um die Installation des Resolvers zu vereinfachen, wird das in Abschnitt 53.1 beschriebene resolvers
Modul verwendet. Der
Resolver wird auf die Klasse FigureCanvas
registriert, die
EditParts
als Unterlemente enthält. Der von QF-Test generierte Name wird
der Funktion getItemName()
beim Aufruf als drittes Argument übergeben.
Wenn man das Skript nun ausführt und dann den Aufnahmeknopf drückt, werden beim
Überfahren der Elemente mit der Maus - man sollte zuvor ein paar davon erzeugt haben
- Informationen im Terminal von QF-Test ausgegeben, etwa wie folgt:
name: Rectangle 16329001
item: org.eclipse.gef.examples.shapes.parts.ShapeEditPart
model: org.eclipse.gef.examples.shapes.model.RectangularShape
Abgesehen von diesen Ausgaben ist der Resolver ohne Funktion. Die Frage ist nun: Gibt
es im Modell irgendeine Eigenschaft oder Methode, die einen vernüftigen Namen
für das Element liefert? Für das GEF Shapes Beispiel lautet die Antwort: Nein.
Hoffentlich sind Sie mit Ihrer Anwendung in einer besseren Lage. Um das
herauszufinden, fügen Sie der Funktion getItemName()
die Zeile
print dir(model)
hinzu und führen das Skript erneut aus. Nun werden beim Bewegen der Maus über die
Elemente (im Aufnahmenmodus) auch die Methoden des Modells angezeigt. Mit etwas
Glück tauchen hier Methoden wie getId()
oder getLabel()
auf, so dass man einen Resolver wie den folgenden implementieren kann.
| ||||
Beispiel 53.36: Ein einfacher ItemNameResolver2 |
Zurück zum GEF Shapes Beispiel, wo es solche Methoden nicht gibt. Hier sind nur Informationen über die Geometrie verfügbar, doch das ist wenig hilfreich. Zumindest lassen sich aber Rechtecke und Ellipsen unterscheiden. Um die Elementnamen eindeutig zu machen, fügen wir einfach den Index der Figur (des Kind-Knotens) an, wie im folgenden Resolver gezeigt:
| ||||
Beispiel 53.37: Ein ItemNameResolver2 für GEF Shapes |
Mit diesem Resolver wird der Element-Index zu sowas wie
/Diagram/Rectangle 1
wobei die abschließende Zahl der Index des Kind-Knotens ist. Diese Implementierung
liefert auch Namen für die Verbindungen, indem getItemName()
rekursiv
für das Quell- und Zielelement aufgerufen wird. Die Typüberprüfung erfolgt mit der
Methode qf.isInstance
(siehe Abschnitt 49.6), wodurch
einem das Importieren der GEF-Klassen (was nicht ganz einfach ist) erspart bleibt.
Sobald der Resolver funktionstüchtig ist, sollte man das Skript in die 'Vorbereitung' Sequenz packen, direkt hinter den 'Warten auf Client' Knoten. Auf diese Weise wird der Resolver automatisch registriert, wenn man das SUT startet.
Üblicherweise besteht ein GEF Editor aus zwei Teilen. Bislang hatten wir uns auf den
Canvas konzentriert, in den die Figuren gezeichnet werden. Nun werfen wir einen
Blick auf die Palette, in der die Art der zu zeichnenden Figur ausgewählt wird (z.
B. Rechteck, Ellipse oder Verbindung). Die Einträge sehen zwar aus wie Buttons, doch
tatsächlich ist die Palette ebenfalls ein FigureCanvas
.
Erfreulicherweise funktioniert hier alles, ohne dass besondere Vorkehrungen
getroffen werden müssten, d. h. ohne einen ItemNameResolver2
zu
implementieren. Wenn man etwa auf den 'Rectangle' Button klickt, erkennt QF-Test ein
/Palette Root/Palette Container (Shapes)/Palette Entry (Rectangle)
Element. Was wird wohl passieren, wenn man einen 'Object value' Check für diesen Button aufnimmt? Man könnte erwarten, den Text 'Rectangle' zu erhalten, doch tatsächlich ist der Wert des Elements
Palette Entry (Rectangle)
Der Grund dafür ist, dass Name und Wert eines Elements normalerweise gleich sind. Um
dieses Verhalten zu ändern und selbstdefinierte Werte zu erhalten, muss ein
ItemValueResolver2
implementiert werden. Diese Schnittstelle ist der
ItemNameResolver2
Schnittstelle ganz ähnlich. Für die Palette können
wir etwa das Folgende codieren:
| ||||
Beispiel 53.38: Ein ItemValueResolver2 für die GEF Shapes Palette |
Die Methode getLabel()
liefert den Text des Elements, so wie er in der
Palette angezeigt wird.
Letzte Änderung: 10.9.2024 Copyright © 1999-2024 Quality First Software GmbH |