Implementierung eines Statechart-Editors mit layoutbasierten

Implementierung eines Statechart-Editors mit layoutbasierten
Christian-Albrechts-Universität zu Kiel
Diplomarbeit
Implementierung eines
Statechart-Editors mit layoutbasierten
Bearbeitungshilfen
cand. inform. Florian Lüpke
13. Juni 2005
Institut für Informatik und Praktische Mathematik
Lehrstuhl für Echtzeitsysteme und Eingebettete Systeme
Prof. Dr. Reinhard von Hanxleden
betreut durch:
Steffen H. Prochnow
ii
Eidesstattliche Erklärung
Hiermit erkläre ich an Eides Statt, dass ich die vorliegende Arbeit selbstständig
verfasst und keine anderen als die angegebenen Hilfsmittel verwendet habe.
Kiel,
iv
Zusammenfassung
Im Projekt Kiel Integrated Environment for Layout (KIEL) wird ein Werkzeug
zur Darstellung, Erstellung, Veränderung und Simulation von Statecharts entwickelt. Besonderes Augenmerk wird im KIEL-Projekt auf automatisiert angewendetes Layout und innovative benutzerfreundliche Darstellungsformen und Techniken
bei der Simulation und Bearbeitung von Statecharts gelegt.
Die vorliegende Diplomarbeit beschäftigt sich mit dem Design und der Implementierung eines Statechart-Editors als Teil von KIEL. Hierfür werden die am
Markt verfügbaren Graph-Editing-Frameworks dahingehend untersucht, in wieweit sie für die Implementierung eingesetzt werden können. Auf Basis des Rahmenwerks JGraph werden dann neben grundlegenden Bearbeitungsfunktionen innovative und bisher in diesem Kontext nicht angewendete Bearbeitungshilfen implementiert und evaluiert. Hierzu zählen die gleitende Strukturveränderung bei
automatisiert erfolgenden Layoutmaßnahmen und Platzierungsmechanismen, die
Anzeige und das visuelle Abspielen der Bearbeitungsschritt-Historie, mehrschichtige transparente Übersichtsdarstellungen und die farbliche Syntaxprüfung. Dabei
sollen sich die Anzeigemodalitäten des Editors an denen von Esterel-Studio orientieren in Bezug auf die Darstellung der Diagramm-Elemente. Daneben werden
wohlbekannte Funktionen wie das Kollabieren und Expandieren von Zuständen,
Diagrammelementtyp-Morphing, rasterorientiertes Bearbeiten, automatische Layouts und syntaxgerichtetes Editieren auf hoher Abstraktionsebene implementiert.
Neben diesen funktionalen Merkmalen wird in besonderem Maße die Realisierung
einer ergonomischen Benutzeroberfläche, einer intuitiven und komfortablen Bedienbarkeit, Mehrsprachigkeit und vielseitigen Konfigurierbarkeit der Anwendung
angestrebt.
vi
Vorwort
Die vorliegende Diplomarbeit entstand im Rahmen des KIEL-Projektes, welches an der Christian-Albrechts-Universität zu Kiel am Lehrstuhl für Echtzeitsysteme und Eingebettete Systeme durchgeführt wird. Herrn Prof. Dr.
Reinhard von Hanxleden danke ich für abschließende Hinweise zu dieser Arbeit. Mein besonderer Dank gilt dem Betreuer dieser Arbeit, Herrn Dipl.
Inform. Steffen H. Prochnow, der eine sehr produktive und angenehme Projektumgebung geschaffen hat, mir eine optimale technische Unterstützung
geboten hat sowie sich in zahlreichen und langen Gesprächen vor allem sehr
viel Zeit für die Betreuung genommen hat und Engagement in diese Arbeit
investiert und viel Geduld mit mir gehabt hat.
vii
viii
Inhaltsverzeichnis
1. Einführung
1.1. Ausgangslage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2. Ziel der Arbeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.3. Aufbau und Überblick . . . . . . . . . . . . . . . . . . . . . . . . .
1
1
1
3
2. Theoretische Grundlagen
2.1. Reaktive Systeme . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2. Endliche Automaten als Grundlage der Modellierung Reaktiver Systeme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3. Grundlagen der Visualisierung Reaktiver Systeme . . . . . . . . . .
2.3.1. Graphen . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3.2. Statecharts . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3.3. Safe-State-Machines . . . . . . . . . . . . . . . . . . . . . .
2.4. Vorgehensmodelle zur Softwareentwicklung und Entwurfsmuster . .
2.4.1. Unified Modelling Language . . . . . . . . . . . . . . . . . .
2.4.2. Softwareentwicklung Best-Practices . . . . . . . . . . . . . .
2.4.3. Entwurfsmuster . . . . . . . . . . . . . . . . . . . . . . . . .
5
6
7
8
9
9
14
15
16
17
18
3. Stand der Technik
3.1. Analyse existierender Statechart-Editoren . . . . . . . . .
3.1.1. Grundlegende Funktionen von Statechart-Editoren
3.1.2. Esterel-Studio . . . . . . . . . . . . . . . . . . . . .
3.1.3. Matlab / Simulink / Stateflow . . . . . . . . . . . .
3.1.4. ArgoUML . . . . . . . . . . . . . . . . . . . . . . .
3.1.5. Poseidon For UML . . . . . . . . . . . . . . . . . .
3.1.6. Ergebnis . . . . . . . . . . . . . . . . . . . . . . . .
3.2. Evaluierung verfügbarer Graph-Editing-Frameworks . . . .
3.2.1. Anforderungen . . . . . . . . . . . . . . . . . . . .
3.2.2. Übersicht über Graph-Editing-Frameworks . . . . .
3.2.3. Ergebnis . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
21
21
21
22
24
28
29
30
30
31
34
34
.
.
.
.
39
40
43
43
43
4. Anforderungsspezifikation des KIEL-Editors
4.1. Syntaxgerichtetes Editieren . . . . . . .
4.2. Graphische Darstellung eines Statecharts
4.3. Anwendung von verschiedenen Layouts .
4.4. Modellorientierung . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
ix
Inhaltsverzeichnis
4.5. Verstecken innerer Zustände . . . . . . . . . . . . . . . . . .
4.6. Layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.7. Layoutgestützte gleitende Strukturveränderung . . . . . . .
4.8. Rasterorientiertes Bearbeiten . . . . . . . . . . . . . . . . .
4.9. Nachvollziehbarkeit von Bearbeitungsschritten . . . . . . . .
4.10. Mehrschichtige Übersichtsdarstellungen . . . . . . . . . . . .
4.11. Farbliche Syntaxprüfung . . . . . . . . . . . . . . . . . . . .
4.12. Positionierungshilfen und Ausrichtungshilfen . . . . . . . . .
4.13. Layouthilfen während der Bearbeitung . . . . . . . . . . . .
4.14. Undo-and-Redo . . . . . . . . . . . . . . . . . . . . . . . . .
4.15. Cut-and-Paste . . . . . . . . . . . . . . . . . . . . . . . . . .
4.16. Zoom und Ausschnittsänderung . . . . . . . . . . . . . . . .
4.17. Diagrammelementtyp-Morphing . . . . . . . . . . . . . . . .
4.18. Änderung von Transitionsprioritäten . . . . . . . . . . . . .
4.19. Ansprechendes Benutzeroberflächendesign . . . . . . . . . .
4.20. KIEL-Anwendungsfenster . . . . . . . . . . . . . . . . . . .
4.21. Intuitive Bedienbarkeit . . . . . . . . . . . . . . . . . . . . .
4.21.1. Erzeugung neuer Diagrammelemente . . . . . . . . .
4.21.2. Selektion und Manipulation von Diagrammelementen
4.22. Konfigurierbarkeit . . . . . . . . . . . . . . . . . . . . . . .
4.23. Bearbeitungsschritt-Historie . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
44
44
45
46
46
47
49
49
50
50
50
51
51
51
52
53
55
56
57
58
59
5. Umsetzung und Implementierung
5.1. Vorgehensweise . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2. Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2.1. Rahmenbedingungen . . . . . . . . . . . . . . . . . . . . . .
5.2.2. Entscheidungsfaktoren . . . . . . . . . . . . . . . . . . . . .
5.2.3. Ergebnisse . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.3. Implementierung . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.3.1. Erweiterung des JGraph-Rahmenwerks . . . . . . . . . . . .
5.3.2. Datenmodell-Transformation zwischen KIEL und JGraph .
5.3.3. Datenmodell-Änderungen . . . . . . . . . . . . . . . . . . .
5.3.4. Editoreigene Layoutmechanismen . . . . . . . . . . . . . . .
5.3.5. Layout-Änderungen . . . . . . . . . . . . . . . . . . . . . .
5.3.6. Layoutgestützte gleitende Strukturveränderung . . . . . . .
5.3.7. Nebenläufigkeit . . . . . . . . . . . . . . . . . . . . . . . . .
5.3.8. Bearbeitungsschritt-Historie und Undo-and-Redo-Funktionalität . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
61
61
62
62
65
68
74
74
77
78
82
83
83
84
6. Schlussbemerkungen
6.1. Ergebnisse . . . . . . . . . . . . . . . . . . . . . . .
6.2. Ausblick . . . . . . . . . . . . . . . . . . . . . . . .
6.2.1. Multidimensionale Undo-and-Redo-Historie
6.2.2. Speichern der Undo-and-Redo-Historie . . .
87
87
88
88
89
x
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
85
Inhaltsverzeichnis
6.2.3.
6.2.4.
6.2.5.
6.2.6.
Bearbeitung von Transitionsbeschriftungen
Erweitertes Diagrammelementtyp-Morphing
Erweiterter Zoom und Ausschnittsänderung
Layouthilfen während der Bearbeitung . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
90
90
90
90
7. Literaturverzeichnis
.1. Funktionsumfang . . . . . . . . . . . . . . . . . . . .
.1.1. Allgemeine Editorfunktionen . . . . . . . . .
.1.2. Funktionen zur Bearbeitung eines Statecharts
.2. Benutzungshinweise für Editorfunktionen . . . . . .
.2.1. Einstellungen . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
93
. 97
. 97
. 99
. 101
. 104
A. Java-Programm-Quelltext
A.1. Überblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
A.1.1. Package kiel.editor . . . . . . . . . . . . . . . . . . .
A.1.2. Package kiel.editor.controller . . . . . . . . . . . .
A.1.3. Package kiel.editor.graph . . . . . . . . . . . . . . .
A.1.4. Package kiel.editor.resources . . . . . . . . . . . . .
A.2. Zusammenspiel der Klassen . . . . . . . . . . . . . . . . . . . .
A.2.1. Kommunikation zwischen View und Controller . . . . .
A.2.2. Kommunikation von Controller nach Model . . . . . . .
A.2.3. Struktur der View -Klassen . . . . . . . . . . . . . . . .
A.2.4. Der UndoClusterManager . . . . . . . . . . . . . . . . .
A.3. Erweiterungs- und Anpassungsmöglichkeiten . . . . . . . . . . .
A.3.1. Änderung eines Editor-Menüeintrags . . . . . . . . . . .
A.3.2. Ändern der Menüstruktur im KIEL-Anwendungsfenster
A.3.3. Erweiterung um andere Statechart-Dialekte . . . . . . .
A.4. Der Quelltext . . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
111
111
111
112
113
114
114
114
115
115
116
116
116
116
117
118
xi
Inhaltsverzeichnis
xii
Tabellenverzeichnis
3.1. Funktionale und projekttechnische Anforderungen . . . . . . . . . .
35
xiii
Tabellenverzeichnis
xiv
Abbildungsverzeichnis
2.1.
2.2.
2.3.
2.4.
Zustände eines TV-Gerätes
Zustände eines TV-Gerätes
Parallelität: AND-State . .
Zustandsbeschriftungen . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3.1. Die Esterel-Studio-Werkzeugleiste für das Erzeugen von Diagrammelementen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2. Ein Beispiel-Statechart aus Stateflow . . . . . . . . . . . . . . . . .
3.3. Anzeige der Actions eines Zustands in Stateflow . . . . . . . . . . .
3.4. Die Stateflow -Werkzeugleiste für die Auswahl von Diagrammelementen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
10
12
13
23
26
27
27
4.1. Ein Referenzbeispiel . . . . . . . . . . . . . . . . . . . . . . .
4.2. Layoutgestützte gleitende Strukturveränderung . . . . . . . .
4.3. Anzeige des Bearbeitungsrasters . . . . . . . . . . . . . . . . .
4.4. Ein Trace-Log von drei Benutzeraktionen . . . . . . . . . . . .
4.5. Die Werkzeugleiste zum Abspielen von Bearbeitungsschritten
4.6. Bearbeitungsschicht und Übersichtsschicht . . . . . . . . . . .
4.7. Zoomregler zur gleitenden Einstellung des Zoomfaktors . . . .
4.8. Ausblendbarkeit von Werkzeugleisten-Elementen . . . . . . .
4.9. Fließende Benutzeroberflächen-Komponenten . . . . . . . . .
4.10. Kontext-Menü zu einem OR-State als Popup-Menü . . . . . .
4.11. Kontext-Menü zu einer Transition als Popup-Menü . . . . . .
4.12. Mehrsprachigkeit . . . . . . . . . . . . . . . . . . . . . . . . .
4.13. Verschiedene Mauszeiger . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
39
45
46
47
47
48
51
52
53
54
55
56
58
5.1.
5.2.
5.3.
5.4.
5.5.
5.6.
5.7.
5.8.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
63
64
69
71
72
73
75
79
6.1. KIEL im Editor-Modus . . . . . . . . . . . . . . . . . . . . . . . .
88
Projektstruktur . . . . . . . . . . . . . . . . . . . . . . . . . .
KIEL-Datenstruktur . . . . . . . . . . . . . . . . . . . . . . .
Das Model-View-Controller -Entwurfsmuster . . . . . . . . . .
Der Controller des MVC -Musters . . . . . . . . . . . . . . . .
Entkopplung der KIEL-Komponenten . . . . . . . . . . . . .
Benachrichtigungsmechanismus bei Konfigurationsänderungen
Erweiterung des JGraph-Rahmenwerks . . . . . . . . . . . . .
Hinzufügen einer Delimiter-Line . . . . . . . . . . . . . . . .
xv
Abbildungsverzeichnis
.1.
.2.
.3.
.4.
.5.
Ausschnitt aus der Werkzeugleiste des Editors
Konfigurationsdialog . . . . . . . . . . . . . .
Unterdrückbare Fehlermeldung . . . . . . . .
Anzeige der Bearbeitungsschritte . . . . . . .
Anzeige der Events . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. 97
. 98
. 99
. 100
. 105
A.1. Ausschnitt aus einer Controller -Klasse . . . . . . . . . . . . . . . . 115
A.2. Das File-Menü . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
A.3. Das Hauptmenü . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
xvi
Verzeichnis der Abkürzungen
AWT
GUI
JVM
kByte
KIEL
MVC
NEA
OOAD
SSM
SVG
UML
XML
Abstract-Windowing-Toolkit
Graphical-User-Interface
Java-Virtual-Maschine
kilo Byte
Kiel Integrated Environment for Layout
Model-View-Controller -Entwurfsmuster
Nichtdeterministischer Endlicher Automat
Objektorientierte Analyse und Design
Safe-State-Machine
Scalable Vector Graphics
Unified Modelling Language
Extensible Markup Language
xvii
Abbildungsverzeichnis
xviii
1. Einführung
1.1. Ausgangslage
Das Kiel Integrated Environment for Layout Projekt (KIEL) [46] entwickelt ein
Werkzeug zur Darstellung, Erstellung, Veränderung und Simulation von Statecharts. Diese sind eine Diagrammform zur Darstellung des Zustandsverhaltens
von eingebetteten Systemen, welche auf ihre Umwelt reagieren. Unter eingebetteten Systemen – auch Reaktive Systeme genannt – versteht man Computer, die
als solche nicht erkennbar sind, weil sie in technischen oder mechanischen Geräten eingebaut sind. Daneben werden Statecharts auch in der Softwareentwicklung
im Bereich der objektorientierten Analyse und Design (OOAD) eingesetzt, um
das Zustandsverhalten von einzelnen Objekten zu modellieren. KIEL gehört zur
Gruppe der so genannten Statechart-Werkzeuge, zu der auch Softwareprodukte
wie Esterel-Studio und Statemate gezählt werden. Besonderes Augenmerk wird
im KIEL-Projekt auf automatisiert angewendetes Layout und innovative benutzerfreundliche Darstellungstechniken und Eingabehilfen bei der Simulation und
Bearbeitung von Statecharts gelegt.
Die KIEL-Anwendung beinhaltet neben einem Browser, welcher Statecharts anzeigt [50], auch eine Dateischnittstelle, welche es erlaubt, Statecharts aus EsterelStudio zu importieren. Später soll im Esterel-Studio-Format auch exportiert werden
können und es sollen Anbindungen zu weiteren Statechart-Werkzeugen hinzukommen.
1.2. Ziel der Arbeit
Die vorliegende Diplomarbeit beschäftigt sich mit dem Entwurf und der Implementierung eines Statechart-Editors für die KIEL-Anwendung. In diesem sollen Statecharts erzeugt und bearbeitet werden können. Neben grundlegenden Bearbeitungsfunktionen sollen innovative und bisher im Kontext der Statechart-Bearbeitung
nicht angewendete Bearbeitungshilfen implementiert und daraufhin evaluiert werden. Dabei sollen sich die Anzeigemodalitäten des Editors an denen von EsterelStudio in Bezug auf die Darstellung der Diagrammelemente orientieren.
Ziel dieser Arbeit ist die Erstellung einer lauffähigen Software, die eine Evaluation sämtlicher implementierter Funktionalitäten ermöglicht. Hierzu ist als Vorarbeit
auf der einen Seite die Analyse am Markt verfügbarer Statechart-Editoren notwendig. Der Funktionsumfang dieser Editoren soll eingeteilt werden in Grundfunktionalitäten und darüber hinausgehende Merkmale, durch welche sich der jeweilige
1
1. Einführung
Editor von anderen am Markt etablierten Produkten absetzt. Auf der anderen
Seite ist eine Evaluierung verfügbarer Graph-Editing-Frameworks durchzuführen,
um bei der Implementierung des Editors nicht grundlegende Editor-Mechanismen
entwickeln zu müssen.
Der aus dieser Arbeit hervorgehende Editor weist die grundlegenden Bearbeitungsfunktionen anderer Statechart-Editoren auf und verwertet zusätzliche Ideen
und Arbeiten aus einem Forschungsgebiet dieses Lehrstuhls, deren Anwendbarkeit
und Nutzen in der vorliegenden Arbeit nach der Fertigstellung des Editors von Benutzern evaluiert werden sollen. Zusammengefasst soll der zu entwickelnde Editor
folgende Merkmale aufweisen, die in Kapitel 4 näher erläutert werden:
• Grundlegende Bearbeitungsmöglichkeiten von Statechart-Diagrammen: Diagrammelemente erzeugen, löschen, beschriften, verschieben und größenändern
• Syntaxgerichtetes Editieren von Statecharts
• Modellorientiert: Unterscheidung zwischen verschiedenen Statechart-Dialekten
• Komposition von Diagrammelementen, deren graphische Repräsentationen
in SVG definiert sind
• Anwendung von Layouts auf verschiedene Sichten eines Statecharts
• Intelligente Bearbeitungstechniken:
– Verstecken innerer Zustände
– Layout
– Layoutgestützte gleitende Strukturveränderung (engl. Morphing)
– Rasterorientiertes Bearbeiten (engl. Snapping)
– Nachvollziehbarkeit von Bearbeitungsschritten
– Mehrschichtige Übersichtsdarstellungen (engl. Layering)
– Farbliche Syntaxprüfung
Neben den obigen Merkmalen, welche von KIEL gefordert werden, wird das
weitere Ziel verfolgt, die Qualität des äußeren Erscheinungsbilds und den Funktionsumfang etablierter Statechart-Editoren nachzubilden. Hierfür soll der Editor
folgende weitere Funktionsmerkmale aufweisen:
• Ansprechendes Benutzeroberflächendesign nach ergonomischen Richtlinien
und Standards
• Bereitstellung eines Anwendungsfensters als Rahmen für die KIEL-Komponenten Editor und Browser
2
1.3. Aufbau und Überblick
• Ausrichtungshilfen für die relative Anordnung von Diagrammelementen
• Layouthilfen zum Einfügen von Diagrammelementen (automatisiertes PlatzSchaffen)
• Undo-and-Redo
• Cut-and-Paste
• Zoom
• Typmorphing von Diagrammelementen
• Mehrsprachigkeit (Englisch / Deutsch)
• ausblendbare Hinweismeldungen für Systemereignisse und aufgetretene Fehler, Hinweise zu Werkzeugleistenelementen (engl. Tooltips), optische Unterstützung bei Bearbeitungsschritten durch unterschiedliche Mauszeiger
• Konfigurierbarkeit: Unter anderem Ausblendbarkeit von Beschreibungselementen und Diagrammelement-Beschriftungen, Änderbarkeit von Farben, initialen Diagrammelement-Größen, Zoomfaktor und Morphing-Geschwindigkeit
• Bearbeitungsschritt-Historie
• Verschiedene Graphik-Exportformate
• Druck-Funktionalität
• Hervorhebung selektierter Diagrammelemente in allen Ansichtsschichten zur
besseren Orientierung
1.3. Aufbau und Überblick
In der vorliegenden Arbeit werden im Anschluß an dieses Kapitel die theoretischen Grundlagen geschaffen (Kapitel 2), welche zum Verständnis der Zielbeschreibung und des Lösungswegs notwendig sind. Hiernach werden zum einen SoftwareProdukte – sogenannte Rahmenwerke – vorgestellt, welche als Basis zur Entwicklung eines Statechart-Editors verwendet werden können (Abschnitt 3.2). Zum anderen werden am Markt verfügbare Statechart-Werkzeuge analysiert, welche ähnliche
Funktionsmerkmale bieten wie die in dieser Arbeit entwickelte Software (Abschnitt
3.1). Ziel des Kapitels 3 soll die Vermittlung dessen sein, was Stand der Technik
ist und soll somit einen Einblick in andere Lösungsstrategien geben. Anschließend
werden die funktionalen Anforderungen an die in dieser Arbeit zu entwickelnde
Software vorgestellt (Kapitel 4), bevor dann der Weg zur Lösung der gestellten
Aufgaben aufgezeigt wird (Kapitel 5). Dieser Weg umfasst neben der Festlegung
auf eine Vorgehensweise (Abschnitt 5.1) auch die Entwicklung des Software-Designs
3
1. Einführung
(Abschnitt 5.2) und seiner Implementierung (Abschnitt 5.3). Abschließend werden
in den Schlussbemerkungen die Ergebnisse, die Bewertung der gefundenen Lösung
sowie ein Ausblick auf Erweiterungsmöglichkeiten vorgestellt (Kapitel 6).
Im Anhang findet sich neben einem Benutzerhandbuch auch der gesamte Programm-Quelltext des Editors.
4
2. Theoretische Grundlagen
Nach einer Erläuterung des Begriffs Reaktive Systeme in Abschnitt 2.1 werden in
diesem Kapitel formale Beschreibungen für solche Systeme vorgestellt. Die Grundlage der Modellierung Reaktiver Systeme bildet der Formalismus der Statecharts,
welche in Abschnitt 2.3.2 vorgestellt werden. Diese bauen auf den Endlichen Automaten auf, welche im Abschnitt 2.2 behandelt werden. Eine Erweiterung der
Statecharts bilden die Safe-State-Machines in Abschnitt 2.3.3. Diese werden in
KIEL modelliert und sind daher insbesondere interessant für die Implementierung
des KIEL-Editors. Der Editor baut in seiner Implementierung auf einem so genannten Graph-Editing-Framework auf. Daher werden im Abschnitt 2.3.1 Graphen kurz
vorgestellt, um als Vorbereitung auf den Abschnitt 3.2 über die Evaluierung von
Graph-Editing-Frameworks zu dienen. Das Design und die Implementierung des
KIEL-Editors sollen sich an Vorgehensmodellen der Softwareentwicklung orientieren und Entwurfsmuster einsetzen. Die Grundlagen hierfür werden in Abschnitt
2.4 behandelt.
In den folgenden Abschnitten werden formale Beschreibungen für Systeme vorgestellt, welche diskrete Eingaben, Ausgaben und Zustände besitzen. Jedes solcher
Systeme kennt eine nur endliche Menge von Zuständen, und für jede mögliche
Eingabe während jedes Zustands ist ein Folgezustand definiert. Ist höchstens ein
Folgezustand oder eine Zustandskombination definiert, so spricht man von deterministischen Modellen. Hieraus folgt, dass ein Zustand durch bestimmte Eingaben
in einer definierten Reihenfolge erreicht wird und jeder Zustand die Reaktion auf
folgende Eingaben beschreibt.
Nahezu alle technischen Geräte des täglichen Lebens können als solche Systeme
aufgefasst und beschrieben werden. Diese Geräte reagieren in Abhängigkeit ihres
aktuellen Zustands auf ihre Umwelt, häufig ist dies ein Mensch. Das Fernsehgerät
ist ein Beispiel für ein System mit einer endlichen Anzahl von Zuständen, welches
auf Eingaben reagiert und seinen Zustand ändert: In Abhängigkeit von getätigten Eingaben befindet sich das Gerät entweder im Zustand Normalbetrieb oder
im Zustand Videotext-Anzeige. Daneben existieren die möglichen Zustände Ton
eingeschaltet und Ton ausgeschaltet. In Abhängigkeit davon, welche Eingaben als
nächste erfolgen, wird z. B. der Kanal oder die Lautstärke geändert oder das Gerät
in den Zustand ausgeschaltet versetzt.
Formal besitzt dieses System:
• eine endliche Menge von Zuständen (z. B. Videotext-Anzeige),
• eine endliche Menge von Zustandsübergängen, ausgelöst durch eine Eingabe
(z. B. das Umschalten auf Videotext-Anzeige mit Videotext-Button auslösen),
5
2. Theoretische Grundlagen
• eine Menge von Aktionen (z. B. Lautstärke ändern) und
• einen Startzustand sowie einen Endzustand (z. B. Fernsehgerät ausgeschaltet).
Hierbei ist anzumerken, dass das Verhalten, beziehungsweise die Aktionen, unterschiedlich mit Zuständen und Zustandsübergängen assoziiert sein können. In
Abschnitt 2.3 wird für diese Zustandsbeschreibung des Systems Fernsehgerät eine
graphische Notation in Form eines so genannten Statecharts vorgestellt. Abbildung
2.3 stellt diese Zustandsbeschreibung in Form eines Statecharts dar.
Beispiele für Systeme mit endlichen Zustandsmengen finden sich auch in der
Informatik. Die Automatentheorie, ein Teilgebiet der Theoretischen Informatik,
beschäftigt sich mit der Untersuchung der Eigenschaften solcher Systeme und entwickelt hierfür passende Modelle, welche Automatenmodelle oder kurz Automaten
genannt werden, z. B. den von Mealy und Moore eingeführten Endlichen Automaten und die von Harel eingeführten Statecharts. Neben der Beschreibung von
Reaktiven Systemen, wie z. B. dem Fernsehgerät, eignet sich die Automatentheorie
z. B. auch zur Analyse von Algorithmen und zur Beschreibung von regulären Ausdrücken. Grundsätzlich kann das Modell des Endlichen Automaten zur Lösungsfindung von Problemen verwendet werden, welche sich mittels einer endlichen Zahl
von Zuständen darstellen lassen. In solch einer Darstellung wird nach einer Reihe
von Eingaben gesucht, welche dazu führen, dass der Automat aus einem Startzustand heraus über Zwischenzustände einen bestimmten gewünschten Endzustand
erreicht. Der Vorteil des Einsatzes von Automatenmodellen liegt also darin, dass sie
sich auf der einen Seite für den Einsatz in vielfältigen Aufgabenstellungen eignen
und auf der anderen Seite schon sehr umfassend erforscht sind, somit die Kenntnis
ihrer Charakteristika der Lösungsfindung vielfältiger Problemstellungen dient.
Automatenmodelle, z. B. die Endlichen Automaten, können graphisch in Form
von Zustandsdiagrammen dargestellt werden. Eine Form von erweiterten Zustandsdiagrammen sind Statecharts. Zustandsdiagramme eignen sich nicht nur für oben
genannte Einsatzgebiete sondern auch zur Beschreibung von Softwaresystemen und
sind daher auch Teil der Unified Modelling Language (UML) [35], siehe Abschnitt
2.4.1. Zustandsdiagramme werden seit einigen Jahren in Softwareentwicklungsprojekten häufig eingesetzt neben anderen UML-Diagrammformen wie Klassendiagrammen und Sequenzdiagrammen, auf die hier jedoch nicht näher eingegangen
wird. Bei der Modellierung von objektorientierten Softwaresystemen werden Zustandsdiagramme genutzt, um die Folge von Zuständen darzustellen, welche ein
Objekt während der Programmlaufzeit einnehmen kann und aufgrund welcher Ereignisse Zustandsänderungen stattfinden [36].
2.1. Reaktive Systeme
Der Begriff der Reaktiven Systeme bezeichnet Systeme, die permanent mit ihrer
Umwelt kommunizieren und interagieren. Charakteristisch ist hierbei, dass Reak-
6
2.2. Endliche Automaten als Grundlage der Modellierung Reaktiver Systeme
tive Systeme auf Ereignisse aus ihrer Umwelt reagieren, und daher ihr Verhalten in
hohem Maße von der Umwelt abhängt. Reaktive Systeme bestehen häufig aus voneinander unabhängig entwickelten Teilsystemen, welche ihrerseits wiederum vielfach Reaktive Systeme sind und untereinander kommunizieren, oder sie lassen sich
willkürlich hierarchisch gliedern in Subsysteme. Einen hohen Grad an Nebenläufigkeit weisen Reaktive Systeme häufig auf, da einerseits die Teilsysteme parallel
ausgeführt werden und andererseits das Gesamtsystem parallel zu seiner Umgebung abläuft, und die Umgebung wiederum unter Umständen als ein Reaktives
System interpretiert werden kann.
Die Steuereinheiten technischer Vorgänge z. B. in Fahrzeugen sind ebenso Reaktive Systeme wie Betriebssysteme und graphische Benutzeroberflächen. Die Anforderungen, welche in diesen Einsatzbereichen gestellt werden bezüglich der Kommunikation und Reaktion des Systems auf seine sich ständig wechselnde Umgebung,
werden durch herkömmliche transformationelle Systeme nicht erfüllt. Transformationelle Systeme unterscheiden sich von Reaktiven Systemen darin, dass erstere
nur eine begrenzte Laufzeit haben und nur in geringerem Maße mit ihrer Umwelt
interagieren.
Der hohe Grad an Kommunikation zwischen den Teilsystemen untereinander und
mit der Systemumgebung bedeutet ein erhöhtes Maß an Aufwand bei der Spezifikation und Implementierung solcher Systeme. Daher wurden spezielle Formalismen
entwickelt, welche die typischen Eigenschaften dieser Systeme, z. B. Hierarchie,
Parallelität und Interaktion, darzustellen vermögen. Zu diesen Formalismen gehören z. B. Prozessalgebren [16], Petrinetze, Ereignisstrukturen sowie graphische
Spezifikationssprachen wie Message-Sequence-Charts, Statecharts und die dynamischen Modelle der UML (Abschnitt 2.4.1). Die vorliegende Arbeit beschäftigt sich
ausschließlich mit Statecharts, diese werden in Abschnitt 2.3.2 vorgestellt.
2.2. Endliche Automaten als Grundlage der
Modellierung Reaktiver Systeme
Der Endliche Automat ist eine formale Beschreibung eines Systems, welches sich zu
jedem Zeitpunkt in genau einem Zustand befindet, welches insgesamt eine endliche
Zahl von Zuständen kennt und welches Eingaben verarbeitet und Ausgaben liefert.
Eingaben können externe Ereignisse sein und Ausgaben können z. B. in Textform
erfolgen. Das Modell des Endlichen Automaten besteht daher aus einer Menge von
Zuständen und einer Zustandsüberführungsfunktion, welche einem Paar, bestehend aus Ereignis, auch Eingabe genannt, und einem Zustand einen neuen Zustand
und optional eine Ausgabe zuordnet [22]. Solch eine Funktion beschreibt also das
Reaktionsverhalten eines Systems in Form von Zustandsänderungen. Den Übergang von einem Zustand zu einem anderen bezeichnet man als Zustandsübergang
oder Transition. Ein Zustandsübergang tritt als Reaktion auf ein äußeres Ereignis
auf. Bei einer Softwareanwendung ist dies z. B. bei einer Benutzeraktion der Fall.
Des Weiteren kennt ein Endlicher Automat einen Startzustand und eine Menge
7
2. Theoretische Grundlagen
von Endzuständen. Erreicht ein Automat durch geeignete Eingaben einen dieser
Endzustände, so sagt man, dieser Automat habe die Eingaben in der erfolgten
Reihenfolge akzeptiert. Besteht jede Eingabe z. B. aus genau einem Buchstaben,
so sagt man, der Automat produziere eine bestimmte Menge von Wörtern, indem
er diese Wörter akzeptiert. Auf diese Weise lassen sich unter anderem reguläre
Ausdrücke definieren.
Es werden unterschieden Endliche Automaten ohne Ausgabe von Endlichen Automaten mit Ausgabe. Erstere kennen als einzige Resultate Eingabe akzeptiert und
Eingabe nicht akzeptiert, je nachdem, ob nach Abarbeitung der Eingabe ein Endzustand erreicht wurde oder nicht.
2.3. Grundlagen der Visualisierung Reaktiver Systeme
Abbildung 2.1.: Zustände eines TV-Gerätes
Wie im vorhergehenden Abschnitt bereits erwähnt, bilden Endliche Automaten
die Grundlage der Modellierung Reaktiver Systeme. Endliche Automaten werden
mittels Zustandsdiagrammen visualisiert, welche ihrerseits auf Graphen-Diagrammen aufbauen. Ein Beispiel für ein Zustandsdiagramm zeigt Abbildung 2.1, auf der
vereinfacht Zustände eines TV-Gerätes mit ihren Transitionen dargestellt werden.
Es werden zunächst die Graphen-Diagramme eingeführt in Abschnitt 2.3.1, um
gleichzeitig die Basis für den Abschnitt über Graph-Editing-Frameworks (Abschnitt
3.2) zu schaffen. Hiernach werden in Abschnitt 2.3.2 die Statecharts betrachtet,
welche auf Graphen und Zustandsdiagrammen aufbauen. Im darauf folgenden Abschnitt 2.3.3 werden die Safe-State-Machines beschrieben, welche ihrerseits wiederum Statecharts erweitern. Gegenstand dieses Kapitels sind jedoch nicht Lösungen
für die Darstellung großer Zustandsmengen wie in [39] beschrieben. Einige solcher
Ideen werden in Kapitel 4 angeführt.
8
2.3. Grundlagen der Visualisierung Reaktiver Systeme
2.3.1. Graphen
Graphen stellen eine Generalisierung von Listen- und Baum-Strukturen dar und
finden Anwendung, wenn die Relationen zwischen Elementen einer Menge nicht
listen- oder baumförmig dargestellt werden können. Beispielsweise hat in einem
Baum ein Element höchstens einen Vater sowie beliebig viele Kindelemente, wohingegen man bei einem Graph nur von beliebig vielen Nachbarn spricht. Formal
sind Graphen Strukturen, welche aus einer Knotenmenge und einer Kantenmenge bestehen, wobei eine Kante typischerweise zwei Knoten miteinander verbindet,
also ein Paar (V, E) mit E ⊆ V × V, wobei die Elemente aus V Knoten (engl.
Vertexes) und die Elemente aus E Kanten (engl. Edges) genannt werden [10].
Einsatzgebiete
Mit Graphen lassen sich vielfältige Anwendungen modellieren, z. B. Verkehrsnetze,
Moleküle und Flussdiagramme von Computerprogrammen. Eine klassische Aufgabe ist das Finden einer kürzesten Route zwischen zwei Orten. Hierbei wird das
Verkehrsnetz als Graph modelliert, dessen Knoten Orte repräsentieren und dessen Kanten mit Gewichten versehen werden, welche die Entfernung zwischen den
Knoten darstellen. Die Graphentheorie bietet Algorithmen für solche Graphenprobleme.
Graphische Darstellung
In dieser Arbeit ist nur die graphische Darstellung von Graphen relevant. Die
Knoten werden im Nachfolgenden immer als Kreise oder Rechtecke dargestellt, die
Kanten als je zwei Knoten verbindende Polygone oder Spline-Kurven. Es werden im
Folgenden nur gerichtete Graphen betrachtet werden, deren Kanten im Gegensatz
zu ungerichteten Graphen eine durch einen Pfeil markierte Richtung besitzen.
2.3.2. Statecharts
Endliche Automaten werden graphisch in Form so genannter Zustandsdiagramme
dargestellt, welche ihrerseits als Erweiterung gerichteter Graphen betrachtet werden können. Statecharts wiederum erweitern Zustandsdiagramme mit dem Ziel,
eingebettete Systeme adäquat darstellen zu können. Ein Beispiel für ein Statechart,
welches das vereinfachte Zustandsverhalten eines TV-Gerätes modelliert, stellt Abbildung 2.2 dar. Statecharts sind ausdrucksstärker als Endliche Automaten, da mit
ihnen auch hierarchische Strukturen, Parallelität und Kommunikation modelliert
und Pseudozustände definiert werden können, siehe hierzu die folgenden Abschnitte. Das Verhalten eines Reaktiven Systems wird dabei beschrieben als die Menge
an erlaubten Eingabeereignis- und Ausgabeereignis-Sequenzen, Bedingungen, Aktionen und Zeitbeschränkungen. Diese Elemente werden ebenfalls in den folgenden
Abschnitten vorgestellt.
9
2. Theoretische Grundlagen
Abbildung 2.2.: Zustände eines TV-Gerätes
Statecharts wurden von David Harel eingeführt, um das komplexe Verhalten Reaktiver Systeme übersichtlich zu beschreiben [19]. Industrielle Werkzeuge, z. B. Rhapsody, Statemate, Artisan, Matlab/Stateflow und Esterel-Studio bieten ein so genanntes Forward-Engineering an, ähnlich dem aus anderen UMLWerkzeugen bekannten Verfahren, welches erlaubt, aus Statechart-Diagrammen
Programm-Quelltext zu erzeugen. Im Laufe der Zeit haben sich allerdings verschiedene Statechart-Dialekte entwickelt. In diesem Abschnitt werden die HarelStatecharts vorgestellt. Andere Dialekte sind z. B. die Safe-State-Machine – verwendet in Esterel-Studio – welche im Abschnitt 2.3.3 beschrieben werden und
die UML-Statecharts, welche z. B. in ArgoUML (Abschnitt 3.1.4) Verwendung finden. Die Entwicklung verschiedener Statechart-Dialekte führte dazu, dass die genannten Werkzeuge auf unterschiedlichen Dialekten und damit unterschiedlichen
Statechart-Semantiken basieren. Daher wird aus dem gleichen Statechart-Modell
durch unterschiedliche Werkzeuge Programm-Quelltext mit unterschiedlichem Verhalten generiert. Des Weiteren bieten einige dieser Werkzeuge das Simulieren von
Statecharts an. Hierbei kann der Benutzer die Rolle der Umwelt übernehmen, indem er an der Tastatur bestimmte Ereignisse produziert, und das Werkzeug zeigt
mittels farblicher Markierungen, in welchen Zuständen sich das Reaktive System
gerade befindet. Jedoch auch in diesem Anwendungsbereich zeigen sich semantische Unterschiede der einzelnen Dialekte. Interessant für die vorliegende Arbeit ist
allerdings nur, dass die Syntax und damit die graphische Repräsentation je nach
Dialekt und damit je nach Werkzeug verschieden ist.
Es wird im Folgenden nur die Syntax und die graphische Repräsentation der
Statecharts betrachtet. Die Semantik wird z. B. in [19] beschrieben und es wird
hier nur aus Gründen der Motivation und auch nur am Rande auf sie eingegangen.
10
2.3. Grundlagen der Visualisierung Reaktiver Systeme
Graphische Darstellung
Statecharts bestehen aus Zuständen und Transitionen – in Graphen Knoten und
Kanten genannt – Transitionsbeschriftungen, Zustandsbeschriftungen, Event-Deklarationen und Variablen-Deklarationen. In den folgenden Abschnitten wird beschrieben, wie diese Diagrammelemente in KIEL dargestellt werden, da diese Darstellungsform von dem in dieser Arbeit zu entwickelnden Editor übernommen werden soll. Diese Form der graphischen Repräsentation orientiert sich an der EsterelStudio-Notation.
Zustände
Hierarchische Strukturen dienen nicht nur der Übersichtlichkeit und erweitern die
Syntax und damit die Semantik von Endlichen Automaten, sondern sie fördern
auch eine hierarchische Entwicklung von Softwarekomponenten. Unter Hierarchie
wird hier verstanden, dass ein Zustand Unterzustände enthalten kann. Solche Zustände werden OR-States, Macro-States oder Processes genannt oder im Falle von
Parallelität Regions eines AND-States. Wird ein solcher hierarchischer Zustand
aktiv, so wird entweder durch darin enthaltenen Initial-State oder den HistoryState definiert, welcher Unterzustand aktiv wird. In Abbildung 2.2 sind die mit
On und Television beschrifteten Zustände OR-State und die mit I beschrifteten
Initial-States. Darüberhinaus handelt es sich bei den mit Normal und Videotext
beschrifteten Zuständen um sogenannte Simple-States.
Sollen zwei oder mehr Zustände auf der gleichen Hierarchiestufe gleichzeitig aktiv sein, so werden sie als Unterzustände einem AND-State hinzugefügt und voneinander getrennt durch eine gestrichelte Linie, eine so genannte Delimiter-Line.
Solche Unterzustände heißen Regions. Beispielsweise handelt es sich bei dem in
Abbildung 2.3 dargestellten mit On beschrifteten Zustand um einen AND-State.
Ist dieser AND-State aktiv, so gibt es in jeder seiner Regions einen aktiven Zustand. Durch diese Konstruktion kann die Anzahl an Zuständen eines Statecharts
insgesamt verringert werden [19].
Zusammenfassend besteht ein Statechart aus folgenden Zuständen, welche in den
Abbildungen 2.2 und 2.3 dargestellt werden.
• Simple-State: Wird dargestellt durch ein Rechteck mit abgerundeten Kanten
und kann Beschriftungen enthalten (Abschnitt 2.3.2).
• OR-State: Wird dargestellt wie ein Simple-State, jedoch mit einer zusätzlichen horizontalen Geraden, welche eine obere Zeile im Rechteck bildet, in
der die Beschriftung gezeichnet wird.
• AND-State: Wird dargestellt wie ein OR-State und enthält gestrichelte waagerechte und horizontale Geraden, welche das Rechteck in Bereiche aufteilen.
• Region: Beschreibt einen Bereich eines AND-States und besitzt keine graphische Repräsentation.
11
2. Theoretische Grundlagen
Abbildung 2.3.: Parallelität: AND-State
Zustände, welche weitere Zustände enthalten dürfen, – namentlich sind dies ORStates, AND-States und Regions – werden auch Composite-States, Macro-States
oder zusammengesetzte Zustände genannt.
Zustandsbeschriftungen
Die folgenden Zustandsbeschriftungen bestehen aus syntaktischen Elementen, auf
deren Bedeutung hier nicht näher eingegangen wird. Dies sind sogenannte OnEntry-Actions, On-Inside-Actions, On-Exit-Actions, (Local) Events und (Local)
Variables, sowie Statechart-globale Input-Events und Output-Events.
• On-Entry-Actions, On-Inside-Actions und On-Exit-Actions werden im Inneren des jeweiligen Zustands und durch waagerechte Linien voneinander
getrennt angezeigt, siehe Abbildung 2.4.
• (Local) Events und (Local) Variables bei Composite-States werden unter dem
Zustandsnamen im Inneren des Zustands angezeigt, ebenfalls durch Linien
voneinander getrennt, siehe Abbildung 2.4.
• Statechart-globale Input-Events und Output-Events werden nur in einem Bearbeitungsdialog angezeigt, der aus einem Menü heraus aufrufbar ist. Diese
Elemente sind im Statechart nicht sichtbar.
Pseudozustände
Sämtliche Pseudo-States werden als Kreis dargestellt mit einem Buchstaben, der
den Typ des Pseudo-States angibt. Pseudozustände werden sofort wieder verlassen,
sobald sie betreten werden.
12
2.3. Grundlagen der Visualisierung Reaktiver Systeme
Abbildung 2.4.: Zustandsbeschriftungen
• Initial-State: Jeder OR-State und jede Region besitzen genau einen InitialState. Ein Initial-State wird als grau ausgefüllter Kreis mit der Beschriftung
’I’ in der Mitte dargestellt.
• Choice, auch Dynamic-Choice und Conditional genannt: Besitzt mehrere eingehende und ausgehende Transitionen, wobei nur die eingehenden Transitionen durch bestimmte Ereignisse aktiviert werden, und die Aktivierung der
eingehenden und ausgehenden Transitionen an Bedingungen geknüpft werden kann. Ein Choice wird als grau ausgefüllter Kreis mit der Beschriftung
’C’ in der Mitte dargestellt.
• History-State: OR-States und Regions können maximal einen History-State
besitzen, welcher anzeigt, dass bei erneutem Betreten seines Vaters sofort
derjenige Zustand aktiv wird, welcher beim Verlassen des Vaters zuletzt aktiv
war, sofern der Zustand durch eine auf den History-State zeigende Transition
betreten wird. Ein History-State wird als grau ausgefüllter Kreis mit der
Beschriftung ’H’ in der Mitte dargestellt.
• Deep-History-State: Es gilt das gleiche wie für History-States, jedoch mit der
Erweiterung, dass bei Betreten des Vaters die zuletzt aktiven Zustände aller
Hierarchiestufen wieder aktiv werden und dass ein Deep-History-State als
Beschriftung ein ’H*’ in der Mitte trägt.
13
2. Theoretische Grundlagen
Transitionsbeschriftungen
Eine Transition kann eine Beschriftung besitzen, welche die Beschreibung eines
sie auslösenden Ereignisses (engl. Trigger ), einer Bedingung (engl. Condition) und
einer Aktion (engl. Action) beinhalten kann. Dabei sind alle diese drei Elemente optional. Ein Trigger bezeichnet die Menge an Ereignissen, welche eintreten
müssen, damit eine Transition aktiviert wird. Unter einer Condition wird ein logischer Ausdruck verstanden, welcher aus Variablen aufgebaut sein kann und von
dem zusätzlich abhängt, ob eine Transition aktiviert wird. Die Action bezeichnet
eine Menge von Aktionen, welche Variablen ändern und Ereignisse auslösen können und welche ausgeführt werden, sobald die Transition aktiviert wird. Transitionsbeschriftungen von und nach Pseudozuständen unterliegen teilweise gewissen
Beschränkungen, welche hier jedoch nicht weiter betrachtet werden sollen.
Transitionen
Transitionen können eine Transitionsbeschriftung besitzen. Durch die Aktivierung
einer Transition wird der Quellzustand der Transition inaktiv und der Zielzustand
aktiv. Eine Transition kann als Polygon oder Spline-Kurve dargestellt werden und
beliebig viele Stützpunkte enthalten.
2.3.3. Safe-State-Machines
Mit Safe-State-Machines (SSM), auch bekannt unter der Bezeichnung SyncCharts,
wird ein visuelles synchrones Automatenmodell bezeichnet [7]. Dieses wurde entworfen als eine graphische Notation für die Sprache Esterel und stellt einen Dialekt
und gleichzeitig eine echte Obermenge der Statecharts dar. In den nachfolgenden
Kapiteln ist bei Verwendung des Begriffs Statechart der SSM -Dialekt gemeint. Nur
diejenigen syntaktischen Konzepte werden im Folgenden aufgeführt, um welche die
SSM die Statecharts erweitern. Beschrieben wird im Folgenden die Darstellung dieser Elemente in KIEL.
Suspendierung
Es kann für das Auftreten bestimmter Ereignisse bestimmt werden, dass alle in
einem bestimmten Zustand befindlichen Prozesse solange suspendiert werden, bis
diese Ereignisse nicht mehr präsent sind. Dies wird modelliert mit dem so genannten Suspend -Diagrammelement und dem Transitionstyp Suspension. Diese Suspension wird aktiviert, wenn jene Ereignisse eintreten und führt in einen Suspend.
Suspends werden als gelb ausgefüllter Kreis mit der Beschriftung ’S’ und Suspensions durch einen kleinen gelben Kreis am Anfang der Transition gekennzeichnet.
Terminierung
Safe-State-Machines kennen Endzustände (engl. Final-States). Sie markieren Zustände, in welchen ein Subsystem eines Reaktiven Systems endet. Solche Zustände
14
2.4. Vorgehensmodelle zur Softwareentwicklung und Entwurfsmuster
werden durch einen doppelten Rahmen gekennzeichnet. Haben in einem Zustand
alle Subzustände einen Endzustand erreicht, so kann mittels einer Terminierungstransition (engl. Normal-Termination) dieser Zustand ohne weitere Eingabeereignisse verlassen werden. Solch eine Terminierungstransition wird durch einen kleinen grünen Kreis am Anfang der Transition gekennzeichnet. In Esterel-Studio wird
stattdessen ein kleines grünes Dreieck dargestellt.
Starker Abbruch
Ein weiteres Modellierungselement stellen die Strong-Abortion-Transitionen dar,
welche bei Aktivierung sofort ausgeführt werden und alle anderen laufenden Aktionen abbrechen. Diese Transitionen werden durch einen kleinen roten Kreis am
Anfang der Transition gekennzeichnet.
Transitionsprioritäten
Grundsätzlich haben Strong-Abortions eine höhere Priorität als Weak-Abortions.
Sobald von einem Zustand mehrere Transitionen abgehen, werden Transitionen
gleichen Typs priorisiert, indem diesen automatisch eine Zahl zugewiesen wird,
welche die Reihenfolge bei der Auswertung der Triggers bestimmt. Je niedriger
diese Zahl ist, desto höher ist die Priorität. Diese Zahl wird am Anfang einer Transition dargestellt. Diese Prioritäten können geändert werden. Doppelte Prioritäten
können allerdings nicht vergeben werden.
2.4. Vorgehensmodelle zur Softwareentwicklung und
Entwurfsmuster
Nachdem in den vorangegangenen Abschnitten auf die Struktur der vom KIELEditor dargestellten Diagramme eingegangen wurde, sollen in diesem Abschnitt
kurz die Grundlagen für das konzeptionelle projekttechnische Vorgehen bei der
Umsetzung der Aufgaben in dieser Arbeit, siehe Kapitel 5, umrissen werden.
Je größer Softwareprojekte sind, je komplexer, verteilter und wichtiger, desto
mehr besteht die Notwendigkeit, die Robustheit und Zuverlässigkeit des zu entwickelnden Softwaresystems durch geeignete und in der Praxis bewährte Vorgehensmodelle sicherzustellen. Kernursachen für das Scheitern solcher Softwareprojekte
sind:
• Ad-hoc-Anforderungs- und Änderungsmanagement: Erfassen und Zulassen
neuer oder geänderter Anforderungen,
• unentdeckte Inkonsistenzen zwischen Anforderungen, Design und Implementierung,
• mangelnde oder ungenaue und undeutliche Projektkommunikation,
15
2. Theoretische Grundlagen
• nicht ausreichender Testumfang und
• unnötig komplexe Anwendungsarchitektur.
Diese Faktoren begünstigen das Eintreten folgender Situationen:
• Die Anforderungen werden nur ungenau verstanden.
• Die Flexibilität bei Änderung der Anforderungen während der Projektdurchführung ist ungenügend.
• Einzelne eigenständige Programm-Module arbeiten nicht einwandfrei zusammen.
• Die Software wird schwer zu warten und zu erweitern.
• Ernste Projektfehler werden zu spät erkannt.
• Die Ausführungsgeschwindigkeit ist unzureichend.
• Die zur Fehlerbehebung häufig notwendige Rekonstruktion der Projekthistorie ist nicht vollständig möglich.
• Es treten zu viele Programmfehler auf.
• Build - und Release-Prozess werden unzuverlässig.
Die in den folgenden Abschnitten vorgestellten Techniken und Ansätze helfen,
diese Probleme zu vermeiden. Hierzu zählen der Einsatz der UML (Abschnitt
2.4.1), die Befolgung so genannter Best Practices (Abschnitt 2.4.2) sowie die Verwendung von Entwurfsmustern (Abschnitt 2.4.3).
2.4.1. Unified Modelling Language
Die Unified Modelling Language (UML) [35] ist eine Sprache und Notation zur
Spezifikation, Konstruktion, Visualisierung und Dokumentation von Modellen für
Softwaresysteme und kann als Industriestandard angesehen werden. Beinahe alle Hersteller von Softwaremodellierungswerkzeugen unterstützen die UML. Vorgehensmodelle zur Softwareentwicklung basieren teilweise auf der UML, denn sie
stellt eine definierte Menge von Modellierungskonstrukten mit einheitlicher Notation und Semantik bereit. Einige Diagrammtypen werden nur bei objektorientierter
Softwareentwicklung eingesetzt. Neben so genannten Anwendungsfalldiagrammen,
Aktivitätsdiagrammen, Kollaborationsdiagrammen, Sequenzdiagrammen und Implementierungsdiagrammen, welche hier nicht näher betrachtet und in dieser Arbeit keine Verwendung finden, kennt die UML folgende weitere Diagrammtypen:
16
2.4. Vorgehensmodelle zur Softwareentwicklung und Entwurfsmuster
• Klassendiagramm: beschreibt zum einen Beziehungen zwischen Klassen, welche durch Vererbung, Realisierung und Assoziation entstehen. Assoziationen
beschreiben als Relationen zwischen Klassen die gemeinsame Semantik und
Struktur von Objektverbindungen. Zum anderen können in Klassendiagrammen je nach Abstraktionsgrad auch Schnittstellen einzelner Klassen angegeben sein.
• Zustandsdiagramm: zeigt Objektzustände, Zustandsübergänge und Ereignisse.
2.4.2. Softwareentwicklung Best-Practices
Im kommerziellen Umfeld haben sich neben dem Befolgen und Umsetzen von Vorgehensmodellen Regeln gefunden, die die Ursachen von Softwareentwicklungsproblemen zuverlässig bekämpfen helfen und sich daher als allgemein anerkannte Strategien durchgesetzt haben. Solche Best-Practices sind:
• Es soll ein striktes und genau definiertes Anforderungsmanagement geführt
werden.
• Software soll in vielen Iterationen statt nach dem Wasserfallmodell entwickelt
werden, siehe Abschnitt 2.4.2.
• Komponentenbasierte Architekturen und Entwurfsmuster sollen eingesetzt
werden.
• Software soll visuell entworfen werden.
• Die Softwarequalität soll kontinuierlich überprüft werden.
• Programm-Quelltext-Änderungen sollen genau protokolliert werden.
In der Anforderungs- und Designphase sollen visuelle Modelle in Diagrammform
entwickelt werden. Dies erhöht auf der einen Seite die Verständlichkeit, und auf
der anderen Seite können unter Zuhilfenahme gängiger visueller Sprachen wie die
UML auf diese Weise sämtliche zu modellierende Sachverhalte eindeutig kommuniziert werden. Hierunter fallen Anwendungsfall-Diagramme, Klassendiagramme,
Zustandsdiagramme und Sequenzdiagramme, welche in Abschnitt 2.4.1 vorgestellt
werden.
Es gibt noch einige weitere solcher Regeln, die unbedingt eingehalten werden
sollen, auf die hier jedoch nicht näher eingegangen wird.
Iterative Modelle und Wasserfall-Modelle
Ein Wasserfall-Modell, in der Literatur auch häufig Top-Down-Entwicklungsmodell
genannt, legt fest, dass die Projektphasen Anforderungsanalyse, Entwurf, Implementierung, Programm-Einheiten-Test, Subsystem-Test und System-Test jeweils
17
2. Theoretische Grundlagen
nur einmal durchlaufen werden und dies in genau der soeben genannten Reihenfolge. In solch einem Modell ist nicht vorgesehen, dass sich Anforderungen mit der
Zeit ändern können und dass Entwurfs- und Anforderungsfragen während der Implementierung erneut überdacht werden. So wirken sich Fehler in frühen Phasen
stark auf nachfolgende Phasen aus, und damit steigt das Projektrisiko mit der Zeit
stark.
Iterative Vorgehensmodelle dagegen verfolgen das Ziel, genau jene Schwächen
des Wasserfall-Modells zu umgehen mit dem einfachen Ansatz, das vollständige
Wasserfall-Modell in vielen Iterationen zu wiederholen. Hierbei werden zum einen
die Ergebnisse einer Iteration ausgewertet und diese Erkenntnisse in der nächsten
Iteration berücksichtigt. Entscheidend ist jedoch zum anderen, dass jede Iteration
einen vollständigen und in sich geschlossenen Entwicklungszyklus darstellt, an dessen Ende immer eine lauffähige Version des zu erstellenden Softwaresystems steht.
Es stellt sich hierbei nicht als Nachteil heraus, dass für jede Phase einer Iteration
weniger Zeit zur Verfügung steht als bei dem Wasserfallmodell. Beispielsweise kostet die Anforderungsanalyse weniger Zeit, wenn ihr Ziel nicht die Erfassung aller
Details der Anforderungen ist. Ein Vertreter dieser iterativen Vorgehensmodelle
ist der Rational Unified Process [30].
2.4.3. Entwurfsmuster
Muster helfen beim Entwurf beliebiger komplexer Systeme. In der Softwareentwicklung spiegeln Entwurfsmuster teilweise Softwareentwicklungs-Paradigmen wider,
namentlich Modularisierung, Objektorientierung und Aspektorientierung.
Die hier vorgestellten Entwurfsmuster, welche umfassend in [14] dargestellt werden, beschreiben einfache und elegante Lösungen für in der vorliegenden Arbeit
relevante Probleme des objektorientierten Entwurfs. Ein Entwurfsmuster stellt eine Abstraktion von vielen gleichartigen konkreten Problemlösungen dar, welche im
Laufe der Zeit gefunden wurden. Die Anwendung von Entwurfsmustern hat zum
Ziel, den Grad an Wiederverwendbarkeit und Flexibilität von Programm-Quelltext
zu erhöhen, vor allem aber dem erfahrenen Softwareentwickler das Einarbeiten in
fremden Programm-Quelltext zu erleichtern. Letzteres gelingt, weil die bekanntesten Entwurfsmuster allgemein anerkannt sind und häufig angewendet werden; sie
beschreiben einen guten Entwurfsstil. Im Folgenden werden diejenigen Entwurfsmuster beschrieben, die das Design und die Implementierung des KIEL-Editors
grundlegend bestimmen.
Zustands-Entwurfsmuster
Dieses Entwurfsmuster kapselt Objekt-Verhalten in Abhängigkeit von Programmzuständen. Nach außen scheint ein Objekt sein Verhalten, also seine Klasse, zu ändern, wenn sich sein interner Zustand ändert. Dieser Mechanismus wird umgesetzt,
indem Zustandsklassen und eine Schnittstelle definiert werden. Die Schnittstelle
wird sowohl von dem Objekt, welches sein Verhalten ändern soll – im Folgenden
18
2.4. Vorgehensmodelle zur Softwareentwicklung und Entwurfsmuster
Kontext genannt – als auch von jeder Zustandsklasse – im Folgenden KonkreterZustand genannt – implementiert. Die Anwendung kommuniziert nur mit dem
Kontext und dieses Objekt leitet alle Anfragen weiter an ein Konkreter-ZustandObjekt. Ändert sich nun der interne Zustand des Kontextes, so wird das KonkreterZustand-Objekt ausgetauscht gegen ein anderes, welches zum aktuellen internen
Zustand passt.
In diesem Entwurfsmuster ist das Delegator -Entwurfsmuster enthalten, welches
bei der Kommunikation zwischen Partnern eine Indirektion vorsieht, in der Anfragen weitergeleitet werden und Aufgaben tatsächlich nicht vom anfrageempfangenden Objekt ausgeführt werden, sondern von dem Objekt, an welches die Anfragen
delegiert werden.
Das Zustands-Entwurfsmuster gruppiert Funktionalitäten nicht wie in objektorientierter Programmierung üblich nach Zuständigkeiten sondern nach Zuständen.
Dies ist eine geeignete Sichtweise, wenn hiermit auf große mehrteilige Bedingungsanweisungen, die vom Objektzustand abhängen, verzichtet werden kann.
Aus Implementierungssicht ist zu beachten, dass nur der Kontext die KonkreterZustand-Klassen referenziert und verwendet. Vorteile dieses Entwurfsmusters sind
zum einen, dass leicht neue Zustände modelliert und hinzugefügt werden können,
ohne die bestehende Implementierung zu ändern und zum anderen, dass Zustandsübergänge explizit repräsentiert werden. Ein Zustandsübergang ist nicht mehr abhängig von verschiedenen Parametern, sondern er hängt allein von der Referenz
einer Variable auf ein Konkreter-Zustand-Objekt ab. Einsatz findet das Zustandsmuster z. B. in der Implementierung von Editoren.
Befehl-Entwurfsmuster
Bei diesem Entwurfsmuster werden Befehle oder Benutzeraktionen als Objekte
gekapselt. Diese Objekte können dann in eine Warteschlange gestellt und sequentiell abgearbeitet oder auch protokolliert werden. Solche Objekte eignen sich bei
Verwendung von Klassenbibliotheken für Benutzungsschnittstellen, da der Aufrufer solch eines Befehlsobjektes, in der Regel ein Element der Benutzeroberfläche,
nichts über die Spezifika des eigentlichen Befehlsaufrufes sondern nur eine standardisierte Schnittstelle zum Befehlsaufruf kennen muss.
Implementiert wird dieses Muster, indem zunächst eine abstrakte Klasse oder
eine Schnittstelle (engl. Interface) definiert wird, welche genau eine Operation besitzt. Zu jedem Befehl wird dann eine diese Schnittstelle implementierende Klasse
entworfen, deren Operation genau den zu kapselnden Befehl ausführt. In Java heißt
diese Schnittstelle javax.swing.Action und findet Verwendung bei allen Steuerelementen wie Buttons und Menü-Elementen einer Benutzeroberfläche.
Model-View-Controller -Entwurfsmuster
Das Model-View-Controller -Entwurfsmuster (MVC ) verfolgt den Ansatz, eine Anwendung mit graphischer Benutzeroberfläche aufzuteilen in ein Modul, welches
19
2. Theoretische Grundlagen
die Reaktion auf Benutzereingaben definiert (engl. Controller ), in ein weiteres
Modul, welches das Datenmodell und Operationen auf diesem beinhaltet (engl.
Model ) und in eine Komponente für die Anzeige der graphischen Benutzeroberfläche (engl. View ). Sogar eine einzelne Komponente einer Benutzeroberfläche kann
hierbei selbst als eine Anwendung mit graphischer Benutzeroberfläche aufgefasst
werden. Daher sind z. B. in Java alle Komponenten für Benutzeroberflächen nach
dem MVC -Muster aufgebaut.
Der entscheidende Punkt bei diesem aus drei Teilen bestehenden System liegt
in der definierten Kommunikation zwischen den Teilen. Die Kommunikation verläuft nur unidirektional und nur von View nach Controller, von Controller nach
Model und von Model nach View. Daneben ist denkbar, dass auch von außen
das Model manipuliert werden kann. Der Controller ist häufig nach dem BefehlEntwurfsmuster implementiert, was zur Folge hat, dass der Controller austauschbar ist, ohne die View oder das Model anpassen zu müssen. Auch die View lässt
sich ohne Änderung von Controller und Model auswechseln. Der wesentliche Vorteil
bei Verwendung dieses Entwurfsmusters liegt wegen der schmalen Kommunikationswege und der Modularisation allerdings in der Verringerung der Komplexität
der Anwendung. Des Weiteren ist leicht realisierbar, mehrere Views nebeneinander existieren zu lassen, welche auf dem gleichen Model basieren und daher ohne
Synchronisationsaufwand die gleichen Daten in gleicher oder unterschiedlicher Repräsentation anzeigen.
Die Kommunikation zwischen View und Controller erfolgt nach dem BefehlEntwurfsmuster, die Kommunikation zwischen Model und View hingegen nach dem
Beobachter-Entwurfsmuster: Die View meldet sich als einer von potentiell mehreren Beobachtern (engl. Subscriber ) der Änderungen am Model (Beobachteter,
engl. Publisher ) an, und das Model wird dann bei jeder Zustandsänderung alle
Interessenten benachrichtigen. Dieses Beobachter-Entwurfsmuster wird daher gelegentlich auch Publisher-Subscriber -Entwurfsmuster genannt. Zentrales Element
des Beobachter-Entwurfsmusters ist die Schnittstelle, welche alle Beobachter implementieren, um so dem Beobachteten eine einheitliche Zugriffsmöglichkeit zur
Verfügung stellen zu können.
Die Separation in View und Controller ermöglicht es ferner, die Reaktion eines
Views auf Benutzungseingaben sogar während der Laufzeit zu ändern. Erreicht
wird dies, indem ein Teil des Controllers nach dem Zustands-Entwurfsmuster implementiert werden kann.
20
3. Stand der Technik
Im vorangegangen Kapitel wurde die Terminologie der Statecharts eingeführt und
der heutige Stand der Technik bezüglich des methodischen Vorgehens in der Software-Entwicklung aufgezeigt. In diesem Kapitel hingegen wird der Stand der Technik im Hinblick auf am Markt verfügbare Software-Produkte vorgestellt. Hierbei
werden zum einen existierende Statechart-Editoren auf ihre Funktionalität hin untersucht, um eine Einordnung des in dieser Arbeit zu entwickelnden Editors zu
ermöglichen und eine Vorgabe an wünschenswerten Funktionsmerkmalen zu finden. Zum anderen werden Graph-Editing-Frameworks dahingehend analysiert, ob
und inwieweit sie für die Realisierung des zu entwickelnden Editors genutzt werden
können.
3.1. Analyse existierender Statechart-Editoren
Wie in Abschnitt 2.3.2 erwähnt, existieren eine Reihe von Statechart-Werkzeugen,
welche auf einer graphischen Notation für Statecharts basieren und daher auch graphische Editoren zur Bearbeitung von Statechart-Diagrammen bereitstellen. Die
Vorteilhaftigkeit des graphischen Modellierens von Statecharts im Gegensatz zu
Ansätzen in Textform beschreibt [18]. Im Fokus der in diesem Kapitel vorgenommenen Analyse von UML- und Statechart-Werkzeugen wird die Erfassung von interessanten Bearbeitungs- und Gestaltungshilfen für Statechart-Diagramme sein,
welche die Editoren der vorgestellten Werkzeuge bieten. Statechart-Editoren müssen grundlegende Bearbeitungsfunktionen zur Verfügung stellen, welche auch von
anderen Diagramm-Editoren her bekannt sind (Abschnitt 3.1.1). Von Interesse für
die vorliegende Arbeit ist dabei zum einen, welche Bearbeitungsfunktionen der
Benutzer von einem Statechart-Editor mindestens erwarten kann, weil jedes Werkzeug sie anbietet. Zum anderen ist aufschlussreich, mit welchen Merkmalen sich
die verschiedenen Editoren von ihrer Konkurrenz absetzen und welche Funktionen
sie zurzeit noch nicht besitzen. Fehlende Funktionsmerkmale eignen sich im Besonderen zur Umsetzung im KIEL-Editor, KIEL als Alternative im Umfeld dieser
Produkte platzieren zu können.
3.1.1. Grundlegende Funktionen von Statechart-Editoren
Sämtliche der hier analysierten Statechart-Editoren verfügen über grundlegende
Funktionalitäten, welche im Folgenden aufgelistet werden und in Kapitel 4 näher
erläutert werden:
21
3. Stand der Technik
• syntaxgerichtetes Editieren,
• Beschriftungsmöglichkeiten für Diagrammelemente und Eingabe von Diagrammelement-Beschriftungen direkt auf der Zeichenfläche ohne Dialogfenster (engl. Inline-Editing),
• Löschen, Verschieben und Größenändern von Diagrammelementen,
• rasterorientiertes Bearbeiten,
• relatives Ausrichten von Diagrammelementen (engl. Alignment),
• Cut-and-Paste,
• Export nach JPG, EPS und in andere Formate,
• Ausdruck und
• kontextsensitive Mauszeiger zur Anzeige der aktuell möglichen Benutzeraktionen.
3.1.2. Esterel-Studio
Esterel [5] ist eine Spezifikationssprache für eingebettete Systeme (Abschnitt 2.1,
welche unterstellt, dass eingebettete Systeme sowohl synchron als auch deterministisch sind. Esterel-Studio [12] ist dagegen eine auf Esterel basierende kommerzielle integrierte Entwicklungsumgebung zur Entwicklung eingebetteter Systeme. Sie
bietet die Möglichkeit, Safe-State-Machine-Modelle (Abschnitt 2.3.3) zu erstellen.
Die formale Spezifikation eines Reaktiven Systems kann dabei graphisch mittels
SSM -Formalismus oder in Form von Esterel -Programm-Quelltext definiert werden.
Hierbei ist es möglich, Esterel -Programm-Quelltext in graphische Elemente einer
SSM einzubetten und damit graphische Elemente mit Textelementen zu mischen.
Nachdem ein Modell vollständig entworfen wurde, kann dieses Modell auf seine
syntaktische Korrektheit hin untersucht werden, indem überprüft wird, ob alle Definitionen des entworfenen Systems konsistent sind. Daneben wird zusätzlich ein
Causality-Problem-Checker angeboten, welcher das Modell auf Determinismus hin
überprüft.
Im Wesentlichen bietet diese Software jedoch die Möglichkeit, interaktiv SafeState-Machines zu simulieren, ausführbaren Programm-Quelltext zu generieren
und Berichte zu erzeugen. Bei der Simulation eines entworfenen Systems kann
der Benutzer manuell die Zeitschritte (engl. Ticks) hochzählen und in jedem Zeitschritt Eingabesignale setzen.
Der Editor und die Simulationsumgebung von Esterel-Studio nutzen die MultipleDocument-Interface-Technik: Sie besteht aus einem primären Fenster, in welches
mehrere Dokument-Fenster eingebettet sind, die nur innerhalb des primären Fensters verschoben werden können. In einem Dokument-Fenster wird ein Teil der
22
3.1. Analyse existierender Statechart-Editoren
SSM dargestellt, welcher ein Composite-State (siehe 2.3.2) sein kann. Dieser Composite-State kann als Modul abgespeichert und an mehreren Stellen der SSM wiederverwendet (instantiiert) werden. Mit Hilfe dieser Modulstruktur und unterstützt
durch die Fenstertechnik kann der Benutzer den Editiervorgang hierarchisch gliedern. Diese Gliederung wird im primären Fenster in einer Baumansicht dargestellt
neben Berichten, Nachrichten und Fehlermeldungen, welche ihrerseits in einem
Konsolenbereich angezeigt werden.
Editor-Funktionalitäten
Zentrales Element der Benutzeroberfläche zum Erstellen von Safe-State-Machines
ist die Werkzeugleiste (engl. Toolbar ) zum Einfügen von Diagrammelementen, siehe
Abbildung 3.1, welche folgende Buttons von links nach rechts besitzt: Wechsel in
den Selektionsmodus, Einfügen eines Simple-State, eines Moduls, eines OR-States,
eines OR-States mit Inhalt in Textform, eines Textblocks, einer Transition, eines
Initial-States, eines Suspend, eines Deep-History-States, eines Choice und einer
horizontalen und vertikalen Delimiter-Line. In OR-States mit Inhalt in Textform
kann Esterel -Programm-Quelltext eingefügt werden, welcher den Inhalt dieses ORStates beschreibt.
Abbildung 3.1.: Die Esterel-Studio-Werkzeugleiste für das Erzeugen von Diagrammelementen
Zur Bearbeitung von Safe-State-Machines werden neben den in Abschnitt 3.1.1
genannten grundlegenden Funktionalitäten folgende Operationen angeboten:
• Bearbeitungsschritte können rückgängig gemacht werden (engl. Undo-andRedo).
• Der innere Bereich eines Composite-States kann vergrößert werden, ohne dass
sich die Grenzen dieses Zustands ändern. Der Composite-State erhält dann
Scrollleisten (engl. Scrollbars). In diesem scrollbaren Bereich kann gezoomt
und navigiert werden.
• Composite-States können komplett eingeklappt werden, so dass nur noch die
Titelleiste zu sehen ist.
• Composite-States können perCTRL-Taste + Doppelklick in einem eigenen
Fenster geöffnet werden.
• Zustände können um Stufen in der Hierarchie nach oben und unten verschoben werden, indem entweder diese Zustände in einen OR-State eingeschlossen
23
3. Stand der Technik
werden oder diese aus dem sie umgebenden Composite-State herausgenommen werden.
• Für Zustände kann ein Typmorphing (Abschnitt 4.17) durchgeführt werden.
• Für Zustände kann die Eigenschaft Ist Endzustand gesetzt werden, jedoch
nur, wenn sie keine ausgehenden Transitionen besitzen.
• Deklaration von On-Entry-Actions, On-Inside-Actions und On-Exit-Actions.
• Ein Initial-State kann auskommentiert werden, was zur Folge hat, dass der
gesamte OR-State deaktiviert wird und so bei der Simulation und ProgrammQuelltext-Generierung unbetrachtet bleibt.
• Lokale Variablen werden für Initial-States deklariert.
• Transitionsendpunkte sind veränderbar.
• Prioritäten können für Transitionen definiert werden, welche abgehen von
Initial-States, Conditional-States und Simple-States. Diese Prioritäten sind
in einem Prioritäteneditor änderbar. Dort werden die Prioritäten in einer
Liste verwaltet.
• Jede Transition ist standardmäßig eine Strong-Abortion. Erst nach dem Erzeugen kann man den Transitionstyp ändern (Abschnitt 4.17).
• Verschieben mehrerer Elemente ist möglich mit der CTRL-Taste + Mausklick
oder indem ein diese Elemente umgebendes Rechteck gezeichnet wird, welches dann mitsamt seinem Inhalt verschoben werden kann.
• Schriftart und Farbe sind einstellbar für Diagrammelemente und ihre Beschriftungen.
• Kommentare sind überall platzierbar.
• Ein globales Suchen und Ersetzen ist möglich.
• Editieren von Transitionsbeschriftungen ist über ein Dialogfenster möglich,
welches Eingaben für Trigger, Condition und Action separiert.
3.1.3. Matlab / Simulink / Stateflow
Matlab ist ein weit verbreitetes Programm im Bereich des wissenschaftlichen numerischen Rechnens. Es handelt sich hierbei um ein interaktives System mit Matrizen
als Basis-Datenelement und bietet graphische Darstellungsmöglichkeiten, welche
auch durch benutzerdefinierte Benutzeroberflächen erweitert werden können. Es
können Befehle ähnlich wie bei einem Taschenrechner direkt über eine Kommandozeile eingegeben werden oder aber auch in Form von Scripts, geschrieben in der
Matlab-eigenen Programmiersprache.
24
3.1. Analyse existierender Statechart-Editoren
Bei Simulink [33] handelt es sich um eine Funktionsbibliothek für Matlab zur
Simulation regelungstechnischer Problemstellungen und besitzt eine auf Matlab
aufgesetzte Benutzeroberfläche, in deren graphischem Editor (Differential-) Gleichungssysteme als hierarchische Signalflusspläne modelliert werden können. Aus
diesen Modellen kann dann C -Programm-Quelltext generiert werden, um diesen
z. B. für Echtzeitsysteme zu kompilieren. Ähnlich wie andere Werkzeuge, welche Programm-Quelltext generieren, gehört Simulink damit auch zur Gruppe der
Rapid-Prototyping-Tools. Daneben können die angefertigten Modelle auch simuliert werden. Sowohl Matlab als auch Simulink sind Produkte der Firma The Math
Works [47].
Stateflow wiederum stellt eine graphische Erweiterung zu Simulink dar und ermöglicht die Modellierung und Syntaxprüfung von Statecharts und durch Simulink
auch die Simulation dieser Modelle. Während der Simulation können dabei alle verfügbaren Matlab-Funktionen benutzt werden, und es steht für die Simulation ein
Debugger zur Verfügung, in welchem Breakpoints an beliebigen Diagrammelementen und Ereignissen gesetzt werden können. Voraussetzung für die Benutzung von
Stateflow ist die Matlab / Simulink -Umgebung.
Jedes Statechart-Werkzeug hat seine eigene Darstellungsform für StatechartDiagrammelemente. Abbildung 3.2 zeigt beispielhaft ein Statechart mit seinen
Diagrammelementen in Stateflow -Notation. Abbildung 3.3 zeigt die Art der Darstellung von State-Actions.
Editor-Funktionalitäten
Die Werkzeugleiste ist Ausgangspunkt zum Einfügen von Diagrammelementen,
siehe Abbildung 3.4, welche folgende Buttons von oben nach unten besitzt: Hinzufügen eines States, eines History-States, eines Initial-States und eines ConditionalPseudo-States. In Stateflow wird bei Hinzufügen eines Initial-States auch gleich
eine Initial-Arc angehängt, welche mit einem Zustand verbunden wird.
Zur Bearbeitung von Statecharts werden neben den in Abschnitt 3.1.1 genannten
grundlegenden Funktionalitäten folgende Operationen angeboten [34]:
• Bearbeitungsschritte können rückgängig gemacht werden.
• Hinzufügen von Diagrammelementen ist möglich im Single-Creation-Modus
und im Multiple-Creation-Modus: Durch Doppelklick auf ein Diagrammelement in der Werkzeugleiste lassen sich mehrere Instanzen dieses Elementtyps
hinzufügen, ohne wiederholt diesen Typ in der Werkzeugleiste anzuwählen.
• Allen Diagrammelementen können Beschreibungen hinzugefügt werden.
• Beschriftungsschriftarten und Farben können für alle Diagrammelemente geändert werden.
• Der Zoomfaktor für Zoom-In und Zoom-Out ist änderbar.
25
3. Stand der Technik
Abbildung 3.2.: Ein Beispiel-Statechart aus Stateflow
• Beim Anlegen von Zuständen wird nicht zwischen Simple-States und Composite-States unterschieden. Sobald in einem Simple-State ein weiterer Zustand
platziert wird, findet ein automatisches Typmorphing nach OR-State statt
(Abschnitt 4.17).
• Über ein Kontext-Menü legt der Benutzer fest, ob es sich bei einem CompositeState um einen AND-State oder einen OR-State handeln soll.
• Parallele Substates eines AND-States beinhalten zusätzlich in der rechten
oberen Ecke eine Nummer, welche die Aktivierungsreihenfolge beim Betreten
des AND-States angibt.
• Gruppieren eines Zustands: Ist ein Zustand als gruppiert markiert, so wird
er mitsamt seinem Inhalt als graphische Einheit behandelt, z. B. wird ein
gruppierter Zustand mitsamt seinen Unterzuständen verschoben; nicht so ist
dies hingegen bei ungruppierten Zuständen.
26
3.1. Analyse existierender Statechart-Editoren
Abbildung 3.3.: Anzeige der Actions eines Zustands in Stateflow
Abbildung 3.4.: Die Stateflow -Werkzeugleiste für die Auswahl von Diagrammelementen
• Der Inhalt eines Zustands kann versteckt und auch wieder sichtbar gemacht
werden, indem die entsprechende Zustandseigenschaft der Sichtbarkeit im
Kontext-Menü eingestellt wird.
• Composite-States können als Teildiagramme deklariert werden, welche als
eigenständige Diagramme bearbeitet werden können. Dies wird in Stateflow
auch Boxing genannt.
• Transitionsbeschriftungen können verschoben werden.
• Die Größe von Transitions-Pfeilspitzen ist änderbar.
• Statecharts werden in Bibliotheken organisiert. Eine Änderung in einem
Bibliotheks-Statechart wirkt sich auf alle Statecharts aus, welche das geänderte Statechart nutzen.
• Zur Verfügung steht ein so genannter Stateflow-Explorer, welcher ein Verzeichnis darstellt, in dem alle Diagrammelemente mitsamt allen Ereignissen
in einer Baumstruktur angezeigt werden. Die Änderung der Sichtbarkeit von
Ereignissen muss über diesen Explorer erfolgen, Hierarchie-Änderungen und
das Anlegen und Löschen von Elementen dagegen können über diesen Explorer durchgeführt werden.
27
3. Stand der Technik
3.1.4. ArgoUML
ArgoUML [3] baut auf dem GEF -Rahmenwerk (Abschnitt 3.2.3) auf und gehört zu
der Familie der UML-Modellierungswerkzeuge, welche eine Teilmenge der in Abschnitt 2.4.1 genannten Diagrammformen zur Erstellung anbieten. Es handelt sich
bei ArgoUML um ein Open-Source-Projekt und ist daher kostenfrei nutzbar. Dafür
wird weder Support angeboten noch ist Dokumentation verfügbar, welche allgemeinen Standards bezüglich Vollständigkeit und Nutzbarkeit genügt. Auch wird
kein Hilfesystem angeboten, welches interaktiv aus der Benutzeroberfläche aufgerufen werden kann [26]. Im Gegensatz zu anderen Statechart-Werkzeugen bietet
ArgoUML ausschließlich Möglichkeiten zum graphischen Editieren von Diagrammen, eine Syntaxprüfung und Programm-Quelltext-Erzeugung nach C++, PHP
und Java zum Zwecke des Forward-Engineering. Darüber hinaus kann das Modell
auf Einhaltung der über die Object-Constraint-Language vom Benutzer definierten
Beschränkungen (engl. Constraints) hin geprüft werden.
ArgoUML beinhaltet so genannte Design-Critics [42]. Design-Critics werden
in [3] beschrieben als einfache Agenten, welche im Hintergrund ständig das Design des Benutzers analysieren, um gegebenenfalls Verbesserungsvorschläge unterbreiten zu können. Diese Vorschläge umfassen Hinweise auf syntaktische Fehler,
noch nicht fertig gestellte Entwurfsbereiche und Verstöße gegen ProgrammierstilRichtlinien sowie Best-Practices der Softwareentwicklung (Abschnitt 2.4.2). Einige
dieser Design-Critics bieten die automatische Durchführung einer Entwurfsverbesserung an. Sämtliche Verbesserungsvorschläge und Hinweise werden lediglich in
einer To-Do-Liste aufgeführt und unterbrechen den Benutzer während des Bearbeitens nicht. Diese To-Do-Liste kann vom Benutzer frei ergänzt werden. Sowohl
Design-Critics als auch To-Do-Liste stellen neben dem Angebot an verschiedenen
Ansichten auf das Modell und Check-Listen eine Anwendung von Erkenntnissen
aus der kognitiven Psychologie dar.
Editor-Funktionalitäten
Ergänzend zu den in Abschnitt 3.1.1 genannten grundlegenden Funktionalitäten
werden in ArgoUML zur Bearbeitung von Statecharts folgende Operationen angeboten:
• Diagramme können exportiert werden nach PS, EPS, PGML, SVG und XMI.
• Optional ist ein Raster anzeigbar und rasterorientiertes Bearbeiten ist möglich.
• Alle Diagrammelemente werden zusätzlich in einer Baumansicht angezeigt.
• Die Baumansicht ist wahlweise diagramm-, transitions- oder zustandszentriert.
• Ein Undo-and-Redo von Navigations- und Selektionsvorgängen ist möglich.
28
3.1. Analyse existierender Statechart-Editoren
• Ausrichtung von Diagrammelementen relativ zueinander mittels eines Balkens, welcher wie ein Besen alle erfassten Diagrammelemente an seiner Kante
verschiebt (engl. Broom-Tool ).
• Zur Verfügung stehen neben den Statechart-Diagrammelementen beliebige
Ovale und Polygone, welche zu Dokumentationszwecken genutzt werden können.
• Am Rahmen eines selektierten Zustands sind zwei Buttons sichtbar, welche
der Erzeugung von eingehenden und ausgehenden Transitionen dienen (engl.
Rapid-Buttons).
• Zustände können auch mit den Cursor -Tasten verschoben werden.
• Im Selektionsmodus kann ein Rechteck gezeichnet werden, dessen Inhalte
nach Beendigung des Zeichnens selektiert sind (engl. Marquee-Selection).
• Zusätzlich zu den üblichen Alignment-Funktionen wird angeboten das Verteilen von horizontalem und vertikalem Platz zwischen Diagrammelementen.
3.1.5. Poseidon For UML
Poseidon For UML von der Firma Gentleware ist eine auf ArgoUML basierende
kommerzielle Software und gehört damit ebenfalls zur Familie der UML-Modellierungswerkzeuge. Es besitzt alle Funktionsmerkmale von ArgoUML, bietet jedoch
einige weitere Bearbeitungshilfen, wie z. B. den Import von Rational Rose-Modellen,
Roundtrip-Engineering für Java und Layoutmechanismen. Diese Layoutmechanismen können als Plugins von verschiedenen Herstellern integriert werden. Angeboten wird derzeit z. B. ein Plugin von der Firma yWorks [52].
Editor-Funktionalitäten
Ergänzend zu den in Abschnitt 3.1.1 genannten grundlegenden Funktionalitäten
und denen von ArgoUML (Abschnitt 3.1.4) werden in Poseidon For UML zur
Bearbeitung von Statecharts folgende Operationen angeboten:
• Bearbeitungsschritte können rückgängig gemacht werden.
• Diagrammausschnitte können als Graphik in andere Anwendungen kopiert
werden.
• Reverse-Engineered Diagramme und graphisch modellierte Diagramme können gelayoutet werden. Wird nach einem generierten Layout das Diagramm
verändert, so kann hiernach statt einer neuen Layoutgenerierung ein aktualisierendes Layout durchgeführt werden, welches ein neues Layout unter Beachtung des letzten generierten Layouts berechnet. Ein auf diese Weise erzeugtes Layout ähnelt dem vorherigen Layout größtmöglich auf Kosten sich
eventuell kreuzender Transitionen.
29
3. Stand der Technik
• Eine Übersichtsansicht des gesamten Diagramms und und eine Eigenschaftsansicht des aktuell selektierten Elements wird angeboten in einem separaten
in die Benutzeroberfläche eingebundenen Bereich.
• Die Wahl des bearbeitbaren sichtbaren Bereichs des Diagramms und dessen
Zoomfaktor ist über die Übersichtsansicht steuerbar.
• Die Sichtbarkeit von Benutzeroberflächen-Elementen ist konfigurierbar.
• Schriftarten und Farben können individuell für jedes Diagrammelement eingestellt werden.
3.1.6. Ergebnis
Folgende Bearbeitungs- und Gestaltungshilfen werden von keinem der hier vorgestellten Statechart-Werkzeuge angeboten:
• automatisches Layout während des Platzierens von Diagrammelementen (Abschnitt 4.13),
• gleitende Strukturveränderung bei Layoutmaßnahmen (Abschnitt 4.7),
• Abspielen von Bearbeitungsschritten (Abschnitt 4.9),
• mehrschichtige Übersichtsdarstellungen (Abschnitt 4.10) und
• Bearbeitungsschritt-Historie (Abschnitt 4.23).
Diese Funktionalitäten werden in dieser Arbeit als nützlich eingestuft und bieten
sich daher zur Implementierung im KIEL-Editor an. Andere Funktionsmerkmale
wie z. B. die Design-Critics des Produktes ArgoUML werden ebenfalls als sinnvoll
erachtet, liegen allerdings nicht im Fokus von KIEL, siehe hierzu Abschnitt 1.1.
3.2. Evaluierung verfügbarer Graph-Editing-Frameworks
Ein Rahmenwerk (engl. Framework ) ist ein Softwaresystem, welches nur partiell
vollständig und damit nicht allein lauffähig ist, welches aber die Architektur für
eine spezifische Klasse von ähnlichen Softwaresystemen definiert und auf diese
Weise zusätzlich problemspezifische Funktionalitäten bietet.
Ein Ziel der vorliegenden Arbeit ist es, die am Markt verfügbaren Rahmenwerke
für Graph-Editoren dahingehend zu untersuchen, inwieweit diese zur Implementierung eines Statechart-Editors genutzt werden können. Durch Verwendung solcher
Rahmenwerke kann der Entwicklungsaufwand zur Realisierung häufig wiederkehrender grundlegender Funktionen von Graph-Bearbeitungs-Werkzeugen deutlich
verringert werden. Einige Rahmenwerke werden überblickartig und ausführlich in
[24] dargestellt.
30
3.2. Evaluierung verfügbarer Graph-Editing-Frameworks
Als Graph-Editing-Frameworks werden solche Softwareprodukte bezeichnet, welche Benutzerinteraktion, Graphdarstellung und Graph-Bearbeitungsmechanismen
bereitstellen. Im Java-Umfeld sind solche Rahmenwerke häufig Swing-orientiert
und setzen das MVC -Muster (Abschnitt 2.4.3) um.
3.2.1. Anforderungen
Jedes der in Abschnitt 3.2.2 untersuchten Rahmenwerke bietet folgende grundlegende Graph-Bearbeitungsfunktionen:
• Darstellung von Knoten mit unterschiedlichen Formen,
• Verbinden zweier Knoten mit einem gerichteten Pfeil,
• Pfeile haften an Knoten beim Verschieben von Knoten,
• Skalierung der Darstellung,
• Cut-and-Paste-Funktionalität und
• Veränderbarkeit der Größen von Knoten.
Alle verfügbaren hier betrachteten Rahmenwerke unterscheiden sich voneinander
allerdings bezüglich folgender Eigenschaften, deren Vorhandensein für den KIELStatechart-Editor notwendig ist:
Graph-Hierarchien: Die Fähigkeit, Hierarchien darzustellen, zeigt sich einerseits
in einer baumartigen Modell-Struktur, und andererseits soll ein Verschieben
vollständiger Hierarchiezweige möglich sein.
KIEL-Konformität der Darstellung: Das Rahmenwerk soll Statecharts genau so
anzeigen können wie der KIEL-Browser [50].
Live-Preview : Als bedienungsfreundlich zeigt sich die Eigenschaft, ein Element
während seines Verschiebens vollständig darzustellen. Der Benutzer sieht auf
diese Weise zu jedem Zeitpunkt, wie das Ergebnis des Verschiebens aussieht.
Des Weiteren sollen während des Verschiebens eines Diagrammelements andere Elemente änderbar sein, um die in Abschnitt 4.13 beschriebenen Layouthilfen implementieren zu können.
Layers: Die Reihenfolge übereinander liegender Diagrammelemente soll variabel
sein, sofern die Elemente nicht als transparente Objekte dargestellt werden.
Anderenfalls würde ein unter einem größerem Diagrammelement liegendes
kleineres Element verdeckt werden.
31
3. Stand der Technik
Model-View-Controller -Konformität: Verschiedene Sichten auf das Statechart sollen möglich sein, ohne Aktualisierungsmechanismen implementieren zu müssen. Im KIEL-Editor sollen bei einer Datenmodell-Änderung – z. B. veranlasst durch eine Benutzeraktion – die Bearbeitungssicht und die Übersichtsdarstellung automatisch aktualisiert werden, siehe Abschnitt 2.4.3, so dass
beide Sichten zu jedem Zeitpunkt eine Repräsentation des aktuellen Model Zustands zeigen.
Verschiedene Pfeil-Stile: Es sollen Spline-Kurven und Polygone gezeichnet werden
können.
Undo-and-Redo-Funktionalität: Bearbeitungsschritte sollen rückgängig gemacht
werden können.
Layout: Vorteilhaft sind in das Rahmenwerk integrierte Layout-Algorithmen, welche die Implementierung der in Abschnitt 4.13 beschriebenen Mechanismen
unterstützen können.
Selektive Sichtbarkeit von Diagrammelementen: Das Kollabieren und Expandieren von Knoten erfordert eine variable Sichtbarkeit von Diagrammelementen,
siehe Abschnitt 4.5.
Beschriften von Knoten und Pfeilen soll möglich sein.
Syntaxgerichtetes Editieren: Pfeile müssen immer Anfangs- und End-Knoten haben.
Um jedoch eines der getesteten Rahmenwerke erfolgreich einsetzen zu können,
sind darüber hinaus auch die folgenden projekttechnischen Eigenschaften von Bedeutung [17].
Projektaktualität: Die schnell fortschreitende Entwicklung im Bereich der JavaProgrammierung fordert ständige Aktualität von Rahmenwerken, um kompatibel zur aktuellen Java-Version zu sein.
Projektaktivität: Es soll eine rege Entwicklungstätigkeit erkennbar sein, z. B. hoch
frequentierte Benutzer-Foren oder eine hohe Fehlerbearbeitungsrate, welche
ihrerseits ersichtlich ist in entsprechenden Fehler-Datenbanken (engl. BugTracking-Tools). Aus einer hohen Aktivität kann auf stabile Versionen und
Produktunterstützung geschlossen werden.
Projektkommunikation: Kommunikation mit den Entwicklern oder Benutzern des
Rahmenwerks über Foren kann hilfreich bei der Anwendung des Rahmenwerks sein.
Dokumentation: Hierzu sollen Design-Papiere gehören, Unterrichtsmaterialien (engl.
Tutorials und How-To’s), Quelltextkommentare (Javadoc, engl. Inline-CodeComments) und die Verfügbarkeit des kompletten Quelltextes.
32
3.2. Evaluierung verfügbarer Graph-Editing-Frameworks
Programm-Quelltext-Umfang: Rahmenwerke werben mit einfachem, schlankem
und leicht verständlichem Design, welches sich hervorragend erweitern und
an viele Bedürfnisse anpassen lässt. Zur objektiven Bewertung dieser Kriterien eignet sich die Größe des Programm-Quelltextes in Relation zur Funktionalität der Beispiele. Hierbei muss jedoch beachtet werden, dass in manchen
Rahmenwerken zusätzlich weitere Standard-Rahmenwerke wie z. B. solche
zur XML-Bearbeitung enthalten sind.
Verwendete Entwurfsmuster: Entwurfsmuster (Abschnitt 2.4.3) erhöhen generell
die Wartbarkeit und Robustheit der Software und senken die Einarbeitungszeit.
Beispiele: Diese dienen der Funktionsanalyse des Rahmenwerks und ergänzen die
Dokumentation.
Grad an Flexibilität und Erweiterbarkeit: Dieser lässt sich an der Anzahl und
Art der Aufsetzpunkte (engl. Hooks) messen. Funktionelle Erweiterungen
sollen allein durch Subklassenbildung und/oder das Setzen von Eigenschaften
implementiert werden können. Der Programm-Quelltext des Rahmenwerks
soll hierfür nicht geändert werden müssen.
Projektstruktur: Die Gliederung in Add-Ons und Rahmenwerk-Erweiterungen
dient der Übersichtlichkeit und Verringerung der Komplexität. Vollständig
auf dem jeweiligen Rahmenwerk basierende Open-Source-Produkte, hier z. B.
komplette Editoren, können zur Verringerung des Entwicklungsaufwandes
führen und zeigen darüber hinaus die Anwendung des Rahmenwerks.
Nichtkommerzielle Open-Source Java-API: Der zu entwickelnde Editor soll Bestandteil von KIEL werden, welches seinerseits in Java geschrieben ist. Zwar
ist keine enge Verzahnung des Editors mit dem Rest des Projektes vorgesehen, zumindest soll jedoch der Editor auf der KIEL-Datenstruktur operieren können. Daher ist es zweckmäßig, den Editor in Java zu entwickeln.
Der Editor wie auch das gesamte Projekt wird zu Forschungszwecken entwickelt und ein Ende der Entwicklungstätigkeit ist nicht abzusehen. Darüber
hinaus soll das fertiggestellte Statechart-Werkzeug auch ohne lizenzrechtliche Restriktionen frei eingesetzt werden. Aus diesen Gründen soll die Wahl
auf ein nichtkommerzielles Open-Source-Graph-Rahmenwerk fallen. Ferner
ist die Änderung des Quelltextes in der Regel bei kommerziellen Produkten nicht möglich. Es gibt über zehn nichtkommerzielle in Java geschriebene
Open-Source-Graph-Rahmenwerke, siehe Abschnitt 3.2.2, daher stellen diese geforderten Eigenschaften keine zu starke Einschränkung in der Auswahl
eines Rahmenwerks dar.
Wie sich im nächsten Abschnitt zeigt, stellen die in diesem Abschnitt geforderten
Eigenschaften an Graph-Editing-Frameworks keine unerfüllbaren Bedingungen bei
der Auswahl eines Rahmenwerks dar.
33
3. Stand der Technik
3.2.2. Übersicht über Graph-Editing-Frameworks
Insgesamt wurden in dieser Arbeit 16 Graph-Editing-Frameworks untersucht, welche als Grundvoraussetzung auf Java basieren. Aus diesen Rahmenwerken wurden
entsprechend den Anforderungen aus dem vorherigen Abschnitt die vier passendsten Produkte ausgewählt und in diesem Abschnitt tabellarisch einander gegenübergestellt. Diese vier Rahmenwerke sind quelloffen, nicht-kommerziell und sind
in einer aktuellen Version verfügbar. Der hier vorgenommene Vergleich dieser Rahmenwerke basiert zum einen auf der Auswertung der zur Verfügung stehenden jeweiligen Dokumentation und zum anderen auf Quelltextanalyse und kleineren Implementierungstests. Die übrigen zwölf Rahmenwerke werden im Abschnitt 3.2.3
kurz vorgestellt.
Das Vorhandensein der in Abschnitt 3.2.1 genannten Merkmale in den hier ausgewählten Rahmenwerken wird in tabellarischer Form im Folgenden ausgewiesen.
In der Tabelle 3.1 werden in einer Übersicht funktionale und projekttechnische
Merkmale dieser Rahmenwerke miteinander verglichen. Nähere Erläuterungen zu
den Angaben in der Tabelle liefert Abschnitt 3.2.3.
Die Symbole in der Tabelle 3.1 bedeuten:
√
• : Ist vorhanden
• ++: Sehr gut, sehr viel
• +: gut, mehrere
• o: Aufwand oder Umfang kann nicht genau geschätzt werden
• -: unterdurchschnittlich, gering
• - -: ungenügend, fehlend
Im nächsten Abschnitt werden Erläuterungen zum Inhalt der Tabelle 3.1 gegeben.
3.2.3. Ergebnis
Nachfolgend werden die Vorteile und Nachteile der Rahmenwerke GEF, GVF,
JGraph und GINY auf Basis der Tabelle 3.1 dargestellt. Das Rahmenwerk JGraph
überzeugt am meisten sowohl im Funktionsumfang als auch in den projekttechnischen Eigenschaften und eignet sich daher am besten als Grundlage für die Implementierung des KIEL-Editors.
GEF - Graph Editing Framework
Positiv fällt in diesem Rahmenwerk [13] auf, dass es bekannte Entwurfsmuster
wie das MVC -Muster (Abschnitt 2.4.3), Befehlsmuster (Abschnitt 2.4.3) und Zustandsmuster (Abschnitt 2.4.3) verwendet, und die Darstellungsebene der Architektur auf den Java-Swing-Klassen javax.swing.JTree und javax.swing.JTable
34
3.2. Evaluierung verfügbarer Graph-Editing-Frameworks
GEF
GVF
JGraph
GINY
√
√
√
√
√
√
√
o
-√
Funktionale Anforderungen
Graphhierarchien
Darstellung KIEL-konform
Live Preview
Layers
Model-View-Controller
Verschiedenartige Pfeil-Stile
(Spline, Bezier, Orthogonal)
Undo-and-Redo
Layout
Selektive Sichtbarkeit von Elementen
Anhängen von Text
Syntaxgerichtetes Editieren (Pfeile)
- - (jedoch
ArgoUML)
-√
√
(gut)
√
√
unvollständig
-o
√
√
-o
o
-o
o
√
√
o
o
√
√
-o
--
√
√
√
√
√
√
++
++
+
--
++/++/++
+
52/++
+
30/+
135
+
7/54
√
- -/- -/- -
-o
Projekttechnische Anforderungen
Projektaktualität
Projektaktivität
Projektkommunikation
(Entwickler / Foren / Aktualität)
Architektur-Dokumentation
(Anz. Seiten / Wertung)
Tutorial-Dokumentation
(Anz. Seiten / Wertung)
Umfang (Größe Bytecode in kB)
Verwendete Entwurfsmuster
Beispiele (Anzahl/Größe in kB)
Erweiterbarkeit
Erweiterungen / Produkte
Nichtkommerziell und Open-Source
++
o
o/- -/o
0/- -
--- -/-/-16/+
0/- 523
++
4 / 95
√
0/- 821
+
0/0
o
- -/++
√
- -/+
√
++/+
√
22+15/+
15/+
1680
+
0/0
o
- -/- √
Tabelle 3.1.: Funktionale und projekttechnische Anforderungen
35
3. Stand der Technik
basiert. Dem gegenüber werden einige wichtige Funktionalitäten wie z. B. GraphHierarchien und Undo-and-Redo-Mechanismen nicht bereitgestellt [42], welche allerdings zumindest im auf dem GEF aufbauenden Softwareprodukt ArgoUML (Abschnitt 3.1.4) implementiert werden. Ebenso unvorteilhaft erscheint die Tatsache,
dass in GEF Funktionalitäten enthalten sind, welche in ein Rahmenwerk nicht
hineingehören, weil sie zu anwendungsspezifisch sind, wie z. B. die Möglichkeit,
Makros aufzeichnen und abspielen zu können. Dies führt zu Unübersichtlichkeit
und erhöhtem Einarbeitungsaufwand, da die Komplexität des Rahmenwerks mit
zunehmender Größe zunimmt.
Aus den Beispielen und der Dokumentation ist nicht ersichtlich, dass verschiedene Darstellungsmöglichkeiten für Diagrammelemente bestehen. Die Dokumentation und Funktionsmerkmal-Liste ist über sechs Jahre alt, neue Releases erscheinen hingegen alle 2-4 Monate. Zwar werden E-Mail-Adressen der Entwickler
veröffentlicht, jedoch gibt es keine Foren für dieses Projekt und auch auf ein Fehlerberichtswerkzeug (engl. Bug-Tracking-Tool ) ist nicht zugreifbar, daher kann die
Projektaktivität nicht beurteilt werden.
GVF - Graph Visualization Framework
Dieses Rahmenwerk, in [31] und [32] näher beschrieben, besitzt neben 16 Seiten
Dokumentation einen vollständig implementierten Graph-Editor, der jedoch undokumentiert ist. Die letzte Version ist sechs Monate alt und die Vorgängerversion
wurde im Jahr 2002 freigegeben. Es existiert keine Projektkommunikation und
auch Foren sind nicht vorhanden. Zumindest Entwurfsmuster wie MVC -Muster
(Abschnitt 2.4.3) und Dekorierer-Muster werden eingesetzt. Positiv fällt auch auf,
dass die Architektur bezüglich Graph-Struktur und Graph-Darstellung derjenigen
von KIEL ähnlich ist und dass weitergehende Funktionalitäten wie Layout und
Fokus-und-Kontext-Zoom [39] implementiert sind.
JGraph
Das Rahmenwerk JGraph [2] zeichnet sich durch eine relativ große Benutzergemeinde aus, welche in mehreren Foren organisiert ist, sowie durch eine hohe Projektaktualität und Aktivität. Neue Versionen des Rahmenwerks werden monatlich
freigegeben. Kommunikation mit den Entwicklern ist ebenso möglich wie das Berichten von Fehlern in Bug-Tracking-Tools. Das Rahmenwerk ist nicht kommerziell.
Allerdings wird durch den Erwerb einer Lizenz eine bevorzugte Unterstützung gewährt.
Die Dokumentation eignet sich zur Erstellung von Applikationen, die auf dieses
Rahmenwerk aufsetzen, und auch beispielhafter ständig aktualisierter ProgrammQuelltext ist in ausreichender Menge vorhanden. Die Schnittstellen-Definition der
Komponenten allerdings ändert sich von Version zu Version, was eine Portierung
einer auf JGraph basierenden Anwendung auf eine neue JGraph-Version erschwert.
Zwar erfüllt JGraph alle funktionalen Anforderungen, jedoch ist das Rahmenwerk
36
3.2. Evaluierung verfügbarer Graph-Editing-Frameworks
nicht Multithreading-fähig, was im Bereich der gleitenden Strukturveränderung
(Abschnitt 4.7) sich als ungünstig erweist.
GINY - Graph Interface library
Bei GINY, beschrieben in [8] und [4], handelt es sich um ein Rahmenwerk, welches aus Schnittstellendefinitionen besteht, die durch Bibliotheken anderer Projekte implementiert werden. Eine dieser Bibliotheken ist das CERN Colt-Projekt,
entwickelt am CERN (Europäische Organisation für Nuklearforschung), welches
Datenstrukturen und Operationen für numerische Daten und komplexe GraphOperationen bereitstellt. Die graphische Seite von GINY wird implementiert von
Piccolo, entwickelt an der Universität Maryland, und enthält eine zoombare Benutzeroberfläche und unterschiedlichste Graph-Knotenarten. Vervollständigt wird
GINY durch die Bibliothek des Open-Source-Projektes Java Universal Network/Graph Framework (JUNG), welches Layoutmechanismen auf Graphen zur Verfügung stellt.
Durch diese Projektstruktur ist GINY umfangreich und unübersichtlich. Daneben wird Benutzerinteraktion in nur geringem Umfang unterstützt. Insgesamt
reichen die Funktionalitäten für eine auf das Rahmenwerk aufbauende Entwicklung
eines Statechart-Editors nicht aus.
Übersicht über nicht geeignete Rahmenwerke
Nachfolgend sind weitere Graph-Frameworks und Graph-Editing-Frameworks aufgelistet, welche entweder aus Gründen mangelnder Projektaktualität, aufgrund zu
geringen Funktions- oder Dokumentationsumfanges oder aufgrund ihres kommerziellen Charakters grundsätzlich nicht in Frage kommen:
• VGJ : Ist zu alt und wird nicht mehr gepflegt [48]
• GFC : Es ist keine aktuelle Version verfügbar [6]
• Grace: Hierbei handelt es sich um einen Statechart-Editor-Generator. Es ist
keine ausreichende Dokumentation vorhanden [27].
• JDigraph: Es existiert noch keine freigegebene Version (engl. Release) sondern nur ein Alpha-Release. Außer Javadoc-Kommentaren steht noch keine
Dokumentation zur Verfügung [49].
• ToughGraph: Dieses Rahmenwerk bietet nur die Darstellung von Graphen.
Bearbeitungsmöglichkeiten sind nicht vorgesehen [41].
• JGraphEd : Unterstützt das Skalieren von Graphteilen, jedoch keine Hierarchien. Die Dokumentation ist nicht ausreichend [20].
• yFiles: yFiles erfüllt alle Anforderungen aus Abschnitt 3.2.1. Da es sich allerdings um eine kommerzielle Software handelt, ist eine Verwendung in KIEL
ungünstig [52].
37
3. Stand der Technik
• Tom Sawyer Software: Ebenso wie bei yFiles handelt es sich bei Tom Sawyer
um ein kommerzielles Rahmenwerk und soll daher in KIEL ebenfalls nicht
eingesetzt werden [40].
• Hypergraph: Für dieses Rahmenwerk ist keine Dokumentation verfügbar [25].
• Jung: Gegen eine Verwendung dieses Rahmenwerks sprechen die fehlende
Lauffähigkeit der Beispiele, der große Umfang und die fehlende Unterstützung von Graph-Hierarchien. Jung bietet lediglich grundlegende Visualisierungsmöglichkeiten, jedoch keine Editorfunktionalität [38].
• WilmaScope: WilmaScope unterstützt keine Hierarchien, besitzt eine Benutzeroberfläche zum Editieren und die Möglichkeit einer 3D-Darstellung von
Graphen. Eine KIEL-konforme Darstellung von Statecharts ist allerdings
nicht möglich [11].
• Eclipse GEF : Dieses Rahmenwerk ist nicht portabel, da es das plattformabhängige SWT -Rahmenwerk verwendet. Ausreichend Dokumentation ist vorhanden, allerdings sind die Beispiele nicht lauffähig [23].
38
4. Anforderungsspezifikation des
KIEL-Editors
Mit dem zu entwickelnden Editor soll es möglich sein, z. B. das in Abbildung 4.1
gezeigte Referenzbeispiel zu erstellen. Zu den hierfür notwendigen grundlegenden
Bearbeitungsfunktionen sollen darüber hinaus innovative und bisher nicht oder
nur teilweise in Statechart-Werkzeugen vorhandene intelligente Bearbeitungshilfen implementiert werden, welche teilweise [39] entnommen sind. Die vorliegende
Anforderungsspezifikation umfasst dabei nicht sämtliche Funktionsmerkmale eines
der in Abschnitt 3.1 vorgestellten Statechart-Editoren, sondern eine willkürliche
Auswahl an Funktionalität aus verschiedenen Statechart-Editoren und zusätzlicher
Funktionsmerkmale.
Abbildung 4.1.: Ein Referenzbeispiel
In diesem Kapitel werden die Anforderungen, welche an die vorliegende Arbeit
gestellt werden, beschrieben. Neben der Umsetzung dieser Anforderungen wird
darüber hinaus der Versuch unternommen, in Bezug auf Funktionalität und Er-
39
4. Anforderungsspezifikation des KIEL-Editors
scheinungsbild eine kompetitive Software zu erstellen. Die hierfür gesteckten Ziele
werden ebenfalls in diesem Kapitel vorgestellt und stellen eine Erweiterung der
Anforderungen dar. Sämtliche Funktionsmerkmale, welche in diesem Kapitel dargestellt werden, sind im KIEL-Editor auch umgesetzt und können angewendet
werden. Somit stellt das vorliegende Kapitel die Spezifikation des tatsächlichen
Funktionsumfangs des Editors dar.
4.1. Syntaxgerichtetes Editieren
Unter Interpretation einer Zeichnung wird verstanden, den einzelnen Elementen
der Zeichnung eine Bedeutung zuzuordnen. Wenn solch eine Zuordnung möglich
ist, dann kann diese Zeichnung in eine andere Darstellungsform übersetzt werden,
welche z. B. eine Baumstruktur oder eine Darstellung in Textform sein kann.
Grundsätzlich kann man graphische Editoren dahingehend unterteilen, in wieweit sie den Benutzer dazu verpflichten, bestimmte syntaktische Regeln bei der
Eingabe einer Zeichnung einzuhalten, um damit eine Interpretation der Zeichnung
zu ermöglichen. Kann der Benutzer beliebige Zeichnungen eingeben und sind beliebige Eingabeschritte erlaubt, so spricht man von freiem Editieren (engl. FreeHand-Editing). Editoren jedoch, welche dem Benutzer eine definierte Menge an
graphischen Formen anbieten und welche die Veränderung und Komposition dieser Formen nur in ganz bestimmter Art und Weise zulassen, definieren eine Menge
von Eingaberegeln, welche die Syntax der eingebbaren Zeichnungen darstellen.
Man spricht hier von syntaxgerichtetem Editieren (Syntax-Directed-Editing), also
vom Einschränken der Eingabemöglichkeiten auf syntaxkonforme Varianten.
Es ist offensichtlich, dass syntaxgerichtetes Editieren in einem Statechart-Editor
die Erstellung syntaktisch korrekter Diagramme vereinfacht. Grundsätzlich verringert syntaxgerichtetes Editieren die Menge an Benutzereingaben, die nötig sind,
um ein gewünschtes Ergebnis zu erhalten. Wenn z. B. nur Rechtecke gezeichnet
werden können, kann dem Benutzer das Wählen und Zeichnen der vier Kanten
eines Rechtecks abgenommen werden und stattdessen das sprachspezifische Editierkommando Rechteck zeichnen (hier: Zustand zeichnen) angeboten werden.
Im Allgemeinen sollen bearbeitete Statecharts auch interpretiert werden können,
um dann simuliert zu werden. Dies ist jedoch nur möglich, wenn der Aufbau des
Statecharts den Regeln der Sprache genügt. Um den Benutzer von Eingaben abzuhalten, welche diesen Regeln zuwiderlaufen, werden solche Benutzeraktionen bei
syntaxgerichtetem Editieren einfach ausgeschlossen. Hierbei werden all die Benutzeraktionen als regelkonform betrachtet, welche zu Statecharts führen, die ihrerseits
ausschließlich durch Hinzufügen von weiteren Diagrammelementen zu vollständigen simulierfähigen Diagrammen erweitert werden können. Genau dieses Merkmal
soll im vorliegenden Statechart-Editor umgesetzt werden.
In wieweit eine Eingabesyntax durch den Editor vorgegeben ist, bestimmt auch
den Zeitpunkt, zu dem die eingegebene Zeichnung interpretiert werden kann. In
Editoren, welche ausschließlich syntaxgerichtetes Editieren erlauben, kann nach je-
40
4.1. Syntaxgerichtetes Editieren
dem Eingabeschritt jedes Element der Zeichnung und somit die gesamte Zeichnung
interpretiert werden, wenngleich sie noch nicht vollständig und damit korrekt sein
muss. Jeder Eingabeschritt wirkt sich als Operation direkt auf das Datenmodell
aus. Es ist daher möglich, das Datenmodell in einem Diagramm oder auch z. B. in
einer Baumstruktur oder einer Repräsentation in Textform darzustellen. So können
verschiedene Darstellungen, welche auf diesem Datenmodell beruhen, nach jedem
Eingabeschritt aktualisiert werden.
Anders verhält es sich bei Editoren, welche freies Editieren erlauben. Bei solchen
Editoren kann das Datenmodell im ungünstigsten Fall erst nach vollständiger Eingabe der Zeichnung erstellt werden. Erst dann nämlich können die gezeichneten
Figuren (hier: Zustände und Transitionen) als vollständig angenommen werden
und sodann diese Figuren, ihre Anordnung, Position und Größe, sowie ihre räumlichen Beziehungen wie Schachtelung (Hierarchie) und Berührung analysiert werden.
Man spricht im Gegensatz zu semantischen Operationen hierbei von graphischem
Scanning, einer lexikalischen Analyse, welche ihrerseits im günstigsten Falle zu
einem korrekten Statechart führt [21].
Folgende Regeln sollen im KIEL-Editor umgesetzt werden:
• Geometrische Regeln:
– Es können nur Rechtecke, Kreise und Pfeile eingegeben werden, wie sie
in Abschnitt 2.3.2 angegeben sind. Es sollen genau die dort aufgezählten
Elemente und diese nur als Ganzes erzeugbar sein.
– Zwei Rechtecke oder Kreise dürfen sich nicht teilweise überlappen. Entweder ist das eine von beiden vollständig in dem anderen enthalten oder
gar nicht.
– Zustandskanten dürfen sich nicht beliebig nahe kommen (z. B. 10 Pixel
Abstand, konfigurierbar).
– Alle Diagrammelemente sind löschbar. Positionsänderbar sind alle Diagrammelemente mit Ausnahme der Delimiter-Lines. Größenänderbar
sind alle Diagrammelemente außer AND-States.
– Pfeile müssen als Anfangs- und Endpunkt die Kante eines Zustands
besitzen.
• Semantische Regeln, siehe hierzu Abschnitt 2.3.2:
– Nur in Composite-States können Zustände eingefügt werden.
– Jeder OR-State und jede Region dürfen höchstens einen Initial-State
besitzen.
– History-States und Deep-History-States dürfen nur in OR-States und
AND-States liegen und dies höchstens jeweils einmal.
– History-States und Deep-History-States können nicht beliebig platziert
werden. Sie ’sitzen’ immer unter dem Expansionssymbol eines CompositeStates.
41
4. Anforderungsspezifikation des KIEL-Editors
– Delimiter-Lines dürfen nur im dafür vorgesehenen Bereich von Composite-States eingefügt werden, nicht jedoch im Root-State.
– Initial-States dürfen nur in Regions und OR-States liegen und dies
höchstens jeweils einmal.
– Quellzustand und Zielzustand einer Transition müssen den gleichen Vater besitzen, d.h., Interlevel-Transitionen können nicht erzeugt werden.
– Transitionen dürfen nicht in Initial-States, Suspends und in den RootState hineinführen.
– Transitionen dürfen nicht aus dem Root-State, History-States, DeepHistory-States und Final-States hinausführen.
– Zustände dürfen nur dann als Endzustand deklariert werden, wenn sie
keine ausgehenden Transitionen besitzen.
– Aus Suspends führen nur Suspend-Transitions heraus. Der Transitionstyp kann nicht geändert werden.
– Aus Initial-States führen nur Initial-Arcs heraus. Der Transitionstyp
kann nicht geändert werden.
– Aus Conditional-States führen nur Conditional-Transitions heraus. Der
Transitionstyp kann nicht geändert werden.
Diese Regeln werden angewendet, sobald der Benutzer ein neues Element hinzufügen möchte oder eine Verschiebe-, Größenänderungs- oder Cut-and-Paste-Aktion
ausführt. Wird gegen eine der obigen Regeln verstoßen, so erscheint am Mauszeiger
ein rotes Kreuz, siehe Abbildung 4.13(a), und die Aktion wird nicht ausgeführt.
Eine Ausnahme hierzu bildet das automatische Layout in bestimmten Situationen,
siehe Abschnitt 4.6.
Zum syntaxgerichteten Editieren gehört neben dem Erzeugen von Diagrammelementen im Falle von Statecharts auch die auf syntaktische Richtigkeit geprüfte
Deklaration von Ereignissen, Variablen und Transitionsbeschriftungen. Es sollen
eingebbar sein:
• On-Entry-Actions, On-Inside-Actions und On-Exit-Actions können für alle
Zustände deklariert und bearbeitet werden.
• Lokale Ereignisse und lokale Variablen können für Composite-States deklariert werden.
• Statechart-globale Input-Events und Output-Events können in einem Dialogfenster editiert werden.
• Transitionsbeschriftungen können editiert werden im Format Trigger {Condition} / Action. Die in der Transitionsbeschriftung angegebenen Ereignisse
und Variablen müssen vorher deklariert worden sein.
42
4.2. Graphische Darstellung eines Statecharts
4.2. Graphische Darstellung eines Statecharts
Die graphische Repräsentation von Statecharts im KIEL-Editor soll der Spezifikation von KIEL entsprechen. Sie ist angegeben in den Abschnitten 2.3.2 und 2.3.3.
Die Anzeige einiger dieser Elemente soll konfigurierbar sein, siehe hierzu Abschnitt
4.22.
4.3. Anwendung von verschiedenen Layouts
In KIEL werden Statecharts während der Simulation dynamisch visualisiert, d.h.,
die graphische Repräsentation eines Statecharts ändert sich mit jedem Simulationsschritt. Je nachdem, welche Zustände im aktuellen Schritt von Bedeutung sind,
sind Zustände ein- oder ausgeklappt. Jede hieraus resultierende Kombination von
ein- und ausgeklappten Zuständen wird Sicht (engl. View ) des Statecharts genannt. Da ein eingeklappter Zustand weniger Platz als ein ausgeklappter Zustand
einnimmt, erfordert jede Sicht ihr eigenes Layout. Das Layout jeder dieser Sichten
entspricht jedoch unter Umständen – sofern es z. B. automatisiert erzeugt wird –
nicht den Wünschen des Benutzers und bedarf deswegen einer Nachbesserung im
Editor. Diese Änderungen sind jedoch nur dann sinnvoll, wenn sie gespeichert werden können, ansonsten sind sie nur im Browser während der Simulation verfügbar.
Sofern in KIEL verschiedene Sichten eines Statecharts gespeichert werden können,
soll der Editor verschiedene Sichten des Statecharts bearbeiten können.
4.4. Modellorientierung
Unter Modellorientierung können und sollen in diesem Kontext verschiedene Sachverhalte verstanden werden:
• Statecharts werden in KIEL in Form zweier Datenstrukturen repräsentiert,
von denen die eine die hierarchische Struktur des Statecharts beschreibt und
die andere Datenstruktur die graphische Repräsentation des Statecharts beinhaltet. Auf diesen Datenstrukturen operieren sämtliche KIEL-Module. Der
KIEL-Editor soll aus Gründen der Interoperabilität auf der gleichen Struktur
– auch Datenmodell genannt – arbeiten.
• Der KIEL-Editor soll den Entwurf verschiedener Statechart-Modelltypen unterstützen. Der Benutzer soll dabei zu Beginn des Editierens eines neuen
Statecharts wählen können zwischen Esterel-Studio- und Matlab-Modellen
und damit die Menge der zur Verfügung stehenden Diagrammelemente bestimmen können. Eine spätere Erweiterung um andere Statechart-Dialekte
soll möglich sein, siehe hierzu im Anhang den Abschnitt A.3.3.
• Die Implementierung soll auf dem MVC -Muster (Abschnitt 2.4.3) basieren.
43
4. Anforderungsspezifikation des KIEL-Editors
4.5. Verstecken innerer Zustände
Hierunter fällt die Veränderung der Sichtbarkeit der Unterzustände von Hierarchiezuständen.
Ähnlich wie beim Betrachten von Statecharts sind während des Bearbeitungsprozesses die Inhalte einiger Hierarchiezustände uninteressant und verbrauchen unnötig Darstellungsfläche. Aus diesem Grund soll es im Editor möglich sein, Hierarchiezustände zu kollabieren und zu expandieren. Dabei soll beim Einklappen neben
dem Verstecken der inneren Zustände der Hierarchiezustand verkleinert werden sowie beim Ausklappen dessen Ursprungsgröße wiederhergestellt werden.
Zusätzlich zu diesen Anforderungen muss ein Mechanismus implementiert werden, welcher das Verschieben anliegender Zustände automatisch vornimmt, wenn
für das Ausklappen nicht genügend Platz zur Verfügung steht, siehe hierzu Abschnitt 4.6. Des Weiteren soll das Ein- und Ausklappen als gleitende Strukturveränderung (Abschnitt 4.7) durchgeführt werden können .
4.6. Layout
Grundsätzlich fördert ein übersichtliches Diagramm die Verständlichkeit desselben.
Besonders bei großen Diagrammen bedeutet das manuelle übersichtliche Platzieren
von Diagrammelementen einen großen Aufwand, welches dazu häufig noch iterativ
durchgeführt werden muss. Während der Erweiterung eines Statecharts kann die
Situation auftreten, dass das Gesamtbild für den Betrachter zunehmend schwerer
verständlich wird, weil eine einheitliche Struktur nicht aufrechterhalten wird. Des
Weiteren können sich im Verlauf der Bearbeitung Transitionen unvermeidbar überkreuzen, gleichartige Zustände unterschiedliche Größen besitzen und der zur Verfügung stehende freie Raum sich ungleichmäßig verteilen. Neben dem erhöhten Aufwand des manuellen iterativen Layoutens stellt sich als weiterer Nachteil heraus,
dass ein nicht nur vom Kontext sondern auch vom Benutzer abhängiges Layout entsteht, was in Projekten zwecks angestrebter Einheitlichkeit der Diagrammdarstellung grundsätzlich unerwünscht ist. Dieses Problem löst die Layouter-Komponente
von KIEL. Diese soll für das im Editor aktuell bearbeitete Statechart ein neues
Layout berechnen. Das Ergebnis soll durch eine gleitende Strukturveränderung
dargestellt werden, siehe Abschnitt 4.7.
Immer wieder bedarf es bei nicht vorausschauendem Entwurf des Diagramms
des Schaffens von zusätzlichem Platz für neue Elemente. Daher soll zusätzlich zur
Benutzung des KIEL-Layouters ein editoreigener Layoutmechanismus angewendet
werden, wenn für einen neu einzufügenden Zustand nicht genug Platz zur Verfügung steht, siehe Abschnitt 4.13.
44
4.7. Layoutgestützte gleitende Strukturveränderung
4.7. Layoutgestützte gleitende Strukturveränderung
Mit Struktur ist hier die graphische Anordnung der Zustandsdiagrammelemente gemeint. Unter Veränderung dieser Anordnung versteht man die Änderung
der Position oder Größe von Zustandsdiagrammelementen. Eine Strukturveränderung (engl. Morphing) wird gleitend genannt, wenn die Veränderung nicht in
einem Schritt sondern als Folge von sich geringfügig unterscheidenden Anordnungen durchgeführt wird. Für den Betrachter soll aus der Ausgangsanordnung heraus
die Zielanordnung erwachsen, siehe Abbildung 4.2.
Worin liegt der Sinn einer gleitenden Veränderung? Große Veränderungen erschweren es dem Benutzer, diese nachzuvollziehen. Der Überblick kann verloren
gehen. Daneben könne sie zu einer Verringerung der Akzeptanz der programmgesteuerten Layoutveränderungen führen. Der Benutzer entwirft ein Statechart derart, wie er sich die Statechart-Struktur gedanklich vorstellt. Dies bezeichnet man
auch als Mental-Map. Dabei ist die vorgestellte Struktur die im ersten Moment einzig korrekte Struktur aus Sicht des Benutzers. Jedes hiervon abweichende Layout
muss daher als Vorschlag dem Benutzer gegenüber dargebracht werden.
(a) Anfangsanordung
(b) 1. Zwischenschritt
(c) 2. Zwischenschritt
(d) Zielanordnung
Abbildung 4.2.: Layoutgestützte gleitende Strukturveränderung
Im hier zu implementierenden Editor soll eine gleitende Strukturveränderung
bei Ausführung eines Layoutvorgangs (Abschnitt 4.6), beim Kollabieren und Expandieren von Zuständen (Abschnitt 4.5), sowie beim automatisch durchgeführten
Vergrößern von Zustandsdiagrammelementen als Folge von Platzproblemen beim
Positionieren von neuen Elementen (Abschnitt 4.13) durchgeführt werden.
45
4. Anforderungsspezifikation des KIEL-Editors
4.8. Rasterorientiertes Bearbeiten
Im Editor werden alle graphischen Elemente in einem Koordinatensystem angeordnet. Die linke obere Ecke hat die Koordinaten (0,0). Dieses ganzzahlige Koordinatensystem kann man als Raster auffassen mit Rastergröße 1.
Im Falle eines Statechart-Editors ist eine so feine Rasterung jedoch nicht notwendig und erschwert sogar das Anordnen von Elementen, sofern sie auf eine bestimmte Art und Weise relativ zueinander angeordnet werden sollen wie z. B. die
Ausrichtung an einer Geraden.
Eine Lösung dieses Problems bietet die Veränderung der Rastergröße auf z. B.
ein Viertel der Größe von Pseudo-States, also etwa 5 Pixel. In diesem Fall wären die
Koordinaten aller Diagrammelemente ganzzahlige Vielfache von 5. Will man bei
solch einem Raster ein Element verschieben, so springt es zwischen den möglichen
Koordinaten. Setzt man das Element ab, hat es Koordinaten mit der genannten Eigenschaft. Dies versteht man unter rasterorientiertem Bearbeiten (engl. Snapping).
Das Raster soll in Form von Punkten sichtbar sein, siehe Abbildung 4.3.
Abbildung 4.3.: Anzeige des Bearbeitungsrasters
Der Editor soll eine vom Benutzer wählbare Rastergröße besitzen und gleichzeitig
das Raster in Form von Punkten auf der Zeichenfläche darstellen, siehe hierzu
Abbildung 4.3. Die Konfigurationsmöglichkeiten werden im Anhang im Abschnitt
.2.1 beschrieben.
4.9. Nachvollziehbarkeit von Bearbeitungsschritten
Ein Bearbeitungsschritt ist hier die Einheit, auf der ein gewöhnlicher Undo-andRedo-Mechanismus basiert (siehe auch Abschnitt 4.14). Die Anzahl der verfügbaren Undo- und Redo-Schritte soll in der Statusleiste dargestellt werden und es
soll möglich sein, in einer Historie die einzelnen Schritte mit einem Zeitstempel
versehen chronologisch aufzulisten (siehe hierzu im Anhang den Abschnitt .1.1).
Darüber hinaus soll diese Historie in dem in Abbildung 4.4 dargestellten Format
exportierbar sein.
46
4.10. Mehrschichtige Übersichtsdarstellungen
1 3 : 3 1 : 2 9 ; E s t e r e l Studio ; Start
1 3 : 3 1 : 3 2 ; Simple S t a t e ; S t a r t
1 3 : 3 1 : 3 2 ; Simple S t a t e ; S u c c e s s f u l
1 3 : 3 1 : 3 6 ; I n i t i a l State ; Start
1 3 : 3 1 : 3 8 ; I n i t i a l State ; Successful
1 3 : 3 1 : 4 1 ; Trace Log ; S t a r t
Abbildung 4.4.: Ein Trace-Log von drei Benutzeraktionen
(a) Vor Beginn eines Abspielvorgangs
(b) Während eines Abspielvorgangs
Abbildung 4.5.: Die Werkzeugleiste zum Abspielen von Bearbeitungsschritten
In komplexen Diagrammen kann die Frage auftreten, welcher Bearbeitungsweg
zu dem vorliegenden Resultat geführt hat. Der Benutzer kann nun mehrfach einen
Undo-Schritt ausführen und hiernach Schritt für Schritt ein Redo, um die Entwicklung des Diagramms über die letzten Bearbeitungsschritte anzusehen. Zur Vermeidung einer hohen Mausklick-Rate zur Durchführung dieses Vorhabens soll dem
Benutzer ein Wiedergabe-Knopf zur Verfügung gestellt werden, wie er auch bei
z. B. Tonträger-Abspielgeräten angeboten wird, neben einer Pause-Taste, schnellem Vorlauf und Rücklauf, sowie schrittweisem Vor- und Rücklauf, siehe Abildung 4.5. Wiedergabe bedeutet hier, dass zunächst sämtliche Undo-Schritte ausgeführt werden und danach sukzessive die Redo-Schritte. Die Stop-Taste beendet
den Wiedergabe-Modus und führt wieder zum Ausgangspunkt. Zusätzlich wird
dem Anwender, wie er es aus Media-Player-Software gewohnt ist, ein Schieberegler
zur Schrittanwahl an die Hand gegeben. Der Benutzer kann darüber hinaus an
jeder Stelle des Wiedergabe-Modus diesen mit der Pause-Taste beenden und neue
Bearbeitungsschritte ausführen.
4.10. Mehrschichtige Übersichtsdarstellungen
Der Benutzer soll frei wählen können, wie viel Information er gleichzeitig betrachten
möchte. Idealerweise ist der editierbare Bereich der gesamte Bildschirm. Werden
Übersichten nicht schichtweise angezeigt, sondern nebeneinander, so geht Platz
für die Bearbeitung des Diagramms verloren. Daher soll die Möglichkeit bestehen,
auf verschiedenen durchsichtigen Schichten Statechart-Informationen darzustellen
(engl. Layering), z. B. eine nicht editierbare Statechart-Übersicht unter einem mo-
47
4. Anforderungsspezifikation des KIEL-Editors
mentan bearbeiteten Statechart-Ausschnitt. Des Weiteren soll ein Diagramm allgemein aus mehreren Ebenen bestehen können, welche unterschiedliche Ausschnitte
des Diagramms zeigen [9].
Übersichtsdarstellungen zeigen das Diagramm in der Regel vollständig. Denkbar
ist allerdings auch die Darstellung eines Diagrammteils. Unterschiedliche Darstellungen für den Inhalt des Diagramms sind dabei vorstellbar. Ein Statechart kann
neben der Diagrammdarstellung auch als Baum oder in Textform wiedergegeben
werden. Fasst man die Darstellungen als durchsichtige Bilder auf, so spricht man
von der Darstellung mehrerer überlagerter Ebenen oder von Mehrschichtigkeit.
Beispielsweise kann das bearbeitbare Diagramm im Ausschnittsformat als oberste Schicht angezeigt werden, wobei darunter, in leichteren Farbtönen wie Grau,
das gesamte Diagramm zur Übersicht dargestellt wird. Zur besseren Orientierung
soll das aktuell selektierte Diagrammelement auch in der Übersichtsdarstellung
hervorgehoben werden. Abbildung 4.6 zeigt neben der Bearbeitungsschicht eine
Übersichtsschicht. In der Abbildung ist die Hervorhebung des selektierten Diagrammelements in der Übersichtsansicht kaum sichtbar.
Abbildung 4.6.: Bearbeitungsschicht und Übersichtsschicht
Mehrschichtige Darstellungen können den Benutzer unter Umständen irritieren
oder sogar überfordern. Mit solchen Darstellungen soll daher zum einen sparsam
umgegangen werden und sie sollen ausschaltbar sein, und zum anderen soll viel
Wert auf die Auswahl der Farben gelegt werden. Beispielsweise ist es sinnvoll,
im Mehrschicht-Anzeige-Modus das aktuell bearbeitete Diagrammelement in allen
Schichten farblich leicht hervorzuheben.
Im Allgemeinen sind Übersichten nicht bearbeitbar. Denkbar wäre allerdings
in diesem Kontext, alle angezeigten Darstellungen zum Editieren freizugeben und
die Reihenfolge der Schichten änderbar zu gestalten. Im vorliegenden Editor sollen zwei Darstellungen übereinander gelegt werden: Die Bearbeitungsschicht als
oberste Schicht liegt über der nicht editierbaren Übersichtsschicht, welche farblich
ausgegraut ist.
48
4.11. Farbliche Syntaxprüfung
4.11. Farbliche Syntaxprüfung
Wie im Abschnitt über syntaxgerichtetes Editieren erwähnt, sollen im Editor modellierte Statecharts konform zu der von einem Statechart-Simulator geforderten
Syntax sein. Das syntaxgerichtete Editieren (Abschnitt 4.1) stellt zwar sicher, dass
während des Bearbeitungsvorgangs Eingaben, die gegen syntaktische Regeln verstoßen, nicht zugelassen werden. Dies führt allerdings nicht zu jederzeit syntaktisch korrekten Diagrammen, da auch unvollständige Diagramme akzeptiert werden müssen, sofern sie durch Hinzufügen weiterer Elemente zu einem syntaktisch
korrekten Diagramm führen können.
Der Benutzer soll bei Beurteilung der Frage unterstützt werden, ob alle vorliegende Diagrammelemente vollständig sind im Sinne der zu prüfenden Syntax.
Ist dies für ein Element nicht der Fall, so wird das Element rot gezeichnet. Ein
Diagrammelement ist vollständig, wenn folgende Regeln eingehalten werden:
Das Element ist
• ein OR-State aber nicht der Root-State und enthält einen Initial-State und
hat eingehende Transitionen.
• der Root-State und enthält einen Initial-State.
• ein AND-State und enthält eingehende Transitionen.
• eine Region und enthält einen Initial-State.
• ein Simple-State und enthält eingehende Transitionen.
• ein Initial-State und enthält ausgehende Transitionen.
Diese Regeln werden unabhängig vom gewählten Modell geprüft, d.h., für MatlabModelle und Esterel-Studio-Modelle werden die gleichen Regeln angewendet.
4.12. Positionierungshilfen und Ausrichtungshilfen
Ein wesentlicher und immer wiederkehrender Bearbeitungsschritt ist der des Positionierens von Diagrammelementen. Elemente sollen übersichtlich angeordnet sein.
So werden sie entweder relativ zueinander platziert oder mit absoluten Koordinaten
versehen. Zur Unterstützung der absoluten Positionierung werden in der Statusleiste des Editors die Mauszeigerkoordinaten angezeigt. Sinnvoll wäre auch, die
gewünschten Koordinaten eines Elements direkt eingeben zu können.
Der Benutzer soll Elemente relativ zueinander anordnen können, indem zunächst
mehrere Elemente mit der CTRL-Taste selektiert werden und sodann ausgewählt
wird, wie alle selektierten Elemente relativ zum ersten selektierten Element angeordnet werden sollen: links-, rechts-, oben- oder untenbündig, gleiche Breite oder
Höhe, vertikal oder horizontal zentriert.
49
4. Anforderungsspezifikation des KIEL-Editors
4.13. Layouthilfen während der Bearbeitung
Eine Layoutmaßnahme kann nicht nur nach einem Bearbeitungsschritt notwendig
werden sondern auch während eines Bearbeitungsschrittes. Dies ist z. B. der Fall,
wenn der Benutzer einen Zustand an einer Stelle hinzufügen möchte, an der nicht
genug Platz ist, die Zustandskanten also die eines anderen Zustands kreuzen würden. Dann ist diese Hinzufüge-Operation an dieser Stelle nicht erlaubt. Folglich
müsste abgebrochen werden, der Benutzer müsste durch eine geeignete Layoutmaßnahme Platz schaffen und könnte danach erneut versuchen, die HinzufügeOperation an der gewünschten Stelle durchzuführen.
Schon allein das Platz-Schaffen kann eine aufwändige Maßnahme sein. Man stelle
sich vor, der Vater des neuen Zustands würde durch eine notwendige Vergrößerung
seinen eigenen Vater schneiden. Dieses Platz-Schaffen soll nun im KIEL-Editor
durch einen geeigneten Algorithmus automatisiert werden, indem diese Operation
vom Editor ausgeführt wird, wann immer dieser die Notwendigkeit solch einer
Layoutmaßnahme erkennt, nämlich genau während des Platzierens eines neuen
Zustands. Während eines Bearbeitungsschritts wird also eine Layouthilfe seitens
des Editors angeboten und durchgeführt.
4.14. Undo-and-Redo
Diese aus Editoren allgemein bekannten Funktionen bewirken ein Zurücknehmen
(engl. Undo) beziehungsweise ein Zurücknehmen des Zurücknehmens (engl. Redo)
eines Bearbeitungsschrittes. Die Undo-Funktion dient der Korrektur ungewollter
Eingaben. Stellt sich unmittelbar nach Anwendung der Undo-Funktion heraus,
dass doch keine ungewollte Eingabe vorlag, so kann der Undo-Schritt rückgängig gemacht werden mit der Redo-Funktion. Redo-Schritte sind nur im direkten
Anschluss an Undo-Schritte möglich. Sobald nach Undo-Schritten ein neuer Bearbeitungsschritt ausgeführt wird, sind keine Redo-Schritte mehr verfügbar.
4.15. Cut-and-Paste
Auch hierbei handelt es sich um eine aus Editoren allgemein bekannte Funktion.
Ein Diagrammelement kann ausgeschnitten werden (engl. Cut), und nach Belieben
häufig wieder eingefügt werden (engl. Paste), und das in beliebigen Anwendungen,
die Cut-and-Paste unterstützen und die mit den ausgeschnittenen Daten etwas
anfangen können. Im vorliegenden Editor soll eine Variante implementiert werden:
Ein ausgeschnittenes Diagrammelement soll höchstens ein Mal und nur im Editor
wieder eingefügt werden. So ist ein Duplizieren von Elementen ausgeschlossen.
50
4.16. Zoom und Ausschnittsänderung
4.16. Zoom und Ausschnittsänderung
Die Ansicht des vorliegenden Diagramms soll nach Belieben vergrößert und verkleinert werden können. Hierfür soll zum einen der Zoomfaktor gleitend über einen
Schieberegler in der Statusleiste eingestellt werden können, siehe Abbildung 4.7,
zum anderen sollen über das Menü einzelne Zoom-In- und Zoom-Out-Schritte ausgeführt werden können. Des Weiteren soll mittels CTRL + Plus-Taste und MinusTaste sowie mit Hilfe CTRL + Mausrad gezoomt werden können.
Der sichtbare Bereich des Statecharts soll über Scrollleisten, das Mausrad sowie
über die Cursor -Tasten geändert werden können (engl. Panning).
Abbildung 4.7.: Zoomregler zur gleitenden Einstellung des Zoomfaktors
Zum anderen soll schrittweise gezoomt werden können mit Zoom-In- und ZoomOut-Buttons. Die Zoom-Schrittweise soll darüberhinaus konfigurierbar sein, siehe
im Anhang den Abschnitt .2.1.
4.17. Diagrammelementtyp-Morphing
Hierunter wird das Ändern des Typs eines Diagrammelementes verstanden. Während des Bearbeitungsprozesses kann die Situation auftreten, dass ein Diagrammelement gegen ein anderes ausgetauscht werden muss, z. B. ein Simple-State gegen
einen OR-State, weil in diesem Simple-State weitere Zustände platziert werden
sollen. Eigentlich müßte jedoch lediglich der Diagrammelementtyp geändert werden. Das Ersetzen dieses Zustands gegen einen neuen Zustand hätte zur Folge,
dass alle mit dem zu ersetzenden Zustand verbundenen Transitionen und sonstigen Eigenschaften verloren gingen. Daher soll der Editor Möglichkeiten bieten,
den Diagrammelementtyp zu ändern, sofern dies syntaktisch gesehen möglich ist.
Ein beliebiger Zustand soll z. B. in einen Endzustand überführt werden können,
wenn er keine ausgehenden Transitionen besitzt. Ein OR-State hingegen soll den
Typ eines Simple-States erhalten können, wenn dieser OR-State keine Zustände
beinhaltet.
4.18. Änderung von Transitionsprioritäten
Im KIEL-Editor sollen Transitionsprioritäten vergeben, angezeigt und geändert
werden können, siehe auch Abschnitt 2.3.3. Beim Erzeugen einer neuen Transition
soll der Editor automatisch dieser Transition eine Priorität zuweisen, wobei keine
zwei Transitionen die gleiche Priorität haben dürfen. Angezeigt sollen Prioritäten
51
4. Anforderungsspezifikation des KIEL-Editors
werden in spitzen Klammern an der Transition in der Nähe des Quellzustands. Der
Benutzer soll eine Priorität ändern können, indem er eine Transition anwählt und
ihr eine neue Priorität p zuweist. Hiernach sollen für alle Transitionen die Prioritäten neu berechnet werden derart, dass die ursprüngliche Reihenfolge erhalten
bleibt, die Transition mit p aber in der Reihenfolge neu eingeordnet wird.
4.19. Ansprechendes Benutzeroberflächendesign
Das KIEL-Projekt soll nicht nur professionellen Anforderungen bezüglich seiner
Funktionalität genügen, es soll daneben vom äußeren Erscheinungsbild mit kommerziellen Produkten konkurrieren können. Hierfür ist die Benutzeroberfläche von
zentraler Bedeutung. Die Anwendung muss eine Freude für die Augen sein. Daher
ist eine ansprechende farbliche Gestaltung vorteilhaft. Die gewählten Farbverläufe
sollen denen neuester Office-Produkte gleichen. Daneben ist das weite Feld der
Software-Ergonomie zu berücksichtigen. Folgende Aspekte sollen bei der Implementierung umgesetzt werden:
• Werkzeugleisten für die komfortable Anwendung häufig genutzter Funktionen, siehe Abbildung 4.8,
• Ausblendbarkeit von Menüs und der Statusleiste, siehe Abbildung 4.8, sowie
der Baumansicht,
Abbildung 4.8.: Ausblendbarkeit von Werkzeugleisten-Elementen
• fließende Komponenten, die per Drag-and-Drop aus dem KIEL-Anwendungsfenster gezogen werden können
• Popup-Menüs, welche abhängig vom Typ des aktuell selektierten Diagrammelementes zusammengestellt werden, siehe Abbildungen 4.10 und 4.11.
52
4.20. KIEL-Anwendungsfenster
(a) Eingebettete Komponente der Benutzeroberfläche
(b) Fließende Komponente der Benutzeroberfläche
Abbildung 4.9.: Fließende Benutzeroberflächen-Komponenten
• Shortcuts und Icons für Menüs und Menü-Elemente
• sinnvolle Gruppierung von Menü-Elementen, so dass ungewünschte Funktionen nicht versehentlich anwählbar sind,
• Bestätigungsdialoge bei nicht widerrufbaren Operationen,
• Mauszeiger mit visuellen Hinweisen auf den aktuellen Bearbeitungsschritt,
• Eine Dateihistorie zum schnellen Zugriff auf kürzlich geladene und gespeicherte Diagramme sowie
• die Wählbarkeit der in der Benutzeroberfläche verwendeten Sprache (wahlweise Englisch oder Deutsch). Siehe hierzu Abbildung 4.12.
4.20. KIEL-Anwendungsfenster
Neben dem Editor-Modul soll eine Rahmenanwendung in Form eines Anwendungsfensters entwickelt werden, in welches das zu entwickelnde Editor-Modul und das
Browser-Modul eingebettet werden können und welches als Kommunikationsmittler zwischen beiden Modulen agiert. Wie in Abschnitt 5.2.1 beschrieben, sollen
die KIEL-Module einerseits weitgehend unabhängig voneinenander implementiert
sein, andererseits sollen jedoch der Editor und der Browser das aktuell angezeigte
Statechart untereinander austauschen können.
Das Anwendungsfenster soll darüber hinaus für jedes der beiden Module folgende fünf unterschiedliche Komponenten einbetten, von denen jede der ersten drei
Komponenten als fließende Komponente (engl. Floatable-Components) aus dem
53
4. Anforderungsspezifikation des KIEL-Editors
Abbildung 4.10.: Kontext-Menü zu einem OR-State als Popup-Menü
Anwendungsfenster herausgezogen werden kann und dann in einem eigenständigen Fenster solange existiert, bis dieses wieder geschlossen wird und sodann seinen
Platz im Anwendungsfenster zurück erhält, siehe Abbildung 4.9:
• eine Baumansicht,
• eine Register-Ansicht mit beliebig vielen Registern,
• eine Werkzeugleiste,
• die Hauptkomponente, dies ist die graphische Anzeige des aktuellen Statecharts und
• Menüs im Anwendungsfenster-Hauptmenü.
Folgende Funktionen soll das Anwendungsfenster bereitstellen:
• Dateien öffnen: Das File-Interface-Modul von KIEL soll angebunden werden.
• Dateinamen speichern: Speichern der Namen der zuletzt geöffneten Dateien
soll angeboten werden.
• Nachrichtendialog unterdrücken: Unerwünschter Meldungen in Meldungsdialogfenstern sollen unterdrückbar sein.
54
4.21. Intuitive Bedienbarkeit
Abbildung 4.11.: Kontext-Menü zu einer Transition als Popup-Menü
• Anwendung beenden: Eine Sicherheitsabfrage zum Speichern vor Beendigung
der Anwendung soll angezeigt werden.
• Menü-Elemente konfigurieren: Die Sichtbarkeit von Menüs soll einstellbar
sein.
• Meldungen anzeigen: Fehlermeldungen und Hinweise sollen in der Statusleiste
dargestellt werden können.
• zwischen Editor und Browser umschalten: Das aktuelle Statechart soll bei
Wechsel von Editor-Anzeige nach Browser-Anzeige zwischen beiden Komponenten ausgetauscht werden und gleichzeitig soll die exklusive Sichtbarkeit
beider Komponenten sichergestellt werden.
4.21. Intuitive Bedienbarkeit
Der Editor soll intuitiv bedienbar sein, das heißt, die Software muss sich zum
einen so verhalten, wie es der Anwender erwartet, zum anderen müssen alle Funktionalitäten leicht aufrufbar sein. Hierfür ist notwendig, dass Funktionsweise und
Erscheinungsbild der graphischen Benutzeroberfläche anderen Editoren und insbesondere Statechart-Editoren ähnelt. Als Vorbild für den KIEL-Editor soll das
Werkzeug Esterel-Studio (Abschnitt 3.1.2) gewählt werden. Der Grad an intuitiver
Bedienbarkeit eines Diagrammeditors lässt sich an der Art und Weise messen, wie
sich:
55
4. Anforderungsspezifikation des KIEL-Editors
(a) Sprachliche Anzeigeelemente auf englisch
(b) Sprachliche Anzeigeelemente auf deutsch
Abbildung 4.12.: Mehrsprachigkeit
• neue Diagrammelemente erzeugen lassen (siehe Abschnitt 4.21.1),
• Selektieren, Verschieben, Vergrößern und Verkleinern von Diagrammelementen realisieren lässt (siehe Abschnitt 4.21.2) und
• syntaxgerichtetes Editieren (Abschnitt 4.1) auf die Arbeit mit dem Editor
auswirkt.
4.21.1. Erzeugung neuer Diagrammelemente
Esterel-Studio kennt wie andere Editoren auch das Konzept der BearbeitungsModi. Hier beschreibt ein Modus die Art und Weise, in welcher auf Benutzereingaben reagiert wird. Grundsätzlich besitzt jede Software mindestens einen Modus.
Sobald jedoch Benutzeraktionen möglich sein sollen, die in einem bestimmten Kontext ausgeführt werden, die also z. B. sich auf vorhergehende Benutzeraktionen beziehen oder von diesen abhängen, muss auch für diese Aktionen ein Modus definiert
werden. Ein Modus zeichnet sich aus durch das Vorhandensein einer Transaktionsklammer, innerhalb der mehrere Benutzeraktionen entweder ganz oder überhaupt
56
4.21. Intuitive Bedienbarkeit
nicht ausgeführt werden.
Ein Statechart-Editor soll sich in Abhängigkeit des jeweiligen Anwendungsfalls
verhalten. Während ein neuer Zustand platziert wird, wird der Editor ein anderes
Verhalten aufweisen müssen, als wenn eine Transition gezeichnet wird. Diese beiden Anwendungsfälle bestehen aus mehreren Schritten. Zunächst wird der Mauszeiger platziert und nach dem Mausklick wird der Zustand oder die Transition
erzeugt. Wie sich hierbei der Mauszeiger verhält und welche Positionsüberprüfungen durchgeführt werden, hängt davon ab, ob ein Zustand oder eine Transition
erzeugt werden soll. Daher muss der Benutzer zunächst festlegen, was er erzeugen
will, damit im nächsten Schritt seine Mausbewegungen entsprechend interpretiert
werden können.
Dieser Sachverhalt gilt für alle Editoren. Daher wird das Konzept der Bearbeitungs-Modi vielfach angewendet. Der Standard-Modus ist der Selektionsmodus. In
den Transitionsmodus soll der Benutzer gelangen, sobald sich der Mauszeiger in
einer Position befindet, in der durch Mausklick das Zeichnen einer Transition begonnen werden könnte. Daneben gibt es für alle hinzufügbaren Diagrammelemente
jeweils einen weiteren Modus, da beim Bewegen des Mauszeigers geprüft werden
muss, ob das Erzeugen des Diagrammelementes an der aktuellen Stelle erlaubt ist
und die hierfür notwendige Überprüfungsregel von der Art des hinzuzufügenden
Diagrammelementes abhängig ist.
Abbildung 4.13 zeigt die Palette an Mauszeigern, welche der Editor verwenden
soll, um anzuzeigen, welcher Bearbeitungsschritt gerade ausgeführt wird. Wählt
der Benutzer z. B. das Hinzufügen eines Simple-States in der Werkzeugleiste, so
verwandelt sich der Mauszeiger auf der Zeichenfläche überall dort in den in Abbildung 4.13(e) dargestellten Mauszeiger, wo dieses Diagrammelement platziert werden darf. Eine besondere Bedeutung besitzt der Mauszeiger in Abbildung 4.13(a).
Dieser Mauszeiger erscheint immer dann, wenn die gewählte Aktion an der aktuellen Position des Mauszeigers nicht möglich ist.
4.21.2. Selektion und Manipulation von Diagrammelementen
Wenn der Benutzer nicht das Erzeugen eines Diagrammelements angekündigt hat
durch Wahl eines entsprechenden Modus, befindet sich der Editor im Selektionsmodus, in welchem mittels des Mauszeigers Diagrammelemente verschoben, verkleinert, vergrößert und gelöscht werden können. Der Benutzer ist gewohnt, dass
immer dasjenige Diagrammelement selektiert ist, auf dem sich der Mauszeiger gerade befindet. Sofern Elemente ineinander geschachtelt sind, erwartet der Benutzer, dass das kleinste Element selektiert wird. Die Selektion wird häufig durch die
Farbgebung, die Linienstärke oder das Erscheinen so genannter Size-Handles angezeigt. Die Visualisierung der Selektion in anderen Ansichten wird in Abschnitt
4.10 dargestellt.
57
4. Anforderungsspezifikation des KIEL-Editors
(a) Stop
(e)
SimpleState
(b) Vertikale
DelimiterLine
(c)
Horizontale
DelimiterLine
(d) Suspend
(f)
OrState
(g)
InitialState
(h)
HistoryState
(i) FinalSimpleState
(j) Choice
(k) DeepHistoryState
Abbildung 4.13.: Verschiedene Mauszeiger
4.22. Konfigurierbarkeit
Der Editor soll auf die individuellen Bedürfnisse des Benutzers eingestellt werden
können. Die Konfiguration soll über ein Dialogfenster erfolgen können, siehe hierzu
Abbildung .2 und die Einstellungen sollen wahlweise gespeichert werden können,
so dass sie bei erneutem Start der Anwendung nicht erneut eingegeben werden
können. Wünschenswert wäre ein sofortiges Aktivwerden der vom Benutzer getätigten Einstellungen. Ungültige Werte werden automatisch verworfen und durch
den letzten gültigen eingegebenen Wert oder den Standardwert ersetzt. Zu jeder
Einstellungsmöglichkeit soll ein Standardwert vorgegeben sein, damit der Benutzer
schon nach dem ersten Start der Anwendung sinnvoll arbeiten kann. Die Konfigurationsmöglichkeiten und die hierzu definierten Standardwerte sind im Anhang im
Abschnitt .2.1 angegeben. Neben dieser Art der Konfiguration über ein Dialogfenster und wahlweiser Speicherung soll die Anzeige der folgenden Editor-Elemente nur
temporär und über das Menü View erreichbar ein- und ausgestellt werden können:
• Übersichtsdarstellung,
• Raster,
• Actions eines Zustands,
• lokale Events eines Zustands und
• lokale Variablen eines Zustands.
58
4.23. Bearbeitungsschritt-Historie
4.23. Bearbeitungsschritt-Historie
Es sollen zwei Historien der vom Benutzer durchgeführten Bearbeitungsschritte gepflegt werden. In einer Historie sollen sämtliche Schritte angezeigt werden, wie z. B.
der Beginn des Anlegens eines Diagrammelements, das erfolgreiche oder erfolglose
Abschließen dieses Schrittes, das Öffnen des Preferences-Dialogs und andere. In
einer zweiten Historie sollen nur diejenigen Schritte dargestellt werden, auf welche der Undo-and-Redo-Mechanismus anwendbar ist. In beiden Historien sollen die
Zeitpunkte angegeben sein, es soll die Anzeigesprache (deutsch / englisch) gewählt
werden können und die Daten sollen exportierbar sein. Da es sich um Tabellenstrukturen handelt, werden die Daten zeichensepariert exportiert im CSV-Format
(engl. Character-Separated-Values), wobei das Trennzeichen frei wählbar sein soll.
Abbildung .4 zeigt links die Undo-and-Redo-Historie, in der farblich unterschieden
wird zwischen Schritten, auf welche der Undo-Mechanismus angewendet werden
kann und Schritten, für welche der Redo-Mechanismus zur Verfügung steht.
59
4. Anforderungsspezifikation des KIEL-Editors
60
5. Umsetzung und Implementierung
Nachdem im vorangegangenen Kapitel der Funktionsumfang des KIEL-Editors
spezifiziert wurde, wird in diesem Kapitel nun unter Beachtung dieser Spezifikation zunächst die Vorgehensweise (5.1) für die Umsetzung und Implementierung
des KIEL-Editors festgelegt. Hiernach werden in den Abschnitten 5.2 und 5.3 die
Ergebnisse der iterativ-inkrementellen Design- und Implementierungsphasen zusammenfassend dargelegt.
5.1. Vorgehensweise
Die theoretischen Grundlagen zu diesem Abschnitt finden sich in Abschnitt 2.4.
Der Softwareentwicklungsprozess und die Vorgehensweise bei der Implementierung
werden durch folgende Ziele bestimmt:
• Flexibilität bezüglich zukünftiger Anforderungen während der Projektlaufzeit und nachfolgender Projekte
• ständige Überprüfbarkeit, Lauffähigkeit und Lesbarkeit des Quelltextes
• minimale Komplexität
• Zuverlässigkeit und Robustheit
Die Erreichung dieser Ziele wird unterstützt durch der Implementierung vorangehende visuelle Modellierung mittels UML und durch Anwendung einer iterativ
inkrementellen Vorgehensweise, welche in Abschnitt 2.4.2 vorgestellt wird. Insbesondere die Lesbarkeit und Verringerung der Komplexität des Quelltextes wird
erreicht mit der Durchführung von Code-Reviews, teilweisem Pair-Programming,
automatisierten Tests und vor allem mit der Anwendung von Entwurfsmustern.
Nach der Festlegung auf diese Techniken besteht der zweite Schritt im Erkennen
der grundlegenden Struktur (siehe Abschnitt 5.2), welche die Software besitzen
muss, um zum einen konform zur KIEL-Struktur und JGraph-Struktur zu sein
und zum anderen den geforderten Funktionsumfang implementieren zu können
und dem Softwaretypus entsprechen zu können. Bei der KIEL-Struktur sind von
wesentlicher Bedeutung die Datenstruktur sowie mit untergeordneter Relevanz die
Schnittstellen zum Gesamtsystem KIEL. Bei der JGraph-Struktur sind die verwendeten Entwurfsmuster, die Datenstruktur sowie die Aufsetzpunkte (engl. Hooks)
zum Erweitern des Funktionsumfangs interessant.
61
5. Umsetzung und Implementierung
Nach Analyse der Struktur werden Klassendiagramme entworfen, in denen beschrieben wird, welche Komponenten benötigt werden, wie Funktionalitäten und
Verantwortlichkeiten auf Klassen verteilt werden und in welchem Verhältnis die
Klassen zueinander stehen. Bei diesem Schritt ist das Erkennen von Problemen
notwendig, für die es schon Lösungen gibt, so genannte Entwurfsmuster (Abschnitt
2.4.3). Implementierungsdetails spielen an dieser Stelle noch keine Rolle. Diese werden in Abschnitt 5.3 dargestellt.
5.2. Design
Zunächst werden für die zu erstellende Anwendung grundsätzliche Strukturen festgelegt, welche sich aus den nachfolgenden Kriterien ergeben.
5.2.1. Rahmenbedingungen
Im Folgenden werden die Ergebnisse der grundlegenden Strukturerkennung dargelegt, die sich aus den Rahmenbedingungen ergeben.
Softwaretypus
Bei der zu entwickelnden Software handelt es sich um eine nicht-verteilte Anwendung mit graphischer Benutzeroberfläche, welche in einer nichtkritischen Umgebung eingesetzt wird. Für die Implementierung bedeutet dies, dass das ModelView-Controller -Entwurfsmuster Anwendung finden wird.
Die Software ist nicht abhängig von externen (Software-) Systemen, es gibt keine zentralen und dezentralen Komponenten, daher sind Client/Server-Strukturen
und andere Kommunikationsstrukturen nicht vorhanden. Des Weiteren werden an
die Anwendung weder erhöhte Anforderungen bezüglich Robustheit und Sicherheit gestellt – anders als dies bei eingebetteten Systemen z. B. der Fall ist – noch
ist das zeitliche Verhalten und der Speicherverbrauch von überdurchschnittlicher
Bedeutung.
Struktur des KIEL-Projektes
Bei KIEL handelt es sich um ein Projekt, welches sich aus mehreren eigenständigen
Arbeiten im Rahmen von Studien- und Diplomarbeiten zusammensetzt. Folglich
besteht der Gesamtumfang des Softwaresystems KIEL zum einen aus voneinander weitgehend unabhängigen Modulen, welche für sich allein lauffähig sind, und
zum anderen in geringerem Umfang aus Ressourcen, Funktionalitäten und der
Statechart-Datenstruktur, welche von diesen Modulen gemeinsam verwendet werden. Folgende Module sind neben dem Editor voneinander unabhängig:
• Browser - Anzeige verschiedener Statechart-Sichten [50]
• Layouter - Layoutalgorithmen auf der KIEL-Datenstruktur [28] [29]
62
5.2. Design
• Simulator - Simulation von Statecharts auf der KIEL-Datenstruktur [37]
• File-Interface - Interpretation von Esterel-Studio-Dateien [51] und MatlabDateien [44]
FileInterface
Layouter
SimulatorChoser
(from fileInterface)
(from layouter)
(from simulator)
Editor
Browser
(from editor)
(from browser)
...)
KielFrame
Abbildung 5.1.: Projektstruktur
Unabhängigkeit bedeutet hier – wie in der Abbildung 5.1 zu sehen –, dass zwar
der Browser den Simulator nutzt, dass jedoch Editor, Browser, Layouter und das
File-Interface nicht gegenseitig voneinander abhängig sind und dass die Schnittstellen zwischen den Modulen sehr schmal sind. Dies hat zur Folge, dass Browser,
Editor, Layouter, Simulator und Dateischnittstelle voneinander vollständig entkoppelt werden können, indem auf die jeweilige Funktionalität verzichtet wird.
Außerdem sind diese Module auch ohne die Funktionalität der anderen Module
sinnvoll verwendbar. Für den Editor bedeutet das z. B., dass ohne Verwendung der
Dateischnittstelle die gezeichneten Diagramme ausdruckbar, speicherbar und ladbar bleiben, dass aber auf die Konvertierung von und nach Esterel-Studio-Format
verzichtet werden muss. Unterbleibt im Weiteren die Verwendung des LayouterModuls, so kann der Editor kein automatisiertes Layout durchführen, wohl aber
eigene Layoutmechanismen weiterhin einsetzen.
Die voneinander unabhängigen Module Browser und Editor können über die
Komponente KielFrame miteinander kommunizieren. Diese Komponente stellt das
Anwendungsfenster zur Verfügung, bettet die beiden Module in das Fenster ein,
übernimmt das Laden von Dateien für diese beiden Module, indem es auf das Modul File-Interface zugreift und stellt eine Schnittstelle zur Layouter-Komponente
zur Verfügung.
Für die Implementierung des Editors bedeutet das, dass dieser nur über eine
schmale Schnittstelle Funktionalität anderer Komponenten nutzt und seine Daten
nur über das KielFrame mit dem Browser austauscht.
Die KIEL-Datenstruktur
Die KIEL-Datenstruktur lässt sich einteilen in drei Teile. In einem Teil wird die
Struktur eines Statecharts
beschrieben. In einem weiteren Teil werden die LayFile: C:\Dokumente und Einstellungen\luepke\Eigene Dateien\Projekte\uni\Diplomarbeit\kiel.mdl 21:42:58 Mittwoch, 8. Juni 2005
project structure Page 1
63
Class Diagram: kiel /
5. Umsetzung und Implementierung
outinformationen in der Komponente View zusammengefasst. Hierbei wird unterschieden zwischen den Layout-Informationen von Knoten, Kanten und ihren Beschriftungen. In einem dritten Teil der KIEL-Datenstruktur werden Ereignisse und
Bedingungsausdrücke modelliert.
Abbildung 5.2 illustriert den Teil der KIEL-Datenstruktur, welcher die Struktur
eines Statecharts beschreibt. Jedes Diagrammelement ist entweder ein Node, eine
Delimiter-Line oder eine Edge. Bei Edges z. B. wird mit Hilfe unterschiedlicher
Klassen unterschieden zwischen Strong-Abortions, Normal-Terminations und anderen Transitionstypen. Jedes Element eines Statecharts wird durch eine Instanz
einer dieser Klassen repräsentiert, z. B. ist ein Initial-State im KIEL-Datenmodell
ein Objekt der Klasse InitialState.
GraphicalObject
Edge
Node
DelimiterLine
Transition
StrongAbortion
PseudoState
State
NormalTermination
ANDState
CompositeState
ORState
Suspend
InitialState
Region
Abbildung 5.2.: KIEL-Datenstruktur
Wie in Abschnitt 2.3.2 beschrieben, unterscheiden sich Composite-States von allen anderen Diagrammelementtypen dadurch, dass Composite-States weitere Komponenten beinhalten können, also durch Composite-States eine Baumstruktur aufgebaut werden kann. Daher beinhalten in der KIEL-Datenstruktur die CompositeState-Komponenten eine Liste von Kind-Knoten. Transitionen besitzen dagegen
einen Quellknoten und einen Zielknoten und sind auf diese Weise in die Baumstruktur eines Statechartsintegriert.
Die graphische Repräsentation der unterschiedlichen Diagrammelementtypen
wird durch eine Konfigurationsdatei der KIEL-Anwendung spezifiziert und muss
von Browser und Editor verwendet werden. Ziel ist eine einheitliche graphische
Repräsentation der Statecharts durch den Browser und Editor.
64
File: C:\Dokumente und Einstellungen\luepke\Eigene Dateien\Projekte\uni\Diplomarbeit\kiel.mdl
dataStructure / hierarchy Page 1
11:15:35 Sonntag, 24. April 2005
Class Diagram:
5.2. Design
Struktur des verwendeten Graph-Editing-Frameworks
Die grundlegende Architektur der JGraph-Komponente ist die gleiche wie die
der Standard-Swing-Komponenten: Sie basiert auf dem MVC -Muster (Abschnitt
2.4.3). Das JGraph-Model beinhaltet dabei neben dem Datenmodell auch auf diesem definierte Operationen. Unter Datenmodell werden die das Statechart beschreibenden Daten in ihrer JGraph-spezifischen Datenstruktur verstanden. Die
JGraphDatenstruktur ist wie die KIEL-Datenstruktur baumförmig aufgebaut. Sie
besteht aus javax.swing.TreeNode-Komponenten. Jeder Knoten und jede Transition des anzuzeigenden Graphen wird von solch einem TreeNode-Objekt repräsentiert, wobei ein TreeNode-Objekt genau einen Vater hat und Kinder haben
kann. In der JGraph-Datenstruktur werden also Transitionen im Gegensatz zur
KIEL-Datenstruktur als Kinder von Knoten modelliert. Dieser Umstand ist bei
der Implementierung der Datenmodell-Transformation zu beachten. Das Design
des JGraph-Rahmenwerks wird in [1] und [15] beschrieben.
Bei der Nutzung des Rahmenwerks muss für die JGraph-Komponente neben einer View und einem Controller ein Model implementiert werden. Dieses Model
kann aufgrund der Modularisierung eine Repräsentation des Statecharts sowohl in
Form eines JGraph-Datenmodells als auch zusätzlich oder stattdessen in Form eines KIEL-Datenmodells beinhalten. Bei einer Hybridlösung ist bei der Implementierung darauf zu achten, dass die notwendigen Transformationen zwischen den
beiden Datenmodellen ausschließlich innerhalb des Models durchgeführt werden.
5.2.2. Entscheidungsfaktoren
Die Entscheidung für bestimmte Strukturen, Mechanismen und die Verwendung
bestimmter Entwurfsmuster ist abhängig von den Rahmenbedingungen des vorhergehenden Abschnitts und von Erfahrungswerten. Das Design der Anwendung
ist daneben auch abhängig von einigen an die vorliegende Arbeit gestellten Anforderungen (Kapitel 4). Diese Anforderungen sind vor dem Hintergrund des Anwendungsentwurfs zu bewerten. Die Ergebnisse hierzu werden in diesem Abschnitt
dargestellt.
Modellorientierung
Alle Komponenten der KIEL-Anwendung arbeiten auf einem gemeinsamen Datenmodell.
Der Einsatz des MVC -Entwurfsmusters dient im KIEL-Projekt im Besonderen
der Kommunikation des Editors mit anderen Projektkomponenten. Der Datenaustausch innerhalb von KIEL erfolgt ausschließlich auf der KIEL-Datenstruktur, welche auf einer Trennung von Statechart-Struktur und seiner Layout-Informationen
beruht. Die Kommunikation des Editors mit anderen Projektteilen ist notwendig,
um die Dateischnittstelle von KIEL nutzen zu können und um die Integration des
Editors in das Gesamtprojekt zu ermöglichen.
65
5. Umsetzung und Implementierung
Da das Rahmenwerk JGraph seinerseits eine eigene Datenstruktur besitzt (siehe Abschnitt 5.2.1), muss eine Transformation zwischen beiden Datenmodellen
erfolgen. Der Editor wird entweder mit einem von der KIEL-Anwendung übergebenen Statechart aufgerufen oder es wird ein neues Statechart angelegt. Im ersten
Fall muss bei Aufruf des Editors eine Transformation vom KIEL-Datenmodell in
das JGraph-Datenmodell erfolgen. Im anderen Fall muss eine Transformation in
der umgekehrten Richtung spätestens am Ende des Editiervorgangs durchgeführt
werden.
Verschiedene Ansätze zur Umsetzung der Transformation sowie des Transformationszeitpunkts und -umfangs sind hierbei denkbar, wobei zu jedem Zeitpunkt das
KIEL- und das JGraph-Datenmodell nebeneinander existieren:
1. Eine komplette Transformation des Datenmodells wird bei Start des Editors
durchgeführt. Es wird hiernach nur noch auf dem JGraph-Datenmodell gearbeitet und das KIEL-Datenmodell wird nicht mehr verwendet. Aktualisiert
wird das KIEL-Datenmodell bei Beendigung des Editierprozesses. Nachteilig
wirkt sich hierbei jedoch aus, dass auch nicht den Editor betreffende KIELDatenstruktur-Änderungen Anpassungen am Editor notwendig machen.
2. Es findet keine Transformation sondern lediglich ein Wrapping des KIELDatenmodells durch das JGraph-Model statt: Das Model besitzt bei dieser
Variante keine Repräsentation des Statechartsin der JGraph-Datenstruktur,
sondern alle Operationen des Models arbeiten auf dem gegebenen oder initial
erzeugten KIEL-Datenmodell. Vorteil hierbei ist, dass keine DatenmodellTransformationen notwendig sind. Allerdings setzt diese Variante einerseits
eine genaue Kenntnis der Implementierung des JGraph-Models, der Klasse DefaultGraphModel, voraus, und andererseits kann der Undo-and-RedoMechanismus von JGraph nicht mehr verwendet werden, da dieser für die
JGraph-Datenstruktur entwickelt ist.
3. Es wird zu Beginn des Editierprozesses ein JGraph-Datenmodell aufgebaut.
Sofern ein KIEL-Datenmodell vorliegt, findet eine Transformation statt. Dabei enthält das JGraph-Datenmodell nur die Editor-relevanten Informationen. Eine vollständige Transformation wird nicht durchgeführt. Beide Datenmodelle sind daher nicht gleichwertig. Das JGraph-Model operiert dann
auf einem JGraph-Datenmodell und einem KIEL-Datenmodell. Dabei ändert
jede Operation beide Datenmodelle. Der Vorzug dieser Variante ist, dass die
Implementierung unabhängig von Editor-irrelevanten KIEL-DatenstrukturÄnderungen ist.
4. Es werden nur die hierarchische Struktur des Statecharts sowie die Diagrammelementtypen und graphischen Informationen transformiert. Daten, welche in JGraph nicht vorgesehen sind, z. B. das isCollapsed-Attribut von
Composite-States, werden weiterhin im KIEL-Datenmodell gehalten. Vorteilhaft erscheint hierbei, dass einige Daten nicht doppelt abgelegt werden und
damit nicht synchronisiert werden müssen.
66
5.2. Design
Es wurde die vierte Variante gewählt. Hierbei müssen nur diejenigen Daten aus
dem KIEL-Datenmodell gelesen und betrachtet werden, welche für den Editor relevant sind. Bei Änderung der Struktur der für den Editor irrelevanten Daten ist
eine Änderung der Implementierung des Editors nicht notwendig. Des Weiteren
spiegelt dieser Ansatz die Tatsache wider, dass beide Datenstrukturen sich nur
in der Repräsentation der hierarchischen Struktur des Statechartsähneln, (siehe
sec:jgraphStruktur). Ob ein Zustand momentan kollabiert ist (isCollapsed) und
welche Elemente wie Events und Variablen dieser besitzt, kann nicht sinnvoll in
der JGraph-Datenstruktur modelliert werden. Insgesamt betrachtet stellt die vierte
Variante auch den intuitiven Lösungsansatz dar. Das JGraph-Rahmenwerk wird
hierbei auf eine Art und Weise erweitert, welche in der JGraph-Dokumentation
vorgeschlagen wird, siehe 5.7. Allerdings ist bei diesen Überlegungen zu beachten,
dass der Undo-Mechanismus des Rahmenwerks verwendet werden soll, welcher
ausschließlich auf dem JGraph-Datenmodell operiert. Soll z. B. das Kollabieren
eines Composite-States mittels Undo-Funktionalität rückgängig gemacht werden
können, so muss das isCollapsed-Flag in die JGraph-Datenstruktur integriert
werden, um Änderungen dieses Flags registrierbar für den Undo-Mechanismus zu
gestalten. Das gleiche gilt für Events und Variablen eines Statecharts. Es wird
entschieden, dass zwar isCollapsed-Änderungen durch den Undo-Mechanismus
rückgängig gemacht werden können, nicht jedoch soll dies für das Editieren von
Events und Variablen gelten.
Graphische Information im SVG -Format
Scalable-Vector-Graphics (SVG) ist eine in der Extensible-Markup-Language (XML)
formulierte Sprache zur Beschreibung zweidimensionaler Vektorgraphiken. Der KIELBrowser verwendet ein SVG-Rahmenwerk zur Darstellung von SVG-Objekten, welche ein Statechart repräsentieren. Ein SVG-basierter Ansatz ist im Editor wünschenswert, um die graphische Repräsentation von Statecharts auf die gleiche technische Weise zu realisieren und damit eine zwischen Browser und Editor exakt
gleiche Darstellung von Statecharts zu erreichen, vergleiche hierzu Abschnitt 5.2.1.
Bei der Frage, ob im KIEL-Editor für die Darstellung graphischer Informationen
das SVG-Format gewählt werden kann, muss unterschieden werden zwischen zwei
Ansätzen: Zum einen ist vorstellbar, ein SVG-Rahmenwerk einzusetzen, welches
als Grundlage für die Darstellung und die benutzergesteuerte Bearbeitung von
Statecharts verwendet wird. Alternativ ist denkbar, ein SVG-Rahmenwerk zusammen mit JGraph zu verwenden, wobei das SVG-Rahmenwerk die Darstellung des
Diagramms übernimmt und JGraph die Benutzerinteraktionen.
Gegen die erste Variante spricht,dass keine SVG-Rahmenwerke verfügbar sind,
welche die Bearbeitung von SVG-Objekten in Form von grundlegenden benutzergesteuerten Graph-Bearbeitungsfunktionen (siehe Abschnitt 3.2.1) erlauben, welche
ihrerseits in Diagramm-Editoren üblicherweise auftreten. Gegen die zweite Variante
spricht, dass die verfügbaren SVG-Rahmenwerke und das für den Editor zur Verwendung vorgesehene Rahmenwerk nicht miteinander vereinbar sind. SVG stellt
67
5. Umsetzung und Implementierung
eine Abstraktionsschicht über der des Java-Abstract-Windowing-Toolkit (AWT)
dar. JGraph verwendet direkt dieses AWT. Eine Zwischenschicht wie die des SVG
lässt sich daher zusammen mit JGraph nicht nutzen.
5.2.3. Ergebnisse
Dieser Abschnitt zieht Schlüsse aus den vorhergehenden Abschnitten über die Rahmenbedingungen und Entscheidungsfaktoren und konkretisiert das Design für die
einzelnen Komponenten des Editors. Hierbei handelt es sich um Ergänzungen zu
den vorhergenden Abschnitten.
Der Editor basiert in seiner grundlegenden Struktur auf dem MVC -Muster, wird
also aus den Komponenten Model, View und Controller bestehen. Der Controller wiederum wird nach dem Zustandsmuster und dem Befehlsmuster aufgebaut
sein. Abbildung 5.3 zeigt die drei MVC -Komponenten Model, Controller und View
in einer Anordnung von links nach rechts. Das Model besteht aus den Klassen
NodePropertiesDialog, UndoClusterManager und MyGraphModel. Die View wird
gebildet aus den Klassen KielFrame, Editor, MyJGraph und weiteren in der Abbildung nicht gezeigten Komponenten. Die ActionXY-Klassen modellieren den Controller des KIEL-Editors. Die Pfeile in der Abbildung 5.3 zeigen die Abhängigkeiten der Klassen untereinander. Da jede der in dieser Abbildung gezeigten Klassen
nur ein Mal instantiiert wird, formuliert dieses Klassendiagramm gleichzeitig die
Objektbeziehungen und damit die Kommunikationswege. Wie in Abschnitt 2.4.3
beschrieben sind hier keine bidirektionalen Kommunikationskanäle zu finden. Benutzerereignisse werden von der View an die jeweiligen Controller -Komponenten
weitergeleitet, welche ihrerseits hauptsächlich auf dem MyGraphModel operieren.
Eine Änderung dieses Models verursacht eine Aktualisierung des Editor-Objekts
und des MyJGraph-Objekts. Diese Klassen werden in den folgenden Abschnitten
weiter erläutert.
Das Model
Das Model, implementiert durch die Klasse MyGraphModel, kapselt die Transformation zwischen den Datenmodellen von KIEL und JGraph und beinhaltet zu jedem
Zeitpunkt das komplette KIEL-Model und das JGraph-Model des Statecharts. Bei
Start des Editors mit einem im KIEL-Datenmodell vorhandenen Statechart wird
eine Transformation in das JGraph-Datenmodell durchgeführt.
Für jedes KIEL-Statechart-Diagrammelement-Objekt existiert ein korrespondierendes JGraph-Diagrammelement-Objekt. Beide Elemente sind miteinander verbunden: Einerseits besitzt jedes der JGraph-Diagrammelement-Objekte eine Referenz auf das zugehörige KIEL-Objekt, andererseits wird ein Mapping aufgebaut, welches zu einem KIEL-Objekt das zugehörige JGraph-Objekt liefert. Diese
Verknüpfungen sind notwendig, weil bei einigen Operationen auf dem JGraphDatenmodell auch Daten aus dem KIEL-Datenmodell gebraucht werden. Daneben werden auch Operationen implementiert, welche auf dem KIEL-Datenmodell
68
5.2. Design
IKielFrame
FileHistory
ActionViewReplayPlay
(from EditorActions)
ActionFileNewEsterelStudio
(from EditorActions)
NodePropertiesDialog
ActionFileProperties
(from EditorActions)
UndoClusterManager
ActionEditRedo
(from EditorActions)
Editor
ActionAddSimpleState
(from EditorActions)
MyGraphModel
ActionEditEdit
(from EditorActions)
ActionFormatAlignRight
(from EditorActions)
MyJGraph
Abbildung 5.3.: Das Model-View-Controller -Entwurfsmuster
arbeiten und hierbei auf Daten der entsprechenden JGraph-Diagrammelemente
zugreifen müssen. Ein Beispiel für solche Operationen wird in Abschnitt 5.3.2 beschrieben.
Änderungen an den JGraph-Elementen können auf zwei verschiedene Arten erfolgen:
1. Das JGraph-Element wird durch das Rahmenwerk direkt geändert. Hierbei findet keine Aktualisierung des zugehörigen KIEL-Elementes statt. Solche Änderungen führen zu temporären Inkonsistenzen zwischen beiden Models, welche bei Bedarf explizit aufgelöst werden müssen. Dieser Bedarf besteht z. B. bei Ausführung eines Diagrammelementtyp-Morphings (Abschnitt
5.3.3), da hier anhand der gültigen Daten eines KIEL-Objekts ein neues
KIEL-Objekt erzeugt werden muss.
2. Das Statechart wird über das Model (Abschnitt 2.4.3) geändert. Bei jeder solFile: C:\Dokumente und Einstellungen\luepke\Eigene Dateien\Projekte\uni\Diplomarbeit\editor.mdl 14:50:52 Donnerstag, 9. Juni 2005 Class Diagram:
editor / Änderungen
mvc Page 1
cher
wird die Änderung auf beiden Datenmodellen durchgeführt
und es entstehen keine Inkonsistenzen.
69
5. Umsetzung und Implementierung
Die Synchronisation auf Anfrage reicht aus, um ein ordnungsgemäßes Arbeiten
mit der Anwendung zu ermöglichen. Nähere Ausführungen hierzu sind im Anhang
im Abschnitt A.4 im Programm-Quelltext zu finden.
Der Controller
Der Controller definiert die Reaktionen auf Benutzereingaben und besteht aus
Befehlsklassen, welche die Namen ActionXXX und EditorModeXXX tragen, siehe
Abbildung 5.3 und 5.4. Zur Entscheidung, welches Entwurfsmuster innerhalb des
Controllers angewendet werden soll, tragen aus Implementationssicht folgende Anforderungen und Faktoren bei:
• Benutzeraktionen, welche Layout-Aufträge beinhalten, werden eine längere
Zeit in Anspruch nehmen, daher müssen Benutzeraktionen grundsätzlich in
einer Schlange abgearbeitet werden können.
• Es sollen Benutzereingaben protokolliert werden.
• Undo-and-Redo-Funktionaliät soll implementiert werden.
• Die Menge an ausführbaren Befehlen soll leicht änderbar sein während der
Entwicklungsphase.
• Einige Benutzeraktionen bestehen aus mehreren Bearbeitungs-Teilschritten.
Jeder dieser Teilschritte wird also im Kontext eventuell vorhergehender Teilschritte durchgeführt.
Das Befehl-Entwurfsmuster eignet sich für die ersten vier genannten Punkte,
da bei diesem Muster alle Benutzeraktionen als Befehlsobjekte implementiert werden und als solche gut gespeichert und sukzessive abgearbeitet werden können.
Der Controller besteht daher aus einer Vielzahl solcher Befehlsklassen, welche eine einheitliche Aufrufschnittstelle besitzen werden und eine Referenz zum Model
besitzen.
Des Weiteren wird es auch Benutzeraktionen geben, welche nicht aus einem einfachen Mausklick, sondern aus einer Gruppe hintereinander folgender Teilschritte
bestehen. Wenn der Benutzer z. B. ein Diagrammelement hinzufügen möchte, dann
besteht die Aktion darin, den Mauszeiger über der Zeichenfläche zu bewegen und
dabei den Editor permanent prüfen zu lassen, ob die aktuelle Mausposition erlaubt ist, und dann eine bestimmte Position zu bestimmen und das Element dort
zu platzieren. Benutzer eines graphischen Editors sind daran gewöhnt, für eine
solche Aktion in einen Einfüge-Modus zu wechseln. Es wird dabei auf einen Button in einer Werkzeugleiste geklickt und damit ändert sich der Mauszeiger und
zeigt an, in welchem Modus sich der Editor nun befindet, welche Bedeutung also
die nächste Mausbewegung hat. Im Editor wird es Aktionen geben, welche ihn in
einen bestimmten Zustand versetzen, in dem der Editor dem Zustand entsprechend
reagiert.
70
5.2. Design
Hierfür findet das Zustands-Entwurfsmuster Anwendung. Beachtet werden muss
hierbei allerdings, dass jeder auf diese Weise modellierte Editor-Zustand gleichzeitig eine Benutzeraktion ist. Daher wird für jeden Editor-Zustand eine Klasse
modelliert, welche ihrerseits eine Befehlsklasse (EditorAction) ist, siehe hierzu
Abbildung 5.4.
EditorAction
(from controller)
EditorMode
ActionEditUndo
ActionEditConvertToFinalState
(from controller)
(from controller)
(from controller)
EditorModeAddNode
EditorModeSelectOrDragOrResizeOrFlipExpand
(from controller)
(from controller)
EditorModeAddOrState
EditorModeAddSimpleState
EditorModeAddInitialState
(from controller)
(from controller)
(from controller)
Abbildung 5.4.: Der Controller des MVC -Musters
Die View
Die View beinhaltet die graphische Benutzeroberfläche des Editors. Hierzu zählen
die Zeichenfläche, die Werkzeugleiste und Teile der Menü-Leiste, nicht aber das
KIEL-Anwendungsfenster, welches eine eigenständige Komponente ist, die vom
Editor-Modul getrennt ist, siehe Abschnitt 4.20.
Die Zeichenfläche des Editors ist eine Benutzeroberflächen-Komponente, welche
das JGraph-Rahmenwerk bereitstellt. Zu den Werkzeugleisten-Buttons und den
editorspezifischen Menü-Einträgen gehören eigenständige Controller, siehe 5.3 und
5.4. Für die View -Komponente müssen keine grundlegenden Design-Entscheidungen
getroffen werden.
Das KIEL-Anwendungsfenster
Das Hauptfenster von KIEL soll eine eigenständige Komponente sein, welche das
Editor-Modul und das Browser-Modul zusammenführt und miteinander verbindet, so dass das angezeigte Statechart zwischen diesen Komponenten ausgetauscht
werden kann, jedoch ohne dass Editor und Browser voneinander anhängig sind.
Die Entkopplung von Komponenten wird mit Hilfe der Definition von Schnittstellen erreicht: einer Schnittstelle (KielComponent) für die Beschreibung von Editor
und Browser sowie einer Schnittstelle (IKielFrame, siehe Abbildung 5.5) für die
Beschreibung des KIEL-Hauptfensters. Dieses Hauptfenster soll Funktionalitäten
bereitstellen, welche von Browser und Editor gleichsam verwendet werden, siehe
File: C:\Dokumente und Einstellungen\luepke\Eigene Dateien\Projekte\uni\Diplomarbeit\kiel.mdl
/ controller Page 1
17:28:35 Mittwoch, 20. April 2005
Class Diagram: kiel
71
5. Umsetzung und Implementierung
Abschnitt 4.20. Diese Funktionalitäten prägen die Schnittstelle IKielFrame, siehe
auch Abbildung 5.5.
KielFrame
IKielFrame
(from main)
Editor
Browser
(from editor)
(from browser)
...)
KielComponent
(from main)
Abbildung 5.5.: Entkopplung der KIEL-Komponenten
Konfigurierbarkeit
In vielen Bereichen des Softwareentwurfs müssen Annahmen getroffen werden über
die Bedürfnisse und Anwendungsgewohnheiten der Benutzer. Beispielsweise muss
festgelegt werden, in welcher Sprache die Benutzeroberfläche mit dem Benutzer
kommunizieren soll und es muß geschätzt werden, welchen Zoomfaktor bei der Anzeige von Objekten der Benutzer erwartet. Anstatt diese Dinge zur Entwicklungszeit bereits festzulegen und damit die Anwendung nur für einen Teil der Benutzer
optimal zu gestalten, ist es vorteilhafter, solche Eigenschaften der Software variabel zu halten und dem Benutzer die Möglichkeit zu geben, sich die Anwendung
nach den eigenen Bedürfnissen zu konfigurieren, siehe Abschnitt 4.22.
Folgende Designentscheidungen müssen für den Editor getroffen werden:
• Welche Eigenschaften sollen konfigurierbar sein?
Es können die in Abschnitt 4.22 aufgezählten Eigenschaften konfiguriert werden. Dies hat zur Folge, dass an entsprechenden Stellen im Programm auf
variable Werte zugegriffen
wird.
File: C:\Dokumente
und Einstellungen\luepke\Eigene Dateien\Projekte\uni\Diplomarbeit\kiel.mdl 17:29:00 Mittwoch, 20. April 2005
/ kielframe Page 1
• Wann sollen sie konfigurierbar sein?
Der Benutzer soll zu jedem Zeitpunkt während des Programmlaufs die Anwendungseigenschaften einstellen können, nicht jedoch nach Beendigung des
Programms. Die Änderungen sollen darüber hinaus nach Beendigung des
Programms erhalten bleiben. Notwendig ist also eine Konfigurationsdatei.
72
Class Diagram: kiel
5.2. Design
• Wann sollen Konfigurationsänderungen aktiv werden und wie sollen diese
durchgeführt werden?
In anderen Anwendungen können Konfigurationsdateien per Hand geändert
werden, was für den Durchschnittsbenutzer unkomfortabel ist und ein Aktivwerden vieler Eigenschaften erst nach erneutem Start der Anwendung zulässt,
da die Anwendung Änderungen an diesen Dateien nicht registriert. Im Editor
sollen hingegen solche Änderungen sofort angewendet werden. Dies erfordert
ein erhöhtes Maß an Flexibilität und Komplexität der Anwendung. Zunächst
ist hierfür erforderlich, dass Änderungen nur über die Benutzeroberfläche
erfolgen dürfen, damit Benutzeränderungen vom Programm registriert werden können. Des Weiteren müssen alle Softwarekomponenten benachrichtigt
werden über benutzergesteuerte Konfigurationsänderungen. Hierfür eignet
sich das Beobachter-Entwurfsmuster, siehe Abschnitt 2.4.3. Um z. B. die
Änderung der Sprache der Benutzeroberfläche zu veranlassen, muss jedes
Benutzeroberflächen-Objekt, welches Text anzeigt – dies sind Buttons, Tooltips, Menü-Einträge und andere – eine Beobachter-Schnittstelle implementieren und sich als Beobachter anmelden. Gleiches gilt für BenutzeroberflächenKomponenten, deren Farbe einstellbar sein soll und für die Zeichenfläche, für
die Eigenschaften wie Rastergröße und Handle-Größe konfiguriert werden
sollen.
• Wie soll mit ungültigen Konfigurationswerten umgegangen werden?
Für jeden konfigurierbaren Wert muss ein Standardwert definiert sein. Dieser
wird immer dann herangezogen, wenn der Benutzer entweder den Wert noch
nicht spezifiziert hat oder wenn er einen ungültigen Wert eingegeben hat. Ein
Wert soll der Einfachheit halber schon dann gültig sein, wenn sein Datentyp
passt. Bereichsprüfungen werden nicht durchgeführt.
PreferencesDialog
MyJGraph
Editor
EditorAction
(from editor)
(from editor)
(from editor)
...)
(from controller)
KielFrame
MyMenuItem
(from editor)
Listener
(from Preferences)
...)
Preferences
(from resources)
...)
Abbildung 5.6.: Benachrichtigungsmechanismus bei Konfigurationsänderungen
Abbildung 5.6 zeigt die Klasse Preferences, in welcher Konfigurationseinstellungen verwaltet werden. Bei jeder Änderung sendet sie allen Listener-Objekten
eine Nachricht hierüber, woraufhin die benachrichtigten Objekte die für sie relevanten Einstellungen abrufen. Zu den Interessenten von Konfigurationseinstellungsänderungen gehören:
73
5. Umsetzung und Implementierung
• das Dialogfenster zur Eingabe der Einstellungen (PreferencesDialog)
• die Statechart-Darstellungsfläche (MyJGraph)
• die Editor-View -Wurzelklasse (Editor) mit ihrer ausblendbaren Übersichtsschicht
• alle Controller -Klassen (EditorAction), deren im Tracelog dargestellter Name sprachabhängig ist (siehe Abschnitt 4.9)
• alle Menüeinträge (MyMenuItem), die ebenfalls sprachabhängig sind
5.3. Implementierung
In diesem Abschnitt wird auf die Umsetzung des im vorherigen Abschnitt entworfenen Designs eingegangen. Dabei werden einige Implementierungsdetails interessanter Funktionalitäten aufgezeigt. Zugunsten der Übersichtlichkeit und Verständlichkeit wird darauf verzichtet, auf sämtliche Implementierungsdetails und technische Probleme einzugehen. Weitergehende Details zur Implementierung, auch des
gesamten KIEL-Projektes, gibt die Javadoc-Dokumentation des Projektes [45].
Der Programm-Quelltext wird unter strikter Einhaltung der Sun-Java-Programing-Guidelines [43] geschrieben. Dies wird durch das Werkzeug Check Style überprüft. Des Weiteren wird JLint eingesetzt. Dieses Werkzeug erkennt bei seiner
statischen Quelltextanalyse mögliche Fehler und Probleme in der Klassenhierarchie, im Datenfluss und bei der Synchronisation von Threads. Sowohl Check-Style
als auch JLint und Javadoc erkennen im Programm-Quelltext des Editormoduls
nach Beendigung der Implementierungsphase keine Fehler mehr und liefern bei
ihrer Analyse auch keine Warnungen mehr.
5.3.1. Erweiterung des JGraph-Rahmenwerks
JGraph basiert auf Java-Swing und dem MVC -Entwurfsmuster. Die nachfolgenden
Beschreibungen illustriert Abbildung 5.7. Die View -Komponente von JGraph besteht unter anderem aus der Klasse JGraph, welche in Form einer Swing-Komponente
einen Graphen darstellt. Das Model wird repräsentiert von der Klasse GraphModel.
Diese verwaltet den Graphen ähnlich wie die javax.swing.JTree-Klasse in Form
einer Baumstruktur. Diese Baumstruktur ist sowohl in der Klasse JGraph als
auch in der Klasse GraphModel in Form einer Menge von javax.swing.TreeNodeObjekten aufgebaut. Jedes konkrete Diagrammelement wird als solch ein TreeNodeObjekt dargestellt. Dieses Element ist gleichzeitig entweder vom Typ DefaultGraphCell, sofern es das Diagrammelement im Model repräsentiert oder vom Typ EdgeView oder VertexView, sofern es das Diagrammelement in der View repräsentiert. Jede View stellt eine individuelle Sicht auf den Graphen dar. Das hat zur
Folge, dass ein einzelnes Diagrammelement durch ein Objekt im Model dargestellt wird und in jeder View durch je View ein ebenso individuelles Objekt. Zu
74
5.3. Implementierung
einer EdgeView- und VertexView-Klasse gehört eine Klasse, welche die graphische Repräsentation beschreibt, ein so genannter Renderer. In diesem werden die
visuellen Eigenschaften des Diagrammelements in Form von Graphik-Primitiven
aus java.awt.Graphics beschrieben. Weiterführende Informationen zu Swing und
Graphik-Primitiven bietet [53].
Die unterschiedlichen Diagrammelementtypen von KIEL bestimmen die Menge an Klassen, welche in KIEL das JGraph-Framework erweitern. Alle Klassen in
der Abbildung 5.7, welche den Zusatz from graph beinhalten, stellen die zu implementierende Erweiterung des JGraph-Rahmenwerks dar. Die Klassen VertexView
und EdgeView werden im Design des KIEL-Editors die Basisklassen für die Pendents der KIEL-Datenstruktur-Klassen Node und Edge sein. Diese Pendents heißen in der JGraph-Erweiterung NodeView und EdgeView. Diese XYView-Klassen
repräsentieren die Diagrammelementtypen in der View -Komponente von JGraph.
Die View besteht des Weiteren aus Instanzen der Klassen VertexRenderer und
EdgeRenderer. Für diese beiden Klassen müssen ebenso je Diagrammelementtyp
Subklassen entworfen werden.
Das JGraph-Model hingegen besteht ausschließlich aus Objekten der Klasse
DefaultGraphCell. Diese Klasse wird die Basisklasse der KIEL-Datenstruktur Klasse GraphicalObject sein. Für jede Datenstruktur-Klasse namens XY wird eine
XYCell-Klasse für das Model und eine XYView-Klasse sowie eine XYRenderer-Klasse
für die View entworfen, wobei die Klassenhierarchie von KIEL übernommen wird.
NormalTerminationView
NormalTerminationRenderer
NodeCell
(from graph)
(from graph)
(from graph)
NodeView
TransitionView
TransitionRenderer
GraphicalObjectCell
(from graph)
(from graph)
(from graph)
(from graph)
VertexView
EdgeView
EdgeRenderer
StateRenderer
StateView
(from graph)
(from graph)
NodeRenderer
(from graph)
VertexRenderer
DefaultGraphCell
GraphCell
JGraph
MyJGraph
DefaultGraphModel
-graph
MyGraphModel
Abbildung 5.7.: Erweiterung des JGraph-Rahmenwerks
CellView
CellViewRendererFactory
Für die Anpassung der JGraph-View auf KIEL muss diese Klasse erweitert wer(from graph)
75
5. Umsetzung und Implementierung
den nach Klasse MyJGraph. Die hierfür notwendigen Schritte werden in den nächsten Abschnitten erläutert.
Darstellung verschiedenartiger Diagrammelemente
In der KIEL-Datenstruktur wird jede Diagrammelement-Art durch eine eigene
Klasse repräsentiert und damit jedes Diagrammelement durch ein individuelles Objekt des entsprechenden Typs dargestellt. Dieser natürliche Ansatz wird auf die umzusetzende Erweiterung des JGraph-Rahmenwerks übertragen. Beispielsweise wird
für die Klasse ORState aus der KIEL-Datenstruktur in der JGraph-Erweiterung eine ORStateCell-Klasse für das Model sowie eine ORStateView-Klasse für die View
und eine ORStateRenderer-Klasse für die graphische Repräsentation definiert. Die
Subklassen von GraphCell und CellView (siehe Abbildung 5.7) stellen lediglich
Typen dar, welche keine Implementierungsdetails beinhalten. Besitzen zwei oder
mehrere Diagrammelemente das gleiche Aussehen, so braucht für diese Diagrammelemente nur ein einziger CellRenderer implementiert zu werden.
Durch diese Art der Erweiterung des JGraph-Rahmenwerks wird die Form der
KIEL-Datenstruktur auf das JGraph-Rahmenwerk übertragen und schafft damit
eine geeignete Struktur für die Transformationsaufgaben, wie sie in Abschnitt 5.2.2
beschrieben werden.
Syntax-Überprüfung
Das Ergebnis der Syntax-Überprüfung eines Statecharts bestimmt die Rahmenfarbe der einzelnen Diagrammelemente. Die Syntax-Prüfung muss daher immer
dann erfolgen, wenn das Statechart durch das Rahmenwerk neu gezeichnet wird,
wenn also die CellViewRenderer aufgerufen werden. Bei diesem Aufruf wird dem
CellViewRenderer das zu zeichnende CellView-Objekt übergeben, welches gezeichnet werden soll. Dieses CellView-Objekt besitzt eine Referenz auf die View, in
welcher es enthalten ist. Die View wird implementiert durch die Klasse MyJGraph.
Nur wenn es sich bei der View um diejenige handelt, welche editiert wird, ist der
Rahmen des CellView-Objektes entsprechend dem Syntax-Überprüfungsergebnis
zu zeichnen.
Diese Anforderungen, verbunden mit dem beschriebenen Mechanismus, mit dem
das Rahmenwerk den Graphen zeichnet, führen zu der Möglichkeit, die gesamte
Syntax-Überprüfung in der MyJGraph-Klasse zu implementieren. Grundsätzlich ist
bei der Implementierung immer zu prüfen, ob durch die Wahl des Ortes einer Implementierung die Komplexität eines Softwaresystems gering gehalten werden soll
und damit Verantwortlichkeiten im Sinne der objektorientierten Programmierung
wie in diesem Fall zusammengefasst werden, oder ob der Gedanke der Erweiterbarkeit verfolgt werden soll, was in diesem Falle eine Aufspaltung in Graph-Anzeige
und Syntaxüberprüfung bedeuten würde. Die Entscheidung fällt für die erstere
Variante. Die Regeln sind in Abschnitt 4.11 angegeben.
76
5.3. Implementierung
Verwaltung der Editor-Modi
Der Editor kennt die Zustände Selektionsmodus sowie die Hinzufüge-Operationen
Transition, Deep-History-State, Horizontal-Delimiter, Vertical-Delimiter, DynamicChoice, Final-Simple-State, History-State, Initial-State, OR-State, Simple-State und
Suspend.
Wie in Abschnitt 5.2.3 erwähnt, wird zur Umsetzung der Editor-Modi das Zustands-Entwurfsmuster, siehe Abschnitt 2.4.3, verwendet. Es wird eine abstrakte
Klasse EditorMode entworfen, deren Schnittstelle Maus-Ereignisse entgegen nimmt
sowie abfragen lässt, ob der Modus im Moment aktiv (engl. enabled ) ist. Dies ist
bei allen Modi, in denen Zustände hinzugefügt werden, abhängig von der aktuellen Mausposition. Die Klasse EditorModes verwaltet die EditorMode-Objekte. Zu
jedem Zeitpunkt erhält man mit EditorModes.getCurrent() das EditorModeObjekt abhängig vom benutzergewählten Zustand. Gesetzt wird das entsprechende EditorMode-Objekt, wenn der Benutzer entweder im Menü eine HinzufügeOperation auswählt oder im Standard-Modus das Ziehen einer Transition beginnt.
Das EditorModes-Objekt muß immer dann reagieren, wenn über der Zeichenfläche – dem von JGraph abgeleiteten MyJGraph-Objekt – der Mauszeiger bewegt wird. Daher wird die Anbindung des EditorModes-Moduls wie folgt realisiert: Am MyJGraph-Objekt wird ein java.awt.event.MouseListener-Objekt
registriert, welches rahmenwerkspezifisch in diesem Fall ein Objekt der Klasse
MyBasicGraphUI.MyMouseHandler ist. Dieses delegiert in seinen MouseListenerMethoden alle Anfragen nach dem Delegator -Muster an das EditorModes-Objekt,
welches über EditorModes.getCurrent() erreichbar ist. Welches EditorMode-Objekt die Methode EditorModes.getCurrent() zurückliefert, hängt davon ab, welchen Modus der Benutzer vorher ausgewählt hat. Der Controller des Simple-StateHinzufügen-Buttons, genannt EditorModeAddSimpleState, ruft bei Klick auf den
Button die Operation EditorModes.setCurrent(this) auf, setzt also sich selbst
als aktuellen EditorMode.
5.3.2. Datenmodell-Transformation zwischen KIEL und JGraph
Die Implementierung der Transformation von Statecharts aus dem KIEL-Format
ins JGraph-Format und umgekehrt richtet sich nach den Ergebnissen aus den Abschnitten 5.2.2 und 5.2.3. Im nachfolgenden bezeichnet der Begriff KIEL-Statechart
ein Statechart im KIEL-Format und analog JGraph-Statechart ein Statechart im
JGraph-Format.
Die Transformation findet im JGraph-Model statt. Es wird hierzu eine Klasse
MyGraphModel entworfen. Diese besitzt eine Referenz zum KIEL-Statechart und zur
KIEL-View, welche ihrerseits die Layout-Informationen für das KIEL-Statechart
beinhaltet. Des Weiteren beinhaltet das MyGraphModel eine Referenz zum RootState des JGraph-Statecharts, dessen sukzessiver Aufbau im Folgenden behandelt
wird.
Das MyGraphModel besitzt Operationen zum Hinzufügen von Diagrammelemen-
77
5. Umsetzung und Implementierung
ten, unter anderem addDelimiter(), addNode() und addTransition(). Zunächst
wird der Fall betrachtet, in dem der Editor mit einem KIEL-Statechart aufgerufen wird. Der Baum dieses KIEL-Statecharts wird traversiert, wobei für jedes
Statechart-Element ein GraphCell-Objekt erzeugt wird. Für die Transformation
elementar sind die Methoden MyGraphModel.add(Node) und MyGraphModel.addRegionOrORState(CompositeState). Gestartet wird die Transformation mit der Methode MyGraphModel.add(Node), der initial der Root-State übergeben wird und
welche rekursiv aufgerufen wird. In dieser Methode wird für das übergebene KIELObjekt ein JGraph-Objekt erzeugt und dann in Abhängigkeit davon, ob es sich um
einen OR-State handelt, die MyGraphModel.addRegionOrORState()-Methode aufgerufen, oder, falls es sich um einen AND-State handelt, die Delimiter-Lines hinzugefügt und für jede Region wiederum die MyGraphModel.addRegionOrORState()Methode aufgerufen. Die MyGraphModel.addRegionOrORState()-Methode fügt zunächst alle Kinder der Region oder des OR-States mit der MyGraphModel.add(Node)Methode hinzu, setzt die Vater-Kind-Beziehung und erzeugt danach für jede ausgehende Transition des Composite-States ein JGraph-Objekt und fügt es als Kind
dem JGraph-Objekt hinzu. Hier liegt der einzige Unterschied zwischen KIELStruktur und JGraph-Struktur: Die Transitionen hängen in der KIEL-Struktur an
ihrem Quell- und Zielzustand. In der JGraph-Struktur hingegen sind Transitionen
Kinder eines Zustands. Bei der hier beschriebenen Transformation wird festgelegt,
dass im JGraph-Modell eine Transition das Kind des Vaters des Quellzustands ist.
Beachtung findet ferner die Tatsache, dass die Koordinaten im JGraph-Modell
relativ zum Nullpunkt des Koordinatensystems angegeben werden. Im KIEL-Modell
hingegen werden diese Koordinaten relativ zur linken oberen Ecke des VaterZustands beschrieben und die Transitionen werden relativ zur linken oberen Ecke
des Quellzustands angegeben. Bei Berechnung der JGraph-Koordinaten wird daher
eine Umrechnung erfolgen müssen. Diese Umrechnung wird bei dem betreffenden
Diagrammelement starten und rekursiv die Hierarchie in Richtung des Root-States
traversieren. Dabei werden die relativen Koordinaten der auf dem Weg liegenden
Zustände aufaddiert und so die absoluten Koordinaten des betreffenden Zustands
erhalten.
5.3.3. Datenmodell-Änderungen
Sofern nachfolgend nicht anders vermerkt, müssen sämtliche Änderungen sowohl
auf dem KIEL-Datenmodell als auch auf dem JGraph-Datenmodell durchgeführt
werden. Bei der Implementierung wird darauf geachtet, die Gemeinsamkeiten der
Datenmodell-Transformation (Abschnitt 5.3.2) und der Datenmodell-Änderungen
herauszuarbeiten, um die Datenmodell-Änderungen auf den Operationen der Datenmodell-Transformation basieren lassen zu können.
78
5.3. Implementierung
Typ-Morphing
Diese Funktionalität erlaubt es, den Typ eines Zustands oder einer Transition zu
ändern. Erlaubt sind hierbei jedoch nur sinnvolle Konvertierungen, nicht also eine
Umwandlung eines Zustands in eine Transition, siehe Abschnitt 4.17.
Zusammenfassend beschrieben nimmt die Methode MyGraphModel.convert(DefaultGraphCell, Class) ein JGraph-Diagrammelement, welches ein Zustand oder
eine Transition sein kann. Die Methode erzeugt ein neues JGraph-Element gemäß
dem Class-Parameter. Hiernach kopiert sie alle Eigenschaften vom ursprünglichen
Element in das neu erzeugte Diagrammelement. Dann löscht sie das ursprüngliche
Element und fügt das neue Element in das vorhandene JGraph-Datenmodell ein.
Bei der Änderung des Datenmodells aufgrund der Ersetzung des alten Elements
durch das neue ist zu beachten, dass sowohl das neue Element an den Vater des
alten Elements gebunden wird als auch der Vater die Referenz zu dem alten Element verliert. Gleiches gilt sinngemäß für die Kinder des alten Elements, welche
Zustände und Transitionen sein können. Diese müssen ebenso umgehängt werden
auf das neue Element. Des Weiteren müssen all diejenigen Transitionen bearbeitet
werden, bei denen das alte Element den Quellzustand oder Zielzustand darstellt.
An jedem GraphCell-Objekt, also jedem JGraph-Model -Diagrammelement, hängt
als weitere Eigenschaft das korrespondierende KIEL-Diagrammelement. Bei Erzeugung eines neuen JGraph-Elements muß auch ein neues KIEL-Element erzeugt
werden, welches an das neue JGraph-Element gehängt wird. Auch hier müssen alle
Eigenschaften des alten KIEL-Elements nach dem neuen KIEL-Element kopiert
werden. Hierzu gehört neben Eigenschaften wie Events, Variablen und Beschriftungen auch das Löschen des alten KIEL-Elements aus dem KIEL-Datenmodell
und das Einfügen des neuen KIEL-Elements in diese Datenstruktur. Bei der Behandlung der Layoutinformationen im KIEL-Datenmodell ist ferner zu beachten,
dass diese bei einem Typ-Morphing zwar nicht neu angelegt werden müssen, dass
aber die vorhandene Layoutinformation im KIEL-Datenmodell an das neu erzeugte
Element gebunden werden muss.
Hinzufügen einer Delimiter-Line
Abbildung 5.8.: Hinzufügen einer Delimiter-Line
79
5. Umsetzung und Implementierung
Dies ist die aufwändigste Datenmodell-Änderung. Die Methode MyGraphModel.addDelimiter(Point2D start, Point2D end) fügt an der angegebenen Koordinatenposition eine Delimiter-Line hinzu. Die folgenden Ausführungen werden in
Abbildung 5.8 illustiert und beziehen sich auf das Hinzufügen der Delimiter-Line
des linken Composite-States und auf das Hinzufügen der horizontalen DelimiterLine des rechten Composite-States. Zunächst ist zu prüfen, ob die angegebene
Position innerhalb eines Composite-States liegt und ob es sich nicht um den RootState handelt. Ist der ermittelte Zustand ein OR-State (in der Abbildung 5.8 der
like Composite-State), so wird zunächst eine Konvertierung in einen AND-State
durchgeführt, siehe Abschnitte 4.17 und 5.3.3. Sofern es sich nun um einen ANDState handelt, werden zwei Regions (in der Abbildung bezeichnet mit Neu 1a und
Neu 2a) erzeugt, andernfalls (in der Abbildung 5.8 der rechte Composite-State)
handelt es sich um eine Region (Region Neu 1b) und diese wird zweigeteilt, es wird
also in diesem Fall nur eine neue Region (Region Neu 2b) erzeugt. In beiden Fällen
besteht die Aufgabe nun darin, zum einen die Koordinaten beider Regions zu bestimmen und zu setzen und zum anderen Kinder in der Hierarchie zu verschieben.
Die neuen Koordinaten der Regions hängen davon ab, ob es sich um eine vertikale oder horizontale Delimiter-Line handelt, und welche räumliche Ausdehnung der
AND-State hat. Wird nur eine Region neu erzeugt, so müssen diejenigen Kinder in
die neue Region hierarchisch verschoben werden, welche in dem räumlichen Gebiet
der neuen Region liegen (in der Abbildung 5.8 Zustand C und der Initial-State).
Werden hingegen zwei Regions erzeugt, der AND-State also auf zwei Regions aufgeteilt, so müssen alle Kinder des AND-States je nach ihrer Lage hierarchisch in
die beiden Regions verschoben werden (Zustände A und B sowie der Initial-State.
Im letzten Schritt werden die neu erzeugten Regions mitsamt der neu erzeugten
Delimiter-Line als Kinder dem AND-State hinzugefügt.
Löschen einer Delimiter-Line
Zunächst müssen diejenigen Regions ermittelt werden, welche durch das Löschen
der Delimiter-Line zusammengeführt werden sollen. Sofern es sich um eine horizontale Delimiter-Line handelt (z. B. in der Abbildung 5.8 im rechten Zustand),
müssen die x-Koordinaten von Region und Delimiter-Line gleich sein, beide müssen
die gleiche Länge aufweisen, und entweder liegt die obere oder die untere Kante
der Region auf der Delimiter-Line. Sinngemäß muss die Prüfung erfolgen, wenn
eine vertikale Delimiter-Line gelöscht werden soll. Bei diesem Vergleich von Koordinatenwerten und Längen- und Breitenangaben ist zu berücksichtigen, dass die
Regions nicht exakt den gesamten Platz eines AND-States ausfüllen müssen und ihre Kanten auch nicht exakt auf Delimiter-Lines liegen müssen. Dies ist bei Regions
nur dann der Fall, wenn diese durch das Hinzufügen einer Delimiter-Line im Editor erzeugt wurden. In anderen Fällen, z. B. nach Anwendung des KIEL-Layouters
oder durch Import eines Statecharts über das KIEL-File-Interface können Ungenauigkeiten auftreten. Als maximal tolerierte Ungenauigkeit werden zehn Pixel im
hier vorgestellten Algorithmus fest definiert.
80
5.3. Implementierung
Nachdem die beiden Regions gefunden sind, werden die Kinder der unteren oder
rechten von beiden Regions hierarchisch verschoben in die obere beziehungsweise
linke Region. Hiernach wird erstere Region gelöscht und die Koordinaten der oberen
beziehungsweise linken Region so angepasst, dass diese Region nun den Platz beider
Regions ausfüllt. Wurde die einzige Delimiter-Line des AND-State gelöscht, so wird
dieser AND-State in einen OR-State konvertiert, siehe hierzu die Abschnitte 4.17
und 5.3.3.
Hinzufügen eines Zustands
Es werden ein KIEL-Diagrammelement und die zugehörige Layout-Information
erzeugt und sodann für diesen Zustand mittels der MyGraphModel.add(Node)Methode, siehe Abschnitt 5.3.2, ein entsprechendes JGraph-Element generiert.
Hiernach wird der Vater dieses Elements ermittelt, indem nach dem kleinsten
Composite-State gesucht wird, welcher die Fläche des neuen Zustands vollständig umfasst.
Hinzufügen einer Transition
Im ersten Schritt werden Quellzustand und Zielzustand ermittelt. Falls der Quellzustand ein Initial-State ist, wird der Typ der neuen Transition ein Initial-Arc sein,
im Falle eines Dynamic-Choice wird es eine Conditional-Transition sein und falls
der Quellzustand ein Suspend ist, wird eine Suspension-Transition erzeugt werden. Falls jedoch der Quellzustand keinem der vorgenannten Typen entspricht, so
wird eine Transition gemäß der Auswahlbox in der Werkzeugleiste der graphischen
Benutzeroberfläche erzeugt.
Als nächstes wird die niedrigste Priorität einer von diesem Zustand ausgehenden Transition ermittelt, um der neuen Transition eine noch um eins niedrigere
Priorität zu geben.
Sofern es sich bei der neu anzulegenden Transition um eine Loop-Transition
handelt, müssen der Transition zwei Stützpunkte mitgegeben werden, um eine
kreisförmige Ausdehnung vom Startpunkt zum Zielpunkt zu erreichen, wobei Startund Zielpunkt identisch sein werden. Die Art des Linienzugs – zur Auswahl stehen
Bezier-Kurve, Spline-Kurve und Polygon – wird entsprechend der Einstellung in
der Auswahlbox der Werkzeugleiste gesetzt.
Zum Erzeugungsprozess gehört des Weiteren eine Überprüfung, ob die zu erzeugende Transition nach den syntaktischen Regeln erlaubt ist. Dies ist nicht der
Fall, wenn der Großvater des Quellzustands ungleich dem Großvater des Zielzustands ist – hierbei würde es sich um eine Interleveltransition handeln – oder wenn
Quell- oder Zielzustand nicht als solcher vorgesehen ist. Alle Final-States und alle
History-States sind als Quellzustand nicht erlaubt, von ihnen dürfen also keine
Transitionen abgehen. Alle History-States, Initial-States, Suspends und der RootState kommen als Zielzustand einer Transition nicht in Frage.
81
5. Umsetzung und Implementierung
Kollabieren und Expandieren eines Composite-States
Das JGraph-Datenmodell wird um die Attribute isCollapsed und expandedBounds
erweitert. Beim Kollabieren eines Composite-States wird das isCollapsed-Attribut
gesetzt, und die aktuellen räumlichen Grenzen des Composite-States werden im
expandedBounds-Attribut gesichert. Mittels gleitendender Strukturveränderung (siehe Abschnitt 4.7), erhält der kollabierende Zustand dann die Standardbreite und
Standardhöhe, welche auch bei Erzeugung von OR-States Anwendung finden. Hiernach wird die Sichtbarkeit aller Kinder dieses Zustands aufgehoben.
Das Expandieren erfolgt analog, jedoch mit dem Unterschied, dass eine gleitende Strukturveränderung in Richtung der zuletzt gespeicherten expandedBounds
durchgeführt wird. Daneben ist beim Expandieren zu beachten, dass die Positionsangaben aller Diagrammelemente im JGraph-Modell relativ zum Ursprung des
Koordinatensystems und nicht relativ zum Vater-Element gesetzt sind. Grundsätzlich werden durch das Rahmenwerk nur die Koordinaten der sichtbaren Diagrammelemente automatisch beim Verschieben geändert. Wird jedoch ein kollabierter
Zustand verschoben und später wieder expandiert, so müssen das räumliche Delta der Verschiebung errechnet und die Koordinaten aller Kinder um dieses Delta
verändert werden.
5.3.4. Editoreigene Layoutmechanismen
Es wird ein Algorithmus implementiert, welcher dem Benutzer die Aufgabe abnimmt, während des Platzierens eines neuen Diagrammelements oder vor dem
Expandieren eines Zustands zunächst andere Diagrammelemente zu verschieben,
um auf diese Weise für die nächste Aktion Platz zu schaffen. Unter Platzieren wird
hier verstanden das Wählen einer Position und das nachfolgende Verschieben, bis
die Maustaste gelöst wird und der Zustand seine endgültige Position erhalten hat.
Sowohl beim Expandieren als auch beim Platzieren eines Zustands wird die Methode MorphingLayouter.addCells(DefaultGraphCell, Rectangle2D) aufgerufen mit dem Diagrammelement, welches entweder platziert oder expandiert werden
soll (erster Parameter) sowie mit den neuen Grenzen dieses Diagrammelements
(zweiter Parameter). Es wird eine Menge von Diagrammelementen ermittelt, welche aufgrund ihrer Lage zu den neuen Grenzen dieses Diagrammelements verschoben oder vergrößert werden müssen. Beim Platzieren oder Expandieren eines neuen
Zustands werden der umgebende Zustand vergrößert und, soweit notwendig, alle
rechts und unterhalb liegenden Elemente weiter nach rechts und unten verschoben.
Zunächst wird geprüft, ob die neue Fläche des expandierenden Zustands größer
als seine alte Fläche ist. Ein neu anzulegender Zustand wird ebenfalls als zu expandierender Zustand betrachtet. Betrachtet werden nun all diejenigen Zustände des
Statecharts, welche mit dem expandierenden Zustand einen gemeinsamen Vater
haben oder Kinder eines solchen Zustands sind, gemeint sind also Geschwister und
ihre Kinder. Für jeden dieser Zustände wird geprüft, ob er rechts oder unter dem
expandierenden Zustand liegt und ob er den Zustand schneiden wird, was auch
82
5.3. Implementierung
abhängig von der Benutzereinstellung morphingLayouterBorderDistance (siehe
Abschnitt 4.22) ist. Sind beide Eigenschaften erfüllt, so wird dieser Zustand entsprechend verschoben. Anhand der neuen Position des Zustands wird sodann überprüft, ob dieser den Vater des expandierenden Zustands schneidet. Ist dies der Fall,
so wird dieser Vater entsprechend vergrößert. Rekursiv wird dieses Verfahren dann
angewendet auf jedes durch diesen Algorithmus veränderte Element.
5.3.5. Layout-Änderungen
Im Standard-Modus, siehe Abschnitt 5.2.3, kann der Benutzer Größen- und Positionsänderungen an Diagrammelementen durchführen. Nach jeder solcher Änderungen werden die Vater-Kind-Beziehungen auf der Basis des aktuellen Layouts
aktualisiert. Dies hat zur Folge, dass Zustände in der Hierarchie ihre Position ändern, falls diese Zustände z. B. durch Vergrößerung eines OR-States in den Bereich
dieses OR-States fallen. Auf diese Weise kann also um eine Menge von Zuständen
ein neuer Zustand gelegt werden und damit diese Zustände in der Hierarchie nach
unten verschoben werden. Ebenso ist es möglich, einen Zustand aus seinem Vater
herauszuziehen. Hierdurch erhält der Zustand einen neuen Vater und ändert somit
ebenso seine Position in der Hierarchie.
5.3.6. Layoutgestützte gleitende Strukturveränderung
Eine gleitende Strukturveränderung besteht, wie in Abschnitt 4.7 beschrieben, aus
mehreren Zwischenanordnungen. Im Folgenden wird beschrieben, wie diese einzelnen Zwischen-Anordnungen berechnet werden und wie die Frequenz der Anordnungen unabhängig von der Rechen- und Darstellungskapazität der Hardware konstant
gehalten wird. Anders als SVG-Rahmenwerke bietet JGraph keine Animationen,
daher muss ein solches Verhalten emuliert werden.
Auf einer Kopie des JGraph-Datenmodells des Ausgangsdiagramms wird die
vollständige Änderung durchgeführt. Sodann wird für jeden Punkt, welcher sich
ändern soll, der Änderungsbetrag in Pixeln errechnet. Beispielsweise werden bei
einer Positionsänderung eines Zustands die x- und y-Koordinate der Ursprungsposition mit den jeweiligen Koordinaten der Zielposition verglichen. Bei Transitionen
wird dies für alle Stützpunkte durchgeführt.
Der hier entwickelte Algorithmus sieht vor, dass die Anzahl n der Anordnungszwischenschritte der größten hierbei ermittelten Änderung in Pixeln entspricht.
Hieraus folgt, dass in jedem Änderungsschritt jeder Punkt höchstens um einen
Pixel geändert wird und im Allgemeinen um einen Bruchteil eines Pixels.
Allgemein folgt für das Delta Dk für jede Koordinate k als Änderung für jeden
Schritt
Dk = (kziel - koriginal ) / n
Rundungsfehler werden umgangen, indem alle Koordinaten als Fließkommazahlen gespeichert werden.
83
5. Umsetzung und Implementierung
Nachdem Dk für alle zu ändernden Koordinaten berechnet ist, können iterativ
in n Schritten Änderungen am Diagramm durchgeführt werden. Eine gleitende
Strukturveränderung kann somit aus mehreren tausend Diagrammänderungen bestehen.
Die Frequenz der Änderungsschritte ist zunächst abhängig von der zur Verfügung
stehenden Rechenleistung. Denn einerseits kann jede dieser Diagrammänderungen
ihrerseits je nach Komplexität des Diagramms aus vielen Berechnungsschritten bestehen. Andererseits ist auch das Darstellen der graphischen Information zeitintensiv. Um die Abhängigkeit der Frequenz der Änderungsschritte durch den Benutzer
festlegen lassen zu können, muss ein Regelmechanismus hinzugefügt werden, der eine bestimmte Frequenz sicherstellt. Eine Zielfrequenz von 50 Hertz bedeutet, dass
jede sich ändernde Koordinate sich um höchstens 50 Pixel pro Sekunde ändert.
Dieser Regelmechanismus muss die tatsächlich erreichte Frequenz verringern und
erhöhen können, um die Zielfrequenz erreichen zu können. Eine Verringerung der
Frequenz wird durch Pausen im Programmablauf erreicht, eine Erhöhung der Frequenz durch Zusammenfassen mehrerer Veränderungsschritte. Werden m solcher
Schritte zusammengefasst, ändert sich jede Koordinate um höchstens m Pixel in
einem zusammengefassten Schritt, eine Koordinate ändert sich jedoch mindestens
um genau m Pixel. Dies folgt aus den obigen Voraussetzungen. Muss der Regelmechanismus die Frequenz erhöhen, resultieren daraus größere Sprünge in der
Veränderung des Diagramms, da die Koordinaten sich nun nicht mehr in Ein-PixelSchritten ändern, sondern in gröberen Weiten.
Ob eine Regelungsmaßnahme notwendig ist, wird periodisch geprüft, indem die
tatsächlich verbrauchte Zeit für einen Veränderungsschritt gemessen und mit dem
Sollwert – bei 50 Hertz wären das 20 Millisekunden – verglichen wird. Natürlich
muss dieses Regelsystem Toleranzen erlauben: Hat ein Veränderungsschritt z. B.
statt der geforderten 20 Millisekunden 21 Millisekunden gebraucht, würde eine Erhöhung der aktuellen Frequenz, also eine neue Schrittweite von zwei, dazu führen,
dass die folgenden Veränderungsschritte nur noch 10,5 Millisekunden benötigen.
Außerdem muss berücksichtigt werden, dass die zur Verfügung stehenden Rechenund Darstellungsressourcen sich von Iteration zu Iteration verändern können und
vom Editor nicht beeinflusst werden können.
Sinnvoll erscheint hier der Ansatz, nicht jeden einzelnen Veränderungsschritt zu
messen, sondern Gruppen von etwa 10 oder 20 Schritten. Hierbei fällt die sich
ständig ändernde Rechenleistung nicht so stark ins Gewicht, vielmehr wirkt sie
sich als Durchschnittswert der letzten 10 oder 20 Schritte aus.
5.3.7. Nebenläufigkeit
Eine gleitende Strukturveränderung, siehe Abschnitt 4.7, wird im Editor immer
vom Benutzer angestoßen, also im AWT-Event-Thread der JVM initiiert. Dieser
Thread ist allerdings höher priorisiert als der System-Thread der JVM, welcher die
graphische Oberfläche aktualisiert. Liefe nun eine gleitende Strukturveränderung
im AWT-Event-Thread, so würde die Oberfläche erst dann neu gezeichnet werden,
84
5.3. Implementierung
wenn die Strukturveränderung bereits abgearbeitet ist. Die Folge wäre, dass nur
das letzte Bild dieser Strukturveränderung angezeigt würde, für den Benutzer also
diese gleitende Strukturveränderung nicht sichtbar wäre.
Aus diesem Grunde sollen langlaufende Aktionen, insbesondere aufwändige Graphik-Routinen, nicht in diesem AWT-Event-Thread der JVM ausgeführt werden.
Die gleitende Strukturveränderung muss daher in einen Thread ausgelagert werden
und im Hintergrund laufen. Problematisch hierbei ist allerdings, dass eine gleitende Strukturveränderung vom Benutzer angestoßen werden kann, auch wenn solch
eine Aktion gerade läuft. Würden nun diese Aktionen sofort in einem neuen Thread
ausgeführt werden, so würden Interferenzen auftreten und das Resultat wäre unvorhersehbar. Tatsächlich möchte der Benutzer allerdings eine gleitende Strukturveränderung immer ausführen auf dem Resultat der vorhergehenden. Folglich
müssen die gleitenden Strukturveränderungen in eine Abarbeitungsschlange aufgenommen werden und sukzessive abgearbeitet werden. Diese Abarbeitungsschlange
wird implementiert durch einen Thread, welcher permanent läuft, um Abarbeitungsanfragen entgegenzunehmen.
5.3.8. Bearbeitungsschritt-Historie und
Undo-and-Redo-Funktionalität
Diese Funktionsmerkmale werden in den Abschnitten 4.9 und 4.14 dargestellt. Wie
in Abschnitt 5.2.3 erläutert, werden alle Benutzeraktionen als Objekt repräsentiert.
Jeder Benutzer-Bearbeitungsschritt, welcher sich auf das Editieren eines Statechartsbezieht, umfasst im Allgemeinen mehrere Datenmodell-Änderungsschritte.
Wird z. B. ein Zustand kollabiert, dann ändert sich mit diesem Benutzer-Bearbeitungsschritt die Sichtbarkeit der Kind-Elemente sowie die Größe des kollabierenden
Zustands.
Die grundlegende Funktionalität der Undo-and-Redo-Funktionen wird durch das
JGraph-Rahmenwerk bereitgestellt. Die dort implementierten Funktionen basieren
allerdings nicht auf Bearbeitungsschritten sondern auf Model -Änderungen. Ein
Bearbeitungsschritt kann mehrere Model -Änderungen nach sich ziehen. Deswegen muss die vom Rahmenwerk bereitgestellte Funktionalität um einen ClusterMechanismus erweitert werden. Dieser Mechanismus ermittelt die Anzahl n aller
Model -Änderungen, welche seit Beginn eines Bearbeitungsschrittes durchgeführt
worden sind. Dafür notwendig ist das Setzen von Transaktionsklammern, innerhalb derer gezählt wird. Ein vom Benutzer angestoßener Undo-Schritt wird n mal
das vom Rahmenwerk bereitgestellte Undo ausführen. Analog wird bei Redo verfahren. Es werden also die Model -Änderungen gruppiert nach Bearbeitungsschritten. Die Bearbeitungsschritte werden gespeichert in Stack -Datenstrukturen, eine
für Bearbeitungsschritte, welche rückgängig gemacht werden können (engl. Undo),
und eine für Bearbeitungsschritte, welche schon rückgängig gemacht wurden und
die erneut ausgeführt werden können (engl. Redo). Auf dem Stack wird dann je
Bearbeitungsschritt die Anzahl n der Model -Änderungsschritte abgelegt.
85
5. Umsetzung und Implementierung
86
6. Schlussbemerkungen
In den nachfolgenden Abschnitten werden zum einen die Ergebnisse der Implementierung dargestellt, wie sie im Abschnitt 6.1 des vorangegangenen Kapitels
beschrieben wurde. Zum anderen wird ein Ausblick auf Erweiterungsmöglichkeiten der vorliegenden Arbeit in Form zusätzlicher Funktionalitäten gegeben. Hierbei
handelt es sich überwiegend um weitere innovative Funktionsmerkmale, die bisher
in verfügbaren Diagramm-Editoren nicht zu finden sind.
6.1. Ergebnisse
Zur Einordnung des Ergebnisses dieser Arbeit tragen eine Betrachtung des Programm-Quelltext-Umfangs, der Stabilität und des Funktionsumfangs bei.
Die Implementierung des Editors umfasst zusammen mit der des KIEL-Anwendungsfensters etwa 18.000 Programm-Quelltext-Zeilen, siehe im Anhang den Abschnitt A.4. Kompiliert und komprimiert entspricht dies etwa 295 kByte Maschinencode. Im Vergleich hierzu besteht das verwendete Framework JGraph aus etwa
143 kByte Maschinencode, der KIEL-Simulator aus 111 kByte, der KIEL-Browser
aus 73 kByte, der KIEL-Layouter aus 59 kByte zuzüglich 16 kByte C -Code, und
das KIEL-Esterel-Studio-File-Interface aus 51 kByte Maschinencode.
Bei einem ersten Systemtest und Gesamtintegrationstest ist erwartungsgemäß
etwa ein Fehler je 1000 Programm-Quelltextzeilen in der Editor-Komponente aufgetreten. Diese Fehler werden im Rahmen dieser Arbeit behoben, um auch einen
produktiven Einsatz des Editor-Moduls zu ermöglichen.
Der KIEL-Editor beinhaltet weit mehr Funktionalitäten als ursprünglich gefordert und geplant, vergleiche hierzu die von KIEL geforderten Merkmale in Abschnitt 1.2 und die tatsächlich implementierten Funktionalitäten, beschrieben in
Kapitel 4. Es sind innovative Funktionsmerkmale enthalten, deren Anwendbarkeit
und Nutzen in einer nachfolgenden Phase evaluiert werden können.
Bei ersten Anwendertests stellte sich heraus, dass auch ohne Benutzerhandbuch
der Editor nach einer Einarbeitungsphase intuitiv genutzt werden kann. Sämtliche
Funktionsmerkmale sind einsetzbar. Schwierigkeiten bereitet das Beschriften von
Transitionen bei fehlender Kenntnis der vom Editor erwarteten Eingabesyntax.
Hier besteht Verbesserungsbedarf, siehe Abschnitt 6.2. Die Anwendertests zeigten
darüber hinaus, dass einige Konfigurationseinstellungen die Bedienbarkeit erheblich beeinflussen und sich ihre Voreinstellungen teilweise nur für geübte Anwender
als günstig und geeignet erwiesen. Solche Einstellungen sind z. B. die Sensitivität
bei der Selektion von Diagrammelementen, die Sichtbarkeit von Size-Handles und
87
6. Schlussbemerkungen
die Größe der unsichtbaren Transitionsende-Verknüpfungspunkte. Als nachteilig
stellt sich des Weiteren heraus, dass AND-States bislang nicht größenänderbar
und Delimiter-Lines nicht verschiebbar sind. Der Grund hierfür ist, dass das Berechnen der Region-Größen nach einer AND-State-Größenänderung eine komplexe
Aufgabe darstellt, welche vom KIEL-Layouter in Zukunft übernommen werden
soll. Daher exisitiert diese Limitierung zur Zeit im Bereich des Größenänderns von
Diagrammelementen. Darüber hinaus exisitieren keine ungelösten Probleme.
Abbildung 6.1 zeigt die Benutzeroberfläche des KIEL-Editors. KIEL soll sich
neben seinem Funktionsumfang durch benutzerfreundliches, übersichtliches und
intuitives Design der Benutzeroberfläche mit seinem Farbschema, welches durch
ein eigenes Look-And-Feel [53] realisiert wird, auszeichnen.
Abbildung 6.1.: KIEL im Editor-Modus
6.2. Ausblick
Im Folgenden werden Funktionalitäten beschrieben, deren Implementierung und
Einsatz als sinnvolle Ergänzung zum bestehenden Funktionsumfang gesehen wird.
6.2.1. Multidimensionale Undo-and-Redo-Historie
Die aus Editoren bekannte Undo-and-Redo-Funktionalität stellt eine eindimensionale Historie der durchgeführten Bearbeitungsschritte dar. Der Benutzer kann n
Bearbeitungsschritte rückgängig machen und sich danach entscheiden, ob er die
n Bearbeitungsschritte endgültig verwerfen möchte, indem er nun einen neuen
Bearbeitungsschritt ausführt, oder ob er die letzten m <= n rückgängig gemachten Schritte doch nicht rückgängig machen möchte, er also weniger weit in die
Bearbeitungsvergangenheit zurück gehen möchte. Entscheidend hierbei ist, dass
88
6.2. Ausblick
bei dem bekannten Verfahren Redo-Schritte nur im direkten Anschluss an UndoSchritte möglich sind. Sobald nach Undo-Schritten ein neuer Bearbeitungsschritt
ausgeführt wird, sind keine Redo-Schritte mehr verfügbar, der vormals gegangene
Bearbeitungsweg ist endgültig verloren.
Eindimensional ist diese Historie, weil Bearbeitungswege verloren gehen und sich
der Benutzer somit nur auf einem linearen Bearbeitungsweg vorwärts und rückwärts bewegen kann. Eine sinnvolle Ergänzung stellt die Erweiterung derUndo-andRedo-Technik um eine Versionsverwaltung mit integrierter Bearbeitungsschritthistorie dar: Sobald nach Undo-Schritten ein neuer Bearbeitungsschritt ausgeführt
werden soll und damit die verworfenen Bearbeitungsschritte entgültig verloren gehen, wird die aktuelle Version, also der zu verwerfende Weg, gespeichert mitsamt
seiner Bearbeitungsschritthistorie. Auf diese Weise geht kein Bearbeitungsschritt
verloren und kann wiederhergestellt werden, sofern der vorhergehende Bearbeitungsschritt wiederhergestellt wurde.
Beispiel
Der Benutzer führt zehn Bearbeitungsschritte aus. Hiernach entscheidet er sich, die
letzten drei Schritte zu verwerfen mittels Undo. Er gelangt also wieder zurück nach
Bearbeitungsschritt sieben. An dieser Stelle schlägt er einen neuen Bearbeitungsweg ein und geht vier neue Schritte. Er stellt nun fest, dass der neu eingeschlagene
Bearbeitungsweg auch ungünstig war, verwirft die vier Schritte und steht nun wieder an Bearbeitungsschritt sieben. Hier kann er sich nun entscheiden, ob er einen
weiteren neuen Weg einschlägt oder er die verworfenen alten drei Schritte oder
die neueren vier Schritte wiederherstellt. Statt eines linearen Bearbeitungswegs
entsteht eine baumförmige Struktur. An Bearbeitungsschritt 7 z. B. gibt es nun
eine Verzweigung in zwei fortführende Richtungen, zu der beliebig viele weitere
Verzweigungen (Versionen) hinzukommen können.
6.2.2. Speichern der Undo-and-Redo-Historie
In einem Editor, welcher eine Undo-and-Redo-Technik anbietet, wächst die Undoand-Redo-Historie der verwerfbaren Bearbeitungsschritte mit jedem Bearbeitungsschritt. Zu jedem Zeitpunkt kann ein Bearbeitungsschritt zurückgenommen werden. Wird jedoch der Editor nach Speicherung der Arbeit verlassen und danach
erneut gestartet, so ist die vormals aufgebaute Bearbeitungsschritt-Historie nicht
mehr vorhanden. Es können grundsätzlich nur Bearbeitungsschritte verworfen werden, die in der aktuellen Sitzung erzeugt wurden. Wünschenswert wäre allerdings,
dass neben dem Speichern der Arbeit auch die Historie gesichert wird. Da solch
eine Funktionalität eine gewisse Menge an Speicherkapazität verbraucht, könnte
das Speichern der Historie auf z. B. diejenigen Arbeiten beschränkt werden, welche
im Menü Files→Last-Files zugreifbar sind.
89
6. Schlussbemerkungen
6.2.3. Bearbeitung von Transitionsbeschriftungen
Bei einem ersten Anwendertest hat sich herausgestellt, dass der Editor das Editieren von Transitionsbeschriftungen unterstützen könnte, indem bei der Eingabe
so wenig syntaktische Regeln wie möglich beachtet werden müssen. Beispielsweise könnte, wie in Esterel-Studio, die Eingabe von Trigger, Condition und Action
auf drei separate Eingabefelder aufgeteilt werden. Des Weiteren könnte farblich
während der Eingabe kenntlich gemacht werden, ob / wann die Eingabe korrekt
ist.
6.2.4. Erweitertes Diagrammelementtyp-Morphing
Bei dem im Editor implementierten Diagrammelementtyp-Morphing, siehe Abschnitt 4.17, kann der Benutzer explizit den Typ eines Diagrammelements ändern,
z. B. kann unter anderem ein Simple-State in einen OR-State verwandelt werden.
Neben diesen expliziten Typänderungen stellen die impliziten Änderungen eine
ebenso hilfreiche Erweiterung dar. Hierunter wird verstanden das Umwandeln eines OR-States in einen AND-State, sobald der Benutzer eine Delimiter-Line hinzufügt. Die Umwandlung geschieht dann automatisch im Hintergrund als zusätzliche
und syntaktisch notwendige Operation. In der Gruppe der impliziten Typumwandlungen wäre des Weiteren sinnvoll die Änderung von Simple-State nach OR-State
oder AND-State, sobald in den Simple-State Zustände eingefügt werden. Gleiches
gilt für das Entfernen aller Unterzustände eines Composite-States. Zudem könnte ein Final-State in einen Non-Final-State umgewandelt werden, sobald er eine
ausgehende Transition erhält.
6.2.5. Erweiterter Zoom und Ausschnittsänderung
Mittels Zoom wird im KIEL-Editor die Ansichtsdarstellung eines Statecharts vergrößert oder verkleinert. Die tatsächlichen Koordinaten der Diagrammelemente
bleiben unverändert. Vorstellbar wäre demgegenüber auch, das Diagramm in seiner tatsächlichen graphischen Repräsentation zu vergrößern oder zu verkleinern,
indem seine Koordinaten verändert werden.
Die Änderung des sichtbaren Statechart-Ausschnitts soll nicht nur mittels Scrollleisten, Tasten und dem Mausrad erfolgen können, sondern es soll auf eine geeignete
Weise die Übersichtsansicht in den Vordergrund treten können, in der dann durch
Zeichnen eines Rechtecks der neue sichtbare Ausschnitt für die Bearbeitungssicht
gewählt werden kann.
6.2.6. Layouthilfen während der Bearbeitung
In Abschnitt 4.13 wird eine Layouthilfe beschrieben, welche den Benutzer während
des Anlegens eines neuen Zustands unterstützt, indem das Layout des Diagramms
während des Platzierens des neuen Elements derart verändert wird, dass genügend
Platz für das einzufügende Diagrammelement zur Verfügung steht. Denkbar ist,
90
6.2. Ausblick
solche Layouthilfen auch während einer Verschiebe- oder Vergrößerungsoperation
anzubieten. Soll ein Zustand verschoben werden, muss der Benutzer angeben, ob
der zu verschiebende Zustand seinen Platz in der Statechart-Hierarchie ändern
soll, oder er innerhalb seines Vaters an einer anderen Stelle platziert werden soll.
In letzterem Fall sollte der Vater bei Bedarf automatisch vergrößert werden. Eine
gleichzeitige notwendige Positionsänderung der Geschwister ist dabei auch denkbar. Möchte der Benutzer dagegen einen Zustand vergrößern und mit dieser Aktion
nicht die Position anderer Zustände in der Statechart-Hierarchie ändern, indem sie
durch Vergrößerung des Zustands Kinder desselben werden, so kann diese Aktion
mit ähnlichen Mechanismen des Platz-Schaffens vom Editor unterstützt werden.
Grundsätzlich sollten solche Layouthilfen wie die hier beschriebenen visuell unterstützt werden durch Verwendung verschiedener Mauszeiger, welche den Benutzer darüber informieren, welche editoreigenen Mechanismen den aktuellen Bearbeitungsschritt begleiten.
91
6. Schlussbemerkungen
92
7. Literaturverzeichnis
[1] Gaudenz Alder. Design and Implementation of the JGraph Swing Component.
http://jgraph.com/paper.html.
[2] Gaudenz Alder.
JGraph Diagram Component, 2001.
sourceforge.net/projects/jgraph.
URL http://
[3] ArgoUML. The ArgoUML project. URL http://argouml.tigris.org/. An
open source UML design tool.
[4] Benjamin B. Bederson, Jesse Grosjean und Jon Meyer. Toolkit Design for
Interactive Structured Graphics. IEEE TRANSACTIONS ON SOFTWARE
ENGINEERING, 30(8), August 2004.
[5] Gerard Berry. The Esterel v5 Language Primer. Draft Book, 1999. URL
ftp://ftp-sop.inria.fr/esterel/pub/papers/primer.ps.
[6] Christian Lenz Cesar. Graph Foundation Classes for Java, 1999. URL http:
//www.alphaworks.ibm.com/tech/gfc.
[7] Charles André.
Semantics of S.S.M (Safe State Machine).
Technischer bericht, I3S, Sophia-Antipolis, France, 2003. URL http://www.
esterel-technologies.com/v3/?id=50399\&dwnID=48.
[8] Rowan Christmas. Graph Interface library, 2002. URL http://sourceforge.
net/projects/csbi.
[9] D. Cox, J. S. Chugh, C. Gutwin und S. Greenberg. The Usability of Transparent Overview Layers. In Companion Proceedings of the CHI ’98 Conference
on Human Factors in Computing Systems. ACM Press, 1997.
[10] Reinhard Diestel. Graphentheorie. Springer-Verlag, 2000.
[11] Tim Dwyer und Peter Eckersley. WilmaScpoe Homepage, 2003. URL http:
//www.wilmascope.org/.
[12] Esterel Technologies.
esterel-technologies.com.
Company
homepage.
http://www.
[13] GEF Graph Editing Framework. Project Homepage, 2003. URL http://gef.
tigris.org/.
93
7. Literaturverzeichnis
[14] Erich Gamma, Richard Helm, Ralph Johnson und John Vlissides. Design
Patterns. Addison-Wesley, 1995.
[15] Gaudenz Alder. The JGraph Tutorial. http://jgraph.com/tutorial.html.
[16] Thomas Gehrke. Dynamische Modelle für Reaktive Systeme mit Daten. PhD
thesis, Technische Universität Braunschweig, Dezember 2000.
[17] Les Grove, Wells Mathews, Rodney Hickman und Kal Toth. Open Source
Software Engineering Tools. Aufsatz, Portland State University, 2004.
[18] Reinhard von Hanxleden. Graphical languages for modeling complex reactive
systems. Workshop on Synchronous Languages SYNCHRON 2003, Luminy,
France, Dezember 2003. http://www-verimag.imag.fr/PEOPLE/Nicolas.
Halbwachs/SYNCHRON03/Abstracts/vonhanxleden.html.
[19] David Harel. Statecharts: A visual formalism for complex systems. Science
of Computer Programming, 8(3):231–274, Juni 1987.
[20] Jon Harris. JGraphEd. URL http://www.jharris.ca/JGraphEd/.
[21] Andreas Hartmann. Ein grafisches Werkzeug zur Unterstützung von ModelChecking-Prozessen. Universität Rostock, 2002.
[22] John E. Hopcroft und Jeffrey D. Ullman. Introduction to Automata Theory,
Languages, and Computation. Addison-Wesley, Reading, MA, 1979.
[23] Randy Hudson. Graphical editing framework, 2003.
eclipse.org/gef/.
URL http://www.
[24] Michael Jünger und Petra Mutzel. Graph Drawing Software. Springer, Oktober 2003. ISBN 3540008810.
[25] Jens Kanschik.
HyperGraph, 2003.
projects/hypergraph.
URL http://sourceforge.net/
[26] Lutz Kirchner und Ulrich Frank. Evaluierung von UML-Modellierungswerkzeugen. Aufsatz, Universität Koblenz-Landau, 2004.
[27] Gerwin Klein. Generating Editors with Grace, 1999. URL http://www.
doclsf.de/grace/.
[28] Tobias Kloss. Flexibles und Automatisiertes Layout von Statecharts. Studienarbeit, Christian-Albrechts-Universität zu Kiel, Institut für Informatik und
Praktische Mathematik, Juli 2003.
[29] Tobias Kloss. Automatisches Layout von Statecharts unter Verwendung von
GraphViz. Diplomarbeit, Christian-Albrechts-Universität zu Kiel, Institut für
Informatik und Praktische Mathematik, Mai 2005.
94
7. Literaturverzeichnis
[30] Philippe Kruchten. The Rational Unified Process An Introduction. Addison
Wesley, Dezember 2003.
[31] M. S. Marshall, I. Herman und G. Melançon. An object-oriented design for
graph visualization. Software: Practice and Experience, 31(8):739–756, 2001.
URL citeseer.ist.psu.edu/article/marshall00objectoriented.html.
[32] M. Scott Marshall. GVF - Graph Visualization Framework, 2001. URL http:
//sourceforge.net/projects/gvf/.
[33] Mathworks Inc. Simulink Documentation, 2005. http://www.mathworks.
com/access/helpdesk/help/toolbox/simulink/.
[34] Mathworks Inc. Stateflow Application Programming Interface, 2005. http:
//www.mathworks.com/access/helpdesk/help/toolbox/stateflow/.
[35] Object Management Group. OMG Unified Modeling Language Specification, Version 1.5, März 2003. http://www.omg.org/cgi-bin/doc?formal/
03-03-01.
[36] Bernd Oestereich. Objektorientierte Softwareentwicklung: Analyse und Design
mit der Unified modeling language. Oldenbourg, München, Wien, 5 edition,
2001.
[37] André Ohlhoff. Simulating the Behavior of Synccharts. Studienarbeit,
Christian-Albrechts-Universität zu Kiel, Institut für Informatik und Praktische Mathematik, November 2004.
[38] Joshua O’Madadhain. Java Universal Network/Graph Framework, 2003. URL
http://sourceforge.net/projects/jung.
[39] Steffen Prochnow und Reinhard von Hanxleden. Visualisierung komplexer
reaktiver Systeme – Annotierte Bibliographie. Technischer Bericht 0406,
Christian-Albrechts-Universität Kiel, Institut für Informatik und Praktische
Mathematik, Juni 2004.
[40] Tom Sawyer. Tom Sawyer Visualization, Java Edition. URL http://www.
tomsawyer.com.
[41] Alexander Shapiro. ToughGraph, 2001. URL http://www.touchgraph.com/.
[42] Frank Steinbrückner. Analyse von Software Systemen - Projekt Argo/UML.
Seminar, Technische Universität Cottbus, 2002.
[43] Sun Microsystems, Inc. Code conventions for the java programming language.
http://java.sun.com/docs/codeconv/.
[44] Jan Täubrich. Untersuchung der nicht-interaktiven Simulation von StateflowStatecharts. Praktikumsbericht, Christian-Albrechts-Universität zu Kiel, Institut für Informatik und Praktische Mathematik, April 2005.
95
7. Literaturverzeichnis
[45] The KIEL Project. Project API Documentation, 2004. URL http://www.
informatik.uni-kiel.de/~rt-kiel/kiel/kiel/doc/. Kiel Integrated Environment for Layout.
[46] The KIEL Project. Project Homepage, 2004. URL http://www.informatik.
uni-kiel.de/~rt-kiel/. Kiel Integrated Environment for Layout.
[47] The Mathworks, Inc. Company homepage. http://www.mathworks.com.
[48] Auburn University.
Drawing Graphs with VGJ, 1998.
URL
http://www.eng.auburn.edu/department/cse/research/graph_drawing/
graph_drawing.html.
[49] Dave Walend. JDigraph, 2001. URL http://sourceforge.net/projects/
jdigraph.
[50] Mirko Wischer. Ein Browser für die Visualisierung dynamischer Sichten von
Statecharts. Diplomarbeit, Christian-Albrechts-Universität zu Kiel, Institut
für Informatik und Praktische Mathematik, 2005.
[51] Mirko Wischer. Ein FileInterface für das KIEL Projekt. Praktikumsbericht,
Christian-Albrechts-Universität zu Kiel, Institut für Informatik und Praktische Mathematik, 2005.
[52] yWorks. yFiles Homepage, 2005.
products_yfiles_about.htm.
URL http://www.yworks.com/ger/
[53] John Zukowski. John Zukowskiś Definite Guide to Swing for Java 2. Apress,
1999.
96
.1. Funktionsumfang
.1. Funktionsumfang
.1.1. Allgemeine Editorfunktionen
Im Folgenden ist mit Konfigurierbarkeit gemeint, dass über den Menüeintrag
File→Preferences ein bestimmtes Verhalten eingestellt werden kann.
• Erzeugung von Statemate- und Esterel-Studio-Modellen: In Menü File→New
lässt sich zwischen diesen beiden Modellen wählen. Abhängig hiervon enthält
die Werkzeugleiste entsprechende Diagrammelemente, siehe Abbildung .1.
(a) Esterel-Studio-Diagrammelemente
(b) Matlab-Diagrammelemente
Abbildung .1.: Ausschnitt aus der Werkzeugleiste des Editors
• Exportformate GIF und EPS, wählbar über den Menüeintrag File→Export
• Ausdruck, wählbar über den Menüeintrag File→Print
• Konfigurierbarkeit von über 40 Eigenschaften über ein Dialogfenster, erreichbar über den Menüeintrag File→Preferences, siehe Abbildung .2 und die detaillierte Auflistung im Anhang .2.1.
• Fehlermeldungen sind selektiv unterdrückbar: Soll eine bestimmte Fehlermeldung in Zukunft nicht mehr angezeigt werden, so kann sie selektiv unterdrückt werden, siehe Abbildung .3. Diese Unterdrückung ist jederzeit wieder
aufhebbar über den Menüeintrag File→Message suppression reset.
• Zwei Darstellungsschichten: Optional kann neben der Bearbeitungsschicht
zusätzlich eine Übersichtsschicht eingeblendet werden, erreichbar über das
Menü View, siehe Abschnitt 4.10.
• In beiden Darstellungsschichten wird das aktuell selektierte Diagrammelement hervorgehoben, siehe Abschnitt 4.10.
• Eine Gitternetzdarstellung ist optional einblendbar, aufrufbar in Menü View,
siehe Abschnitt 4.8.
• Undo-and-Redo-Funktionalität, enthalten in Menü Edit
• Lokale Eventdeklarationen, Variablendeklarationen und State-Actions sind
optional einblendbar über das Menü View.
• Replay: Bearbeitungsschritte können abgespielt werden in normalem und
schnellem Tempo vorwärts und rückwärts; Mediaplayer-Optik und -Handhabung; Diese Funktionalität ist erreichbar über die Werkzeugleiste und das
Menü Replay.
97
7. Literaturverzeichnis
Abbildung .2.: Konfigurationsdialog
• Eine Bearbeitungsschitt-Historie, welche jede Benutzeraktion protokolliert
mit Zeitstempel und Information darüber, ob die Aktion erfolgreich ausgeführt wurde. Eine Undo-and-Redo-Historie, welche farblich kennzeichnet,
welche Aktionen rückgängig gemacht werden können, dargestellt in hellblau,
und welche wiederholt werden können,dargestellt in dunkelblau. Die Historien sind exportierbar, siehe Abbildung .4, aufrufbar über den Menüeintrag
Replay→Trace Log.
• Zoom, gleitend über den Regler in der Statusleiste und in konfigurierbaren
Schritten über das Menü Format
• Sprache wahlweise Englisch und Deutsch, einstellbar über den Menüeintrag
File→Preferences und dort den Eintrag Language
• Aktuelle Maus-Koordinaten-Anzeige und Undo-and-Redo-Schritt-Anzeige in
der Statusleiste
• Werkzeugleisten-Gruppen wahlweise einblendbar über den Menüeintrag FilePreferences oder im Kontextmenü, welches über der freien Fläche der Werk-
98
.1. Funktionsumfang
Abbildung .3.: Unterdrückbare Fehlermeldung
zeugleiste geöffnet wird.
.1.2. Funktionen zur Bearbeitung eines Statecharts
• Es gelten die in Abschnitt 4.1 angeführten Regeln.
• Morphing bei allen automatischen Plazierungsmechanismen und Layouts.
Die Geschwindigkeit ist konfigurierbar.
• Kollabieren und Expandieren von OR-States und AND-States. Beim Kollabieren werden die innereren Zustände unsichtbar.
• Rasterorientiertes Bearbeiten mit konfigurierbarer Rasterweite
• Farbliche Syntaxprüfung: Hervorhebung unvollständiger Zustände
• Typmorphing für Diagrammelemente: Nachträgliches Ändern des Typs eines Diagrammelementes (Simple-State nach OR-State, OR-State nach ANDState, Transitionsarten beliebig, und andere. Aufrufbar ist dies über das Kontextmenü auf einem Diagrammelement oder über das Menü Edit.
• Für jeden Zustand kann über das Kontextmenü beliebig das Final -Attribut
gesetzt oder gelöscht werden, welches besagt, dass dieser Zustand ein finaler
oder nichtfinaler Zustand ist.
• Transitionsprioritäten werden automatisch vergeben. Bei manueller Änderung einer Transitionspriorität findet eine automatische Prioritätenanpassung aller Transitionen des gleichen Quellzustands statt.
• Cut-and-Paste
• Drag-and-Drop
99
7. Literaturverzeichnis
(a) Undo-/ Redo-Historie
(b) Komplette Bearbeitungsschritt-Historie
Abbildung .4.: Anzeige der Bearbeitungsschritte
• Live-Preview
• Anwendung eines KIEL-Layouts auf das gesamte Statechart oder auf einzelne
States, aufrufbar über das Kontextmenü.
• Layout on the fly: Automatisches Platz schaffen mit Morphing beim Einfügen
eines neuen Zustands:
– Wird innerhalb eines Composite-States ein neuer Zustand platziert, wird
der Composite-State automatisch vergrößert, sofern nach der Vergrößerung der neue Zustand platziert werden kann. Dies ist jedoch noch
nicht der Fall, wenn der neue Zustand aufgrund der Lage zukünftiger
Geschwister (vorhandener Zustände) nicht platziert werden kann.
– Ein OR-State und ein AND-State kann jederzeit ausgeklappt werden. Ist
für das Ausklappen nicht genügend Platz vorhanden, so werden rekursiv alle kollidierenden Geschwister verschoben, sowie, falls notwendig,
der Vater des ausklappenden Zustands vergrößert. Vergrößert sich dieser Vater, so wird der gleiche Mechanismus eine Stufe höher (rekursiv)
angewandt.
• Editieren von On-Entry-Actions, On-Inside-Actions und On-Exit-Actions bei
allen Zuständen, aufrufbar über das Kontextmenü. Diese werden im Inneren
des jeweiligen Zustands angezeigt.
100
.2. Benutzungshinweise für Editorfunktionen
• Deklaration von lokalen Ereignissen und lokalen Variablen bei CompositeStates, editierbar über das Kontextmenü. Diese werden unter dem Zustandsnamen im Inneren des Zustands angezeigt.
• Editieren von statechart-globalen Input-Events und Output-Events. Diese
werden nur im Bearbeitungsdialog angezeigt, aufrufbar über den Menüeintrag Edit→Edit Statechart input events und Edit→Edit Statechart output
events.
• Editieren von Transitionsbeschriftungen
• Relatives Ausrichten von States an anderen States und dasTrimmen auf eine
gemeinsame Größe: Es müssen mehrere Zustände mittels CTRL-Taste selektiert werden, wobei am ersten Element ausgerichtet wird.
• Verschiedene Kurvenarten für Transitionen: Spline, Bezier, orthogonal, wählbar über das Kontextmenü
• Nachträgliches Ändern der Hierarchie: Kind-Zustände können herausgezogen
werden.
.2. Benutzungshinweise für Editorfunktionen
Bei der ersten Arbeit mit dem Editor ist es empfehlenswert, die Standardwerte für Benutzereinstellungen zu aktivieren, welche später über den Menüeintrag
File→Preferences geändert werden können. Die Aktivierung der Standardeinstellungen wird erreicht durch File→Preferences und im sich öffnenden Dialog mit
dem Button Default Values.
Im nachfolgenden werden Benutzungshinweise für Editorfunktionen, welche nicht
intuitiv ausführbar sind, gegeben.
Einstellung der Morphing-Geschwindigkeit :
Die Art der Einstellung der Geschwindigkeit ist abhängig vom Betriebssystem. Grundsätzlich auf jeder Plattform kann mittels der Benutzereinstellung morphingLayouterStepInterval die Geschwindigkeit eingestellt werden.
Sinnvolle Werte liegen bei 50-300. Formel: morphingLayouterStepInterval /
Anzahl Diagrammelemente = Maximalpixeländerung je Graphik-RefreshZyklus. Für Windows-Rechner ist auch die direkte Angabe der Geschwindigkeit in Pixels je Sekunde möglich mit der Benutzereinstellung morphingLayouterSpeed. Sinnvolle Werte liegen hier um 200.
Nur wenn morphingLayouterStepInterval auf den Wert Null gesetzt ist, wird
der Wert von morphingLayouterSpeed berücksichtigt. Die passenden Werte
sind abhängig von der zur Verfügung stehenden Rechenleistung.
101
7. Literaturverzeichnis
Selektion von Diagrammelementen :
Bei der Selektion von Diagrammelementen mittels CTRL-Taste – dies wird
bei Mehrfachselektion für relatives Ausrichten und Verschieben von mehreren
Elementen – ist darauf zu achten, dass das zu selektierende Element mehrmals geklickt werden muss, bis es tatsächlich selektiert ist. Welches Element
nach einem Mausklick selektiert ist, ist erkennbar an den Size-Handles.
Entfernen eines Elements aus einer Region :
Durch einen bisher nicht behobenen Softwarefehler ist es notwendig, nach
dem Entfernen des letzten Kind-Elements einer Region, sei es durch Herausziehen oder direktes Löschen, den umgebenden AND-State einmal einzuklappen und anschließend wieder aufzuklappen.
Preferences-Werte ändern : Nach Änderung eines Wertes in der Tabelle der Benutzereinstellungen muss die Eingabe mit der Entertaste abgeschlossen werden.
Erzeugen von Zuständen :
Bei der Erzeugung von Zuständen ist zu beachten, dass vor jeder HinzufügeOperation der Editor in den Hinzufüge-Modus geschaltet werden muss, indem das gewünschte Element angewählt wird in der Werkzeugleiste oder im
Menü Insert. Nach dem Platzieren des Elements ist der Editor wieder im Selektionsmodus. Beim Platzieren ist auf den Mauszeiger zu achten: Erscheint
ein rotes Kreuz, dann ist die aktuelle Mausposition für das Erzeugen des
Elementes nicht erlaubt. Hierbei ist zu bedenken, dass ein Mindestabstand
zu anderen Elementen gewahrt bleiben muß und dass an bestimmten Orten
das gewünschte Element nicht zulässig ist.
Erzeugen von Transitionen :
Zunächst muß der Mauszeiger genau in der Mitte des Quellzustands platziert
werden, so dass er sich in einen Hand-Mauszeiger verwandelt. Bei Mausklick
wird der selektierte Quellzustand umrahmt. Dann wird der aktuelle Punkt
geklickt und die Transition gezogen, indem der Mauszeiger über der Mitte
des Zielzustands so platziert wird, dass dieser Zustand optisch durch einen
Rahmen hervorgehoben wird. Dann ist das Ziehen zu beenden. Der Transitionstyp wird durch den Quellzustand bestimmt, siehe Abschnitt 5.3.3, und
durch die Auswahlbox in der Werkzeugleiste.
Transitionen ändern :
Ein Stützpunkt ist hinzufügbar, indem an der gewünschten Stelle auf der
Transition mit Shift+Kontextmenü-Maustaste geklickt wird. Dieser Stützpunkt kann verschoben werden, indem der Mauszeiger derart auf dem Stützpunkt platziert wird, dass sich der Mauszeiger in ein Kreuz verwandelt. Dann
kann gezogen werden.
Quellzustand und Zielzustand können geändert werden, indem der Mauszeiger so auf eine der Transitionsenden platziert wird, dass sich der Mauszeiger
102
.2. Benutzungshinweise für Editorfunktionen
in ein Kreuz verwandelt. Dann kann dieser Punkt verschoben werden, wobei darauf zu achten ist, dass der Zielpunkt sich in der Mitte eines anderen
Zustands befindet, genau wie beim Zeichnen einer neuen Transition.
Selektieren und Verschieben von kleinen Diagrammelementen :
Für das Selektieren und Verschieben von kleinen Elementen wie z. B. PseudoStates empfiehlt es sich, das Erzeugen von Transitionen temporär auszuschalten durch Klick auf den Menüeintrag Insert→Transition Mode.
Das Ziehen des Mauszeigers auf einem Diagrammelement wird je nach Position des Mauszeigers vom Editor unterschiedlich interpretiert: Befindet sich
der Mauszeiger in der Mitte eines Zustands, so wird erwartet, dass der Benutzer eine Transition erzeugen möchte. Sofern sich der Mauszeiger allerdings
am Rand eines Zustands befindet, so wird angenommen, dass die Größe des
Zustands geändert werden soll. Befindet sich der Mauszeiger an einer anderen Stelle innerhalb des Zustands, so wird ein Ziehen des Mauszeigers den
Zustand verschieben. Bei kleinen Diagrammelementen jedoch ist es kaum
möglich, eine Stelle innerhalb des Zustands zu finden, welche nicht das Erzeugen einer Transition oder eine Größenänderung sondern das Verschieben
des Zustands bewirkt.
Relatives Ausrichten :
Ausgerichtet wird immer an dem ersten von mehreren selektierten Zuständen. Mehrere Zustände werden selektiert mit Hilfe der CTRL-Taste. Der
Mauszeiger ist über den ersten zu selektierenden Zustand zu positionieren,
dann ist die CTRL-Taste zu drücken und gedrückt zu halten, dann mehrmals
der Zustand anzuklicken, bis der gewünschte Zustand selektiert ist. Danach
ist die CTRL-Taste gedrückt zu halten und weitere Zustände auf gleiche Weise der Selektion hinzuzufügen. Hiernach kann eine Ausrichtungsfunktion im
Menü oder der Werkzeugleiste ausgewählt werden.
Bearbeiten der Variablendeklaration eines Zustands :
Über das Kontextmenü, Eintrag Variables, kann die Deklaration von Variablen für den betreffenden Zustand vorgenommen werden. Die bereits deklarierten Variablen werden mit ihrem Typ kommasepariert im Dialogfenster
angezeigt. Es können Variablen gelöscht und hinzugefügt werden. Eine vollständige Variablendeklaration hat die Form varname : typname. Die erlaubte
verkürzte Schreibweise varname, also ohne Typangabe, bedeutet das gleiche
wie varname : integer. Fehlt die Angabe des Typs einer Variablen, so ist ihr
Typ also integer.
Ausblenden von Benutzeroberflächen-Elementen :
Mit Mausklick auf die freie Fläche der Werkzeugleiste erscheint ein KontextMenü, in welchem die Sichtbarkeit von Werkzeugelementen sowie der Statusleiste eingestellt werden kann. Soll diese Einstellung dauerhaft geändert
werden, so ist diese Änderung unter File→Preferences vorzunehmen.
103
7. Literaturverzeichnis
Benutzereinstellungen :
Siehe hierzu .2.1
.2.1. Einstellungen
Über den Menüeintrag File→Preferences lassen sich Anwendungseigenschaften einstellen. Änderungen werden sofort aktiv. Sollen die Änderungen von
Dauer sein, so muss nach dem Ändern auf Speichern geklickt werden. Ein
Klick auf Abbrechen stellt nicht die Ursprungswerte wieder her. Im Folgenden wird für jede Eigenschaft die Wertemenge angegeben. bool steht für die
Zeichenkette true oder false, int steht für eine natürliche Zahl, float steht für
eine Fließkommazahl, string steht für eine Zeichenkette.
Show overview layer :
Wertemenge [bool];
Soll die Übersichtsdarstellung angezeigt werden?
Zoom in factor :
Wertemenge [float]; sinnvoll sind Werte > 1.
Um wieviel soll vergrößert werden bei Klick auf den Zoom +-Button?
Zoom out factor :
Wertemenge [float]; sinnvoll sind Werte < 1.
Um wieviel soll verkleinert werden bei Klick auf den Zoom --Button?
Trace Log separator :
Wertemenge [string]; sinnvoll sind Zeichenketten wie ’;’ oder ’,’.
Welcher Separator soll verwendet werden bei Export von Tracelog-Daten? Siehe hierzu Abbildung 4.4.
Default root state dimension : Wertemenge [int, int]; sinnvoll sind Werte,
welche zur Monitorauflösung passen.
Definiert die initiale Größe des Anwendungsfensters
Show composite State events :
Wertemenge [bool];
Sollen die Events eines Composite-States angezeigt werden? Siehe Abbildung .5. Dies kann auch als temporäre Einstellung über das Menü
gesteuert werden.
Show composite state variables :
Wertemenge [bool];
Sollen die Variablen eines Composite-States angezeigt werden? Siehe
Abbildung .5. Dies kann auch als temporäre Einstellung über das Menü
gesteuert werden.
Show state actions :
Wertemenge [bool];
Sollen Zustandsaktionen angezeigt werden?
104
.2. Benutzungshinweise für Editorfunktionen
(a) Events werden angezeigt
(b) Events werden ausgeblendet
Abbildung .5.: Anzeige der Events
Replay step time fast :
Wertemenge [int]; sinnvoll sind Werte 0 - 10000 (Millisekunden).
Wie groß soll der zeitliche Abstand zwischen zwei Schritten sein beim
schnellen Abspielen von Bearbeitungsschritten? Siehe hierzu Abschnitt
4.9.
Replay step time : Wertemenge [int]; sinnvoll sind Werte 0 - 10000 (Millisekunden).
Wie groß soll der zeitliche Abstand zwischen zwei Schritten sein beim
normalen Abspielen von Bearbeitungsschritten? Siehe hierzu Abschnitt
4.9.
Show alignment toolbar on load :
Wertemenge [bool];
Sollen die Ausrichtungs-Buttons initial in der Werkzeugleiste angezeigt
werden? Dies kann auch als temporäre Einstellung im Kontextmenü
zum Hauptmenü eingestellt werden, siehe hierzu Abschnitt 4.19.
Show replay toolbar on load : Wertemenge [bool];
Soll die Replay-Werkzeugleiste initial angezeigt werden? Dies kann auch
als temporäre Einstellung im Kontextmenü zum Hauptmenü eingestellt
werden, siehe hierzu Abschnitt 4.19.
Grid size :
Wertemenge [int]; sinnvoll sind Werte 1 - 200 und der Wert muß kleiner
sein als der der ’Intersection sensitivity’
Wie groß soll das Raster sein, welches angezeigt werden kann und welches bei dem rasterorientierten Bearbeiten eine Rolle spielt? Siehe Abschnitt 4.8.
Intersection sensitivity :
105
7. Literaturverzeichnis
Wertemenge [int]; sinnvoll sind Werte von 0 - 20 und der Wert muß
größer sein als der der Grid Size.
Ab welcher Entfernung zweier Zustände sollen die beiden als sich schneidend interpretiert werden?
Grid enabled :
Wertemenge [bool];
Soll rasterorientiertes Bearbeiten eingeschaltet sein? Siehe Abschnitt
4.8.
Grid visible :
Wertemenge [bool];
Soll das Bearbeitungsraster sichtbar sein? Davon unabhängig ist, ob
rasterorientiertes Bearbeiten eingeschaltet sein soll, siehe Abschnitt 4.8
und insbesondere Abbildung 4.3.
Default OR-State dimension :
Wertemenge [int, int]; sinnvoll sind Werte um 100.
Wie groß sollen OR-States initial sein?
Default Node dimension :
Wertemenge [int, int];
Wie groß sollen Pseudo-States initial sein?
Default state dimension :
Wertemenge [int ,int]
Wie groß sollen Simple-States initial sein?
Layout on insert :
Wertemenge [bool];
Soll beim Absetzen eines neu zu erzeugenden Zustands automatisch
Platz geschaffen werden? Der Prozess des Absetzens dauert so lange,
bis die Maustaste losgelassen wird, siehe Abschnitt 4.13.
Flip Area :
Wertemenge [int, int, int, int]; sinnvoll sind Werte 1 - 30.
In welchem Bereich eines OR-States und AND-States soll bei Mausklick
in diesen Bereich dieser Zustand kollabieren oder expandieren? Siehe
hierzu Abschnitt 4.5. Die vier Werte beschreiben ein Rechteck mit xKoordinate, y-Koordinate, Breite und Höhe.
Arc width and height :
Wertemenge [int]; sinnvoll sind Werte 0 - 40.
Wie weit soll die Rundung der Ecken von Zuständen sein?
File history last files count :
Wertemenge [int]; sinnvoll sind Werte um 10.
Wie viele Dateien sollen im Menü File→Last Files angezeigt werden?
Unabhängig von dieser Einstellung erhalten nur die ersten neun Einträge zusätzlich einen Key-Shortcut.
106
.2. Benutzungshinweise für Editorfunktionen
Final State border :
Wertemenge [int]; sinnvoll sind Werte 1 - 10.
Wie groß soll der Abstand der beiden Rahmenlinien von Final-States
sein?
Pseudo State name offset :
Wertemenge [int, int]; sinnvoll sind Werte von 0 - 20.
Wo soll der den Pseudo-State beschreibende Buchstabe (’I’, ’S’, ’C’) innerhalb des Pseudo-States gezeichnet werden? Eine Änderung des Standardwertes kommt nur in Betracht, wenn alle Pseudo-States eine neue
Standardgröße erhalten sollen.
Language :
Wertemenge [string]; Erlaubt sind ’en’ und ’de’.
Setzt für alle sprachlichen Anzeigeelemente des Editors (Dialoge, Menüeinträge) die Sprache auf deutsch (’de’) oder Englisch (’en’). Siehe hierzu
Abbildung 4.12.
Line end diameter :
Wertemenge [int]; sinnvoll sind Werte um 6.
Wie groß soll der grüne und rote Kreis am Ende einer Strong-Abortion
und Normal-Termination sein?
Label offset :
Wertemenge [int, int]; sinnvoll sind Werte um 0.
Wo soll die Transitionsbeschriftung positioniert werden?
Initial root state offset :
Wertemenge [int]; sinnvoll sind Werte > 0.
Mit welchem Offset soll das Statechart gezeichnet werden auf der Zeichenfläche?
MorphingLayouter check interval :
Wertemenge [int]; sinnvoll sind Werte um 10.
Nach wie vielen Iterationsschritten soll der Geschwindigkeitsregelmechanismus des Morphing die Geschwindigkeit überprüfen?
Cell selection tolerance :
Wertemenge [int]; sinnvoll sind Werte um 10.
Ein Diagrammelement wird selektiert, sobald der Mauszeiger über diesem Element bewegt wird. Allerdings kann ein Diagrammelement auch
selektiert werden, indem es angeklickt wird. Wie nahe muss der Mauszeiger bei Mausklick bei einem Diagrammelement sein, damit dieses
selektiert wird?
Place of Deep-History-State :
Wertemenge [int, int]; sinnvoll sind Werte > 0.
Wo soll ein Deep-History-State platziert werden innerhalb eines Composite-States?
107
7. Literaturverzeichnis
Composite State image offset :
Wertemenge [int]; sinnvoll sind Werte um 5.
Wo soll das Plus- und Minus-Zeichen für das Kollabieren und Expandieren eines Composite-States platziert werden?
Morphing layouter speed :
Wertemenge [int]; sinnvoll sind Werte um 200.
Wie schnell soll ein Morphing durchgeführt werden? Angabe in Pixeln
pro Sekunde.
border offset for valid area of composite states :
Wertemenge [int]; sinnvoll sind Werte um 10.
Wie nahe dürfen Kind-Elemente am Rahmen ihres Vaters liegen?
Show splash sceen :
Wertemenge [bool];
Soll das Startbild angezeigt werden beim Laden der Anwendung?
Zoom out factor :
Wertemenge [float]; sinnvoll sind Werte < 1.
Morphing layouter border distance :
Wertemenge [int]; sinnvoll sind Werte um 50.
Wie nahe dürfen aufklappende Zustände an andere Zustände herankommen und von welchem Abstand an diese anderen Zustände verschoben
werden?
Show Collapse Buttons :
Wertemenge [bool];
Sollen die Plus- und Minus-Zeichen bei OR-States und AND-States angezeigt werden? Auch wenn die Zeichen nicht angezeigt werden, können
diese Composite-States kollabiert und expandiert werden.
Overview layer color :
Wertemenge [int, int, int]; Erlaubt sind nur Werte <= 255.
Welche Farbe soll die Übersichtsdarstellung haben?
GUI color light :
Wertemenge [int,int,int]; Erlaubt sind nur Werte <= 255.
Die Anwendung kennt zwei Hauptfarben: im Standardfall sind dies hellblau und dunkelblau. Mit dieser Eigenschaft lässt sich die hellblaue Farbe ändern.
GUI color dark :
Wertemenge [int,int,int]; Erlaubt sind nur Werte <= 255.
Die Anwendung kennt zwei Hauptfarben: im Standardfall sind dies hellblau und dunkelblau. Mit dieser Eigenschaft lässt sich die dunkelblaue
Farbe ändern.
108
.2. Benutzungshinweise für Editorfunktionen
GUI selected button light :
Wertemenge [int, int, int]; Erlaubt sind nur Werte <= 255.
Welche helle Farbe soll der Toggle-Button in der Werkzeugleiste haben?
GUI selected button dark :
Wertemenge [int, int, int]; Erlaubt sind nur Werte <= 255.
Welche dunkle Farbe soll der Toggle-Button in der Werkzeugleiste haben?
109
7. Literaturverzeichnis
110
A. Java-Programm-Quelltext
In diesem Teil des Anhangs wird im Abschnitt A.1 ein Überblick über den Programm-Quelltext gegeben. Hieran anschließend ist der vollständige ProgrammQuelltext des KIEL-Editors und des KIEL-Anwendungsfensters in Abschnitt A.4
aufgeführt.
A.1. Überblick
Zunächst wird ein nach Packages gegliederter Überblick über sämtliche Klassen
gegeben, welche im Rahmen dieser Arbeit implementiert wurden und zusammen
den KIEL-Editor und das KIEL-Anwendungsfenster bilden. Danach wird ergänzend zu Kapitel 5 im Abschnitt A.2 das Zusammenspiel der Klassen untereinander
erläutert. Abschließend werden in Abschnitt A.3 Erweiterungsmöglichkeiten und
häufig auftretende Ergänzungs- und Anpassungsaufgaben beschrieben.
A.1.1. Package kiel.editor
Dieses Package enthält gemäß dem MVC -Entwurfsmuster die Model - und View Komponente des Editors. Das Model besteht aus folgenden Klassen:
• MyGraphModel: Enthält das das Statechart in Form eines JGraph- und KIELDatenmodells und auf diesen Modellen operierende Methoden.
• MyGraphModelUtilities: Enthält häufig verwendete Operationen auf Datenmodell-Objekten. Diese Operationen beziehen sich nicht auf ein konkretes
Datenmodell und gehören daher nicht in die Klasse MyGraphModel. Diese
Operationen werden vom MyGraphModel und von einigen Controller -Klassen
verwendet.
• UndoClusterManager: Verwaltet Benutzer-Bearbeitungsschritte in Form von
gruppierten Datenmodell-Änderungsschritten.
• UndoClusterManagerListener: Dies ist ein Interface, welches nur von der
Klasse Editor implementiert wird.
• EditStep: Definiert die Datenstruktur, auf der der UndoClusterManager
operiert.
• FileHistory: Beinhaltet eine Liste der zuletzt göffneten Dateien. Diese Komponente wird von der KIEL-Hauptklasse kiel.KielFrame verwendet.
111
A. Java-Programm-Quelltext
• EditListener: Dieses Interface wird ausschließlich implementiert von der
Klasse ActionEditEdit. Dieser Listener wird von der MyBasicGraphUI-Komponente (siehe unten) immer dann benachrichtigt, wenn das Beschriften eines
Diagrammelements beendet wurde.
• MorphingLayouter: Führt auf dem Datenmodell eine gleitende Strukturveränderung durch. Für jeden Morphing-Vorgang wird diese Klasse instantiiert:
Beim Kollabieren, Expandieren und Platzieren eines neuen Zustands und bei
Anwendung eines Layouts des KIEL-Layouters.
Die View wird aus folgenden Klassen gebildet:
• Editor: Dies ist die Wurzelklasse des KIEL-Editors, welche vom Anwendungsfenster kiel.KielFrame instantiiert wird.
• MyJGraph: Diese Klasse erweitert die Klasse org.jgraph.JGraph und stellt
die Zeichenfläche des Editors dar.
• MyBasicGraphUI: Bestimmt unter anderem die Interpretation von MausEreignissen und passt als Subklasse von org.jgraph.BasicGraphUI das Verhalten des Rahmenwerks hinsichtlich des Zeichnens von hierarchischen Zuständen und der Zeichenqualität an die Anforderungen von KIEL an. Des
Weiteren wird in dieser Klasse die Änderung des Editor-Modus initiiert.
• PreferencesDialog: Zeigt in einem separaten Fenster die änderbaren Konfigurationseinstellungen.
• TraceLogDialog: Stellt tabellarisch in einem separaten Fenster die Bearbeitungshistorie dar.
• Utils: Stellt dem Editor und dem Anwendungsfenster GUI-Komponenten
zur Verfügung, welche ein einheitliches Aussehen haben, ihre Textelemente
bei Änderung der Sprache sofort ändern und welche zum Teil per Drag-andDrop in der Benutzeroberfläche verschoben werden können.
• MyDefaultCellViewFactory: Erzeugt die Objekte, welche in einer Instanz
der Klasse MyJGraph – der View – die Diagrammelemente repräsentieren.
A.1.2. Package kiel.editor.controller
Dieses Package enthält den Controller des KIEL-Editors hinsichtlich des ModelView-Controller -Entwurfsmusters. Dies sind allesamt EditorAction-Klassen, einige von ihnen sind darüber hinaus auch EditorMode-Klassen. Insgesamt sind in
diesem Package 78 Klassen zusammengefaßt.
• ActionXY: XY steht für einen Menüeintrag, z. B. ist ActionEditRedo eine
Operation, welche ausgeführt wird, wenn der Menüeintrag Edit→Redo gewählt wird.
112
A.1. Überblick
• EditorAction: Dies ist die Basisklasse für alle ActionXY-Klassen.
• EditorActions: Von jeder ActionXY-Klasse wird nur eine Instanz erzeugt.
Diese Instanzen werden in der Klasse EditorActions gehalten.
• EditorModeXY: Hier steht XY für einen Editor-Modus, der durch Klick auf
einen Diagrammelement-Button in der Werkzeugleiste gewählt wird. EditorModeAddOrState beschreibt z. B. das Verhalten des Editors, nachdem der
Benutzer den Button für das Hinzufügen eines OR-States geklickt hat. Eine
Ausnahme bildet die Klasse EditorModeSelectOrDragOrResizeOrFlipExpand: Wie der Name besagt, repräsentiert diese Klasse den Editor-Modus,
der durch Klick auf den Selektionspfeil-Button in der Werkzeugleiste gewählt
wird.
• EditorMode: Dies ist die Basisklasse für alle EditorModeXY-Klassen und ist
selbst abgeleitet von EditorAction.
• EditorModes: Von jeder EditorModeXY-Klasse wird nur eine Instanz erzeugt.
Diese Instanzen werden in der Klasse EditorModes gehalten. Des Weiteren
wird hier der aktuelle Editor-Modus als Instanz einer EditorMode-Klasse
gesetzt.
• MyMarqueeHandler: Diese Klasse repräsentiert das Verhalten des Editors
beim Erzeugen einer Transition. Die Namensgebung ist durch die JGraphStruktur bedingt.
A.1.3. Package kiel.editor.graph
Dieses Package enthält die KIEL-Editor-Erweiterungen der CellView- und GraphCell-Implementationen von JGraph zur Darstellung unterschiedlicher Diagrammelement-Formen.
• XYCell: Für jeden Diagrammelement-Typ XY aus der KIEL-Datenstruktur
wird hier eine Klasse bereitgestellt, für die Klasse kiel.datastructure.ORState z. B. ist dies die Klasse kiel.editor.graph.ORStateCell. Hierbei
wird die Klassenhierarchie aus der KIEL-Datenstruktur übernommen. XYCellInstanzen bilden das Datenmodell, auf dem das Editor-Model operiert.
• XYView: Zu jeder XYCell-Klasse gibt es eine XYView-Klasse. XYView-Instanzen
bilden das Datenmodell, auf dem die Editor-View operiert.
• XYRenderer: Zu Diagrammelementen, welche sich in ihrer graphischen Repräsentation von anderen Typen unterscheiden, wird eine XYRenderer-Klasse
bereitgestellt. Diese Klassen beinhalten in Form von Graphik-Primitiven die
Beschreibung der graphischen Repräsentation eines Diagrammtyps.
113
A. Java-Programm-Quelltext
• CellViewRendererFactory: Von jeder XYRenderer-Klasse wird nur eine Instanz erzeugt. Diese Instanzen werden in der Klasse CellViewRendererFactory gehalten.
• MyGraphConstants: Jedes XYCell-Objekt besitzt eine Menge von Attributen,
welche durch die Klassen org.jgraph.GraphConstants und MyGraphConstants gesetzt werden. Hierbei ist die Klasse MyGraphConstants zuständig
für diejenigen Attribute, welche durch die Implementierung des Editors hinzukommen.
A.1.4. Package kiel.editor.resources
Dieses Package enthält Klassen für den Zugriff auf Anwendungsressourcen wie
Bilder, sprachabhängige Texte und Konfigurationseinstellungen.
• Preferences: Lädt und speichert Konfigurationseinstellungen, welche über
den PreferencesDialog vom Benutzer geändert werden.
• ResourceBundle: Stellt einen Zugriff auf spracheinstellungsabhängige Texte
bereit, welche als Beschriftungen von Menüeinträgen und Tooltips dienen.
• ResourceLoader: Lädt Bilder als ImageIcon-Objekte.
• MyPreferences.properties: Enthält für jede Konfigurationseinstellung einen
Standardwert.
• MyResources.properties: Enthält die Key-Shortcuts für alle Menüeinträge.
• MyResources_de.properties: Enthält alle deutschsprachigen Texte für Beschriftungen und Meldungen der Benutzeroberfläche.
• MyResources_en.properties: Enthält alle englischsprachigen Texte für Beschriftungen und Meldungen der Benutzeroberfläche.
A.2. Zusammenspiel der Klassen
A.2.1. Kommunikation zwischen View und Controller
Die Controller -Klassen werden als Singletons [14] in einem Cache in den Klassen EditorActions und EditorModes verwaltet. Beim Aufbau der Menüs und
der Werkzeugleiste, welcher in der Klasse Editor erfolgt, werden die Controller Klassen instantiiert und als java.awt.ActionListener mit den Menüelementen
und Werkzeugleisten-Buttons assoziiert. Jeder Controller ist abgeleitet von der
Klasse EditorAction.
Bei Instantiierung der Klasse Editor durch das KielFrame wird die EditorInstanz in einer statischen Variable der Klasse EditorAction gespeichert. Damit
erhält jede Controller -Klasse die Möglichkeit, auf das Editor-Objekt und damit
114
A.2. Zusammenspiel der Klassen
auf die gesamte View des KIEL-Editors zuzugreifen. Diese Richtung der Kommunikation ist im MVC -Entwurfsmuster nicht vorgesehen. Allerdings verstößt dies
nicht gegen das Entwurfsmuster, da im KIEL-Editor in dieser Richtung lediglich
Eigenschaften der View abgefragt werden wie z. B. diejenige des aktuell selektierten Diagrammelements. Eine Manipulation der View hingegen findet nicht statt.
Des Weiteren erhält ein Controller mittels dieser Referenz auf das Editor-Objekt
Zugriff auf das Model in Form von getEditor().getGraph().getMyGraphModel()
und getEditor().getGraph().getUndoClusterManager().
A.2.2. Kommunikation von Controller nach Model
Der Controller ruft über getEditor().getGraph().getMyGraphModel() Methoden des Models auf, welche das Datenmodell ändern. In der Regel ist dies genau
ein Methodenaufruf. Generell wird jeder Controller, welcher eine Änderung auf
dem Model durchführt, eine Transaktionsklammer setzen, um zum einen einen
Eintrag in der Bearbeitungshistorie zu erzeugen und zum anderen einen Bearbeitungsschritt zu definieren für die Undo-and-Redo-Funktionen.
MyJGraph graph = g e t E d i t o r ( ) . getGraph ( ) ;
graph . getUndoClusterManager ( ) . s e t U n d o C l u s t e r S t a r t ( ) ;
D e f a u l t G r a p h C e l l c e l l = graph . g e t S e l e c t i o n C e l l ( ) ;
...
graph . getMyGraphModel ( ) . a d d T r a n s i t i o n ( . . . ) ;
graph . getUndoClusterManager ( ) . setUndoClusterEnd ( t h i s ) ;
Abbildung A.1.: Ausschnitt aus einer Controller -Klasse
Abbildung A.1 zeigt einen Programm-Quelltext-Ausschnitt aus der Klasse ActionAddLoopTransition.
A.2.3. Struktur der View -Klassen
Die Klasse Editor ist keine Java-Swing-Komponente sondern vom Typ kiel.util.main.KielComponent. Sie beinhaltet alle Benutzeroberfächen-Objekte des KIELEditors, indem sie ein MyJGraph-Objekt (siehe Abschnitt A.1.1, die Menüleiste,
die Werkzeugleiste mitsamt ihren Elementen und eine mehrschichtige Java-SwingKomponente referenziert, welche zwei MyJGraph-Objekte auf je einer Schicht anordnet. Eines der beiden MyJGraph-Objekte – die Bearbeitungsschicht – enthält eine
Referenz auf das weitere MyJGraph-Objekt – die Überischtsschicht. Wann immer
sich etwas an dem Bearbeitungsschicht-MyJGraph-Objekt ändert, benachrichtigt es
sein referenziertes Übersichtsschicht-MyJGraph-Objekt.
115
A. Java-Programm-Quelltext
A.2.4. Der UndoClusterManager
Diese Klasse ist ein Wrapper für ein org.jgraph.graph.GraphUndoManager-Objekt,
seinerseits abgeleitet von javax.swing.undo.UndoManager. Wann immer am MyJGraph-Objekt eine neue MyGraphModel-Instanz als Model gesetzt wird, wird in
dem Wrapper ein neues org.jgraph.graph.GraphUndoManager-Objekt erzeugt
und dieses als UndoableEditListener am neuen Model registriert.
Der Editor ist der einzige Beobachter des UndoClusterManagers. Wann immer ein Undo- oder Redo-Schritt durchgeführt wird, sich also einer der Stacks des
UndoClusterManager ändert (siehe Abschnitt 5.3.8), wird der Editor benachrichtigt. Dieser aktualisiert dann die Anzeige der verfügbaren Undo-and-Redo-Schritte
in der Statusleiste des KIEL-Editors (siehe Abschnitt 4.9).
A.3. Erweiterungs- und Anpassungsmöglichkeiten
In diesem Abschnitt wird nur ein kurzer Auszug aus der Umsetzung möglicher
Änderungsanforderungen gegeben. Die im folgenden beschriebenen Anpassungsmöglichkeiten können ohne Programmierkenntnisse umgesetzt werden.
A.3.1. Änderung eines Editor-Menüeintrags
Soll der angezeigte Name geändert werden, so ist in der Datei MyResources_en.properties und MyResources_de.properties der Text entsprechend zu ändern. Diese Datei enthält Schlüssel-Wert-Paare. Zu finden ist der zu ändernde Text unter
dem Schlüssel, welcher den Menüeintrag beschreibt. ActionFilePreferences bezeichnet z. B. den Eintrag File→Preferences. Jeder Menüeintrag besitzt in der Datei
MyResources.properties des Weiteren einen Key-Shortcut. Das Schlüssel-WertPaar acceleratorForActionFormatAlignLeft=2F5 in dieser Datei bedeutet z. B.,
dass für den Menüeintrag Format→Align-Left der Key-Shortcut 2F5 gelten soll.
F5 steht für die gleichnamige Funktionstaste. An dieser Stelle kann auch ein Buchstabe oder z. B. DEL für die Löschtaste stehen. Die 2 steht für die CTRL-Taste.
Weiterführende Informationen über diese Art der Codierung enthält die Dokumentation zu der Klasse javax.swing.KeyStroke.
Soll das angezeigte Bild zu einem Menüeintrag geändert werden, so ist die Bilddatei im GIF -Format im Package kiel.editor.resources abzulegen und der Dateiname in der entsprechenden Controller -Klasse ActionXY zu ändern.
A.3.2. Ändern der Menüstruktur im KIEL-Anwendungsfenster
Hauptmenü und File-Menü des Hauptfensters sind aufgeteilt in Bereiche, welche
von der Klasse KielFrame bereitgestellt werden und welche, die vom KIEL-Browser
und KIEL-Editor definiert werden.
Wie in der Abbildung A.2 zu sehen, sind die variablen Bereiche diejenigen über
dem Open...-Menüeintrag und zwischen dem Open...- und Last Files-Menüeintrag.
116
A.3. Erweiterungs- und Anpassungsmöglichkeiten
(a) In der Browser-Ansicht
(b) In der Editor-Ansicht
Abbildung A.2.: Das File-Menü
Abbildung A.3 zeigt eine ähnliche Aufteilung des Hauptmenüs. Entsprechend
dem Bereich, in dem eine Änderung der Menüstruktur erfolgen soll, sind die Klassen KielFrame, Editor oder Browser anzupassen. Die hierfür relevanten Methoden
– definiert im Interface KielComponent – sind getFileMenuItems1(), getFileMenuItems2() und getRootMenus().
(a) In der Browser-Ansicht
(b) In der Editor-Ansicht
Abbildung A.3.: Das Hauptmenü
A.3.3. Erweiterung um andere Statechart-Dialekte
Zur Zeit sind im Menü File→New die Einträge Esterel Studio und Matlab Model vorhanden. Das Attribut StateChart.ModelSource im KIEL-Datenmodell erhält als Wert die Menüeintrag-Beschriftung. Das Attribut StateChart.ModelVersion wird konstant auf den Wert 5.0 gesetzt. Die Auswahl der WerkzeugleistenElemente entsprechend dem gewählten Statechart-Dialekt im Menü File→New erfolgt in der Methode Editor.updateToolBarAndMenuBar().
Die Implementierung sieht nur unterschiedliche Werkzeugleistenelemente für verschiedene Statechart-Dialekte vor. Andere Bereiche wie die Regeln der Syntaxprüfung und des syntaxgerichteten Editierens weisen bei jedem gewählten StatechartDialekt das gleiche Verhalten auf.
117
A. Java-Programm-Quelltext
A.4. Der Quelltext
Der nachfolgende Programm-Quelltext wurde bereinigt um alle Fehler und Warnungen, welche der Javac-Kompiler, der Javadoc-Dokumentation-Generator sowie
die Werkzeuge JLint sowie Check Style mit seinen Sun-Coding-Conventions liefern. Der vorliegende Programm-Quelltext ist daher mit einem Java-Kompiler ab
Version 1.4 kompilierbar, sofern die vom Editor verwendeten KIEL-Komponenten
sowie das JGraph-Rahmenwerk in Version 5.4 als Kompilat vorliegen.
118
50
40
30
20
10
kiel . dataStructure . StateChart ;
kiel . editor . controller . A c t i o n A d d T r a n s i t i o n T o g g l e ;
kiel . editor . controller . A c t i o n E d i t C o l l a p s e d ;
kiel . editor . controller . Ac tionE ditC opy ;
kiel . editor . controller . ActionEditCut ;
kiel . editor . controller . Ac tionE ditE dit ;
kiel . editor . controller . Ac tionE ditF ind ;
kiel . editor . controller . Ac t io n Ed i tP a ste ;
kiel . editor . controller . Ac tionE ditR edo ;
kiel . editor . controller . A c t i o n E d i t R e m ove ;
kiel . editor . controller . A c t i o n E d i t S e l e c t A l l ;
kiel . editor . controller . A c t i o n E d i t S t a t e C h a r t I n p u t E v e n t s ;
kiel . editor . controller . A c t i o n E d i t S t a t e C h a r t O u t p u t E v e n t s ;
kiel . editor . controller . Ac tionE ditU ndo ;
kiel . editor . controller . A c t i o n F i l e E x p ort ;
kiel . editor . controller . A c t i o n F i l e N e w E s t e r e l S t u d i o ;
kiel . editor . controller . A c t i o n F i l e N e w M a t l a b ;
kiel . editor . controller . A c t i o n F i l e P r e f e r e n c e s ;
kiel . editor . controller . Ac t io n Fi l eP r int ;
kiel . editor . controller . Ac tionF ileS ave ;
kiel . editor . controller . A c t i o n F i l e S a v eAs ;
kiel . editor . controller . A c t i o n F o r m a t A l i g n B o t t o m ;
javax . swing . ButtonGroup ;
javax . swing . ImageIcon ;
javax . swing . J C h e c k B o x M e n u I t e m ;
javax . swing . JComboBox ;
javax . swing . JComponent ;
javax . swing . JLabel ;
javax . swing . JLayeredPane ;
javax . swing . JMenu ;
javax . swing . JMenuItem ;
javax . swing . JPanel ;
javax . swing . JScrollPane ;
javax . swing . JSlider ;
javax . swing . JTabbedPane ;
javax . swing . JToggleButton ;
javax . swing . JToolBar ;
javax . swing . event . ChangeEvent ;
javax . swing . event . Chan geLis tene r ;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
java . awt . Color ;
java . awt . Dimension ;
java . awt . FlowLayout ;
java . awt . event . C o m p o n e n t A d a p t e r ;
java . awt . event . Comp onent Even t ;
java . awt . event . M ou s eW h ee l Ev e nt ;
java . awt . geom . Point2D ;
java . util . ArrayList ;
import
import
import
import
import
import
import
import
package kiel . editor ;
kiel.editor.Editor
100
90
80
70
60
kiel . editor . controller . A c t i o n F o r m a t A l i g n C e n t e r H o r i z o n t a l ;
kiel . editor . controller . A c t i o n F o r m a t A l i g n C e n t e r V e r t i c a l ;
kiel . editor . controller . A c t i o n F o r m a t A l i g n J u s t i f y H o r i z o n t a l ;
kiel . editor . controller . A c t i o n F o r m a t A l i g n J u s t i f y V e r t i c a l ;
kiel . editor . controller . A c t i o n F o r m a t A l i g n L e f t ;
kiel . editor . controller . A c t i o n F o r m a t A l i g n R i g h t ;
kiel . editor . controller . A c t i o n F o r m a t A l i g n T o p ;
kiel . editor . controller . A c t i o n F o r m a t Z o o m 1 0 0 ;
kiel . editor . controller . Ac t i on F or m a tZ o om I n ;
kiel . editor . controller . A c t i o n F o r m a t Z o o m O u t ;
kiel . editor . controller . ActionLayout ;
kiel . editor . controller . A c t i o n L a y o u t S e l e c t e d S t a t e ;
kiel . editor . controller . ActionViewGrid ;
kiel . editor . controller . Ac t i on V ie w O ve r vi e w ;
kiel . editor . controller . A c t i o n V i e w R e p l a y F a s t F o r w a r d ;
kiel . editor . controller . A c t i o n V i e w R e p l a y P l a y ;
kiel . editor . controller . A c t i o n V i e w R e p l a y R e w i n d ;
kiel . editor . controller . A c t i o n V i e w R e p l a y S t e p B a c k ;
kiel . editor . controller . A c t i o n V i e w R e p l a y S t e p F o r w a r d ;
kiel . editor . controller . A c t i o n V i e w R e p l a y S t o p ;
kiel . editor . controller . A c t i o n V i e w R e p l a y T r a c e L o g ;
kiel . editor . controller . A c t i o n V i e w S h o w C o m p o s i t e S t a t e E v e n t s ;
kiel . editor . controller . A c t i o n V i e w S h o w C o m p o s i t e S t a t e V a r i a b l e s ;
kiel . editor . controller . A c t i o n V i e w S h o w S t a t e A c t i o n s ;
kiel . editor . controller . EditorAction ;
kiel . editor . controller . EditorActions ;
kiel . editor . controller . E d i t o r M o d e A d d D e e p H i s t o r y ;
kiel . editor . controller . E d i t o r M o d e A d d D y n a m i c C h o i c e ;
kiel . editor . controller . E d i t o r M o d e A d d F i n a l S i m p l e S t a t e ;
kiel . editor . controller . E d i t o r M o d e A d d H i s t o r y ;
kiel . editor . controller . E d i t o r M o d e A d d H o r i z o n t a l D e l i m i t e r ;
kiel . editor . controller . E d i t o r M o d e A d d I n i t i a l S t a t e ;
kiel . editor . controller . E d i t o r M o d e A d d O r S t a t e ;
kiel . editor . controller . E d i t o r M o d e A d d S i m p l e S t a t e ;
kiel . editor . controller . E d i t o r M o d e A d d S u s p e n d ;
kiel . editor . controller . E d i t o r M o d e A d d V e r t i c a l D e l i m i t e r ;
kiel . editor . controller . E d i t o r M o d e S e l e c t O r D r a g O r R e s i z e O r F l i p E x p a n d ;
kiel . editor . controller . EditorModes ;
kiel . editor . graph . C o mp o si t e St a te C e ll ;
kiel . editor . resources . Preferences ;
kiel . editor . resources . ResourceBundle ;
kiel . editor . resources . ResourceLoader ;
kiel . g r a p h i c a l I n f o r m a t i o n s . View ;
kiel . util . LogFile ;
kiel . util . main . IKielFrame ;
kiel . util . main . KielComponent ;
import org . jgraph . event . G r a p h S e l e c t i o n E v e n t ;
import org . jgraph . event . G r a p h S e l e c t i o n L i s t e n e r ;
import org . jgraph . graph . Def au ltG ra phM od el ;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
A.4. Der Quelltext
119
120
150
140
130
120
110
//
/**
* Covers many ( not all !) Editor ’ s menu items . Take care , that this
180
method
* leaves some menu items disabled .
* @param b enable the buttons ?
*/
private void s e t M e n u I t e m s E n a b l e d ( final boolean b ) {
EditorActions . get ( Act ionFi leSa ve . class ) . setEnabled ( b ) ;
EditorActions . get ( A c t i o n F i l e S a v e A s . class ) . setEnabled ( b ) ;
EditorActions . get ( A c t i o n F i l e E x p o r t . class ) . setEnabled ( b ) ;
EditorActions . get ( A c ti o nF i le P ri n t . class ) . setEnabled ( b ) ;
EditorActions . get ( A c t i o n F i l e P r o p e r t i e s . class ) . setEnabled ( b ) ;
EditorActions . get ( Act ionEd itEd it . class ) . setEnabled ( b ) ;
EditorActions . get ( ActionEditCut . class ) . setEnabled ( b ) ;
190
EditorActions . get ( Act ionEd itCo py . class ) . setEnabled ( b ) ;
EditorActions . get ( A c ti o nE d it P as t e . class ) . setEnabled ( b ) ;
EditorActions . get ( A c t i o n E d i t R e m o v e . class ) . setEnabled ( b ) ;
EditorActions . get ( A c t i o n E d i t S e l e c t A l l . class ) . setEnabled ( b ) ;
EditorActions . get ( Act ionEd itFi nd . class ) . setEnabled ( b ) ;
EditorActions . get ( A c t i o n E d i t C o l l a p s e d . class ) . setEnabled ( b ) ;
EditorModes . get ( E d i t o r M o d e A d d S i m p l e S t a t e . class ) . setEnabled ( b ) ;
EditorModes . get ( E d i t o r M o d e A d d F i n a l S i m p l e S t a t e . class ) . setEnabled ( b ) ;
EditorModes . get ( E d i t o r M o d e A d d O r S t a t e . class ) . setEnabled ( b ) ;
200
EditorModes . get ( E d i t o r M o d e A d d I n i t i a l S t a t e . class ) . setEnabled ( b ) ;
EditorModes . get ( E d i t o r M o d e A d d S u s p e n d . class ) . setEnabled ( b ) ;
EditorModes . get ( E d i t o r M o d e A d d H i s t o r y . class ) . setEnabled ( b ) ;
EditorModes . get ( E d i t o r M o d e A d d D y n a m i c C h o i c e . class ) . setEnabled ( b ) ;
/**
* The editor ’ s graph drawing area . An Editor instance will be notified
* with every graph ’ s model change in order to update button states .
*/
private MyJGraph graph = new MyJGraph ( new D efa ul tGr ap hMo de l () , true ) ;
/**
* The editor ’ s architecture is based on the model - view - controller ( MVC )
design
* pattern . The Editor class is the root class of the MVC ’ s view component .
* It contains all visible GUI - components : the drawing area ( graph ) , the
menubar
* and the toolbar . The kiel . KielFrame class uses a single instance of the
* Editor class and the Editor class itself has a reference to the KielFrame
,
160
* since it will be the parent Frame for the Editor .
* Mainly , the Editor just implements the KielComponent interface , to
provide
* the KielFrame its gui - components .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.143 $ last modified $Date : 2005/08/02 18:51:08 $
*/
public final class Editor implements KielComponent , Preferences . Listener ,
UndoClusterManagerListener {
170
//
//
//
//
EditorModes . get ( E d i t o r M o d e A d d V e r t i c a l D e l i m i t e r . class ) . setEnabled ( b ) ;
EditorActions . get ( A c t i o n V i e w R e p l a y F a s t F o r w a r d . class ) . setEnabled ( b ) ;
EditorActions . get ( A c t i o n V i e w R e p l a y P l a y . class ) . setEnabled ( b ) ;
EditorActions . get ( A c t i o n V i e w R e p l a y R e w i n d . class ) . setEnabled ( b ) ;
EditorActions . get ( A c t i o n V i e w R e p l a y S t e p B a c k . class ) . setEnabled ( b ) ;
EditorActions . get ( A c t i o n V i e w R e p l a y S t e p F o r w a r d . class ) . setEnabled ( b ) ;
EditorActions . get ( A c t i o n V i e w R e p l a y S t o p . class ) . setEnabled ( b ) ;
graph . g e t U n d o C l u s t e r M a n a g e r () . getSlider () . setEnabled ( b ) ;
EditorActions . get ( A c t i o n A d d T r a n s i t i o n T o g g l e . class ) . setEnabled ( b ) ;
EditorActions . get ( A c t i o n F o r m a t Z o o m 1 0 0 . class ) . setEnabled ( b ) ;
EditorActions . get ( A c t io n Fo r m at Z oo m I n . class ) . setEnabled ( b ) ;
EditorActions . get ( A c t i o n F o r m a t Z o o m O u t . class ) . setEnabled ( b ) ;
EditorActions . get ( A c t i o n F o r m a t A l i g n L e f t . class ) . setEnabled ( false ) ;
EditorActions . get ( A c t i o n F o r m a t A l i g n R i g h t . class ) . setEnabled ( false ) ;
EditorActions . get ( A c t i o n F o r m a t A l i g n T o p . class ) . setEnabled ( false ) ;
EditorActions . get ( A c t i o n F o r m a t A l i g n B o t t o m . class ) . setEnabled ( false ) ;
EditorActions . get ( A c t i o n F o r m a t A l i g n C e n t e r H o r i z o n t a l . class )
. setEnabled ( false ) ;
EditorActions . get ( A c t i o n F o r m a t A l i g n C e n t e r V e r t i c a l . class )
. setEnabled ( false ) ;
EditorActions . get ( A c t i o n F o r m a t A l i g n J u s t i f y H o r i z o n t a l . class )
. setEnabled ( false ) ;
EditorActions . get ( A c t i o n F o r m a t A l i g n J u s t i f y V e r t i c a l . class )
. setEnabled ( false ) ;
EditorModes . get ( E d i t o r M o d e A d d H o r i z o n t a l D e l i m i t e r . class ) . setEnabled ( b
if ( statechart != null && view != null ) {
if ( getGraph () . getMyGraphModel () == null
|| getGraph () . getMyGraphModel () . g e t C u r r e n t S t a t e C h a r t ()
!= statechart ) {
setModel ( new MyGraphModel ( statechart , view ,
getGraph () . g e t G r a p h L a y o u t C a c h e () ) ) ;
getGraph () . getMyGraphModel () . p ro c e ss I sC o l la p s e d (
( Co m p os i te S t at e Ce l l ) getGraph () . getMyGrap h Mo d el ()
. getRootCell () , getGraph () , true ) ;
getGraph () . g e t U n d o C l u s t e r M a n a g e r () . d i s c a r d C u r r e n t C l u s t e r () ;
}
} else {
getGraph () . setModel (
new De fau lt Gr aph Mo del () ) ;
}
/**
* if the parameters are not null , this method will set up the graph
drawing
* area ( the graph ) with a new model .
* @see kiel . util . main . KielComponent # s e t C u r r e n t S t a t e C h a r t (
*
kiel . dataStructure . StateChart ,
*
kiel . g r a p h i c a l I n f o r m a t i o n s . View )
*/
public void s e t C u r r e n t S t a t e C h a r t ( final StateChart statechart ,
final View view ) {
}
);
A. Java-Programm-Quelltext
250
240
230
220
210
290
280
270
/**
* Sets the text for the editor status line .
* @param point current cursor position .
*/
public void s e t L a b e l C u r s o r P o s i t i o n ( final Point2D point ) {
l a b e l C u r s o r P o s i t i o n . setText (
( int ) point . getX () + ":" + ( int ) point . getY () ) ;
}
310
/**
* @see kiel . editor . U n d o C l u s t e r M a n a g e r L i s t e n e r # stackChanged ( int , int )
*/
public void stackChanged ( final int undoableEditSteps ,
final int r e d o a b l e E d i t S t e p s ) {
300
l a b e l E d i t S t e p C o u n t . setText (
u n d o a b l e E d i t S t e p s + ":" + r e d o a bl eEd it Ste ps ) ;
}
/**
* The status line component showing the current edit step count .
*/
private JLabel l a b e l E d i t S t e p C o u n t = new JLabel () ;
/**
* The status line component showing the cursor ’ s coordinates .
*/
private JLabel l a b e l C u r s o r P o s i t i o n = new JLabel () ;
/**
* Delegates to the graph .
* @see kiel . util . main . KielComponent # getCurrentView ()
*/
public View getC urren tVie w () {
return getGraph () . getCu rren tView () ;
}
/**
* Delegates to the graph .
* @see kiel . util . main . KielComponent # g e t C u r r e n t S t a t e C h a r t ()
*/
public StateChart g e t C u r r e n t S t a t e C h a r t () {
return getGraph () . g e t C u r r e n t S t a t e C h a r t () ;
}
260
/**
* Returns the editor - icon displayed in the browser for the switching
* button browser < - - > editor .
* @see kiel . util . main . KielComponent # getImageIcon ()
*/
public ImageIcon getImageIcon () {
return Re sour ceLoa der . get (" Edit16 . gif ") ;
}
}
return s t a t u s L i n e C o m p o n e n t ;
/**
* The logging handle . Prints logs to standard out .
*/
private LogFile logFile = new LogFile (" Editor " , 2) ;
/**
* returns the editor ’ s drawing area .
* @return the editor ’ s graph component .
*/
public MyJGraph getGraph () {
return graph ;
}
}
s t a t u s L i n e C o m p o n e n t . add ( l ab e l Ed i tS t e pC o un t ) ;
s t a t u s L i n e C o m p o n e n t . add ( new JLabel ("
") ) ;
s t a t u s L i n e C o m p o n e n t . add ( l a b e l C u r s o r P o s i t i o n ) ;
s t a t u s L i n e C o m p o n e n t . add (
new JLabel ("
" + ResourceBundle . getString (" Zoom ") + ":
s t a t u s L i n e C o m p o n e n t . add (
new JLabel ( ResourceLoader . get (" ZoomOut16 . gif ") ) ) ;
s t a t u s L i n e C o m p o n e n t . add ( slider ) ;
s t a t u s L i n e C o m p o n e n t . add (
new JLabel ( ResourceLoader . get (" ZoomIn16 . gif ") ) ) ;
s t a t u s L i n e C o m p o n e n t . add ( new JLabel (" ") ) ;
}) ;
final int labelWidth = 50;
final int labelHeight = 24;
l a b e l C u r s o r P o s i t i o n . setPrefe rredSize (
new Dimension ( labelWidth , labelHeight ) ) ;
") ) ;
public void stateChanged ( final ChangeEvent e ) {
final int middle = 50;
getGraph () . setScale ( slider . getValue () / ( double ) middle ) ;
}
final JSlider slider = Utils . createJSlider () ;
final int width = 200;
final int height = 24;
slider . setPreferr edSize ( new Dimension ( width , height ) ) ;
slider . a dd Cha ng eLi st ene r ( new ChangeListener () {
JPanel s t a t u s L i n e C o m p o n e n t = Utils . createJPanel (
new FlowLayout ( FlowLayout . RIGHT , 0 , 0) ) ;
/**
* Returns the label text area , the cursor coordinates area and the zoom
* area of the status line as a single component .
* @see kiel . util . main . KielComponent # g e t S t a t u s L i n e C o m p o n e n t ()
*/
public JComponent g e t S t a t u s L i n e C o m p o n e n t () {
A.4. Der Quelltext
121
122
360
350
340
330
320
370
390
400
graph . a d d G r a p h S e l e c t i o n L i s t e n e r ( new G r a p h S e l e c t i o n L i s t e n e r () {
public void valueChanged ( final G r a p h S e l e c t i o n E v e n t e ) {
boolean enabled = graph . g e t Se lec ti onC ou nt () > 1;
EditorActions . get ( A c t i o n F o r m a t A l i g n L e f t . class )
. setEnabled ( enabled ) ;
EditorActions . get ( A c t i o n F o r m a t A l i g n R i g h t . class )
. setEnabled ( enabled ) ;
EditorActions . get ( A c t i o n F o r m a t A l i g n T o p . class )
. setEnabled ( enabled ) ;
EditorActions . get ( A c t i o n F o r m a t A l i g n B o t t o m . class )
410
. setEnabled ( enabled ) ;
EditorActions . get ( A c t i o n F o r m a t A l i g n C e n t e r H o r i z o n t a l . class )
. setEnabled ( enabled ) ;
EditorActions . get ( A c t i o n F o r m a t A l i g n C e n t e r V e r t i c a l . class )
. setEnabled ( enabled ) ;
EditorActions . get ( A c t i o n F o r m a t A l i g n J u s t i f y H o r i z o n t a l . class )
. setEnabled ( enabled ) ;
menuLayout = getKielFrame () . c r e a t e L ay o ut e r Me n u ( true ,
ActionLayout . class ) ;
final int comboWidth = 70;
final int comboHeight = 28;
c o m b o B o x T r a n s i t i o n L i n e T y p e s . se tMax imumSize (
new Dimension ( comboWidth , comboHeight ) ) ;
c o m b o B o x T r a n s i t i o n T y p e s . setM aximu mSize (
new Dimension ( comboWidth , comboHeight ) ) ;
setKielFrame ( aKielFrame ) ;
Preferences . addListener ( this ) ;
EditorAction . initialize ( this ) ;
s e t M e n u I t e m s E n a b l e d ( false ) ;
graph . g e t U n d o C l u s t e r M a n a g e r () . setListener ( this ) ;
graph . s et L ay o ut e rM e nu ( getKielFrame () . c r ea t e La y ou t e rM e nu ( false ,
A c t i o n L a y o u t S e l e c t e d S t a t e . class ) ) ;
/**
* Attachs itself as listener to the Preferences , initializes the
toolbar ’ s
* comboboxes , sets all menu items to disabled , adds itself as listener
* to the graph object to update some buttons and menu items depending
on
* whether a diagram element is selected or not .
380
* @param aKielFrame .
*/
public Editor ( final IKielFrame aKielFrame ) {
/**
*
* @return .
*/
public LogFile getLogFile () {
return logFile ;
}
//
}) ;
c o m b o B o x T r a n s i t i o n T y p e s . s etSelectedIndex (2) ;
updateMenuEdit () ;
getGraph () . getOverviewG raph () . setOpaque ( true ) ;
/**
* Delegates to the graph and updates the toolbar .
* Should be moved to MyJGraph .
* @param model the new model to be set .
*/
public void setModel ( final MyGraphModel model ) {
// @TODO move to MyJGraph and install listeners
getGraph () . setModel ( model ) ;
u p d a t e T o o l B a r A n d M e n u B a r () ;
updateMenuEdit () ;
getKielFrame () . r e si z eT o o lb a rP a n el () ;
if ( model instanceof MyGraphModel
&& getGraph () . get OverviewGraph () != null ) {
/**
* Update the " Edit " - menu .
*/
public void updateMenuEdit () {
menuEdit . removeAll () ;
menuEdit . add ( Utils . createJMenuItem ( ActionEditUndo . class ) ) ;
menuEdit . add ( Utils . createJMenuItem ( ActionEditRedo . class ) ) ;
menuEdit . addSeparator () ;
menuEdit . add ( Utils . createJMenuItem ( A c t i o n E d i t S e l e c t A l l . class ) ) ;
menuEdit . add ( Utils . createJMenuItem ( ActionEditFind . class ) ) ;
menuEdit . addSeparator () ;
if ( getGraph () . getMyGraphModel () != null ) {
menuEdit . add ( Utils . createJMenuItem (
A c t i o n E d i t S t a t e C h a r t I n p u t E v e n t s . class ) ) ;
menuEdit . add ( Utils . createJMenuItem (
A c t i o n E d i t S t a t e C h a r t O u t p u t E v e n t s . class ) ) ;
menuEdit . addSeparator () ;
}
ArrayList allItems =
(( MyJGraph ) getGraph () ) . g e t M e n u I t e m s F o r S e l e c t e d () ;
for ( int i = 0; i < allItems . size () ; i ++) {
if ( allItems . get ( i ) instanceof JComponent ) {
menuEdit . add (( JComponent ) allItems . get ( i ) ) ;
} else {
menuEdit . add (( EditorAction ) allItems . get ( i ) ) ;
}
}
}
}
}
EditorActions . get ( A c t i o n F o r m a t A l i g n J u s t i f y V e r t i c a l . class )
. setEnabled ( enabled ) ;
A. Java-Programm-Quelltext
460
450
440
430
420
}
}
menuLayout . g e t M e n u C o m p o n e n t s () [ i ]. setEnabled ( true ) ;
470
for ( int i = 0; i < menuLayout . g etM en uCo mp one nt s () . length ; i ++)
/**
* Just creates the alignment toolbar with 8 buttons .
* @return a new alignment toolbar object .
*/
private JToolBar c r e a t e A l i g n m e n t T o o l B a r () {
JToolBar a l i g n m e n t T o o l b a r = Utils . createJToolBar () ;
a l i g n m e n t T o o l b a r . add ( Utils . createJButton ( EditorActions . get (
A c t i o n F o r m a t A l i g n L e f t . class ) , " tooltipAl ignLeft ") ) ;
a l i g n m e n t T o o l b a r . add ( Utils . createJButton ( EditorActions . get (
A c t i o n F o r m a t A l i g n R i g h t . class ) , " t oo lti pA lig nR igh t ") ) ;
a l i g n m e n t T o o l b a r . add ( Utils . createJButton ( EditorActions . get (
A c t i o n F o r m a t A l i g n T o p . class ) , " tooltipAlignTop ") ) ;
a l i g n m e n t T o o l b a r . add ( Utils . createJButton ( EditorActions . get (
A c t i o n F o r m a t A l i g n B o t t o m . class ) , " t oo l ti p A li g nB o t to m ") ) ;
a l i g n m e n t T o o l b a r . add ( Utils . createJButton ( EditorActions . get (
A c t i o n F o r m a t A l i g n C e n t e r H o r i z o n t a l . class ) ,
" t o o l t i p A l i g n C e n t e r H o r i z o n t a l ") ) ;
a l i g n m e n t T o o l b a r . add ( Utils . createJButton ( EditorActions . get (
A c t i o n F o r m a t A l i g n C e n t e r V e r t i c a l . class ) ,
" t o o l t i p A l i g n C e n t e r V e r t i c a l ") ) ;
a l i g n m e n t T o o l b a r . add ( Utils . createJButton ( EditorActions . get (
A c t i o n F o r m a t A l i g n J u s t i f y H o r i z o n t a l . class ) ,
" t o o l t i p J u s t i f y H o r i z o n t a l ") ) ;
510
500
/**
* Just creates the replay toolbar with 6 buttons and the slider .
* @return a new replay toolbar object .
*/
private JToolBar c r e a t e R e p l a y T o o l B a r () {
JToolBar replayToolbar = Utils . cr eateJToolBar () ;
replayToolbar . add ( Utils . createJButton ( EditorActions . get (
480
A c t i o n V i e w R e p l a y S t o p . class ) , " t ool ti pRe pl ayS to p ") ) ;
replayToolbar . add ( Utils . createJButton ( EditorActions . get (
A c t i o n V i e w R e p l a y P l a y . class ) , " t ool ti pRe pl ayP la y ") ) ;
replayToolbar . add ( Utils . createJButton ( EditorActions . get (
A c t i o n V i e w R e p l a y R e w i n d . class ) , " t o o l t i p R e p l a y R e w i n d ") ) ;
replayToolbar . add ( Utils . createJButton ( EditorActions . get (
A c t i o n V i e w R e p l a y S t e p B a c k . class ) , " t o o l t i p R e p l a y S t e p B a c k ") ) ;
replayToolbar . add ( Utils . createJButton ( EditorActions . get (
A c t i o n V i e w R e p l a y S t e p F o r w a r d . class ) , " t o o l t i p R e p l a y S t e p F o r w a r d ") )
;
490
replayToolbar . add ( Utils . createJButton ( EditorActions . get (
A c t i o n V i e w R e p l a y F a s t F o r w a r d . class ) , " t o o l t i p R e p l a y F a s t F o r w a r d ") )
;
replayToolbar . add ( getGraph () . g e t U n d o C l u s t e r M a n a g e r () . getSlider () ) ;
return replayToolbar ;
}
}
{
}
}
}
protected void p r o c e s s M o u s e W h e e l E v e n t ( final MouseWh e el E ve n t e ) {
if ( e . isControlDown () ) {
if ( e . getWheelRot ation () > 0) { // " down "
EditorActions . get ( A c t io n Fo r m at Z oo m I n . class )
. actionPerformed ( null ) ;
} else {
EditorActions . get ( A c t i o n F o r m a t Z o o m O u t . class )
. actionPerformed ( null ) ;
}
} if ( e . isShiftDown () ) {
if ( e . getWheelRot ation () > 0) { // " down "
EditorActions . get ( ActionEditUndo . class )
p re f e re n ce s C ha n ge d () ;
JScrollPane pane = new Utils . MyJScrollPane ( getGraph () ) {
/**
* Returns the layered pane decorated with a Scroll pane . this method
* defines a mouse wheel listener for that scroll pane for handling
* zoom and undo requests . Next , it provides a mechanism to update
* the overview ’ s scale , so that the overview always fits the window .
*
* @see kiel . util . main . KielComponent # getMainComponen t ()
*/
public JComponent getM ainComponent () {
};
);
super . setBounds (x , y , width , height ) ;
final int layers = 3;
for ( int i = 0; i < layers ; i ++) {
if ( g e t C o m p o n e n t s I n L a y e r ( i ) . length != 0) {
g e t C o m p o n e n t s I n L a y e r ( i ) [0]. setBounds (0 , 0 , width , height
public void setBounds ( final int x , final int y , final int width ,
final int height ) {
/**
* Defines a JLayeredPane with some special behaviour : whenever the
* component ’ s bounds are changed , the containing child ’ s bounds are
changed
* as well . This Layered pane will contain 3 layers : the splash screen ,
* the graph drawing area and the overview graph .
*/
private JLayeredPane mainComponent = new JLayeredPane () {
}
alignment Toolbar . add ( Utils . createJButton ( EditorActions . get (
A c t i o n F o r m a t A l i g n J u s t i f y V e r t i c a l . class ) ,
" t o o l t i p J u s t i f y V e r t i c a l ") ) ;
return alignmentT oolbar ;
A.4. Der Quelltext
123
124
570
560
550
540
530
520
//
//
//
//
//
//
return mainComponent ;
590
580
;
610
} else {
p = new JPanel () ;
p . setBackground ( Color . WHITE ) ;
620
if ( Preferences . g e t S h o w O v e r v i e w L a y e r () ) {
mainComponent . add ( getGraph () . g e tOverv iewGraph () , new Integer (1) )
if ( Preferences . g e t S h o w S p l a s h S c r e e n () ) {
mainComponent . add (
new JLabel ( Re sourc eLoa der . get (" splashscreen2 . gif ") ) ,
new Integer (0) ) ;
} else {
JPanel p = new JPanel () ;
p . setBackground ( Color . WHITE ) ;
mainComponent . add (p , new Integer (0) ) ;
}
for ( int i = 0; i < 2; i ++) {
600
// TODO Why 2? --> constant or mainComponent . getLayers () . length
if ( mainComponent . g e t C o m p o n e n t C o u n t I n L a y e r ( i ) > 0) {
mainComponent . remove ( mainComponent . g e t C o m p o n e n t s I n L a y e r ( i )
[0]) ;
}
}
/**
* This notifies the editor with every change of the users preferences .
* The editor will then check if still the splash screen and the
overview
* layer should be shown .
* @see kiel . editor . resources . Preferences . Listener # pr e f er e nc e s Ch a ng e d ()
*/
public void p r e f e r e n c e s C h a n g e d () {
}
}) ;
}
};
mainComponent . add ( pane , new Integer (2) ) ;
mainComponent . a d d C o m p o n e n t L i s t e n e r ( new Componen tAdapter () {
public void c o m p o n e n t R e s i z e d ( final ComponentEvent e ) {
getGraph () . u p d a t e O v e r v i e w G r a p h S c a l e () ;
}
. ac t io n Pe r fo r me d ( null ) ;
} else {
EditorActions . get ( ActionEditRedo . class )
. ac t io n Pe r fo r me d ( null ) ;
}
} else {
super . p r o c e s s M o u s e W h e e l E v e n t ( e ) ;
}
}
items [0] = Utils . createJMenu (" ActionFileNew " , " newMnemonic " ,
" New16 . gif ") ;
(( JMenu ) items [0]) . add ( Utils . createJMenuItem (
A c t i o n F i l e N e w E s t e r e l S t u d i o . class ) ) ;
(( JMenu ) items [0]) . add ( Utils . createJMenuItem (
A c t i o n F i l e N e w M a t l a b . class ) ) ;
return items ;
JMenuItem [] items = new JMenu [1];
/**
* Returns the " New Esterel Studio " and " New Matlab " menu items .
* @see kiel . util . main . KielComponent # ge tF ile Me nuI te ms1 ()
*/
public JMenuItem [] ge tF ile Me nuI te ms1 () {
/**
* Returns the main toolbar , the replay toolbar and the alignment
toolbar .
* @see kiel . util . main . KielComponent # getToolBars ()
*/
public ToolBar [] getToolBars () {
return new ToolBar []{
new ToolBar ( toolbar , ResourceBundle . getString (" MainMenu ") , true )
,
new ToolBar ( c r e a t e R e p l a y T o o l B a r () ,
ResourceBundle . getString (" ReplayMenu ") ,
Preferences . g e t S h o w R e p l a y T o o l B a r O n L o a d () ) ,
new ToolBar ( c r e a t e A l i g n m e n t T o o l B a r () ,
ResourceBundle . getString (" AlignmentMenu ") ,
Preferences . g e t S h o w A l i g n m e n t T o o l B a r O n L o a d () ) };
}
/**
* Returns nothing ( null ) since the editor does not have a tree panel .
* @see kiel . util . main . KielComponent # getTreePanel ()
*/
public JComponent getTreePanel () {
return null ;
}
/**
* Just returns nothing ( null ) .
* @see kiel . util . main . KielComponent # getSubPanels ()
*/
public JTabbedPane getSubPanels () {
return null ;
}
}
mainComponent . add (p , new Integer (1) ) ;
}
mainComponent . repaint () ;
A. Java-Programm-Quelltext
670
660
650
640
630
680
/**
* Creates a checkbox menu item and sets the selected state .
* @param actionClass for which action a checkbox menu item should be
720
* created ?
* @param selected the selected state of the new menu item .
* @return a new menu item .
*/
private JMenuItem c re a te J Me n uI t em ( final Class actionClass ,
final boolean selected ) {
710
/**
* The content of this menu is dependent on what type of Statechat model
* is used ( Esterel studio or matlab ) .
*/
private JMenu menuEinfuegen =
Utils . createJMenu (" insert " , " i nser tMnemonic ") ;
/**
* Used by the E d i t o r M o d e S e l e c t O r D r a g O r R e s i z e O r F l i p E x p a n d on every mouse
* move event , indicating whether the currently selected state is
700
collapsed
* or not .
* @return the menu item representing the collapsed state of the
currently
* selected state .
*/
public JMenuItem g e t M e n u I t e m C o l l a p s e d () {
return m e n u I t e m C o l l a p s e d ;
}
/**
* Defines the menu item showing whether the currently selected state 690
* is collapsed or not . for that purpose there exists a getter for that
* variable to set it checked or not , used whenever the mouse is moved .
*/
private JMenuItem m e n u I t e m C o l l a p s e d = Utils . addAccelerator (
new J C h e c k B o x M e n u I t e m ( EditorActions . get ( A c t i o n E d i t C o l l a p s e d . class ) ) )
;
/**
* Returns the menu items : Close , Save , Save as , Export , Properties ,
Print
* and Preferences .
* @see kiel . util . main . KielComponent # g e tF il eMe nu Ite ms 2 ()
*/
public JMenuItem [] g e t F i l e M e n u I t e m s 2 () {
return new JMenuItem []{
Utils . c re a te J Me n uI t em ( A ction FileSave . class ) ,
Utils . c re a te J Me n uI t em ( A c t i o n F i l eSaveAs . class ) ,
Utils . c re a te J Me n uI t em ( A c t i o n F i l eExport . class ) ,
Utils . c re a te J Me n uI t em ( Ac t io n Fi l ePrint . class ) ,
Utils . c re a te J Me n uI t em ( A c t i o n F i l e P r e f e r e n c e s . class ) };
}
items [++ menuIndex ] =
Utils . createJMenu (" Action ViewReplay " , " Replay_Mnemo n ic ") ;
items [ menuIndex ]. add ( Utils . createJMenuItem (
A c t i o n V i e w R e p l a y S t o p . class ) ) ;
items [ menuIndex ]. add ( Utils . createJMenuItem (
items [++ menuIndex ] =
Utils . createJMenu (" view " , " viewMnemonic ") ;
items [ menuIndex ]. add ( createJMenuItem ( A c ti o n Vi e wO v e rv i ew . class ,
Preferences . g e t S h o w O v e r v i e w L a y e r () ) ) ;
items [ menuIndex ]. add ( createJMenuItem ( ActionViewGrid . class ,
Preferences . getShowGrid () ) ) ;
items [ menuIndex ]. add ( createJMenuItem (
A c t i o n V i e w S h o w S t a t e A c t i o n s . class ,
Preferences . g e t S h o w S t a t e A c t i o n s () ) ) ;
items [ menuIndex ]. add ( createJMenuItem (
A c t i o n V i e w S h o w C o m p o s i t e S t a t e E v e n t s . class ,
Preferences . g e t S h o w C o m p o s i t e S t a t e E v e n t s () ) ) ;
items [ menuIndex ]. add ( createJMenuItem (
A c t i o n V i e w S h o w C o m p o s i t e S t a t e V a r i a b l e s . class ,
Preferences . g e t S h o w C o m p o s i t e S t a t e V a r i a b l e s () ) ) ;
updateMenuEdit () ;
items [++ menuIndex ] = menuEdit ;
final int menuTotalCount = 6;
int menuIndex = -1;
JMenu [] items = new JMenu [ menuTotalCount ];
/**
* Returns all menus for the menubar between the " file -" and " help -"
menu .
* @see kiel . util . main . KielComponent # getRootMenus ()
*/
public JMenu [] getRootMenus () {
/**
* The contents of this menu change according to the currently selected
* graph element .
*/
private JMenu menuLayout ;
}
/**
* The contents of this menu change according to the currently selected
* graph element .
*/
private JMenu menuEdit =
Utils . createJMenu (" Edit " , " editMnemonic ") ;
JC he ckB ox Men uI tem item =
new JC hec kB oxM en uIt em ( EditorActions . get ( actionClass ) ) ;
item . setSelected ( selected ) ;
return item ;
A.4. Der Quelltext
125
126
770
760
750
740
730
return items ;
/**
* The toolbar ’ s combo box for transition types .
*/
private JComboBox c o m b o B o x T r a n s i t i o n T y p e s =
Utils . c re a te J Co m bo B ox ( new String []{
/**
* My toolbar .
*/
private JToolBar toolbar = Utils . cr eate JToolBar () ;
}
790
780
830
820
items [++ menuIndex ] = Utils . createJMenu (" Format " , " formatMnemonic ") ;
items [ menuIndex ]. add ( Utils . c r ea t eJ M enuItem (
A c t i o n F o r m a t Z o o m 1 0 0 . class ) ) ;
items [ menuIndex ]. add ( Utils . c r ea t eJ M enuItem (
A c t i o n F o r m a t Z o o m I n . class ) ) ;
800
items [ menuIndex ]. add ( Utils . c r ea t eJ M enuItem (
A c t i o n F o r m a t Z o o m O u t . class ) ) ;
items [ menuIndex ]. addSeparator () ;
items [ menuIndex ]. add ( Utils . c r ea t eJ M enuItem (
A c t i o n F o r m a t A l i g n L e f t . class ) ) ;
items [ menuIndex ]. add ( Utils . c r ea t eJ M enuItem (
A c t i o n F o r m a t A l i g n R i g h t . class ) ) ;
items [ menuIndex ]. add ( Utils . c r ea t eJ M enuItem (
A c t i o n F o r m a t A l i g n T o p . class ) ) ;
items [ menuIndex ]. add ( Utils . c r ea t eJ M enuItem (
810
A c t i o n F o r m a t A l i g n B o t t o m . class ) ) ;
items [ menuIndex ]. add ( Utils . c r ea t eJ M enuItem (
A c t i o n F o r m a t A l i g n C e n t e r H o r i z o n t a l . class ) ) ;
items [ menuIndex ]. add ( Utils . c r ea t eJ M enuItem (
A c t i o n F o r m a t A l i g n C e n t e r V e r t i c a l . class ) ) ;
items [ menuIndex ]. add ( Utils . c r ea t eJ M enuItem (
A c t i o n F o r m a t A l i g n J u s t i f y H o r i z o n t a l . class ) ) ;
items [ menuIndex ]. add ( Utils . c r ea t eJ M enuItem (
A c t i o n F o r m a t A l i g n J u s t i f y V e r t i c a l . class ) ) ;
items [++ menuIndex ] = menuEinfuegen ;
items [++ menuIndex ] = menuLayout ;
A c t i o n V i e w R e p l a y P l a y . class ) ) ;
items [ menuIndex ]. add ( Utils . c r ea t eJ M enuItem (
A c t i o n V i e w R e p l a y R e w i n d . class ) ) ;
items [ menuIndex ]. add ( Utils . c r ea t eJ M enuItem (
A c t i o n V i e w R e p l a y S t e p B a c k . class ) ) ;
items [ menuIndex ]. add ( Utils . c r ea t eJ M enuItem (
A c t i o n V i e w R e p l a y S t e p F o r w a r d . class ) ) ;
items [ menuIndex ]. add ( Utils . c r ea t eJ M enuItem (
A c t i o n V i e w R e p l a y F a s t F o r w a r d . class ) ) ;
items [ menuIndex ]. add ( Utils . c r ea t eJ M enuItem (
A c t i o n V i e w R e p l a y T r a c e L o g . class ) ) ;
/**
/**
* @see kiel . util . main . KielComponent # g etK ie lFr am eTi tl e ()
*/
public String get Ki elF ra meT it le () {
return ResourceBundle . getString (" K I E L _ S t a t e c h a r t _ E d i t o r ") ;
}
/**
* @return .
*/
public int g e t C u r r e n t T r a n s i t i o n T y p e () {
return c o m b o B o x T r a n s i t i o n T y p e s . getSe lectedIndex () ;
}
/**
* @return .
*/
public int g e t C u r r e n t T r a n s i t i o n L i n e () {
return c o m b o B o x T r a n s i t i o n L i n e T y p e s . g etSelectedIndex () ;
}
/**
* the button representing the default editor mode , the selection mode .
* ( its the first button in the row ) .
*/
private JToggleButton buttonSelection ;
/**
* sets the button representing the default editor mode , the selection
* mode . ( its the first button in the row ) .
*/
public void s e t S e l e c t i o n B u t t o n S e l e c t e d () {
// this method is also called before the menu ( and its selection
button )
// is initialized
if ( buttonSelection != null ) {
buttonSelection . setSelected ( true ) ;
}
}
/**
* The toolbar ’ s combo box for transition line types .
*/
private JComboBox c o m b o B o x T r a n s i t i o n L i n e T y p e s =
Utils . createJComboBox ( new String []{
ResourceBundle . getString (" Spline ") ,
ResourceBundle . getString (" Bezier ") ,
ResourceBundle . getString (" Orthogonal ") }) ;
ResourceBundle . getString (" Normal ") ,
ResourceBundle . getString (" Weak ") ,
ResourceBundle . getString (" Strong ") }) ;
A. Java-Programm-Quelltext
880
870
860
850
840
),
// For the single - selection of creation - buttons ...
ButtonGroup bg = new ButtonGroup () ;
for ( int i = 0; i < toolbar . getComponents () . length ; i ++) {
" t o o l t i p B a c k T o S e l e c t i o n M o d e ") ;
toolbar . add ( b u tt o nS e le c ti on ) ;
toolbar . addSeparator () ;
toolbar . add ( Utils . c r e a t e J T o g g l e B u t t o n ( EditorModes . get (
E d i t o r M o d e A d d I n i t i a l S t a t e . class ) ,
" t o o l t i p A d d I n i t i a l S t a t e ") ) ;
if ( i s E s t e r e l S t u d i o T y p e () ) {
toolbar . add ( Utils . c r e a t e J T o g g l e B u t t o n ( EditorModes . get (
E d i t o r M o d e A d d D e e p H i s t o r y . class ) ,
" t o o l t i p A d d D e e p H i s t o r y ") ) ;
toolbar . add ( Utils . c r e a t e J T o g g l e B u t t o n ( EditorModes . get (
E d i t o r M o d e A d d S u s p e n d . class ) ,
" t o o l t i p A d d S u s p e n d ") ) ;
} else {
toolbar . add ( Utils . c r e a t e J T o g g l e B u t t o n ( EditorModes . get (
E d i t o r M o d e A d d H i s t o r y . class ) ,
" t o o l t i p A d d H i s t o r y ") ) ;
}
toolbar . add ( Utils . c r e a t e J T o g g l e B u t t o n ( EditorModes . get (
E d i t o r M o d e A d d D y n a m i c C h o i c e . class ) ,
" t o o l t i p A d d D y n a m i c C h o i c e ") ) ;
toolbar . add ( Utils . c r e a t e J T o g g l e B u t t o n ( EditorModes . get (
E d i t o r M o d e A d d S i m p l e S t a t e . class ) ,
" t o o l t i p A d d S i m p l e S t a t e ") ) ;
toolbar . add ( Utils . c r e a t e J T o g g l e B u t t o n ( EditorModes . get (
E d i t o r M o d e A d d F i n a l S i m p l e S t a t e . class ) ,
" t o o l t i p A d d F i n a l S i m p l e S t a t e ") ) ;
toolbar . add ( Utils . c r e a t e J T o g g l e B u t t o n ( EditorModes . get (
E d i t o r M o d e A d d O r S t a t e . class ) ,
" t o o l t i p A d d O r S t a t e ") ) ;
toolbar . add ( Utils . c r e a t e J T o g g l e B u t t o n ( EditorModes . get (
E d i t o r M o d e A d d H o r i z o n t a l D e l i m i t e r . class ) ,
" t o o l t i p A d d H o r i z o n t a l D e l i m i t e r ") ) ;
toolbar . add ( Utils . c r e a t e J T o g g l e B u t t o n ( EditorModes . get (
E d i t o r M o d e A d d V e r t i c a l D e l i m i t e r . class ) ,
" t o o l t i p A d d V e r t i c a l D e l i m i t e r ") ) ;
930
920
910
900
toolbar . removeAll () ;
if ( getGraph () . g e tM y Gr a ph M od e l () == null ) {
return ;
}
b ut t on S el e ct i on = Utils . c r e a t e J T o g g l e B u t t o n (
EditorModes . get ( E d i t o r M o d e S e l e c t O r D r a g O r R e s i z e O r F l i p E x p a n d . class
* Updates the toolbar and menubar depending on which statechart model
* is currently used . this method next builds a button group for the
editor
* modes buttons ( Selection , Add XY State ) .
*/
private void u p d a t e T o o l B a r A n d M e n u B a r () {
890
s e t M e n u I t e m s E n a b l e d ( true ) ;
toolbar . addSeparator () ;
toolbar . add ( Utils . createJButton ( EditorActions . get (
ActionEditUndo . class ) , " tooltipEditUndo ") ) ;
toolbar . add ( Utils . createJButton ( EditorActions . get (
ActionEditRedo . class ) , " tooltipEditRedo ") ) ;
toolbar . addSeparator () ;
toolbar . add ( Utils . createJButton ( EditorActions . get (
A c t i o n F o r m a t Z o o m 1 0 0 . class ) , " t o o l t i p F o r m a t Z o o m 1 0 0 ") ) ;
toolbar . add ( Utils . createJButton ( EditorActions . get (
A ct i o nF o rm a t Zo o mI n . class ) , " t o o l t i p F o r m a t Z o m m I n ") ) ;
toolbar . add ( Utils . createJButton ( EditorActions . get (
A c t i o n F o r m a t Z o o m O u t . class ) , " t o o l t i p F o r m a t Z o o m O u t ") ) ;
toolbar . addSeparator () ;
toolbar . add ( Utils . createJButton ( EditorActions . get (
ActionEditEdit . class ) , " tooltipEditEdit ") ) ;
toolbar . addSeparator () ;
toolbar . add ( Utils . createJButton ( EditorActions . get (
ActionEdi tRemove . class ) , " t ool ti pEd it Re mov e ") ) ;
toolbar . addSeparator () ;
toolbar . add ( c o m b o B o x T r a n s i t i o n T y p e s ) ;
toolbar . add ( c o m b o B o x T r a n s i t i o n L i n e T y p e s ) ;
toolbar . addSeparator () ;
toolbar . add ( Utils . createJButton ( EditorActions . get (
A c t i o n A d d T r a n s i t i o n T o g g l e . class ) , " t o o l t i p A d d T r a n s i t i o n T o g g l e ") )
}
buttonSelection . setSelected ( true ) ;
menuEinfuegen . removeAll () ;
menuEinfuegen . add ( EditorModes . get ( E d i t o r M o d e A d d S i m p l e S t a t e . class ) ) ;
menuEinfuegen . add ( EditorModes . get ( E d i t o r M o d e A d d F i n a l S i m p l e S t a t e .
class ) ) ;
menuEinfuegen . add ( EditorModes . get ( E d i t o r M o d e A d d O r S t a t e . class ) ) ;
menuEinfuegen . addSeparator () ;
menuEinfuegen . add ( EditorModes . get ( E d i t o r M o d e A d d I n i t i a l S t a t e . class ) ) ;
menuEinfuegen . add ( EditorModes . get ( E d i t o r M o d e A d d D y n a m i c C h o i c e . class ) )
;
if ( i s E s t e r e l S t u d i o T y p e () ) {
menuEinfuegen . add ( EditorActions . get (
E d i t o r M o d e A d d D e e p H i s t o r y . class ) ) ;
menuEinfuegen . add ( EditorModes . get ( E d i t o r M o d e A d d S u s p e n d . class ) ) ;
} else {
menuEinfuegen . add ( EditorActions . get ( E d i t o r M o d e A d d H i s t o r y . class ) )
;
}
menuEinfuegen . addSeparator () ;
menuEinfuegen . add ( EditorModes . get (
E d i t o r M o d e A d d H o r i z o n t a l D e l i m i t e r . class ) ) ;
;
if ( toolbar . getComponents () [ i ] instanceof JToggleButton ) {
bg . add (( JToggleButton ) toolbar . getComponents () [ i ]) ;
}
A.4. Der Quelltext
127
128
950
940
960
/**
970
* Reference to the main application window . Used as parent for dialog
* windows .
/**
* Checks the model type .
* @return true if the current model is a Estudio model .
*/
private boolean i s E s t e r e l S t u d i o T y p e () {
return Re sour ceBun dle . getString (" A c t i o n F i l e N e w E s t e r e l S t u d i o ")
. equals ( getGraph () . g et M yG r ap h Mo del () . g e t C u r r e n t S t a t e C h a r t ()
. g etMod elSo urce () ) ;
}
}
);
menuEinfuegen . add ( EditorModes . get (
E d i t o r M o d e A d d V e r t i c a l D e l i m i t e r . class ) ) ;
menuEinfuegen . addSeparator () ;
menuEinfuegen . add ( EditorActions . get ( A c t i o n A d d T r a n s i t i o n T o g g l e . class )
}
/**
* @see kiel . util . main . KielComponent # setKielFrame ( kiel . util . main .
IKielFrame )
*/
public void setKielFrame ( final IKielFrame aFrame ) {
kielFrame = aFrame ;
}
/**
* Returns the main application window .
* @return the main application window .
*/
public IKielFrame getKielFrame () {
return kielFrame ;
}
*/
private IKielFrame kielFrame ;
A. Java-Programm-Quelltext
40
30
20
10
50
/**
/**
* When did this step occur .
*/
private long c u r r e n t T i m e M i l l i s ;
/**
* Which EditorAction is represented by this EditStep .
*/
private EditorAction editorAction ;
/**
* How many JGraph - framework - edit - steps are clustered with this edit
step .
*/
private int count ;
/**
* This is a Reso urceB undl e key representing that a started edit step
has
* been cancelled .
*/
public static final String TY PE_C ANCEL LED = " e d i t S t e p T y p e C a n c e l l e d ";
100
90
80
70
/**
* This is a Reso urceB undl e key representing that an edit step has been
* ended successfully .
*/
public static final String TY P E_ S UC C ES S FUL = " e d i t S t e p T y p e S u c c e s s f u l ";
/**
* This is a Reso urceB undl e key representing that a edit step has been
* started .
*/
public static final String TYPE_START = " ed itS te pTy pe Sta rt ";
/**
* Models an ( undoable ) edit step containing a timestamp and a reference to
* the editor action . This is used for statistics ( Trace log ) and could be
* used for a named undo history , even displayed in the undo menu item .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 60
* @version $Revision : 1.15 $ last modified $Date : 2005/03/21 22:53:57 $
*/
public final class EditStep {
import kiel . editor . controller . EditorAction ;
package kiel . editor ;
kiel.editor.EditStep
/**
* Was the edit step successful or cancelled or whatever .
* @see # type
/**
* When did this user edit step occur .
* @see # cur re ntT im eMi ll is
* @return @see # cu rr ent Ti meM il lis
*/
public long g e t C u r r e n t T i m e M i l l i s () {
return c ur ren tT ime Mi lli s ;
}
/**
* Returns the EditorAction object which performed this user edit step .
* @see # editorAction
* @return @see # editorAction
*/
public EditorAction getEditorAction () {
return editorAction ;
}
/**
* Returns the count of JGraph model changes clustered in this user edit
* step .
* @see # count
* @return @see # count
*/
public int getCount () {
return count ;
}
}
count = aCount ;
editorAction = anEditorAction ;
cu rr ent Ti meM il lis = System . c urr en tTi me Mil li s () ;
type = aType ;
/**
* Creates an EditStep , done in EditorAction , u n do C lu s t er M an a g e r and
* Ed ito rM ode Ad dNo de .
* @param aCount @see count
* @param anEditorAction @see editorAction
* @param aType @see type
*/
public EditStep ( final int aCount , final EditorAction anEditorAction ,
final String aType ) {
* Is this Edit step started , ended successfully or cancelled .
*/
private String type ;
A.4. Der Quelltext
129
* @return @see # type
*/
public String getType () {
}
}
return type ;
A. Java-Programm-Quelltext
130
40
30
20
10
java . awt . event . ActionEvent ;
java . io . File ;
java . io . F il e In p ut S tr e am ;
java . io . F i l e O u t p u t S t r e a m ;
java . io . IOException ;
java . util . Properties ;
java . util . Vector ;
javax . swing . Abst ract Actio n ;
javax . swing . JMenu ;
javax . swing . JMenuItem ;
javax . swing . KeyStroke ;
60
50
}
if ( instance == null ) {
instance = new FileHistory ( aKielFrame ) ;
}
return instance ;
/**
* just returns the single instance of this class .
* @param aKielFrame Reference to the main application window .
* @return just returns the single instance
*/
public static FileHistory getInstance ( final IKielFrame aKielFrame ) {
/**
* The file history is used in this application just as single object .
*/
private static FileHistory instance ;
90
/**
* Organizes the file history , displayed in the file - > Last files menu .
Mainly
* this class provides the JMenu containing the last files . This information
70
is
* stored in the user ’ s home directory and updated whenever the add () method
is
* called .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.45 $ last modified $Date : 2005/07/25 11:44:37 $
*/
80
public final class FileHistory {
import kiel . editor . resources . Preferences ;
import kiel . util . LogFile ;
import kiel . util . main . IKielFrame ;
import
import
import
import
import
import
import
import
import
import
import
package kiel . editor ;
kiel.editor.FileHistory
/**
* Adds a menu item to the menu .
* @param i the index of the item to be added .
*/
}
try {
properties . load ( new FileInputStream ( FILENAME ) ) ;
} catch ( IOException e ) {
logFile . log (0 , " A new filelist will be created .") ;
// Its ok . new environment ...
}
for ( int i = 0; i < Preferences . g et Las tF ile sC oun t () ; i ++) {
if ( properties . get ("" + i ) != null ) {
addItem ( i ) ;
}
}
kielFrame = aKielFrame ;
/**
* The FileHistory needs a reference to the KielFrame in order to
* use its open ( File ) method .
* @param aKielFrame @see # kielFrame
*/
private FileHistory ( final IKielFrame aKielFrame ) {
/**
* The logging handle . Prints logs to standard out .
*/
private LogFile logFile = new LogFile (" Editor " , 2) ;
/**
* The file in which the last opened file names are stored .
*/
private static final String FILENAME =
System . getProperty (" user . home ")
+ File . separator + ". kiel "
+ File . separator + " filelist ";
/**
* Reference to the application ’ s main window , for using its file open
* functionality .
*/
private IKielFrame kielFrame ;
/**
* Used as handle for the file containing the file ’ s list information .
*/
private Properties properties = new Properties () ;
A.4. Der Quelltext
131
132
130
120
110
100
if ( file == null ) {
return ;
}
Vector list = new Vector () ;
for ( int i = 0; i < properties . size () ; i ++) {
if (! list . contains ( properties . getProperty ("" + i ) ) ) {
list . add ( properties . getProperty ("" + i ) ) ;
}
}
if (! list . contains ( file . toString () ) ) {
list . add (0 , file . toString () ) ;
/**
* Called by the editor whenever the user opens or stores a file .
* This updates the list of recent used files .
* @param file A new file to be added .
*/
public void add ( final File file ) {
}
160
150
}) ;
final int m a x A c c e l e r a t o r C o u n t = 9;
if ( i < m a x A c c e l e r a t o r C o u n t ) {
mi . s etAcc eler ator ( KeyStroke . getKeyStroke (( char ) ( ’1 ’ + i ) , 2) ) ;
}
l a s t O p e n e d F i l e s M e n u . add ( mi ) ;
}
public void a c ti o nP e rf o rm e d ( final ActionEvent e ) {
kielFrame . open ( new File ( properties . getProperty ("" + i ) ) ) ; 140
JMenuItem mi = new JMenuItem ( new AbstractAction ( new File ( properties
. getProperty ("" + i ) ) . getName () , null ) {
private void addItem ( final int i ) {
}
}
return l a s t O p e n e d F i l e s M e n u ;
/**
* Returns the main last files menu .
* @return the main last files menu .
*/
public JMenu getMenu () {
/**
* The main menu , provided for the KielFrame .
*/
private JMenu l a s t O p e n e d F i l e s M e n u =
Utils . createJMenu (" lastFiles " , " las tF ile sM nem on ic " ,
" Open16 . gif ") ;
}
}
while ( list . size () > Preferences . ge tLa st Fi les Co unt () ) {
list . removeElementAt ( Preferences . g etL as tFi le sCo u n t () ) ;
}
properties . clear () ;
l a s t O p e n e d F i l e s M e n u . removeAll () ;
for ( int i = 0; i < list . size () ; i ++) {
properties . setProperty ("" + i , ( String ) list . elementAt ( i ) ) ;
addItem ( i ) ;
}
try {
properties . store ( new FileOutputStre am ( FILENAME ) , null ) ;
} catch ( IOException ex ) {
kielFrame . handleException (
ex . getMessage () , true , ex ) ;
}
A. Java-Programm-Quelltext
40
30
20
10
org . jgraph . graph . AttributeMap ;
org . jgraph . graph . D e f a u l t G r a p h C e l l ;
org . jgraph . graph . G raphC onst ants ;
org . jgraph . graph . Port ;
import
import
import
import
60
50
/**
* The M o r p h i n g L a y o u t e r takes a set of " current " coordinates and a
corresponding
70
* set of " target " - coordinates , searches for the largest delta beween
current
* and target , counted in pixels , and this largest delta will be the count n
of
* " delta - slices " the M o r p h i n g L a y o u t e r will produce . The Morphing Layouter
will
* then perform the change from current to target in exactly n steps . That
* means , in every step at least one coordinate will change exactly at 1
pixel ,
* and no other coordinate will change more than 1 pixel . All coordinates
are
* provided as floats , so most of them will change in a range between [0..1]
80
in
* every step .
* In every step the calculated delta will be applied to the JGraph - objects
and
* a real change is performed on the JGraph - model by calling JGraphModel .
edit () .
* The effect will be , that the complete delta ( or change ) will look like a
kiel . dataStructure . ANDState ;
kiel . dataStructure . DelimiterLine ;
kiel . dataStructure . G r ap h ic a lO b je c t ;
kiel . dataStructure . Node ;
kiel . dataStructure . Transition ;
kiel . editor . graph . D e l i m i t e r L i n e C e l l ;
kiel . editor . graph . M y G r a p h C o n s t a n t s ;
kiel . editor . graph . NodeCell ;
kiel . editor . graph . Tran sitio nCell ;
kiel . editor . resources . Preferences ;
kiel . g r a p h i c a l I n f o r m a t i o n s . D e l i m i t e r L i n e L a y o u t I n f o r m a t i o n ;
kiel . g r a p h i c a l I n f o r m a t i o n s . N o d e L a y o u t I n f o r m a t i o n ;
kiel . g r a p h i c a l I n f o r m a t i o n s . View ;
kiel . util . LogFile ;
java . awt . geom . Point2D ;
java . awt . geom . Rectangle2D ;
java . util . ArrayList ;
java . util . HashMap ;
java . util . List ;
java . util . Map ;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
package kiel . editor ;
kiel.editor.MorphingLayouter
movie to the user with a speed which is adjustable though the Preferences
class . The Morphing Layouter even takes into account that this speed will
be different on every computer depending on its resources and processor
speed . So after 10 steps ( that is also adjustable though the Preferences
class ) , the mechanism will check , if the current speed fits the desired
speed . That means , after each 10 ( or more or less ) steps it will reduce
the
speed ( by taking some sleep () calls ) or enhance the speed by clustering
steps . Whenever a caller wants a change to be performed by the
MorphingLayouter , then all subsequent changes to the JGraph - model should
be
done though the Mo rphingLayouter as well because the Morphin g L a y o u t e r
ensures that all calls ( all model changes ) will be performed in the
correct
order . That is why the constructor wants to know if a real morphing
should
be done or just a one - step - change .
<p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
<p > Company : Uni Kiel </ p >
@author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </a >
@version $Revision : 1.79 $ last modified $Date : 2005/08/01 17:54:30 $
/**
/**
* Reference to the current graph . That includes the current coordinates
*/
private final MyJGraph sourceGraph ;
}
/**
* Will be called when the MorphingLayoute r finished its work of one
* " user " - call .
*/
void mo rphingFinished () ;
/**
* This should be implemented by a Morphing Layouter user , who wants to
be
* informed when his asynchronous call has finished .
* @author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </
a>
*/
public interface MyListener {
/**
* The logging handle . Prints logs to standard out .
*/
private LogFile logFile = new LogFile (" Editor " , 2) ;
*
*
*
*
*
*/
public final class MorphingLayoute r implements Runnable {
*
*
*
*
*
*
*
*
*
*
*
*
A.4. Der Quelltext
133
134
130
120
110
100
90
threadQueue . add ( m o r p h i n g L a y o u t e r ) ;
170
160
/**
* Ensures all M o r p h i n g L a y o u t e r calls will be processed in the correct
* order .
*/
private static M o r p h i n g L a y o u t e r Q u e u e threadQueue =
new M o r p h i n g L a y o u t e r Q u e u e () ;
180
/**
* Provides a permanently running thread checking all 30 milliseconds if
* there is a M o r p h i n g L a y o u t e r request to be performed . The problem is :
* While processing a M o r p h i n g L a y o u t e r call , it is dangerous to do other
* changes to the JGraph - model except for the changes that are processed
* currently . Lets say coordinate x is changed in 10 steps from value 42
* to value 52. Lets say the M o r p h i n g L a youter just performed the 4 th
step ,
}
/**
* Is called in the public user - methods , ensuring all asynchronous
* calls will be performed in the correct order .
* @param m o r p h i n g L a y o u t e r the instance to be processed .
*/
private static synchronized void startThread (
final M o r p h i n g L a y o u t e r m o r p h i n g L a y o uter ) {
}
sourceGraph = aSourceGraph ;
listener = aListener ;
doMorphing = aDoMorphing ;
/**
* This list contains Morphi ngLayouter objects .
*/
private ArrayList queue = new ArrayList () ;
*/
M o r p h i n g L a y o u t e r Q u e u e () {
start () ;
}
/**
* Checks every 30 milliseconds if there is a Morphi n g L a y o u t e r
object
* in the queue . if so , this object will be started synchronously on
* this thread
/**
* Checks if at least one element is in the list .
* @return true if the queue is not empty .
*/
private synchronized boolean isFull () {
return ! queue . isEmpty () ;
}
/**
* Append a new Mor phingLayouter object to the queue .
* @param runnable .
*/
public synchronized void add ( final Runnable runnable ) {
queue . add ( runnable ) ;
}
/**
* Take the first object out of the queue and remove it from the
queue .
* @return the first element of the queue .
*/
public synchronized Runnable consumeNext () {
return ( Mor phingLayouter ) queue . remove (0) ;
}
.
/**
* Immediately starts the Mo rphingLayouter after the class is loaded
/**
* @param aSourceGraph information about the current coordinates .
* @param aListener usually the caller , who wants to be informed when
150
the
* asynchronous call will be terminated .
* @param aDoMorphing should a real morphing be done or should the
change
* be performed in one single step .
*/
public M o r p h i n g L a y o u t e r ( final MyJGraph aSourceGraph ,
final MyListener aListener , final boolean aDoMorphing ) {
/**
* There is at most one listener to be informed about the end of the
* M o r p h i n g L a y o u t e r call .
*/
private MyListener listener ;
* so the value is currently 46. If now different Morphi n g L a y o u t e r call
* would change the value of x to the value 60 , then this change would
be
* destroyed by the 5 th step of the first Mo rphingLayout e r call , which
* will set the value to 47. ; -)
*
* @author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </
a>
*/
private static class M o r p h i n g L a y o u t e r Q u e u e extends Thread {
* contains a mapping graphCell -- Rectangle2D , containing the target
140
* coordinates .
*/
private HashMap targetMapping ;
A. Java-Programm-Quelltext
230
220
210
200
190
260
250
240
/**
*
}
targetMapping = new HashMap () ;
targetMapping . put ( cell , targetBounds ) ;
// recursion : root := aTa rget Mappi ng . keySet () . iterator () . next () ;
// All ancestors have to be moved , the parent has to be resized ,
then
// recursive : root := parent
addCells ( cell , targetBounds ) ;
startThread ( this ) ;
290
270
/**
* Not just simply enlarges the given graph cell . In addition to that
all
* ancestors have to be moved to a probably new position , then maybe the
* parent has to be resized . This resize has to be applied recursively !
* @param cell contains the current coordinates .
* @param targetBounds defines the target coordinates .
*/
public void e x p a n d C o m p o s i t e S t a t e ( final DefaultGraphCe ll cell ,
final Rectangle2D targetBounds ) {
280
}
targetMapping = new HashMap () ;
targetMapping . put ( cell , targetBounds ) ;
startThread ( this ) ;
/**
* Simply ensmalls the given graph cell .
* @param cell contains the current coordinates .
* @param targetBounds defines the target coordinates .
*/
public void c o l l a p s e C o m p o s i t e S t a t e ( final Def aultGraphCell cell ,
final Rectangle2D targetBounds ) {
}
* @see java . lang . Runnable # run ()
*/
public void run () {
while ( true ) { // TODO Just run on request !
try {
if ( isFull () ) {
consumeNext () . run () ;
} else {
final int sleepingTime = 30;
sleep ( sleepingTime ) ;
}
} catch ( I n t e r r u p t e d E x c e p t i o n e ) {
e . p ri n tS t ac k Tr a ce () ;
}
}
}
final Rectangle2D sourceBounds =
sourceGraph . g e t G r a p h L a y o u t C a c h e () . getMapping (
cell , false ) . getBounds () ;
if ( sourceBounds . getX () != targetBounds . getX ()
|| sourceBounds . getY () != targetBounds . getY () ) {
return ;
}
final double deltaWidth = targetBounds . getWidth ()
- sourceBounds . getWidth () ;
final double deltaHeight = targetBounds . getHeight ()
- sourceBounds . getHeight () ;
if ( deltaWidth < 0 && deltaHeight < 0) {
// move nodes only on expand ...
return ;
}
Rectangle2D parentBounds = null ;
if ( cell . getParent () != null ) {
parentBounds = sourceGraph . g e t G r a p h L a y o u t C a c h e ()
. getMapping ( cell . getParent () , false ) . getBounds () ;
}
// The ancestors and its childs have to be moved ...
final Object [] all = sourceGraph . getDescendants ( sourceGraph . getRoots
() ) ;
double m ax Par en tOv er lap X = 0;
double m ax Par en tOv er lap Y = 0;
for ( int i = 0; i < all . length ; i ++) {
if ( all [ i ] instanceof NodeCell
/**
* Is called by e x p a n d C o m p o s i t e S t a t e () and recursively . Checks the
* ancestors of the cell and the parent .
* @param cell the cell whose ancestors and parent have to be checked .
* @param targetBounds the cell ’ s target bounds .
*/
private void addCells ( final D efaultGraphCell cell ,
final Rectangle2D targetBounds ) {
* @param cell .
* @param testCell .
* @return .
*/
private static boolean i s A n c e s t o r O r C h i l d O f A n c e s t o r (
final Defaul tGraphCell cell , final DefaultGra phCell testCell ) {
if ( cell == testCell . getParent () ) {
return false ;
} else if ( cell . getParent () == testCell . getParent () ) {
return true ;
} else if ( testCell . getParent () == null ) {
return false ;
} else {
return i s A n c e s t o r O r C h i l d O f A n c e s t o r (
cell , ( Defa ultGraphCell ) testCell . getParent () ) ;
}
}
A.4. Der Quelltext
135
136
340
330
320
310
300
bottom )
bottom )
i ])
360
350
370
}
if ( overlapX > 0 || overlapY > 0) {
if (! targetMapping . containsKey ( all [ i ]) ) {
targetMapping . put (
all [ i ] ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
bounds . getX () + overlapX ,
bounds . getY () + overlapY ,
}
if ( overlapY < 0) {
overlapY = 0;
}
390
380
overlapY = targetBounds . getY ()
+ targetBounds . getHeight ()
+ Preferences
. g e t M o r p h i n g L a y o u t e r B o r d e r D i s t a n c e ()
- bounds . getY () ;
}
if ( bounds . getY () > sourceBounds . getY ()
+ sourceBounds . getHeight ()
&& bounds . getX ()
+ bounds . getWidth () > sourceBounds . getX () ) {
// is under
if ( bounds . getX () < targetBounds . getX ()
+ targetBounds . getWidth () ) {
// and will be captured ( not right hand on the
}
if ( overlapX < 0) {
overlapX = 0;
}
overlapX = targetBounds . getX ()
+ targetBounds . getWidth ()
+ Preferences
. g e t M o r p h i n g L a y o u t e r B o r d e r D i s t a n c e ()
- bounds . getX () ;
&& all [ i ] != cell ) {
// its an ancestor ...
final Rectangle2D bounds =
Gra phCo nstan ts . getBounds ((( DefaultGr aphCell ) all [ i ])
. getAttributes () ) . getBounds2D () ;
double overlapX = 0;
double overlapY = 0;
if ( bounds . getX () > sourceBounds . getX ()
+ sourceBounds . getWidth ()
&& bounds . getY ()
+ bounds . getHeight () > sourceBounds . getY () ) {
// is right hand next to ...
if ( bounds . getY () < targetBounds . getY ()
+ targetBounds . getHeight () ) {
// and will be captured ( not right hand on the
&& i s A n c e s t o r O r C h i l d O f A n c e s t o r ( cell , ( DefaultGraphCell ) all [
}
if ( parentOverlapX > ma xPa re ntO ve rla pX ) {
ma xP are nt Ove rl apX = parentOverlapX ;
}
if ( parentOverlapY > ma xPa re ntO ve rla pY ) {
ma xP are nt Ove rl apY = parentOverlapY ;
}
if ( parentBounds != null ) {
double parentOverlapX = targetBounds . getX ()
+ targetBounds . getWidth ()
+ Preferences . g e t M o r p h i n g L a y o u t e r B o r d e r D i s t a n c e ()
- parentBounds . getX ()
- parentBounds . getWidth () ;
double parentOverlapY = targetBounds . getY ()
+ targetBounds . getHeight ()
+ Preferences . g e t M o r p h i n g L a y o u t e r B o r d e r D i s t a n c e ()
- parentBounds . getY ()
- parentBounds . getHeight () ;
}
bounds . getWidth () ,
bounds . getHeight () ) ) ;
}
if ( parentBounds == null ) {
logFile . log (2 , " parentBounds is null ") ;
continue ;
}
// Check the parent bounds ...
double parentOverlapX =
bounds . getX ()
+ overlapX
+ bounds . getWidth ()
+ Preferences . g e t M o r p h i n g L a y o u t e r B o r d e r D i s t a n c e ()
- parentBounds . getX ()
- parentBounds . getWidth () ;
if ( parentOverlapX < 0) {
parentOverlapX = 0;
}
double parentOverlapY =
bounds . getY ()
+ overlapY
+ bounds . getHeight ()
+ Preferences . g e t M o r p h i n g L a y o u t e r B o r d e r D i s t a n c e ()
- parentBounds . getY ()
- parentBounds . getHeight () ;
if ( parentOverlapY < 0) {
parentOverlapY = 0;
}
if ( parentOverlapX > ma xP are nt Ove rl apX ) {
ma xP are nt Ove rl apX = parentOverlapX ;
}
if ( parentOverlapY > ma xP are nt Ove rl apY ) {
ma xP are nt Ove rl apY = parentOverlapY ;
}
A. Java-Programm-Quelltext
440
430
420
410
400
}
;
;
offset . setLocation (
offset . getX () + layout . getXPos () ,
if ( g ra p hi c al O bj e ct instanceof ANDState ) {
Point2D offset = M y G r a p h M o d e l U t i l i t i e s . calculateOffset (
( Node ) graphicalObject ,
targetView ) ;
N o d e L a y o u t I n f o r m a t i o n layout = targetView
. g e t L a y o u t I n f o r m a t i o n (( Node ) graphicalObject ) ;
mapping . put (
all [ i ] ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
layout . getXPos () + offset . getX () ,
layout . getYPos () + offset . getY () ,
layout . getWidth () ,
layout . getHeight () ) ) ;
if ( g ra p hi c al O bj e ct instanceof Node ) {
490
G ra p hi c al O bj e ct g ra p hi c al O bj e ct = MyGraphConstan ts
. g e t G r a p h i c a l O b j e c t ((( D e f a u l t G r aphCell ) all [ i ]) . getAttributes ()
)
480
for ( int i = 0; i < all . length ; i ++) {
HashMap mapping = new HashMap () ;
D e f a u l t G r a p h C e l l [] all = sourceGraph . getMyGraphModel () . getAllCells ()
/**
* Is called only by applyNewView () . Iterates though the target view and
* fills a hash map with graph cell -- Rectangle2D pairs .
* @param targetView the view of which the target coordinates is taken470
.
* @return the filled hash map as equivalent to the target view .
*/
private HashMap c r e a t e T a r g e t M a p p i n g ( final View targetView ) {
}
450
}
if ( m a x P a r e n t O v e r l a p X > 0 || m a xP ar ent Ov erl ap Y > 0) {
// The parent has to be resized ...
if (! targetMapping . containsKey ( cell . getParent () ) ) {
targetMapping . put ( cell . getParent () ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
parentBounds . getX () ,
parentBounds . getY () ,
parentBounds . getWidth () + maxParentOverlapX ,
parentBounds . getHeight () + max Pa ren tO ver la pY ) ) ;
460
}
addCells (( D e f a u l t G r a p h C e l l ) cell . getParent () ,
( Rectangle2D ) targetMapping . get ( cell . getParent () ) ) ;
}
/**
* Calculates a target mapping out of the target view and then starts
the
}
}
mapping . put ( sourceGraph . getMyGraphModel ()
. getGraphCell ( delimiterLines [ j ]) , targetBounds ) ;
1) ;
} else if ( graphicalObject instanceof Transition ) {
}
}
// TODO this check is done in MyGraphModel as well !
if ( targetBounds . getWidth () == 0) {
targetBounds . setRect ( targetBounds . getX () ,
targetBounds . getY () , 1 ,
targetBounds . getHeight () ) ;
}
if ( targetBounds . getHeight () == 0) {
targetBounds . setRect ( targetBounds . getX () ,
targetBounds . getY () , targetBounds . getWidth ()
Rectangle2D targetBounds =
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
d e l i m i t e r L i n e L a y o u t . getStart () . getX ()
+ offset . getX () ,
d e l i m i t e r L i n e L a y o u t . getStart () . getY ()
+ offset . getY () ,
d e l i m i t e r L i n e L a y o u t . getEnd () . getX ()
- d e l i m i t e r L i n e L a y o u t . getStart () . getX () ,
d e l i m i t e r L i n e L a y o u t . getEnd () . getY ()
- d e l i m i t e r L i n e L a y o u t . getStart () . getY () )
for ( int j = 0; j < delimiterLines . length ; j ++) {
DelimiterLineLayoutInformation delimiterLineLayout =
targetView . g e t L a y o u t I n f o r m a t i o n (( DelimiterLine )
delimiterLines [ j ]) ;
mapping . put ( all [ i ] ,
MyGraphModelUtilities .
convertTransitionPointsKielToJGraph (
( Transition ) graphicalObject , targetView ) ) ;
}
}
return mapping ;
,
;
offset . getY () + layout . getYPos () ) ;
DelimiterLine [] delimiterLines = ( DelimiterLine [])
(( ANDState ) graphicalObject ) . g etD el imi t e r L i n e s ()
. toArray ( new DelimiterLine [0]) ;
A.4. Der Quelltext
137
138
550
540
530
520
510
500
590
// Perform the morphing ...
// the " true " ensures that the last iteration will have
if ( Preferences . g e t M o r p h i n g L a y o u t e r S t e p I n t e r v a l () > 0) {
stepDelta = ( int ) ( Preferences . g e t M o r p h i n g L a y o u t e r S t e p I n t e r v a l ()
/ cells . length ) ;
if ( stepDelta == 0) {
stepDelta = 1;
}
}
600
if (! doMorphing ) {
stepDelta = ( int ) steps ;
}
final long start = System . c u r r e n t T i m eM ill is () ;
int stepDelta = 1;
long c u r r e n t S l e e p i n g T i m e = 0;
steps = Math . round ( steps ) ;
final Object [] cells = targetMapping . keySet () . toArray () ;
final Map deltaMapping = ca l cu l at e Deltas ( cells ) ;
/**
* This method processes the morphing : first calculates the deltas to be
* performed with every step and second the iteration over the steps
count
* is performed . After every 10 steps ( can be changed in Preferences )
* the used time is checked to decide whether a sleep () or clustering of
580
* steps is needed to ensure the correct speed of the algorithm .
* @see java . lang . Runnable # run ()
*/
public synchronized void run () {
/**
* Should a real morphing be performed ? if no , then the change old - - > new
* will be done in one beat and so this MorphingLayoute r won ’ t do a real
570
* morphing .
*/
private boolean doMorphing ;
560
/**
* Holds the maximum delta of points of the most changing coordinate .
This
* defines through how many steps the morphing should be processed .
*/
private double steps ;
* morphing .
* @param targetView the target coordinates are taken from this object .
*/
public void applyNewView ( final View targetView ) {
targetMapping = c r e a t e T a r g e t M a p p i n g ( targetView ) ;
startThread ( this ) ;
}
//
//
//
//
;
lastIteration = stepCount == steps ;
+= stepDelta ;
+ stepDelta > steps ) {
= ( int ) steps - stepCount ;
= ( int ) steps ;
List target = new ArrayList () ;
Point2D [] source = ( Point2D []) GraphCons tants . getPoints (
(( DefaultGraphCel l ) cells [ i ]) . getAttributes () )
. toArray ( new Point2D [0]) ;
Point2D [] delta = ( Point2D []) deltaMapping . get ( cells [ i ])
} else if ( cells [ i ] instanceof TransitionCell ) {
GraphConstants . setBounds (
newAttributes ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
get ( source . getX () , delta . getX () ,
stepDelta , stepCount , lastIteration ) ,
get ( source . getY () , delta . getY () ,
stepDelta , stepCount , lastIteration ) ,
get ( source . getWidth () , delta . getWidth () ,
stepDelta , stepCount , lastIteration ) ,
get ( source . getHeight () , delta . getHeight () ,
stepDelta , stepCount , lastIteration ) ) ) ;
if ( cells [ i ] instanceof Del im ite rL ine C e l l ) {
System . out . println ( GraphConstants . getBounds (
newAttributes ) ) ;
}
Rectangle2D source = GraphConstants . getBounds (
(( DefaultGraphCel l ) cells [ i ]) . getAttributes () ) ;
Rectangle2D delta = ( Rectangle2D ) deltaMapping . get (
cells [ i ]) ;
} else if ( cells [ i ] instanceof NodeCell
|| cells [ i ] instanceof D el imi te rLi ne Cel l ) {
continue ;
if ( cells [ i ] instanceof Port
|| deltaMapping . get ( cells [ i ]) == null ) {
AttributeMap newAttributes = new AttributeMap () ;
for ( int i = 0; i < cells . length ; i ++) {
Map transportMap = new HashMap () ;
if ( stepCount
stepDelta
stepCount
} else {
stepCount
}
final boolean
// stepCount == steps
for ( int stepCount = 0; stepCount < steps ;) {
A. Java-Programm-Quelltext
650
640
630
620
610
//
}
transportMap . put ( cells [ i ] , newAttributes ) ;
if ( Preferences . g e t M o r p h i n g L a y o u t e r S t e p I n t e r v a l () == 0) {
// Check the morphing speed ...
final double oneSecond = 1000;
final int stepInterval =
Preferences . g e t M o r p h i n g L a y o u t e r C h e c k I n t e r v a l () ;
final int s l e e p i n g T i m e I n c r e a s e = 10;
try {
long t e m p S l e e p i n g T i m e =
( long ) (( stepCount + 1)
/ Preferences . g e t M o r p h i n g L a y o u t e r S p e e d ()
* oneSecond )
- ( System . c u r r e n tT ime Mi lli s () - start ) ;
if ( stepCount % stepInterval == 0) {
if ( stepCount == stepInterval ) { // fit only once
if ( t e m p S l e e p i n g T i m e
< -( oneSecond
/ Preferences . g e t M o r p h i n g L a y o u t e r S p e e d ()
* ( stepDelta + 1) ) ) {
// we are too slow
stepDelta ++;
if ( c u r r e n t S l e e p i n g T i m e > 0) {
c u r r e n t S l e e p i n g T i m e = 0;
}
} else if ( t e m p S l e e pingTime > oneSecond
/ Preferences . g e t M o r p h i n g L a y o u t e r S p e e d ()
* ( stepDelta - 1)
&& stepDelta > 1) { // we are too fast
stepDelta - -;
c u r r e n t S l e e p i n g T i m e += s l e e p i n g T i m e I n c r e a s e ;
}
}
if ( c u r r e n t S l e e p i n g T i m e > 0 && stepDelta == 1) {
Thread . sleep ( c u r r e n t S l e e p i n g T i m e ) ;
}
} catch ( I n t e r r u p t e d E x c e p t i o n e ) {
e . p ri n tS t ac k Tr a ce () ;
if ( stepCount == steps ) {
break ;
}
sourceGraph . getModel () . edit ( transportMap , null , null , null ) ;
}
for ( int k = 0; k < source . length ; k ++) {
target . add ( new AttributeMap . S e r i a l i z a b l e P o i n t 2 D (
get ( source [ k ]. getX () , delta [ k ]. getX () ,
stepDelta , stepCount , lastIteration ) ,
get ( source [ k ]. getY () , delta [ k ]. getY () ,
stepDelta , stepCount , lastIteration ) ) ) ;
}
Gra phCo nstan ts . setPoints ( newAttributes , target ) ;
710
700
690
680
670
660
// maybe some of the source points have to be deleted ...
while ( target . size () < sourceClone . size () ) {
sourceClone . remove (0) ;
}
// maybe some new points have to be inserted in source ...
while ( target . size () > sourceClone . size () ) {
sourceClone . add ( target . get (0) ) ;
// handle different points lengths ...
List sourceClone = ( List ) (( ArrayList ) source ) . clone () ;
sourceClone . remove ( TransitionCell . DUMMY_POINT ) ;
sourceClone . remove ( TransitionCell . DUMMY_POINT ) ;
List source = GraphConstants . getPoints (
(( DefaultGraphCel l ) cells [ i ]) . getAttributes () ) ;
List target = ( List ) targetMapping . get ( cells [ i ]) ;
} else if ( cells [ i ] instanceof TransitionCell ) {
deltaMapping . put ( cells [ i ] ,
calculateDelta ( sourceGraph . getCellBounds ( cells [ i ]) ,
( Rectangle2D ) targetMapping . get ( cells [ i ]) ) ) ;
} else if ( cells [ i ] instanceof Del im ite rL ine Ce ll ) {
deltaMapping . put ( cells [ i ] ,
calculateDelta ( sourceGraph . getCellBounds ( cells [ i ]) ,
( Rectangle2D ) targetMapping . get ( cells [ i ]) ) ) ;
} else if ( cells [ i ] instanceof NodeCell ) {
// Skip !
continue ;
if ( cells [ i ] instanceof Port ) {
for ( int i = 0; i < cells . length ; i ++) {
HashMap deltaMapping = new HashMap () ;
/**
* Calculates for each node the bounds change to be performed and for
each
* transition the points change to be performed .
* @param cells all nodes and transitions to be changed .
* @return the deltaMapping .
*/
private Map calculateDeltas ( final Object [] cells ) {
}
}
}
}
listener . morph ingFinished () ;
A.4. Der Quelltext
139
140
760
750
740
730
720
/**
}
for ( int i = 0; i < delta . length ; i ++) {
if ( Double . isInfinite ( target [ i ]. getX () )
|| Double . isInfinite ( target [ i ]. getY () ) ) {
delta [ i ] = new AttributeMap . S e r i a l i z a b l e P o i n t 2 D (0 , 0) ;
} else {
delta [ i ] = new AttributeMap . S e r i a l i z a b l e P o i n t 2 D (
target [ i ]. getX () - source [ i ]. getX () ,
target [ i ]. getY () - source [ i ]. getY () ) ;
}
if ( Math . abs ( delta [ i ]. getX () ) > steps ) {
steps = Math . abs ( delta [ i ]. getX () ) ;
}
if ( Math . abs ( delta [ i ]. getY () ) > steps ) {
steps = Math . abs ( delta [ i ]. getY () ) ;
}
}
return delta ;
if ( source == null || target == null ) {
return null ;
}
Point2D [] delta = new Point2D [ source . length ];
/**
* .
* @param source the source points .
* @param target the target points .
* @return the delta .
*/
private Point2D [] calc ulate Delt a (
final Point2D [] source , final Point2D [] target ) {
}
}
}
return deltaMapping ;
810
800
790
}
double stepValue = delta * stepDelta / steps ;
/**
* calculates the delta for a particular coordinate depending on all
these
* parameters .
* @param current the current value to be morphed .
* @param delta the complete delta for all steps altogether
* for this current value
* @param stepDelta first it will be one . if no morphing is desired ,
then
* this will be the value of steps .
* @param currentStep How many steps have already been done ?
* @param doRound has the result to be rounded ?
* @return for how much the current value has to be morphed in the
current
* step ?
*/
private double get ( final double current , final double delta ,
final int stepDelta , final double currentStep , final boolean doRound
) {
Rectangle2D delta = new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
target . getX () - source . getX () ,
target . getY () - source . getY () ,
target . getWidth () - source . getWidth () ,
target . getHeight () - source . getHeight () ) ;
if ( Math . abs ( delta . getX () ) > steps ) {
steps = Math . abs ( delta . getX () ) ;
}
if ( Math . abs ( delta . getY () ) > steps ) {
steps = Math . abs ( delta . getY () ) ;
}
if ( Math . abs ( delta . getWidth () ) > steps ) {
steps = Math . abs ( delta . getWidth () ) ;
}
if ( Math . abs ( delta . getHeight () ) > steps ) {
steps = Math . abs ( delta . getHeight () ) ;
}
return delta ;
if ( source == null || target == null ) {
return null ;
}
deltaMapping . put ( cells [ i ] ,
cal cula teDel ta (( Point2D []) GraphConstants . getPoints (
(( D e f a u l t G r a p h C e l l ) cells [ i ]) . getAttributes () )
. toArray ( new Point2D [0]) ,
( Point2D []) target . toArray ( new Point2D [0]) ) ) ;
780
770
* .
* @param source the source bounds .
* @param target the target bounds .
* @return the delta .
*/
private Rectangle2D calculateDelta (
final Rectangle2D source , final Rectangle2D target ) {
// ...
}
AttributeMap newAttributes = new AttributeMap () ;
Gra phCo nstan ts . setPoints ( newAttributes , sourceClone ) ;
HashMap transportMap = new HashMap () ;
transportMap . put ( cells [ i ] , newAttributes ) ;
sourceGraph . g et M yG r ap h Mo d el () . edit (
transportMap , null , null , null ) ;
A. Java-Programm-Quelltext
double result = current - ( currentStep * stepValue ) + (( currentStep
+ 1)
820
* stepValue ) ;
if ( doRound ) {
return Math . round ( result ) ;
}
}
} else {
return result ;
}
A.4. Der Quelltext
141
142
40
30
20
10
org . jgraph . JGraph ;
org . jgraph . graph . AttributeMap ;
org . jgraph . graph . CellHandle ;
org . jgraph . graph . CellView ;
org . jgraph . graph . GraphContext ;
org . jgraph . plaf . basic . BasicGraphUI ;
import
import
import
import
import
import
70
60
50
/**
* Just defines a mechanism to store the current preview bounds ( while
* dragging ) in the belonging cell view . This information is needed for
* checking whether the current preview position is valid or invalid
* ( red cross on the cursor ) .
/**
* The BasicGraphUI class of the JGraph framework is a hook to change the
* behaviour of mouse events and drawing child elements for example .
* MyBas icGr aphUI defines a speical handling for drawing child elements ,
since
* JGraph does not know statechart hierarchy . then there is also set the
80
kind
* of drawing : turning on an antialiasing for smooth effects and higher
* rendering quality . this is done directly on the Graphics object .
* The mouse handlers defined in this class control the popup menu , the
* changing of the Editor Modes ( core feature !) , and the delegating of mouse
* events to the EditorMode objects . The MouseHandler also turns of the
* JGraphs legacy kind of element selection . The RootHandle defined in this
* class handles some special behaviour concerning the preview feature .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 90
* @version $Revision : 1.51 $ last modified $Date : 2005/07/24 23:02:51 $
*/
class M yBasi cGra phUI extends BasicGraphUI {
kiel . editor . controller . Ac tionE ditE dit ;
kiel . editor . controller . EditorActions ;
kiel . editor . controller . E d i t o r M o d e A d d Nod e ;
kiel . editor . controller . E d i t o r M o d e A d d T r a n s i t i o n ;
kiel . editor . controller . E d i t o r M o d e S e l e c t O r D r a g O r R e s i z e O r F l i p E x p a n d ;
kiel . editor . controller . EditorModes ;
kiel . editor . graph . Previewable ;
java . awt . Graphics ;
java . awt . Graphics2D ;
java . awt . Ren derin gHin ts ;
java . awt . event . MouseEvent ;
java . awt . event . MouseListener ;
java . awt . geom . Point2D ;
java . awt . geom . Rectangle2D ;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
package kiel . editor ;
kiel.editor.MyBasicGraphUI
}
/**
/**
* Returns the associated JGraph object .
* @return the associated JGraph object .
*/
protected JGraph getGraph () {
return graph ;
}
/**
* The hook for defining an own MouseHandler .
* @see org . jgraph . plaf . basic . BasicGraphUI # c r e a t e M o u s e L i s t e n e r ()
*/
protected MouseListener c r e a t e M ou s e L i s t e n e r () {
return new MyMouseHandler () ;
}
}
for ( int i = 0; i < views . length ; i ++) {
CellView movingView = getGraph () . g e t G r a p h L a y o u t C a c h e ()
. getMapping ( views [ i ]. getCell () , false ) ;
if ( movingView instanceof Previewable ) {
if (!(( Previewable ) movingView ) . isResizing () ) {
(( Previewable ) movingView ) . setP revie w B o u n d s (
views [ i ]. getBounds () ) ;
}
}
}
/**
* Read the class description .
* @see org . jgraph . graph . CellHandle # mouseDragged (
* java . awt . event . MouseEvent )
*/
public void mouseDragged ( final MouseEvent e ) {
super . mouseDragged ( e ) ;
/**
* Constructs an instance by just calling the super constructor .
* @param context the graph context .
*/
MyRootHandle ( final GraphContext context ) {
super ( context ) ;
}
* @author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </
a>
*/
private class MyRootHandle extends RootHandle {
A. Java-Programm-Quelltext
140
130
120
110
100
180
170
160
// correct the selection done in super . mousePressed
190
CellView selected = graph . g e t G r a p h L a y o u t C a c h e () . getMapping (
graph . g e t S e l e c t i o n C ell () , false ) ;
if (! e . isControlDown () && selected != null ) {
cell = selected ;
}
// ...
if ( e . is Popu pTrig ger () && ! e . isShiftDown () ) {
handlePopupTrigger (e);
} else {
super . mousePressed ( e ) ;
/**
* Delegates the event to the current EditorMode .
* In addition a new EditorMode is set .
* @see java . awt . event . MouseListener # mousePressed (
* java . awt . event . MouseEvent )
*/
public void mousePressed ( final MouseEvent e ) {
/**
* Delegates the event to the current EditorMode .
* @see java . awt . event . M o u s e M o t i o n L i s t e n e r # mouseDragged (
* java . awt . event . MouseEvent )
*/
public void mouseDragged ( final MouseEvent e ) {
super . mouseDragged ( e ) ;
EditorModes . getCurrent () . mouseDragged (
getGraph () . fromScreen ( e . getPoint () ) ) ;
}
/**
* Delegates the event to the current EditorMode .
* @see java . awt . event . M o u s e M o t i o n L i s t e n e r # mouseMoved (
* java . awt . event . MouseEvent )
*/
public void mouseMoved ( final MouseEvent e ) {
super . mouseMoved ( e ) ;
EditorModes . getCurrent () . mouseMoved (
getGraph () . fromScreen ( e . getPoint () ) ) ;
}
150
* This is the central class for the EditorMode - classes . The
My Mouse Handl er
* receives mouse events from the graph surface and delegates them to
the
* current EditorMode object . In addition at mousePressed a new
* EditorMode is set , at mouseReleased the popup menu is shown .
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </
a>
*/
private class M yMou seHan dler extends MouseHandler {
}
. start () ;
}
}
EditorModes . getCurrent () . mousePressed ( point , e . isControlDown
EditorModes . get (
E d i t o r M o d e A d d T r a n s i t i o n . class ) . start () ;
}
} else {
EditorModes . get (
E d i t o r M o d e S e l e c t O r D r a g O r R e s i z e O r F l i p E x p a n d . class
!= null && getGraph () . isPortsVisible () ) {
// getPortViewAt () result !
if ( getGraph () . getPortViewAt ( point . getX () , point .
getGraph () . s e t J u m p T o D e f a u l t P o r t ( false ) ;
// JGraph framework
// always switches to " true " back ! That produces a
if ( getGraph () . getSelectionCe ll () != null ) {
() ,
() ,
1 , 1) , getGraph () . g e t G r a p h L a y o u t C a c h e () , true ,
null ) ;
if ( view == null ) {
return ;
// Happens when no statechart is displayed
}
Object cell = view . getCell () ;
(( MyJGraph ) getGraph () ) . g e t C u r r e n t P o p u p P o i n t () . getY
(( MyJGraph ) getGraph () ) . s e t C u r r e n t P o p u p P o i n t ( e . getPoint () ) ;
// correct right mouse clicks ( these are only popup triggers , no
// selection change !)
CellView view =
MyGraphModelUtilities . getSmallestViewOfType (
CellView . class ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
(( MyJGraph ) getGraph () ) . g e t C u r r e n t P o p u p P o i n t () . getX
/**
* Opens the context menu .
* @param e the corresponding event .
*/
private void ha n dl e P op u pT r i gg e r ( final MouseEvent e ) {
}
() ) ;
)
getY () )
wrong
) {
Point2D point = getGraph () . fromScreen ( e . getPoint () ) ;
if (!( EditorModes . getCurrent () instanceof E dit o r M o d e A d d N o d e )
A.4. Der Quelltext
143
144
240
230
220
210
200
/**
* The hook for defining an own RootHandle .
* @see org . jgraph . plaf . basic . BasicGraphUI
* # createHandle ( org . jgraph . graph . GraphContext )
*/
public CellHandle createHandle ( final GraphContext context ) {
}
/**
* Just do nothing if the cell is selected .
* @see org . jgraph . plaf . basic . BasicGraphUI . MouseHandler
* # p o s t P r o c e s s S e l e c t i o n ( java . awt . event . MouseEvent ,
* java . lang . Object , boolean )
*/
protected void p o s t P r o c e s s S e l e c t i o n ( final MouseEvent e ,
final Object cell , final boolean wasSelected ) {
}
}
250
280
270
if ( e . is Popu pTrig ger () && ! e . isShiftDown () ) {
handlePopupTrigger (e);
260
} else {
super . mouseReleased ( e ) ; // should not be called when
// is Popup Trig ger . otherwise the selection would be changed !
EditorModes . getCurrent () . mouseReleased (
getGraph () . fromScreen ( e . getPoint () ) ) ;
}
/**
* Delegates the event to the current EditorMode .
* In addion the popup menu is shown if needed .
* @see java . awt . event . MouseListener # mouseReleased (
* java . awt . event . MouseEvent )
*/
public void mouseReleased ( final MouseEvent e ) {
}
}
(( MyJGraph ) getGraph () ) . showPopup ( e . getX () , e . getY () ) ;
getGraph () . s e t S e l e c t i o n C e l l ( cell ) ;
(( MyJGraph ) getGraph () ) . s e t C u r r e n t P o p u p P o i n t ( null ) ;
return ;
if ( cell != null && getGraph () . getSelectionCell ()
!= cell ) {
}
return new MyRootHandle ( context ) ;
} else {
return null ;
}
if ( context != null && ! context . isEmpty () && getGraph () . isEnabled () )
/**
* @see org . jgraph . plaf . basic . BasicGraphUI # startEditing (
* java . lang . Object , java . awt . event . MouseEvent )
*/
protected boolean startEditing ( final Object cell , final MouseEvent event
) {
EditorActions . get ( ActionEditEdit . class ) . actionPerfor m ed ( null ) ;
return true ;
}
}
RenderingHints renderHints = new RenderingHints (
RenderingHints . KEY_ANTIALIASING ,
RenderingHints . V AL U E _A N TI A L IA S _O N ) ;
renderHints . put (
RenderingHints . KEY_RENDERING ,
RenderingHints . V A L U E _ R E N D E R _ Q U A L I T Y ) ;
(( Graphics2D ) g ) . set Re nde ri ngH in ts ( renderHints ) ;
super . paintCell (g , view , bounds , preview ) ;
// Then Paint Children
CellView [] children = view . getChildViews () ;
for ( int i = 0; i < children . length ; i ++) {
paintCell (g , children [ i ] , children [ i ]. getBounds () , preview ) ;
}
/**
* Defines a special handling for drawing child elements , since
* JGraph does not know statechart hierarchy . then there is also set the
* kind of drawing : turning on an antialiasing for smooth effects and
* higher rendering quality . this is done directly on the Graphics
object .
* @see org . jgraph . plaf . GraphUI # paintCell ( java . awt . Graphics ,
*
org . jgraph . graph . CellView , java . awt . geom . Rectangle2D ,
*
boolean )
*/
public void paintCell ( final Graphics g , final CellView view ,
final Rectangle2D bounds , final boolean preview ) {
}
{
A. Java-Programm-Quelltext
50
40
30
20
10
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
kiel . editor . graph . ANDStateCell ;
kiel . editor . graph . ANDStateView ;
kiel . editor . graph . ChoiceCell ;
kiel . editor . graph . ChoiceView ;
kiel . editor . graph . C o n d i t i o n a l T r a n s i t i o n C e l l ;
kiel . editor . graph . C o n d i t i o n a l T r a n s i t i o n V i e w ;
kiel . editor . graph . D ee p Hi s to r yC e ll ;
kiel . editor . graph . D ee p Hi s to r yV i ew ;
kiel . editor . graph . D e l i m i t e r L i n e C e l l ;
kiel . editor . graph . D e l i m i t e r L i n e V i e w ;
kiel . editor . graph . D y n a m i c C h o i c e C e l l ;
kiel . editor . graph . D y n a m i c C h o i c e V i e w ;
kiel . editor . graph . F i n a l A N D S t a t e C e l l ;
kiel . editor . graph . F i n a l A N D S t a t e V i e w ;
kiel . editor . graph . F i n a l O R S t a t e C e l l ;
kiel . editor . graph . F i n a l O R S t a t e V i e w ;
kiel . editor . graph . F i n a l S i m p l e S t a t e C e l l ;
kiel . editor . graph . F i n a l S i m p l e S t a t e V i e w ;
kiel . editor . graph . Fina lStat eCell ;
kiel . editor . graph . Fina lStat eView ;
kiel . editor . graph . F o r k C o n n e c t o r C e l l ;
kiel . editor . graph . F o r k C o n n e c t o r V i e w ;
kiel . editor . graph . HistoryCell ;
kiel . editor . graph . HistoryView ;
kiel . editor . graph . Init ialAr cCell ;
kiel . editor . graph . Init ialAr cView ;
kiel . editor . graph . I n i t i a l S t a t e C e l l ;
kiel . editor . graph . I n i t i a l S t a t e V i e w ;
kiel . editor . graph . JoinCell ;
kiel . editor . graph . JoinView ;
kiel . editor . graph . JunctionCell ;
kiel . editor . graph . JunctionView ;
kiel . editor . graph . N o r m a l T e r m i n a t i o n C e l l ;
kiel . editor . graph . N o r m a l T e r m i n a t i o n V i e w ;
kiel . editor . graph . ORStateCell ;
kiel . editor . graph . ORStateView ;
kiel . editor . graph . RegionCell ;
kiel . editor . graph . RegionView ;
kiel . editor . graph . S im p le S ta t eC e ll ;
kiel . editor . graph . S im p le S ta t eV i ew ;
kiel . editor . graph . StateCell ;
kiel . editor . graph . StateView ;
kiel . editor . graph . S t r o n g A b o r t i o n C e l l ;
kiel . editor . graph . S t r o n g A b o r t i o n V i e w ;
kiel . editor . graph . SuspendCell ;
kiel . editor . graph . SuspendView ;
kiel . editor . graph . Susp ensio nCell ;
kiel . editor . graph . Susp ensio nVie w ;
kiel . editor . graph . Sync hStat eCel l ;
package kiel . editor ;
kiel.editor.MyDefaultCellViewFactory
100
90
80
70
60
kiel . editor . graph . SynchStateView ;
kiel . editor . graph . TransitionCell ;
kiel . editor . graph . TransitionView ;
kiel . editor . graph . WeakAbortionCell ;
kiel . editor . graph . WeakAbortionView ;
if ( cell . getClass () == ANDStateCell . class ) {
/**
* @see org . jgraph . graph . D e f a u l t C e l l V i e w F a c t o r y # createVer tex V i e w (
* java . lang . Object )
*/
protected VertexView createVertexVie w ( final Object cell ) {
}
if ( cell . getClass () == C o n d i t i o n a l T r a n s i t i o n C e l l . class ) {
return new C o n d i t i o n a l T r a n s i t i o n V i e w ( cell ) ;
} else if ( cell . getClass () == InitialArcCell . class ) {
return new InitialArcView ( cell ) ;
} else if ( cell . getClass () == N o r m a l T e r m i n a t i o n C e l l . class ) {
return new N o r m a l T e r m i n a t i o n V i e w ( cell ) ;
} else if ( cell . getClass () == SuspensionCell . class ) {
return new SuspensionView ( cell ) ;
} else if ( cell . getClass () == TransitionCell . class ) {
return new TransitionView ( cell ) ;
} else if ( cell . getClass () == St r on g A bo r ti o n Ce l l . class ) {
return new S tr o ng A b or t io n V ie w ( cell ) ;
} else if ( cell . getClass () == WeakAborti onCell . class ) {
return new WeakA bortionView ( cell ) ;
} else {
return null ;
}
/**
* @see org . jgraph . graph . D e f a u l t C e l l V i e w F a c t o r y # createEdgeV iew (
* java . lang . Object )
*/
protected EdgeView createEdgeView ( final Object cell ) {
/**
* The factory for Cell views , used by MyJGraph .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.7 $ last modified $Date : 2005/03/21 22:53:57 $
*/
class M y D e f a u l t C e l l V i e w F a c t o r y extends D e f a u l t C e l l V i e w F a c t o r y {
import org . jgraph . graph . D e f a u l t C e l l V i e w F a c t o r y ;
import org . jgraph . graph . EdgeView ;
import org . jgraph . graph . VertexView ;
import
import
import
import
import
A.4. Der Quelltext
145
146
120
110
return new ANDStateView ( cell ) ;
} else if ( cell . getClass () == ChoiceCell . class ) {
return new ChoiceView ( cell ) ;
} else if ( cell . getClass () == De e pH istoryCell . class ) {
return new D ee p Hi s to r yV i ew ( cell ) ;
} else if ( cell . getClass () == D y n a m i cC hoi ce Cel l . class ) {
return new D y n a m i c C h o i c e V i e w ( cell ) ;
} else if ( cell . getClass () == F i n a l A ND Sta te Cel l . class ) {
return new F i n a l A N D S t a t e V i e w ( cell ) ;
} else if ( cell . getClass () == F i n a l ORSt ateCell . class ) {
return new F i n a l O R S t a t e V i e w ( cell ) ;
} else if ( cell . getClass () == F i n a l S i m p l e S t a t e C e l l . class ) {
return new F i n a l S i m p l e S t a t e V i e w ( cell ) ;
} else if ( cell . getClass () == Fi nalStateCell . class ) {
return new F inal State View ( cell ) ;
} else if ( cell . getClass () == F o r k C o nn ect or Cel l . class ) {
return new F o r k C o n n e c t o r V i e w ( cell ) ;
} else if ( cell . getClass () == HistoryCell . class ) {
return new HistoryView ( cell ) ;
} else if ( cell . getClass () == I n i t i alSta teCell . class ) {
return new I n i t i a l S t a t e V i e w ( cell ) ;
} else if ( cell . getClass () == JoinCell . class ) {
140
130
}
}
return new JoinView ( cell ) ;
} else if ( cell . getClass () == JunctionCell . class ) {
return new JunctionView ( cell ) ;
} else if ( cell . getClass () == ORStateCell . class ) {
return new ORStateView ( cell ) ;
} else if ( cell . getClass () == RegionCell . class ) {
return new RegionView ( cell ) ;
} else if ( cell . getClass () == SimpleStateCell . class ) {
return new SimpleStateView ( cell ) ;
} else if ( cell . getClass () == StateCell . class ) {
return new StateView ( cell ) ;
} else if ( cell . getClass () == SuspendCell . class ) {
return new SuspendView ( cell ) ;
} else if ( cell . getClass () == SynchStateCell . class ) {
return new SynchStateView ( cell ) ;
} else if ( cell . getClass () == D el imi te rLi ne Cel l . class ) {
return new Del im ite rL ine Vi ew ( cell ) ;
} else {
return null ;
}
A. Java-Programm-Quelltext
50
40
30
20
10
java . awt . Dimension ;
java . awt . geom . Point2D ;
java . awt . geom . Rectangle2D ;
java . lang . reflect . I n v o c a t i o n T a r g e t E x c e p t i o n ;
java . util . ArrayList ;
java . util . Arrays ;
java . util . Collection ;
java . util . Collections ;
java . util . Comparator ;
java . util . HashMap ;
java . util . Hashtable ;
java . util . List ;
java . util . Map ;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
kiel . dataStructure . ANDState ;
kiel . dataStructure . Choice ;
kiel . dataStructure . Com posit eSta te ;
kiel . dataStructure . CompoundLabel ;
kiel . dataStructure . C o n d i t i o n a l T r a n s i t i o n ;
kiel . dataStructure . DeepHistory ;
kiel . dataStructure . DelimiterLine ;
kiel . dataStructure . DynamicChoice ;
kiel . dataStructure . FinalANDState ;
kiel . dataStructure . FinalORState ;
kiel . dataStructure . F i n a l S i m p l e S t a t e ;
kiel . dataStructure . FinalState ;
kiel . dataStructure . ForkConnector ;
kiel . dataStructure . G r ap h ic a lO b je c t ;
kiel . dataStructure . History ;
kiel . dataStructure . InitialArc ;
kiel . dataStructure . InitialState ;
kiel . dataStructure . Join ;
kiel . dataStructure . Junction ;
kiel . dataStructure . Node ;
kiel . dataStructure . N o r m a l T e r m i n a t i o n ;
kiel . dataStructure . ORState ;
kiel . dataStructure . PseudoState ;
kiel . dataStructure . Region ;
kiel . dataStructure . SimpleState ;
kiel . dataStructure . State ;
kiel . dataStructure . StateChart ;
kiel . dataStructure . Str ongAb orti on ;
kiel . dataStructure . Suspend ;
kiel . dataStructure . Suspension ;
kiel . dataStructure . SynchState ;
kiel . dataStructure . Transition ;
kiel . dataStructure . WeakAbortion ;
import javax . swing . undo . UndoableEdit ;
import
import
import
import
import
import
import
import
import
import
import
import
import
package kiel . editor ;
kiel.editor.MyGraphModel
100
90
80
70
60
kiel . editor . graph . ANDStateCell ;
kiel . editor . graph . ChoiceCell ;
kiel . editor . graph . C o mp o si t e St a te C e ll ;
kiel . editor . graph . C o mp o si t e St a te V i ew ;
kiel . editor . graph . C o n d i t i o n a l T r a n s i t i o n C e l l ;
kiel . editor . graph . DeepHistoryCell ;
kiel . editor . graph . De lim it er Lin eC ell ;
kiel . editor . graph . Dy nam ic Ch oic eC ell ;
kiel . editor . graph . Fi nal AN DS tat eC ell ;
kiel . editor . graph . FinalORStateCell ;
kiel . editor . graph . F i n a l S i m p l e S t a t e C e l l ;
kiel . editor . graph . FinalStateCell ;
kiel . editor . graph . Fo rkC on ne cto rC ell ;
kiel . editor . graph . HistoryCell ;
kiel . editor . graph . InitialArcCell ;
kiel . editor . graph . InitialStateCell ;
kiel . editor . graph . JoinCell ;
kiel . editor . graph . JunctionCell ;
kiel . editor . graph . MyGraphConstants ;
kiel . editor . graph . NodeCell ;
kiel . editor . graph . N o r m a l T e r m i n a t i o n C e l l ;
kiel . editor . graph . ORStateCell ;
kiel . editor . graph . PseudoStateCell ;
kiel . editor . graph . RegionCell ;
kiel . editor . graph . SimpleStateCell ;
kiel . editor . graph . StateCell ;
kiel . editor . graph . S t ro n gA b o rt i on C e ll ;
kiel . editor . graph . SuspendCell ;
kiel . editor . graph . SuspensionCell ;
kiel . editor . graph . SynchStateCell ;
kiel . editor . graph . TransitionCell ;
kiel . editor . graph . WeakAbortionCell ;
kiel . editor . resources . Preferences ;
kiel . editor . resources . ResourceBundle ;
kiel . g r a p h i c a l I n f o r m a t i o n s . C o m p o s i t e S t a t e L a y o u t I n f o r m a t i o n ;
kiel . g r a p h i c a l I n f o r m a t i o n s . D e l i m i t e r L i n e L a y o u t I n f o r m a t i o n ;
kiel . g r a p h i c a l I n f o r m a t i o n s . E d g e L a y o u t I n f o r m a t i o n ;
kiel . g r a p h i c a l I n f o r m a t i o n s . L a b e l L a y o u t I n f o r m a t i o n ;
kiel . g r a p h i c a l I n f o r m a t i o n s . LinetoPath ;
kiel . g r a p h i c a l I n f o r m a t i o n s . N o d e L a y o u t I n f o r m a t i o n ;
kiel . g r a p h i c a l I n f o r m a t i o n s . Point ;
kiel . g r a p h i c a l I n f o r m a t i o n s . Properties ;
kiel . g r a p h i c a l I n f o r m a t i o n s . View ;
kiel . util . C o m p o u n d L a b e l E x c e p t i o n ;
kiel . util . C o m p o u n d L a b e l P a r s e r ;
kiel . util . LogFile ;
org . jgraph . graph . AttributeMap ;
org . jgraph . graph . CellView ;
org . jgraph . graph . ConnectionSet ;
org . jgraph . graph . Defaul tGraphCell ;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
A.4. Der Quelltext
147
148
160
150
/**
* The root of the JGraph datastructure ..
*/
private D e f a u l t G r a p h C e l l s t a t e c h a r t R o o t C e ll ;
/**
* The root for graphical informations of the KIEL datastructure .
*/
private View kielView ;
200
140
/**
* The root for topological information of the KIEL datastructure .
*/
private StateChart kie lSta techa rt ;
/**
* looks up the JGraph graph cell object for the KIEL graphical object .
* @param g r ap h ic a lO b je c t the look up key .
* @return the corresponding graph cell .
*/
public D e f a u l t G r a p h C e l l getGraphCell (
190
final G ra p hi c al O bj e ct gr a ph i ca l Ob j ect ) {
return ( D e f a u l t G r a p h C e l l ) nodesToCells . get ( graphicalObject ) ;
}
130
/**
* MyGraphModel represents the model in the MVC pattern . Mainly it contains
* functions for transforming between the KIEL datatstructure and the
* JGraph datastructure . The MyGraphModel contains the complete KIEL
* data model as well .
170
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.104 $ last modified $Date : 2005/08/02 19:27:55 $
*/
public final class MyGraphModel extends D e f aul tG rap hM ode l {
org . jgraph . graph . D e f a u l t G r a p h M o d e l ;
org . jgraph . graph . DefaultPort ;
org . jgraph . graph . Edge ;
org . jgraph . graph . GraphCell ;
org . jgraph . graph . G raphC onst ants ;
org . jgraph . graph . G r a p h L a y o u t C a c h e ;
org . jgraph . graph . ParentMap ;
org . jgraph . graph . Port ;
/**
* This mapping is used for building up the transitions in the new
* JGraph - Tree . This is needed since jgraph transitions are connected 180
to
* a parent cell , but kiel transitions are just connected by source and
* target .
*/
private Hashtable nodesToCells = new Hashtable () ;
120
110
import
import
import
import
import
import
import
import
/**
* Checks if a transition ’ s source is ok .
* @param edge is not interpreted .
* @param port checks for the parent of this port , if it accepts
outgoing
* transitions .
* @return false if the port belongs to a history cell , a deepHistory
cell
* or the root cell .
* @see org . jgraph . graph . GraphModel # acceptsSource ( java . lang . Object ,
*
java . lang . Object )
*/
public boolean acceptsSource ( final Object edge , final Object port ) {
return port != null
&& (( DefaultPort ) port ) . getParent () . getClass ()
!= FinalStateCell . class
&& (( DefaultPort ) port ) . getParent () . getClass ()
!= F i n a l S i m p l e S t a t e C e l l . class
&& (( DefaultPort ) port ) . getParent () . getClass ()
!= F in alA ND Sta te Cel l . class
&& (( DefaultPort ) port ) . getParent () . getClass ()
!= FinalORSt ateCell . class
&& (( DefaultPort ) port ) . getParent () . getClass ()
!= HistoryCell . class
&& (( DefaultPort ) port ) . getParent () . getClass ()
!= DeepHistoryCell . class
&& (( DefaultPort ) port ) . getParent ()
!= st a t ec h ar t R oo t Ce l l ;
/**
* Returns all cells of this model .
* @return all cells of this model .
*/
public DefaultGrap hCell [] getAllCells () {
return getAllCells ( s t at e c ha r tR o o tC e ll ) ;
}
/**
* The logging handle . Prints logs to standard out .
*/
private static LogFile logFile = new LogFile (" Editor " , 2) ;
/**
* Returns the model ’ s root cell .
* @return the model ’ s root cell .
*/
public DefaultGrap hCell getRootCell () {
return st a t ec h ar t Ro o t Ce l l ;
}
/**
* contains the real transition bounds .
*/
private Gr aphLayoutCache graphLayoutCache ;
A. Java-Programm-Quelltext
250
240
230
220
210
260
/**
/**
* Constructs a graph model with a root graph cell and KIEL
datastructure
* with a root node .
* @param modelSource Estudio or Matlab .
* @param a G r a p h L a y o u t C a c h e .
*/
public MyGraphModel ( final String modelSource ,
final G r a p h L a y o u t C a c h e a G r a p h L a y o u t Cac he ) {
graphLayoutCache = aGraphLayoutCache ;
kielView = new View () ;
kie lStat echa rt = new StateChart () ;
kie lStat echa rt . s etMo delSo urce ( modelSource ) ;
kie lStat echa rt . s et M od e lV e rs i on ("5.0") ;
ORState root = new ORState (
Res ourc eBund le . getString (" newStatechart ") ) ;
N o d e L a y o u t I n f o r m a t i o n r = new C o m p o s i t e S t a t e L a y o u t I n f o r m a t i o n () ;
r . setHeight ( Preferences . g e t D e f a u l t R o o t S t a t e () . height ) ;
r . setWidth ( Preferences . g e t D e f a u l t R o o t S t a t e () . width ) ;
r . s e t U p p e r L e f t P o i n t ( new kiel . g r a p h i c a l I n f o r m a t i o n s . Point (0 , 0) ) ;
kielView . s e t L a y o u t I n f o r m a t i o n ( root , r ) ;
kie lStat echa rt . setRootNode ( root ) ;
s t a t e c h a r t R o o t C e l l = add ( kie lSta techart . getRootNode () ) ;
}
310
300
290
/**
* Checks if a transition ’ s target is ok .
* @param edge is not interpreted .
* @param port checks for the parent of this port , if it accepts
incoming
* transitions .
* @return false if the port belongs to a initialState cell , a suspend
cell
* or the root cell .
270
* @see org . jgraph . graph . GraphModel # acceptsTarget ( java . lang . Object ,
*
java . lang . Object )
*/
public boolean acceptsTarget ( final Object edge , final Object port ) {
return port != null
&& (( DefaultPort ) port ) . getParent () . getClass ()
!= HistoryCell . class
&& (( DefaultPort ) port ) . getParent () . getClass ()
!= De e pH i st o ry C el l . class
&& (( DefaultPort ) port ) . getParent () . getClass ()
!= I n i t i a l S t a t e C e l l . class
280
&& (( DefaultPort ) port ) . getParent () . getClass ()
!= SuspendCell . class
&& (( DefaultPort ) port ) . getParent ()
!= s t a t e c h a r t R o o t C e l l ;
}
}
/**
* Mapping Node --> NodeCell .
* Creates a GraphCell object for the KIEL node object , for example
* returns an ANDStateCell for an ANDState . The order of the if clauses
is
* significant . This method uses instanceof in order to accept new kiel
* datastructure types .
* @param graphicalObject The object for which a JGraph object has to be
* created .
* @return A new JGraph GraphCell object .
*/
private De faultGraphCell c r ea t e Gr a ph C el l F or (
final GraphicalObject graphicalObject ) {
DefaultGra phCell cell = null ;
String name = null ;
if ( graphicalObject instanceof Node ) {
name = (( Node ) graphicalObject ) . getName () ;
}
if ( graphicalObject instanceof Choice ) {
cell = new ChoiceCell ( name ) ;
} else if ( graphicalObject instanceof DeepHistory ) {
cell = new DeepHistoryCell ( name ) ;
} else if ( graphicalObject instanceof DynamicChoice ) {
cell = new Dyn am icC ho ice Ce ll ( name ) ;
} else if ( graphicalObject instanceof ForkConnector ) {
cell = new For kC onn ec tor Ce ll ( name ) ;
} else if ( graphicalObject instanceof History ) {
cell = new HistoryCell ( name ) ;
} else if ( graphicalObject instanceof InitialState ) {
cell = new Init ialStateCell ( name ) ;
} else if ( graphicalObject instanceof Join ) {
cell = new JoinCell ( name ) ;
} else if ( graphicalObject instanceof Junction ) {
cell = new JunctionCell ( name ) ;
} else if ( graphicalObject instanceof Suspend ) {
cell = new SuspendCell ( name ) ;
} else if ( graphicalObject instanceof SynchState ) {
cell = new SynchStateCell ( name ) ;
} else if ( graphicalObject instanceof PseudoState ) {
cell = new PseudoStateCell ( name ) ;
* Constructs a model transforming the given KIEL datastructure .
* @param aStatechart The statechart to be transformed in JGraph
structure .
* @param aView The related view of this statechart .
* @param aG ra phL ay out Ca che .
*/
public MyGraphModel ( final StateChart aStatechart , final View aView ,
final GraphL ayoutCache aG rap hL ayo ut Cac he ) {
graphLayou tCache = a Gra ph Lay ou tCa ch e ;
kielView = aView ;
kielStatechart = aStatechart ;
s ta t e ch a rt R o ot C el l = add ( aStatechart . getRootNode () ) ;
}
A.4. Der Quelltext
149
150
360
350
340
330
320
}
nodesToCells . put ( graphicalObject , cell ) ;
return cell ;
/**
* Adds a node to the model , creates a NodeCell and in case of an
ANDState ,
* it calls a d d R e g i o n O r O R S t a t e () , in case of an ORState , it calls
* a d d R e g i o n O r O R S t a t e () for its regions .
* @param node The node to be added .
* @return The created GraphCell for this node .
*/
}
;
410
} else if ( g ra p hi c al O bj e ct instanceof FinalANDState ) {
cell = new F i n a l A N D S t a t e C e l l ( name ) ;
} else if ( g ra p hi c al O bj e ct instanceof ANDState ) {
cell = new ANDStateCell ( name ) ;
} else if ( g ra p hi c al O bj e ct instanceof FinalORState ) {
cell = new F i n a l O R S t a t e C e l l ( name ) ;
} else if ( g ra p hi c al O bj e ct instanceof ORState ) {
370
cell = new ORStateCell ( name ) ;
} else if ( g ra p hi c al O bj e ct instanceof Region ) {
cell = new RegionCell ( name ) ;
} else if ( g ra p hi c al O bj e ct instanceof CompositeState ) {
cell = new C o m p o s i t e S t a t e C e l l ( name ) ;
} else if ( g ra p hi c al O bj ec t instanceof FinalState ) {
cell = new Final State Cell ( name ) ;
} else if ( g ra p hi c al O bj ec t instanceof F inalSimpleState ) {
cell = new F i n a l S i m p l e S t a t e C e l l ( name ) ;
380
} else if ( g ra p hi c al O bj ec t instanceof SimpleState ) {
cell = new S im p le S ta t eC e ll ( name ) ;
} else if ( g ra p hi c al O bj ec t instanceof State ) {
cell = new StateCell ( name ) ;
} else if ( g ra p hi c al O bj ec t instanceof Node ) {
cell = new NodeCell ( name ) ;
} else if ( g ra p hi c al O bj ec t instanceof C o n d i t i o n a l T r a n s i t i o n ) {
cell = new C o n d i t i o n a l T r a n s i t i o n C e l l () ;
} else if ( g ra p hi c al O bj ec t instanceof InitialArc ) {
cell = new Initi alArc Cell ( null ) ;
} else if ( g ra p hi c al O bj ec t instanceof No rma lT erm in ati on ) {
390
cell = new N o r m a l T e r m i n a t i o n C e l l () ;
} else if ( g ra p hi c al O bj ec t instanceof StrongAbortion ) {
cell = new S t r o n g A b o r t i o n C e l l () ;
} else if ( g ra p hi c al O bj ec t instanceof Suspension ) {
cell = new Suspe nsion Cell () ;
} else if ( g ra p hi c al O bj ec t instanceof WeakAbortion ) {
cell = new W e a k A b o r t i o n C e l l () ;
} else if ( g ra p hi c al O bj ec t instanceof Transition ) {
cell = new Trans ition Cell () ;
400
} else if ( g ra p hi c al O bj ec t instanceof DelimiterLine ) {
cell = new D e l i m i t e r L i n e C e l l ( null ) ;
} else {
logFile . log (2 , " Unexpected type : " + graphicalObject . getClass () )
Point2D offset =
M y G r a p h M o d e l U t i l i t i e s . calculateOffset ( parent , kielView ) ;
offset . setLocation (
offset . getX () + parentLayout . getXPos () ,
/**
* Adds a delimiter line to the model , creates a De lim it e r L i n e C e l l .
* @param delimiterLine The delimiter line to be added .
* @param parent the delimiter line ’ s parent .
* @return The created GraphCell for this delimiter line .
*/
private De lim it erL in eCe ll add ( final DelimiterLine delimiterLine ,
final ANDState parent ) {
De li mit er Lin eC ell cell =
( Del im ite rL ine Ce ll ) cr e at e G ra p hC e l lF o r ( delimiterLine ) ;
nodesToCells . put ( delimiterLine , cell ) ;
MyGraphCon stants . s et G ra p hi c a lO b je c t ( cell . getAttributes () ,
delimiterLine ) ;
D e l i m i t e r L i n e L a y o u t I n f o r m a t i o n layout =
kielView . g e t L a y o u t I n f o r m a t i o n ( delimiterLine ) ;
if ( layout != null ) {
N o d e L a y o u t I n f o r m a t i o n parentLayout =
kielView . g e t L a y o u t I n f o r m a t i o n ( parent ) ;
private NodeCell add ( final Node node ) {
NodeCell cell = ( NodeCell ) c r ea t e Gr a ph C e ll F or ( node ) ;
M y G r a p h M o d e l U t i l i t i e s . u p d a t e K i e l P a r e n t C h i l d R e l a t i o n ( node ) ;
if ( node instanceof ORState ) {
return ad d R eg i on O r OR S ta t e (( ORState ) node , ( ORStateCell ) cell ) ;
}
nodesToCells . put ( node , cell ) ;
MyGraphCon stants . s et Nod eA ttr ib ut es ( cell . getAttributes () , node ,
kielView ) ;
ParentMap parentMap = new ParentMap () ;
if (!( node instanceof Region ) && !( node instanceof ORState ) ) {
parentMap . addEntry ( new DefaultPort () , cell ) ;
}
if ( node instanceof ANDState ) {
Region [] regions = ( Region []) (( ANDState ) node ) . getSubnodes ()
. toArray ( new Region [0]) ;
for ( int i = 0; i < regions . length ; i ++) {
parentMap . addEntry ( a dd R eg i o nO r OR S t at e ( regions [ i ] ,
new RegionCell ( regions [ i ]. getName () ) ) , cell ) ;
}
DelimiterLine [] delimiterLines = ( DelimiterLine []) (( ANDState )
node ) . g etD el imi te rLi ne s () . toArray ( new DelimiterLine [0]) ;
for ( int i = 0; i < delimiterLines . length ; i ++) {
parentMap . addEntry (
add ( delimiterLines [ i ] , ( ANDState ) node ) , cell ) ;
}
}
insert ( new Object []{ cell } , null , null , parentMap , null ) ;
return cell ;
}
A. Java-Programm-Quelltext
460
450
440
430
420
1) ;
490
/**
* Adds an ORState or Region to the model and connects this node with
its
* children ( recursively !) .
* @param node The node to be added .
* @param cell The corresponding GraphCell .
* @return the cell parameter .
*/
private NodeCell a d d R e g i o n O r O R S t a t e ( final CompositeState node ,
final C o m p o s i t e S t a t e C e l l cell ) {
500
nodesToCells . put ( node , cell ) ;
M y G r a p h C o n s t a n t s . s e t N o d e A t t r i b u t e s ( cell . getAttributes () , node ,
kielView ) ;
Node [] childNodes = null ;
if ( node instanceof C ompo siteS tate ) {
childNodes = ( Node []) (( Com positeState ) node ) . getSubnodes ()
. toArray ( new Node [0]) ;
}
M y G r a p h M o d e l U t i l i t i e s . u p d a t e K i e l P a r e n t C h i l d R e l a t i o n ( node ) ;
Map transportMap = new HashMap () ;
510
ConnectionSet cs = new ConnectionSet () ;
ParentMap parentMap = new ParentMap () ;
if (!( node instanceof Region ) ) {
parentMap . addEntry ( new DefaultPort () , cell ) ;
}
if ( childNodes != null ) {
for ( int i = 0; i < childNodes . length ; i ++) {
parentMap . addEntry ( add ( childNodes [ i ]) , cell ) ;
}
// ( for insert )
520
for ( int i = 0; i < childNodes . length ; i ++) {
}
}
}
insert ( new Object []{ cell } , null , null , null , null ) ;
return cell ;
() ,
offset . getY () + parentLayout . getYPos () ) ;
470
Rectangle2D bounds = new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
layout . getStart () . getX () + offset . getX () ,
layout . getStart () . getY () + offset . getY () ,
layout . getEnd () . getX () - layout . getStart () . getX () ,
layout . getEnd () . getY () - layout . getStart () . getY () ) ;
Gra phCo nstan ts . setBounds ( cell . getAttributes () , bounds ) ;
if ( bounds . getWidth () == 0) {
bounds . setRect ( bounds . getX () , bounds . getY () , 1 ,
bounds . getHeight () ) ;
480
}
if ( bounds . getHeight () == 0) {
bounds . setRect ( bounds . getX () , bounds . getY () , bounds . getWidth
N o d e L a y o u t I n f o r m a t i o n r = null ;
// 1. Create a KIEL - node object ...
Node node = M y G r a p h M o d e l U t i l i t i e s . cre at eKI EL Nod eF or ( nodeClass ) ;
/**
* Is called by Edi to rMo de Ad dNo de . doPlaceAction () . Creates
* a KIEL datastructure object and fills the KIEL view with the current
* mouse coordinates and the init ialDimension for the nodeClass
* @param nodeClass Which kind of node has to be created ?
* @param x The x - coordinate for the new node .
* @param y The y - coordinate for the new node .
* @param aG rap hL ayo ut Cac he .
*/
public void addNode ( final Class nodeClass , final double x , final double
y,
final GraphL ayoutCache aG rap hL ayo ut Cac he ) {
}
if ( layout . g e tA l lP a th E l em e nt s () != null
&& layout . g et A ll P a th E le m e nt s () . size () > 2
&& layout . g et A ll P a th E le m e nt s () . get (1)
instanceof LinetoPath ) {
GraphConstants . setLineStyle (
newAttributes , GraphConstants . STYLE _ O R T H O G O N A L ) ;
}
GraphConstants . setPoints ( newAttributes ,
MyGraphModelUtilities
. convertTransitionPointsKielToJGraph (
o u t g o i n g T r a n s i t i o n s [ j ] , kielView ) ) ;
transportMap . put ( transitionCell , newAttributes ) ;
}
}
}
insert ( new Object []{ cell } , transportMap , cs , parentMap , null ) ;
return cell ;
]) ;
Node child = ( Node ) childNodes [ i ];
Transition [] o u t g o i n g T r a n s i t i o n s = ( Transition []) child
. g e t O u t g o i n g T r a n s i t i o n s () . toArray ( new Transition [0]) ;
for ( int j = 0; j < o u t g o i n g T r a n s i t i o n s . length ; j ++) {
TransitionCell transitionCell = ( TransitionCe ll )
c re a t eG r ap h C el l Fo r ( o u t g o i n g T r a n s i t i o n s [ j ]) ;
AttributeMap newAttributes = new AttributeMap () ;
cs . connect ( transitionCell ,
getGraphCell ( child ) . getChildAt (0) ,
getGraphCell ( o u t g o i n g T r a n s i t i o n s [ j ]. getTarget () )
. getChildAt (0) ) ;
parentMap . addEntry ( transitionCell , cell ) ;
MyGraphCon stants . s e t T r a n s i t i o n A t t r i b u t e s ( newAttributes ,
o u t g o i n g T r a n s i t i o n s [ j ]) ;
// Set Line Style ...
E d g e L a y o u t I n f o r m a t i o n layout =
kielView . g e t L a y o u t I n f o r m a t i o n ( o u t g o i n g T r a n s i t i o n s [ j
A.4. Der Quelltext
151
152
570
560
550
540
530
590
Object cell = g e t S m a l l e s t C e l l O f T y p e ( GraphCell . class ,
new Rectangle2D . Double ( p . getX () , p . getY () , 1 , 1) , false ) ;
if ( cell == null
|| !( cell instanceof C o m p o s i t e St a te C e ll )
610
|| M y G r a p h C o n s t a n t s . isCollapsed (
(( D e f a u l t G r a p h C e l l ) cell ) . getAttributes () )
|| ( e xc l ud e Ro o tC e ll && cell == s t at e ch a r tR o ot C e ll )
|| ! Arrays . asList ( c h e c k e d C e ll C la s s es ) . contains (
cell . getClass () ) ) {
return false ;
} else {
List children = (( C o m p o s i t e S t a t e C e ll ) cell ) . getChildren () ;
boolean existsAlready = false ;
for ( int i = 0; ! existsAlready && i < children . size () ; i ++) {
620
if ( children . get ( i ) . getClass () == aCellClass ) {
existsAlready = true ;
}
}
return ! existsAlready ;
}
/**
* Is called by EditorMode . i s Va l id P os i tion () . Checks if a node of a
* particular type can be added to the graph at the given position .
* @param aCellClass which type of k ielStatechart element should be
* tested to create ?
* @param p at which point should the kielStatechart element be placed ?
* @param c h e c k e d C e l l C l a s s e s which are the generally accepted parent
* classes ? ( ORState and Region for InitialStates for example )
* @param e x cl u de R oo tC e ll Is the kiel Statechart root cell generally an
* acceptable place for the new element ?
600
* @return true if can be added .
*/
public boolean canBeAdded ( final Class aCellClass , final Point2D p ,
final Class [] checkedCellClasses , final boolean excludeRootCell )
{
}
// 2. Transform to JGraph - nodeCell object ...
NodeCell cell = add ( node ) ;
changeParent ( cell , a G r a p h L a y o u t C a c h e ) ;
if ( node instanceof C ompo siteS tate ) {
r = new C o m p o s i t e S t a t e L a y o u t I n f o r m a t i o n () ;
} else {
r = new N o d e L a y o u t I n f o r m a t i o n () ;
}
r . s e t U p p e r L e f t P o i n t ( new kiel . g r a p h i c a l I n f o r m a t i o n s . Point (
580
( int ) x , ( int ) y ) ) ;
r . setHeight ( M y G r a p h M o d e l U t i l i t i e s . g e t I n i t i a l D i m e n s i o n O f ( nodeClass )
. height ) ;
r . setWidth ( M y G r a p h M o d e l U t i l i t i e s . g e t I n i t i a l D i m e n s i o n O f ( nodeClass )
. width ) ;
kielView . s e t L a y o u t I n f o r m a t i o n ( node , r ) ;
Rectangle2D initialBounds =
new Rectangle2D . Double (x , y , d . width , d . height ) ;
return intersect ( null , initialBounds , true , null , false ) ;
Dimension d = M y G r a p h M o d e l U t i l i t i e s . g e t I n i t i a l D i m e n s i o n O f ( nodeClass )
i)
if ( parent instanceof ANDStateCell ) {
for ( int j = 0; j < parent . getChildCount () ; j ++) {
if (! parentsNewBounds . intersects (
M y G r a p h M o d e l U t i l i t i e s . getBoundsOf (
parent . getChildAt ( j ) , false ) )
&& !( parent . getChildAt ( j )
instanceof Port )
&& !( parent . getChildAt ( j )
instanceof D eli mi ter Li ne C e l l )
&& !( parent . getChildAt ( j )
instanceof TransitionCell ) ) {
// TODO Take care of the ports !?
, false ) )
&& !( parent . getChildAt ( i ) instanceof Port )
&& !( parent . getChildAt ( i ) instanceof De l i m i t e r L i n e C e l l )
&& !( parent . getChildAt ( i ) instanceof Trans itio nCell ) ) {
// TODO Take care of the ports !?
for ( int i = 0; i < parent . getChildCount () ; i ++) {
if (! parentsNewBounds . contains (
M y G r a p h M o d e l U t i l i t i e s . getBoundsOf ( parent . getChildAt (
/**
* Checks if all children of the given graph cell are inside of a given
* rectangle . This method can be used to check , if a resizing of a
parent
* state is allowed .
* @param parent the cell whose children are to be checked .
* @param parentsNewBounds Are these children in these new bounds ?
* @return true if all children are spatially inside its parent .
*/
public boolean a r e A l l C h i l d r e n I n s i d e ( final DefaultGraphCe l l parent ,
final Rectangle2D parentsNew Bounds ) {
}
;
/**
* Checks if a node of the given class would intersect any other node if
* the node is placed at the given coordinates .
* @param nodeClass which type of node ?
* @param x placing position
* @param y placing position
* @return true if intersects
*/
public boolean intersect ( final Class nodeClass , final double x ,
final double y ) {
}
A. Java-Programm-Quelltext
670
660
650
640
630
}
return true ;
690
680
);
} else if ( excludedCell != null ) {
a l l E x c l u d e d C e l l s . add ( excludedCell ) ;
730
D e f a u l t G r a p h C e l l [] all = getAllCells () ;
List a l l E x c l u d e d C e l l s = new ArrayList () ;
if ( e x c l u d e C h i l d r e n O f E x c l u d e d C e l l ) {
a l l E x c l u d e d C e l l s . addAll ( Arrays . asList ( getAllCells ( excludedCell ) )
/**
* Checks whether the given testBounds intersect one of the graph cell
710
* bounds except for the excluded cell ( and except
* the children of the excluded cell ) .
* @param excludedCell the cell which is dragged
* @param testBounds the cell which is moving or the preview of the
* dragged cell
* @param e x c l u d e C h i l d r e n O f E x c l u d e d C e l l .
* @param a n Ex c lu d ed C el l s .
* @param orContain if true , then return true if intersect OR contain
* @return true if intersect
*/
720
public boolean intersect ( final GraphCell excludedCell ,
final Rectangle2D testBounds ,
final boolean e xcl ud eC hi ld ren Of Ex cl udedCell ,
final List anExcludedCells , final boolean orContain ) {
/**
* Returns all GraphCells of the GraphModel starting at the given root
cell .
700
* @param rootCell Starting point in the hierarchy .
* @return All cells below the given root cell .
*/
private D e f a u l t G r a p h C e l l [] getAllCells ( final Object rootCell ) {
return ( D e f a u l t G r a p h C e l l []) getD escendants ( this ,
new Object [] { rootCell }) . toArray ( new DefaultGraphCell [0]) ;
}
}
}
return false ;
}
}
for ( int j = 0; j < parent . getChildCount () ; j ++) {
boolean b = a r e A l l C h i l d r e n I n s i d e (
( D e f a u l t G r a p h C e ll ) parent . getChildAt ( j ) ,
parentsNewBounds );
if (! b ) {
return false ;
}
}
} else {
return false ;
}
/**
* Checks if aCell ’ s bounds intersect bBounds .
* @param aCell .
* @param bBounds .
* @param o r B B o u n d s C o n t a i n s A C e l l if true , then return true if
* intersect or ( bBounds contain aCell )
* @return true if intersects .
*/
public boolean intersect ( final De faultGraphCell aCell ,
final Rectangle2D bBounds , final boolean o r B B o u n d s C o n t a i n s A C e l l ) {
/**
* .
* @param cell .
* @return .
*/
private boolean isInvisible ( final Defa ultGraphCell cell ) {
DefaultGra phCell parent = ( Defaul tGraphCell ) cell . getParent () ;
while ( parent != null ) {
if ( MyG raphConstants . isCollapsed ( parent . getAttributes () ) ) {
return true ;
}
parent = ( DefaultGrap hCell ) parent . getParent () ;
}
return false ;
}
}
}
if ( anExcludedCells != null ) {
allExclud edCells . addAll ( anExcludedCells ) ;
}
for ( int i = 0; i < all . length ; i ++) {
if (! allExcludedCell s . contains ( all [ i ])
&& !( all [ i ] instanceof TransitionCell )
&& !( all [ i ] instanceof D el imi te rLi ne Cel l )
&& !( all [ i ] instanceof Port )
&& ! isInvisible ( all [ i ]) ) {
if ( all [ i ] == null ) {
logFile . log (2 , " kielGraphModel . intersect Null - Value ") ;
} else if ( intersect ( all [ i ] , testBounds , orContain )
&& !( excludedCell instanceof ANDStateCell
&& all [ i ] instanceof RegionCell )
&& !( excludedCell instanceof D eli mi ter Li neC e l l
&& all [ i ] instanceof RegionCell )
&& !( excludedCell instanceof D eli mi ter Li neC e l l
&& all [ i ] instanceof ANDStateCell )
) {
// Resize ANDState
return true ;
}
}
}
return false ;
A.4. Der Quelltext
153
154
780
770
760
750
740
/**
* Finds out the smallest element which contains the given cell ’ s bounds
* completely . This is used whenever the given cell has been moved and
830
you
* want to assign to it the new spatial parent .
* @param child .
* @param a G r a p h L a y o u t C a c h e .
*/
public void changeParent ( final D e f a u l t G raphCell child ,
}
800
if ( aBounds . getWidth () < bBounds . getWidth () ) {
t h e B i g s V a l i d A r e a = bBounds ;
theSmall = aBounds ;
theBig = bBounds ;
} else {
t h e B i g s V a l i d A r e a = M y G r a p h M o d e l U t i l i t i e s . getValidArea ( aCell ) ; 810
theSmall = bBounds ;
theBig = aBounds ;
}
final boolean onl yInte rsec ts =
(! theBig . contains ( theSmall ) && theBig . intersects ( theSmall ) )
|| (! t h e B i g s V a l i d A r e a . contains ( theSmall )
&& t h e B i g s V a l i d A r e a . intersects ( theSmall ) )
|| ( theBig . contains ( theSmall )
&& ! t h e B i g s V a l i d A r e a . contains ( theSmall ) ) ;
820
if (! o r B B o u n d s C o n t a i n s A C e l l ) {
return o nlyIn terse cts ;
} else {
return o nlyIn terse cts || bBounds . contains ( aBounds ) ;
}
if ( aBounds == null ) {
logFile . log (2 , " aBounds is null ") ;
return true ;
}
if ( bBounds == null ) {
logFile . log (2 , " bBounds is null ") ;
return true ;
}
Rectangle2D t h e B i g s V a l i d A r e a = null ;
Rectangle2D theSmall = null ;
Rectangle2D theBig = null ;
Rectangle2D aBounds = M y G r a p h M o d e l U t i l i t i e s
. getBoundsOf ( aCell , false ) . getBounds2D () ;
aBounds . setRect (
aBounds . getX () - Preferences . g e t I n t e r s e c t i o n S e n s i t i v i t y () ,
aBounds . getY () - Preferences . g e t I n t e r s e c t i o n S e n s i t i v i t y () ,
aBounds . getWidth () + 2 * Preferences . g e t I n t e r s e c t i o n S e n s i t i v i t y
790
() ,
aBounds . getHeight () + 2 * Preferences . g e t I n t e r s e c t i o n S e n s i t i v i t y
() ) ;
}
/**
* Copies all attributes , the parent map and connection set of fromCell
to
* toCell .
* @param fromCell .
* @param toCellClass .
/**
* Sets the cell ’ s parent according to its attached KIEL node ’ s parent .
* @param cell .
*/
private void updateKielP arent ( final GraphCell cell ) {
if ( cell instanceof NodeCell ) {
NodeCell nodeCell = ( NodeCell ) cell ;
Node node = ( Node ) MyGraphConstant s . ge t Gr a p hi c al O b j e c t (
nodeCell . getAttributes () ) ;
if ( getRootCell () == cell ) {
node . setParent ( null ) ;
} else {
node . setParent (( CompositeState )
MyGraphCon stants . ge t G ra p hi c a lO b je c t ((( D e f a u l t G r a p h C e l l )
nodeCell . getParent () ) . getAttributes () ) ) ;
}
}
}
}
ParentMap parentMap = new ParentMap () ;
parentMap . addEntry ( child , new Sm all es tPa re nt . getCell () ) ;
edit ( null , null , parentMap , null ) ;
// setParent ...
updateKie lParent ( child ) ;
DefaultGra phCell cell = child ;
if ( cell instanceof TransitionCell ) {
cell = ( Def aultGraphCell ) (( DefaultPort ) (( Transit ionC ell ) cell )
. getSource () ) . getParent () ;
}
Rectangle2D cellBounds =
GraphConstants . getBounds ( cell . getAttributes () ) . getBounds2D () ;
// consider the case that 2 states with same bounds overlap each
other
cellBounds . setRect ( cellBounds . getX () - 1 , cellBounds . getY () - 1 ,
cellBounds . getWidth () + 1 , cellBounds . getHeight () + 1) ;
CellView new Sm all es tPa re nt =
MyGraphModelUtilities . getSmallestViewOfType (
C om p o si t eS t a te V ie w . class , cellBounds , aGraphLayoutCache , true ,
cell ) ;
if ( new Sm all es tP are nt != null
&& n ew Sma ll est Pa ren t . getCell () /* NEW */
!= (( DefaultGraphCel l ) child ) . getParent () ) {
final GraphL ayoutCache aG rap hL ayo ut Cac he ) {
A. Java-Programm-Quelltext
880
870
860
850
840
{
(i);
930
Edge [] edges =
( Edge []) fromCellPort . getEdges () . toArray ( new Edge [0]) ;
for ( int eCount = 0; eCount < edges . length ; eCount ++) {
if ( edges [ eCount ]. getSource () == fromCell . getChildAt ( i )
&& edges [ eCount ]. getTarget () == fromCell . getChildAt ( i ) )
DefaultPort toCellPort = new DefaultPort () ;
DefaultPort fromCellPort = ( DefaultPort ) fromCell . getChildAt
for ( int i = 0; i < fromCell . getChildCount () ; i ++) {
if ( fromCell . getChildAt ( i ) instanceof Port ) {
* @return .
*/
public D e f a u l t G r a p h C e l l convert ( final D e faultGraphCell fromCell ,
final Class toCellClass ) {
D e f a u l t G r a p h C e l l toCell = null ;
try {
890
toCell = ( D e f a u l t G r a p h C e l l ) toCellClass . getConstructor (
new Class [] { Object . class }) . newInstance ( new Object [1]) ;
} catch ( I n s t a n t i a t i o n E x c e p t i o n e ) {
e . p ri n tS t ac k Tr a ce () ;
} catch ( I l l e g a l A c c e s s E x c e p t i o n e ) {
e . p ri n tS t ac k Tr a ce () ;
} catch ( I n v o c a t i o n T a r g e t E x c e p t i o n e ) {
e . p ri n tS t ac k Tr a ce () ;
} catch ( N o S u c h M e t h o d E x c e p t i o n e ) {
900
e . p ri n tS t ac k Tr a ce () ;
}
g e t C u r r e n t S t a t e C h a r t () ; // Update the cells bounds ...
// Store the current fromCell KIEL data structure
G ra p hi c al O bj e ct f r o m G r a p h i c a l O b j e c t =
M y G r a p h C o n s t a n t s . g e t G r a p h i c a l O b je c t ( fromCell . getAttributes () ) ;
Transition [] i n c o m i n g T r a n s i t i o n s = new Transition [0];
Transition [] o u t g o i n g T r a n s i t i o n s = new Transition [0];
if ( f r o m G r a p h i c a l O b j e c t instanceof Node ) {
i n c o m i n g T r a n s i t i o n s = ( Transition []) (( Node ) f r o m G r a p h i c a l O b j e c t
910
)
. g e t I n c o m i n g T r a n s i t i o n s () . toArray ( new Transition [0]) ;
o u t g o i n g T r a n s i t i o n s = ( Transition []) (( Node ) f r o m G r a p h i c a l O b j e c t
)
. g e t O u t g o i n g T r a n s i t i o n s () . toArray ( new Transition [0]) ;
}
// ********** 1. UPDATE THE GRAPH CELL ... **********
Map transportMap = new HashMap () ;
ConnectionSet cs = new ConnectionSet () ;
ParentMap parentMap = new ParentMap () ;
920
parentMap . addEntry ( fromCell , null ) ;
parentMap . addEntry ( toCell , fromCell . getParent () ) ;
transportMap . put ( toCell , fromCell . getAttributes () . clone () ) ;
toCell . setUserObject ( fromCell . getUserObject () ) ; // TODO Necessary ?
toNode . setParent ( fromNode . getParent () ) ;
(( CompositeState ) fromNode . getParent () ) . removeSubnode ( fromNode ) ;
(( CompositeState ) fromNode . getParent () ) . addSubnode ( toNode ) ;
// A . Parent - Child relation ...
Node fromNode = ( Node ) f r o m G r a p h i c a l O b j e c t ;
Node toNode = ( Node ) toG ra phi ca lOb je ct ;
GraphicalObject toG ra phi ca lOb je ct =
c r e a t e K I E L E l e m e n t F o r ( toCell , ( GraphCell ) toCell . getParent () ) ;
// ********** 2. UPDATE THE GRAPHICAL OBJECT ... **********
if ( toCell instanceof NodeCell ) {
}
if ( toCell instanceof TransitionCell ) {
cs . connect (
toCell ,
(( TransitionCell ) fromCell ) . getSource () ,
(( TransitionCell ) fromCell ) . getTarget () ) ;
}
remove ( new Object []{ fromCell }) ;
insert ( new Object []{ toCell } , transportMap , null , parentMap , null ) ;
insert ( cs . getChangedEdges () . toArray () , null , cs , null , null ) ;
}
parentMap . addEntry ( fromCellPort , null ) ;
parentMap . addEntry ( toCellPort , toCell ) ;
} else {
parentMap . addEntry ( fromCell . getChildAt ( i ) , toCell ) ;
}
}
parentMap . addEntry ( edges [ eCount ] , fromCell . getParent () ) ;
cs . disconnect ( edges [ eCount ] , false ) ;
cs . connect (
edges [ eCount ] ,
edges [ eCount ]. getSource () ,
toCellPort ) ;
cs . disconnect ( edges [ eCount ] , true ) ;
cs . connect (
edges [ eCount ] ,
toCellPort ,
edges [ eCount ]. getTarget () ) ;
} else if ( edges [ eCount ]. getTarget ()
== fromCell . getChildAt ( i ) ) {
cs . disconnect ( edges [ eCount ]) ;
cs . connect (
edges [ eCount ] ,
toCellPort ,
toCellPort ) ;
} else if ( edges [ eCount ]. getSource ()
== fromCell . getChildAt ( i ) ) {
A.4. Der Quelltext
155
156
980
970
960
950
940
i n c o m i n g T r a n s i t i o n s [ i ]. setSource (
i n c o m i n g T r a n s i t i o n s [ i ]. getSource () ) ;
o u t g o i n g T r a n s i t i o n s [ i ]. setTarget (
o u t g o i n g T r a n s i t i o n s [ i ]. getTarget () ) ;
}
Node [] children = ( Node []) // TODO necessary ?
kie lSta techa rt . getRootNode () . getSubnodes () . toArray ( new Node
1030
// D . Outgoing Transitions ...
for ( int i = 0; i < o u t g o i n g T r a n s i t i o n s . length ; i ++) {
toNode . g e t O u t g o i n g T r a n s i t i o n s () . remove ( o u t g o i n g T r a n s i t i o n s [ i
1020
o u t g o i n g T r a n s i t i o n s [ i ]. setSource ( toNode ) ;
o u t g o i n g T r a n s i t i o n s [ i ]. getTarget ()
. g e t I n c o m i n g T r a n s i t i o n s () . remove ( o u t g o i n g T r a n s i t i o n s [ i ])
}
i n c o m i n g T r a n s i t i o n s [ i ]. setTarget ( toNode ) ;
1010
i n c o m i n g T r a n s i t i o n s [ i ]. getSource ()
. g e t O u t g o i n g T r a n s i t i o n s () . remove ( i n c o m i n g T r a n s i t i o n s [ i ])
AttributeMap newAttributes = new AttributeMap () ;
M y G r a p h C o n s t a n t s . s e t N o d e A t t r i b u te s (
newAttributes , toNode , kielView ) ;
transportMap = new HashMap () ;
transportMap . put ( toCell , newAttributes ) ;
edit ( transportMap , null , null , null ) ;
} else {
Transition fro mTra nsiti on = ( Transition ) f r o m G r a p h i c a l O b j e c t ;
[0]) ;
;
]) ;
;
]) ;
1000
990
// C . Incoming Transitions ...
for ( int i = 0; i < i n c o m i n g T r a n s i t i o n s . length ; i ++) {
toNode . g e t I n c o m i n g T r a n s i t i o n s () . remove ( i n c o m i n g T r a n s i t i o n s [ i
}
(( Com posit eSta te ) toNode ) . addLocalEvents (
(( Com posit eSta te ) fromNode ) . getLocalEvents () ) ;
(( Com posit eSta te ) toNode ) . addVariables (
(( Com posit eSta te ) fromNode ) . getVariables () ) ;
// B . Variables and Events ...
if ( fromNode instanceof State && toNode instanceof State ) {
(( State ) toNode ) . setDoActivity (
(( State ) fromNode ) . getDoActivity () ) ;
(( State ) toNode ) . setEntry (
(( State ) fromNode ) . getEntry () ) ;
(( State ) toNode ) . setExit (
(( State ) fromNode ) . getExit () ) ;
}
if ( fromNode instanceof Comp ositeState
&& toNode instanceof Comp ositeState ) {
/**
* .
* @param i s V e r t i c a l D e l i m i t e r .
* @param bounds .
* @param c o m p o s i t e S t a t e U p p e r O f f s e t .
* @param start .
* @param end .
* @param regionCell1 .
* @param regionCell2 .
*/
private void setRegionBounds ( final boolean isVerticalDelimiter ,
final Rectangle2D bounds , final int compositeStateUpperOffset ,
final Point2D start , final Point2D end ,
final RegionCell regionCell1 , final RegionCell regionCell2 ) {
if ( i s V e r t i c a l D e l i m i t e r ) {
final double leftNewWidth = start . getX () - bounds . getX () ;
GraphConstants . setBounds ( regionCell1 . getAttributes () ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
bounds . getX () ,
start . getY () ,
leftNewWidth ,
end . getY () - start . getY () ) ) ;
GraphConstants . setBounds ( regionCell2 . getAttributes () ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
Transition toTransition = ( Transition ) toG ra phi c a l O b j e c t ;
// update the grpahicalObject ...
toTransition . setSource ( fromTransition . getSource () ) ;
toTransition . setTarget ( fromTransition . getTarget () ) ;
toTransition . setPriority ( fromTransition . getPriority () ) ;
toTransition . setLabel ( fromTransition . getLabel () ) ;
// Prio - Fix
toTransition . getSource () . a d d O u t g o i n g T r a n s i t i o n ( toTransition ) ;
//
toTransition . getTarget () . a d d I n c o m i n g T r a n s i t i o n ( toTransition ) ;
fromTransition . getSource () . r e m o v e O u t g o i n g T r a n s i t i o n (
fromTransition ) ;
fromTransition . getTarget () . r e m o v e I n c o m i n g T r a n s i t i o n (
fromTransition ) ;
kielView . put (
toTransition . getID () ,
kielView . g e t L a y o u t I n f o r m a t i o n ( fromTransition ) ) ;
AttributeMap newAttributes = new AttributeMap () ;
MyGraphCo nstants . s e t T r a n s i t i o n A t t r i b u t e s (
newAttributes , toTransition ) ;
GraphConstants . setPoints ( newAttributes ,
MyGraphModelUtilities . convertTransitionPointsKielToJGraph (
toTransition , kielView ) ) ;
transportMap = new HashMap () ;
transportMap . put ( toCell , newAttributes ) ;
edit ( transportMap , null , null , null ) ;
}
// @TODO What should be done here ? Take care of undo support !
//
kielView . r e m o v e L a y o u t I n f o r m a t i o n ( f r o m G r a p h i c a l O b j e c t ) ;
return toCell ;
}
A. Java-Programm-Quelltext
1080
1070
1060
1050
1040
//
//
//
//
//
//
1100
1090
if ( cell == null || cell == s t a t e c h a r t Ro o tC e ll ) {
return ;
}
GraphCell [] children =
( GraphCell []) cell . getChildren () . toArray ( new GraphCell [0]) ;
ParentMap parentMap = new ParentMap () ;
if ( cell instanceof ORStateCell ) {
Port oldPort = null ;
for ( int i = 0; i < cell . getChildCount () ; i ++) {
if ( cell . getChildAt ( i ) instanceof Port ) {
oldPort = ( Port ) cell . getChildAt ( i ) ;
}
}
cell = ( StateCell ) convert ( cell , ANDStateCell . class ) ;
1140
1130
/**
1110
* First calculates which state will get the delimiter line , then
converts
* to an ANDState , if the calculated state is an ORState , and then
either
* the target state will get one new region or two . The children have to
* copied to the new parents (= regions ) . ( This is the most sophisticate
and
* complex method of MyGraphModel : - p )
* @param start .
1120
* @param end .
*/
public void addDelimiter ( final Point2D start , final Point2D end ) {
// Which state gets a delimiter line (= at least one new region ?)
g e t C u r r e n t S t a t e C h a r t () ; // TODO avoid access to KIEL
StateCell cell = ( StateCell ) g e t S m a l l e s t C e l l O f T y p e (
C o m p o s i t e S t a t e C e l l . class ,
new Rectangle2D . Double ( start . getX () , start . getY () , 1 , 1) , false )
;
}
} else {
final double uppe rNewH eigh t = start . getY () - bounds . getY ()
- compositeStateUpperOffset ;
Gra phCo nstan ts . setBounds ( regionCell1 . getAttributes () ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
bounds . getX () ,
bounds . getY () + compositeStateUpperOffset ,
bounds . getWidth () , upp erNewHeight ) ) ;
Gra phCo nstan ts . setBounds ( regionCell2 . getAttributes () ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
bounds . getX () , start . getY () , bounds . getWidth () ,
bounds . getHeight () - u pperNewHeight
- compositeStateUpperOffset ));
}
start . getX () ,
start . getY () ,
bounds . getWidth () - leftNewWidth ,
end . getY () - start . getY () ) ) ;
//
//
//
//
//
//
);
// 2. Region
regionParentMap = new ParentMap () ;
childrenToMove = ge t B ou n de d C hi l dr e n ( children , GraphCo nstan ts
. getBounds ( regionCell2 . getAttributes () ) ) ;
for ( int i = 0; i < childrenToMove . length ; i ++) {
regionParentMap . addEntry ( childrenToMove [ i ] , regionCell2 ) ;
}
insert (
parentMap . addEntry ( oldPort , cell ) ;
}
// now cell is a regionCell or an empty AndStateCell
final boolean i s V e r t i c a l De l i m i t e r = start . getX () == end . getX () ;
Rectangle2D bounds = GraphConstants . getBounds ( cell . getAttributes () ) ;
CompositeState compositeState = ( CompositeState ) MyGraph C o n s t a n t s
. g et G ra p h ic a lO b j ec t ( cell . getAttributes () ) ;
Rectangle2D c o m p o s i t e S t a t e C e l l B o u n d s = bounds ;
if ( compositeState instanceof Region ) {
compositeState = compositeState . getParent () ;
c o m p o s i t e S t a t e C e l l B o u n d s = GraphConstants . getBounds (
(( GraphCell ) cell . getParent () ) . getAttributes () ) ;
}
final int c o m p o s i t e S t a t e U p p e r O f f s e t =
Properties . getUpperOffset ( compositeState ) ;
// correct start and end point
if ( i s V e r t i c a l D e l i m i t e r ) {
start . setLocation ( start . getX () , c o m p o s i t e S t a t e C e l l B o u n d s . getY ()
+ compositeStateUpperOffset );
end . setLocation ( end . getX () , bounds . getY () + bounds . getHeight () ) ;
} else {
start . setLocation ( bounds . getX () , start . getY () ) ;
end . setLocation ( bounds . getX () + bounds . getWidth () , end . getY () ) ;
}
// create Regions ...
if ( cell instanceof ANDStateCell ) {
// has no region yet and gets 2 new ones
RegionCell regionCell1 = new RegionCell ( null ) ;
RegionCell regionCell2 = new RegionCell ( null ) ;
MyGraphCo nstants . set No deA tt rib ut es ( regionCell1 . getAttributes () ,
( Region ) c r e a t e K I E L E l e m e n t F o r ( regionCell1 , cell ) , kielView ) ;
MyGraphCo nstants . set No deA tt rib ut es ( regionCell2 . getAttributes () ,
( Region ) c r e a t e K I E L E l e m e n t F o r ( regionCell2 , cell ) , kielView ) ;
setRegionBounds ( isVerticalDelimiter , bounds ,
compositeStateUpperOffset , start , end ,
regionCell1 , regionCell2 ) ;
// 1. Region
ParentMap regionParentMap = new ParentMap () ;
GraphCell [] childrenToMove = g et B ou n d ed C hi l d re n ( children ,
GraphConstants . getBounds ( regionCell1 . getAttributes () ) ) ;
for ( int i = 0; i < childrenToMove . length ; i ++) {
regionParentMap . addEntry ( childrenToMove [ i ] , regionCell1 ) ;
}
insert (
new Object []{ regionCell1 } , null , null , regionParentMap , null
A.4. Der Quelltext
157
158
1190
1180
1170
1160
1150
);
new Object []{ regionCell2 } , null , null , regionParentMap , null
1230
}
DelimiterLine delimiterLine = new DelimiterLine () ;
ANDState parent = ( ANDState )
Map transportMap = new HashMap () ;
transportMap . put ( regionCell1 , n e w R e g i o n 1 A t t r i b u t e s ) ;
edit ( transportMap , null , null , null ) ;
ParentMap r eg i on P ar e nt M ap = new ParentMap () ;
GraphCell [] ch ildre nToM ove = g e t B ou n de d C hi l dr e n ( children ,
Gra phCo nstan ts . getBounds ( regionCell2 . getAttributes () ) ) ;
for ( int i = 0; i < child renT oMove . length ; i ++) {
r eg i on P ar e nt M ap . addEntry ( ch ildrenToMove [ i ] , regionCell2 ) ;1240
}
insert ( new Object []{ regionCell2 } , null , null , regionParentMap ,
null ) ;
cell = ( StateCell ) cell . getParent () ;
parentMap . addEntry ( regionCell2 , cell ) ;
}
Gra phCo nstan ts . setBounds ( regionCell2 . getAttributes () ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
bounds . getX () , start . getY () , bounds . getWidth () ,
bounds . getHeight () - upperNewHeight ) ) ;
}
}
return ( GraphCell []) list . toArray ( new GraphCell [0]) ;
/**
* Is just called from addDelimiter (..) and sets the La y o u t I n f o r m a t i o n
for
* the new delimiter line . This code here was just extracted to fit the
* maximum size of 150 lines .
* @param start .
* @param end .
* @param cell .
* @param delimiterLine .
* @param de li mit er Lin eC ell .
*/
private void s e t D e l i m i t e r L i n e L a y o u t ( final Point2D start , final Point2D
end ,
final Def aultGraphCell cell , final DelimiterLine delimiterLine ,
final De lim it erL in eCe ll d eli mi ter Li neC el l ) {
// Delimiter lines have relative Coordinates to the * AND - State *...
}
/**
* Returns the subset of given children , that is contained in the given
* rect .
* Is called from within addDelimiter () .
* @param children .
* @param rect .
* @return .
*/
private GraphCell [] ge t B ou n de d C hi l dr e n ( final GraphCell [] children ,
final Rectangle2D rect ) {
ArrayList list = new ArrayList () ;
for ( int i = 0; i < children . length ; i ++) {
if ( children [ i ] instanceof NodeCell
&& rect . contains ( GraphConstants . getBounds (
(( GraphCell ) children [ i ]) . getAttributes () ) ) ) {
list . add ( children [ i ]) ;
list . addAll ( Arrays . asList ( MyGraphModel . getEdges (
this , children [ i ] , false ) ) ) ;
}
AttributeMap n e w R e g i o n 1 A t t r i b u t e s = new AttributeMap () ;
parentMap . addEntry ( delimiterLineCell , cell ) ;
edit ( null , null , parentMap , null ) ;
s e t D e l i m i t e r L i n e L a y o u t ( start , end , cell , delimiterLine ,
de li mit er Lin eC ell ) ;
MyGraphCo nstants . g et G ra p h ic a lO b j ec t ( cell . getAttributes () ) ;
parent . addDelimit erLine ( delimiterLine ) ;
De li mit er Lin eC ell d el imi te rLi ne Cel l = add ( delimiterLine , parent ) ;
GraphConstants . setBounds ( de lim it erL in eCe ll . getAttributes () ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
start . getX () , start . getY () , end . getX () - start . getX () + 1 ,
end . getY () - start . getY () + 1) ) ;
1210
if ( i s V e r t i c a l D e l i m i t e r ) {
double leftNewWidth = start . getX () - bounds . getX () ;
Gra phCo nstan ts . setBounds ( newRegion1Attributes ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
bounds . getX () , start . getY () , leftNewWidth ,
end . getY () - start . getY () ) ) ;
Gra phCo nstan ts . setBounds ( regionCell2 . getAttributes () ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
start . getX () , start . getY () ,
bounds . getWidth () - leftNewWidth ,
1220
end . getY () - start . getY () ) ) ;
} else {
double up perNe wHei ght = start . getY () - bounds . getY () ;
Gra phCo nstan ts . setBounds ( newRegion1Attributes ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
bounds . getX () , bounds . getY () , bounds . getWidth () ,
up perNe wHei ght ) ) ;
parentMap . addEntry ( regionCell1 , cell ) ;
parentMap . addEntry ( regionCell2 , cell ) ;
1200
} else {
// the AndState gets 1 more Region
RegionCell regionCell1 = ( RegionCell ) cell ;
RegionCell regionCell2 = new RegionCell ( null ) ;
M y G r a p h C o n s t a n t s . s e t N o d e A t t r i b u te s ( regionCell2 . getAttributes () ,
( Region ) c r e a t e K I E L E l e m e n t F o r (
regionCell2 , ( GraphCell ) cell . getParent () ) , kielView ) ;
A. Java-Programm-Quelltext
1290
1280
1270
1260
1250
final boolean flag = u s e D e f a u l t B o u n d s F o r C o l l a p s e d S t a t e s ; // as
shortcut
Object [] all = getAllCells ( bounds ) ;
Object n e w S m a l l e s t P a r e n t = null ;
for ( int i = 0; i < all . length ; i ++) {
if ( cellClass . isInstance ( all [ i ])
&& ! isInvisible (( D e f a u l t G r a phCell ) all [ i ]) ) {
/**
* Returns the smallest node of the given cellClass , containing the
given
* bounds .
* @param cellClass .
* @param bounds .
* @param u s e D e f a u l t B o u n d s F o r C o l l a p s e d S t a t e s for every collapsed
* composite state take its default bounds instead of its expanded
bounds
* @return only visible cells !
*/
public Object g e t S m a l l e s t C e l l O f T y p e ( final Class cellClass ,
final Rectangle2D bounds ,
final boolean u s e D e f a u l t B o u n d s F o r C o l l a p s e d S t a t e s ) {
/**
* Helper method .
* @param clip .
* @return all cells that intersect the given rectangle .
*/
public Object [] getAllCells ( final Rectangle2D clip ) {
java . util . List result = new ArrayList () ;
Object [] all = getAllCells () ;
for ( int i = 0; i < all . length ; i ++) {
if ( M y G r a p h M o d e l U t i l i t i e s . getBoundsOf ( all [ i ] , false )
. intersects ( clip ) ) {
result . add ( all [ i ]) ;
}
}
return result . toArray () ;
}
1340
1330
1320
D e l i m i t e r L i n e L a y o u t I n f o r m a t i o n layout =
new D e l i m i t e r L i n e L a y o u t I n f o r m a t i o n () ;
1300
Rectangle2D bounds = Gr aphCo nsta nts . getBounds ( cell . getAttributes ()
);
start . setLocation (
start . getX () - bounds . getX () , start . getY () - bounds . getY () ) ;
end . setLocation (
end . getX () - bounds . getX () , end . getY () - bounds . getY () ) ;
layout . setStart ( new Point (( int ) start . getX () , ( int ) start . getY () ) ) ;
layout . setEnd ( new Point (( int ) end . getX () , ( int ) end . getY () ) ) ;
kielView . s e t L a y o u t I n f o r m a t i o n ( delimiterLine , layout ) ;
M y G r a p h C o n s t a n t s . s e t G r a p h i c a l O b j e c t ( d eli mi ter Li neC el l . getAttributes
() ,
delimiterLine ) ;
}
1310
. getHeight () ) {
ne wS mal le stP ar ent = all [ i ];
}
}
}
return n ew Sma ll est Pa ren t ;
}
/**
* Calls super . insert () and then calls c h a n g e K i e l N o d e P a r e n t () just in
case ,
* that this needs to be updated .
/**
* Calls super . edit () and then calls c h a n g e K i e l N o d e P a r e n t () just in case
,
* that this needs to be updated .
* @see org . jgraph . graph . GraphModel # edit ( java . util . Map ,
*
org . jgraph . graph . ConnectionSet , org . jgraph . graph . ParentMap ,
*
javax . swing . undo . UndoableEdit [])
*/
public synchronized void edit ( final Map transportMap ,
final ConnectionSet cs , final ParentMap parentMap ,
final UndoableEdit [] edits ) {
super . edit ( transportMap , cs , parentMap , edits ) ;
M y G r a p h M o d e l U t i l i t i e s . upda teKielParent ( parentMap ) ;
}
}
Map map = new AttributeMap () ;
GraphConstants . setLineStyle ( map , style ) ;
Map transportMap = new Hashtable () ;
transportMap . put ( cell , map ) ;
edit ( transportMap , null , null , null ) ;
/**
* Changes the line style of the given cell .
* @param cell .
* @param style .
*/
public void changeLineStyle ( final GraphCell cell , final int style ) {
}
)
if ( M y G r a p h M o d e l U t i l i t i e s . getBoundsOf ( all [ i ] , flag )
. contains ( bounds ) ) {
if ( ne wSm al les tP are nt == null ) {
ne wS mal le stP ar ent = all [ i ];
} else if ( M y G r a p h M o d e l U t i l i t i e s . getBoundsOf (
newSmallestParent , flag ) . getWidth ()
* M y G r a p h M o d e l U t i l i t i e s . getBoundsOf (
newSmallestParent , flag ) . getHeight ()
> M y G r a p h M o d e l U t i l i t i e s . getBoundsOf ( all [ i ] , flag )
. getWidth ()
* M y G r a p h M o d e l U t i l i t i e s . getBoundsOf ( all [ i ] , flag
A.4. Der Quelltext
159
160
1390
1380
1370
1360
1350
);
} else if ( matches ( d e li miterBounds . getY () ,
regionBounds . getY () ) ) {
upperLeftCell = ( RegionCell ) parentCell . getChildAt ( j
// Find the two corresponding regions ...
RegionCell upperLeftCell = null ;
RegionCell low erRig htCe ll = null ;
for ( int j = 0; j < parentCell . getChildCount () ; j ++) {
if ( parentCell . getChildAt ( j ) instanceof RegionCell ) {
regionCount ++;
Rectangle2D regionBounds =
1430
Gra phCo nstan ts . getBounds (
(( GraphCell ) parentCell . getChildAt ( j ) ) . getAttributes
() ) ;
if ( isHorizontal
// left corner
&& matches ( regionBounds . getX () , delimiterBounds . getX () )
// length
&& matches ( regionBounds . getWidth () ,
d el i mi t er B ou n ds . getWidth () ) ) {
// region next to delimiterLine
1440
if ( matches ( regionBounds . getY ()
+ regionBounds . getHeight () ,
d el i mi t er B ou n ds . getY () ) ) {
;
1420
final boolean isHorizontal = matches ( delimiterBounds . getHeight () , 0)
Rectangle2D d el i mi t er Bo u nd s =
Gra phCo nstan ts . getBounds ( d e l i m i t erL in eCe ll . getAttributes () ) ;
ANDStateCell parentCell = ( ANDStateCell ) de lim it erL in eCe ll . getParent
() ;
int regionCount = 0;
/**
* removes a region as well and copies children from the removed region
1410
* ( the lower right ) to the to the upper left .
* @param d e l i m i t e r L i n e C e l l to be removed .
*/
private void r e m o v e D e l i m i t e r L i n e (
final D e l i m i t e r L i n e C e l l d e l i m i t e r L i neC el l ) {
* @see org . jgraph . graph . GraphModel # insert ( java . lang . Object [] ,
*
java . util . Map , org . jgraph . graph . ConnectionSet ,
*
org . jgraph . graph . ParentMap , javax . swing . undo . UndoableEdit []) 1400
*/
public void insert ( final Object [] roots , final Map transportMap ,
final ConnectionSet cs , final ParentMap parentMap ,
final UndoableEdit [] edits ) {
super . insert ( roots , transportMap , cs , parentMap , edits ) ;
M y G r a p h M o d e l U t i l i t i e s . u p d a t e K i e l P a r ent ( parentMap ) ;
}
}
lowerRightCell = ( RegionCell ) parentCell . getChildAt (
}
}
lowerRightCell = ( RegionCell ) parentCell . getChildAt (
} else if ( matches ( delimiterBounds . getX () ,
regionBounds . getX () ) ) {
upperLeftCell = ( RegionCell ) parentCell . getChildAt ( j
}
} else if (
! isHorizontal
// left corner
&& matches ( regionBounds . getY () ,
delimiterBounds . getY () )
// length
&& matches ( regionBounds . getHeight () ,
delimiterBounds . getHeight () ) ) {
// region next to delimiterLine
if ( matches ( regionBounds . getX ()
+ regionBounds . getWidth () , delimiter Bo u nd s . getX () ) )
ParentMap pm = new ParentMap () ;
// Copy from lower right to upper left ...
for ( int i = 0; i < lowerRightCell . getChildCount () ; i ++) {
if ( lowerRightCell . getChildAt ( i ) instanceof NodeCell
|| lowerRightCell . getChildAt ( i ) instanceof T ransi tion Cell ) {
pm . addEntry ( lowerRightCell . getChildAt ( i ) , upperLeftCell ) ;
}
}
Map transportMap = new HashMap () ;
AttributeMap newAttributes = new AttributeMap () ;
transportMap . put ( upperLeftCell , newAttributes ) ;
Rectangle2D upperLeftBounds = GraphConstants . getBounds (
upperLeftCell . getAttributes () ) ;
Rectangle2D lowerRi ghtBounds = GraphConstants . getBounds (
lowerRightCell . getAttributes () ) ;
if ( isHorizontal ) {
GraphConstants . setBounds ( newAttributes ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
}
if ( upperLeftCell == null ) {
logFile . log (0 , " No upperLeft found ") ;
return ;
}
if ( lowerRightCell == null ) {
logFile . log (0 , " No lowerRight found ") ;
return ;
}
j);
);
{
j);
A. Java-Programm-Quelltext
1500
1490
1480
1470
1460
1450
1540
/**
* Calls super . remove () and then disconnects the given cells from the
rest
* of the tree and from the transitions .
* @see org . jgraph . graph . GraphModel # remove ( java . lang . Object [])
*/
public void remove ( final Object [] roots ) {
1550
if ( roots == null ) {
return ;
}
/**
* Checks whether the two parameters are nearly equal .
* @param a compare with b .
* @param b compare with a .
* @return true if a and b are nearly equal (+ - 10)
*/
private static boolean matches ( final double a , final double b ) {
final int tolerance = 15;
return Math . abs ( a - b ) < tolerance ;
}
}
1510
if ( regionCount == 2) {
pm = new ParentMap () ;
// Copy from the only region to the ANDState ...
1520
for ( int i = 0; i < upperLeftCell . getChildCount () ; i ++) {
if ( upperLeftCell . getChildAt ( i ) instanceof NodeCell
|| upperLeftCell . getChildAt ( i ) instanceof TransitionCell
) {
pm . addEntry ( upperLeftCell . getChildAt ( i ) , parentCell ) ;
}
}
remove ( new Object [] { upperLeftCell }) ;
edit ( null , null , pm , null ) ;
convert ( parentCell , ORStateCell . class ) ;
1530
}
} else {
Gra phCo nstan ts . setBounds ( newAttributes ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
u pp e rL e ft B ou n ds . getX () ,
u pp e rL e ft B ou n ds . getY () ,
u pp e rL e ft B ou n ds . getWidth ()
+ l o w e r R i g h t B o u n d s . getWidth () ,
u pp e rL e ft B ou n ds . getHeight () ) ) ;
}
edit ( transportMap , null , pm , null ) ;
remove ( new Object [] { l ower Right Cell }) ;
u pp e rL e ft B ou n ds . getX () ,
u pp e rL e ft B ou n ds . getY () ,
u pp e rL e ft B ou n ds . getWidth () ,
u pp e rL e ft B ou n ds . getHeight ()
+ l o w e r R i g h t B o u n d s . getHeight () ) ) ;
}
super . remove ( roots ) ;
remove ( new Object []{ getGraphCell ( transitions [ tCount ]) }) ;
}
} else if ( object instanceof Transition ) {
(( Transition ) object ) . getSource () . r e m o v e O u t g o i n g T r a n s i t i o n (
( Transition ) object ) ;
(( Transition ) object ) . getTarget () . r e m o v e I n c o m i n g T r a n s i t i o n (
( Transition ) object ) ;
}
/**
/**
* Just returns the current KIEL view .
* @return .
*/
public View getCurrentView () {
return kielView ;
}
/**
* Updates the KIEL datastructure and returns the current k ielS tatec hart
.
* @return .
*/
public StateChart g e t C u r r e n t S t a t e C h a r t () {
// TODO Check why 2 times ??
updateKiel Object ( s ta t ec h a rt R oo t Ce l l ) ;
updateKiel Object ( s ta t ec h a rt R oo t Ce l l ) ;
return kielStatechart ;
}
}
{
for ( int i = 0; i < roots . length ; i ++) {
GraphicalObject object = MyGraphCon stants . ge t G ra p hi c a l O b j e c t (
(( GraphCell ) roots [ i ]) . getAttributes () ) ;
if ( object instanceof DelimiterLine ) {
r e m o v e D e l i m i t e r L i n e (( De lim it erL in eCe ll ) roots [ i ]) ;
} else if ( object instanceof Node ) {
// remove the node itself ...
if ((( Node ) object ) . getParent () instanceof Compo siteS tate ) {
(( CompositeState ) (( Node ) object ) . getParent () )
. removeSubnode (( Node ) object ) ;
}
// Remove its transitions ...
Collection t r a n s i t i o n C o l l e c t i o n =
(( Node ) object ) . g e t I n c o m i n g T r a n s i t i o n s () ;
t r a n s i t i o n C o l l e c t i o n . addAll (
(( Node ) object ) . g e t O u t g o i n g T r a n s i t i o n s () ) ;
Transition [] transitions =
( Transition []) t r a n s i t i o n C o l l e c t i o n . toArray (
new Transition [0]) ;
for ( int tCount = 0; tCount < transitions . length ; tCount ++)
A.4. Der Quelltext
161
162
1600
1590
1580
1570
1560
));
node ) ;
1620
// update children relation ...
if ( node instanceof C ompo siteS tate ) {
(( Com posit eSta te ) node ) . getSubnodes () . clear () ;
if ( node instanceof ANDState ) {
(( ANDState ) node ) . r e m o v e A l l D e l i m i t e r L i n e s () ;
}
if ( M y G r a p h C o n s t a n t s . isCollapsed ( cell . getAttributes () ) ) {
expand ( null , ( C o m p o s i t e S t at e Ce l l ) cell ,
1650
new Point2D . Double (0 , 0) , null , null , false ) ;
}
}
for ( int i = 0; i < (( NodeCell ) cell ) . getChildCount () ; i ++) {
GraphCell childCell =
( GraphCell ) (( NodeCell ) cell ) . getChildAt ( i ) ;
u p d a t e K i e l O b j e c t ( childCell ) ;
Rectangle2D bounds = Gr aphCo nstants . getBounds (
cell . getAttributes () ) . getBounds () ;
if ( bounds != null ) {
// @TODO can be null !?
// Clicking on some elements causes to hide them
Rectangle2D e xpan dedBo unds = M yGraphConstants
1630
. g e t E x p a n d e d B o u n d s ( cell . getAttributes () ) ;
if ( M y G r a p h C o n s t a n t s . isCollapsed ( cell . getAttributes () )
&& ex pand edBou nds != null ) {
layout . setHeight (( int ) expandedBounds . getHeight () ) ;
layout . setWidth (( int ) expandedBounds . getWidth () ) ;
} else {
layout . setHeight (( int ) bounds . getHeight () ) ;
layout . setWidth (( int ) bounds . getWidth () ) ;
}
}
layout . s e t U p p e r L e f t P o i n t (
1640
M y G r a p h M o d e l U t i l i t i e s . g e t R e l a t i v e C o o r d i n a t e s (( NodeCell ) cell
// Update Bounds / Points
N o d e L a y o u t I n f o r m a t i o n layout = kielView . g e t L a y o u t I n f o r m a t i o n (
// Update name ...
node . setName ( cell . toString () ) ;
if ( cell instanceof NodeCell ) {
// Update parent - child relation ...
Node node = ( Node ) M y G r a p h C o n s t an ts . ge t Gr a p hi c al O b je c t (
cell . getAttributes () ) ;
u p d a t e K i e l P a r e n t ( cell ) ;
* Updates the given cell ’ s associated KIEL node . It updates the
* parent - child relation , the name , the bounds / transition points , the
* delimiter lines .
* @param cell .
* @return .
*/
1610
private GraphCell u p d a t e K i e l O b j e c t ( final GraphCell cell ) {
);
Transition transition = ( Transition ) MyGraphCons t a n t s
. g et G ra p h ic a lO b j ec t ( cell . getAttributes () ) ;
}
} else if ( cell instanceof TransitionCell ) {
}
if (! found ) {
node . r e m o v e O u t g o i n g T r a n s i t i o n (
( kiel . dataStructure . Edge ) o u t g o i n g T r a n s i t i o n s [ i ]) ;
}
if ( My GraphConstants . g e tG r a ph i ca l O bj e ct (
(( DefaultGraphCel l ) port . getChildAt ( tCount ) )
. getAttributes () ) == o u t g o i n g T r a n s i t i o n s [ i ]) {
found = true ;
}
}
}
Object [] o u t g o i n g T ra n s i t i o n s = node . g e t O u t g o i n g T r a n s i t i o n s ()
. toArray () ;
for ( int i = 0; i < o u t g o i n g T r a n s i t i o n s . length ; i ++) {
// search for it ...
boolean found = false ;
for ( int tCount = 0;
! found && tCount < port . getChildCount () ; tCount ++) {
if ((( NodeCell ) cell ) . getChildAt ( cCount )
instanceof DefaultPort ) {
port = ( DefaultPort ) (( NodeCell ) cell ) . getChildAt ( cCount
// Have KIEL - Transitions to be deleted ?
// 1. get the port ...
DefaultPort port = null ;
for ( int cCount = 0; port == null
&& cCount < (( NodeCell ) cell ) . getChildCount () ; cCount ++) {
}
if ( layout instanceof C o m p o s i t e S t a t e L a y o u t I n f o r m a t i o n ) {
(( C o m p o s i t e S t a t e L a y o u t I n f o r m a t i o n ) layout ) . setCollapsed (
MyGraphCons tants . isCollapsed ( cell . getAttributes () ) ) ;
}
(( CompositeState ) node ) . addSubnode (
( Node ) MyGraphCons tants . ge t G ra p hi c a l O b j e c t (
childCell . getAttributes () ) ) ;
} else if ( node instanceof ANDState
&& childCell instanceof De lim it erL in eCe l l ) {
(( ANDState ) node ) . addDelimiterLine (
( DelimiterLine ) MyGraphConstants . g e t G r a p h i c a l O b j e c t (
childCell . getAttributes () ) ) ;
}
if ( node instanceof CompositeState
&& childCell instanceof NodeCell ) {
A. Java-Programm-Quelltext
1700
1690
1680
1670
1660
1750
1760
/**
* Defines the mapping GraphCell --> G r aphicalObject and creates the
* appropriate Gr a ph i ca l Ob j ec t for the given cell .
* @param cell .
}
layout . setStart ( new Point (
( int ) ( bounds . getX () - parentBounds . getX () ) ,
( int ) ( bounds . getY () - parentBounds . getY () ) ) ) ;
layout . setEnd ( new Point (
( int ) ( bounds . getX () + bounds . getWidth ()
- parentBounds . getX () ) ,
( int ) ( bounds . getY () + bounds . getHeight ()
- parentBounds . getY () ) ) ) ;
} else if (!( cell instanceof Port ) ) {
logFile . log (2 , " Unexpected cell type :" + cell . getClass () ) ;
}
return cell ;
D e l i m i t e r L i n e L a y o u t I n f o r m a t i o n layout =
kielView . g e t L a y o u t I n f o r m a t i o n ( delimiterLine ) ;
1740
Rectangle2D bounds =
Gra phCo nstan ts . getBounds ( cell . getAttributes () ) . getBounds () ;
Rectangle2D parentBounds =
Gra phCo nstan ts . getBounds ((( DefaultGra phCell )
(( D e f a u l t G r a p h C e l l ) cell ) . getParent () ) . getAttributes () ) ;
DelimiterLine delimiterLine =
( DelimiterLine ) M y G r a p h C o n s tant s . ge t Gr a ph i c al O bj e c t (
cell . getAttributes () ) ;
1730
// Update the points ...
kielView . g e t L a y o u t I n f o r m a t i o n ( transition ) . setPath (
MyGraphModelUtilities . convertTransitionPointsJGraphToKiel (
( T ransi tion Cell ) cell , kielView , transition ) ) ;
1720
. getParent () ) . getAttributes () ) ;
transition . getTarget () . r e m o v e I n c o m i n g T r a n s i t i o n ( transition ) ;
transition . setTarget ( newTarget ) ;
. getParent () ) . getAttributes () ) ;
transition . getSource () . r e m o v e O u t g o i n g T r a n s i t i o n ( transition ) ;
transition . setSource ( newSource ) ;
Node newTarget = ( Node ) M y G r a p h Constants . g e tG r ap h i ca l Ob j e ct (
(( NodeCell ) (( DefaultPort ) (( TransitionCell ) cell ) . getTarget
// Update the Label position ...
updateKielTransitionLabelsPosition (
( T ransi tion Cell ) cell , null ) ;
} else if ( cell instanceof D e l i m i t e rL ine Ce ll ) {
() )
() )
1710
// Update source and target ...
Node newSource = ( Node ) M y G r a p h Constants . g e tG r ap h i ca l Ob j e ct (
(( NodeCell ) (( DefaultPort ) (( TransitionCell ) cell ) . getSource
GraphicalObject graphicalObject = null ;
if ( cell . getClass () == ANDStateCell . class ) {
graphicalObject = new ANDState () ;
} else if ( cell . getClass () == ChoiceCell . class ) {
graphicalObject = new Choice () ;
} else if ( cell . getClass () == C o n d i t i o n a l T r a n s i t i o n C e l l . class ) {
graphicalObject = new C o n d i t i o n a l T r a n s i t i o n () ;
} else if ( cell . getClass () == DeepHistoryCell . class ) {
graphicalObject = new DeepHistory () ;
} else if ( cell . getClass () == D yn ami cC hoi ce Cel l . class ) {
graphicalObject = new DynamicChoice () ;
} else if ( cell . getClass () == F in alA ND Sta te Cel l . class ) {
graphicalObject = new FinalANDState () ;
} else if ( cell . getClass () == FinalORSta teCell . class ) {
graphicalObject = new FinalORState () ;
} else if ( cell . getClass () == F i n a l S i m p l e S t a t e C e l l . class ) {
graphicalObject = new FinalSimp leState () ;
} else if ( cell . getClass () == FinalStateCell . class ) {
graphicalObject = new FinalState () ;
} else if ( cell . getClass () == F or kCo nn ect or Cel l . class ) {
graphicalObject = new ForkConnector () ;
} else if ( cell . getClass () == HistoryCell . class ) {
graphicalObject = new History () ;
} else if ( cell . getClass () == InitialArcCell . class ) {
graphicalObject = new InitialArc () ;
} else if ( cell . getClass () == InitialSta teCell . class ) {
graphicalObject = new InitialState () ;
} else if ( cell . getClass () == JoinCell . class ) {
graphicalObject = new Join () ;
} else if ( cell . getClass () == JunctionCell . class ) {
graphicalObject = new Junction () ;
} else if ( cell . getClass () == N o r m a l T e r m i n a t i o n C e l l . class ) {
graphicalObject = new N or mal Te rmi na tio n () ;
} else if ( cell . getClass () == ORStateCell . class ) {
graphicalObject = new ORState () ;
} else if ( cell . getClass () == RegionCell . class ) {
graphicalObject = new Region () ;
} else if ( cell . getClass () == SimpleStateCell . class ) {
graphicalObject = new SimpleState () ;
} else if ( cell . getClass () == StateCell . class ) {
graphicalObject = new State () ;
} else if ( cell . getClass () == St r on g A bo r ti o n Ce l l . class ) {
graphicalObject = new StrongAbortion () ;
} else if ( cell . getClass () == SuspensionCell . class ) {
graphicalObject = new Suspension () ;
} else if ( cell . getClass () == St r on g A bo r ti o n Ce l l . class ) {
graphicalObject = new StrongAbortion () ;
} else if ( cell . getClass () == SynchStateCell . class ) {
graphicalObject = new SynchState () ;
} else if ( cell . getClass () == TransitionCell . class ) {
* @return .
*/
private GraphicalObject c r e a t e K I E L E l e m e n t F o r ( final GraphCell cell ) {
A.4. Der Quelltext
163
164
1810
1800
1790
1780
1770
return gr a ph i ca l Ob j ec t ;
/**
* Creates a new KIEL - transition connecting the given ports according to
* the line type and transition type currently choosen in the editor .
* @param source .
}
1830
1820
if ( g ra p hi c al O bj e ct instanceof Transition ) {
1840
kielView . s e t L a y o u t I n f o r m a t i o n (
graphicalObject , new E d g e L a y o u t I n f o r m a t i o n () ) ;
} else {
N o d e L a y o u t I n f o r m a t i o n layout = null ;
if ( g ra p hi c al O bj e ct instanceof CompositeState ) {
layout = new C o m p o s i t e S t a t e L a y o u t I n f o r m a t i o n () ;
} else {
layout = new N o d e L a y o u t I n f o r m a t i o n () ;
}
kielView . s e t L a y o u t I n f o r m a t i o n ( graphicalObject , layout ) ;
(( Node ) g r ap h ic a lO b je c t ) . setParent (
( C ompos iteS tate ) M y G r a p h C o n stants . ge t G ra p hi c a lO b je c t (
1850
parentCell . getAttributes () ) ) ;
Rectangle2D bounds = Gr aphCo nstants . getBounds ( cell . getAttributes
() ) ;
if ( bounds != null ) {
layout . setWidth (( int ) bounds . getWidth () ) ;
layout . setHeight (( int ) bounds . getHeight () ) ;
}
layout . s e t U p p e r L e f t P o i n t (
M y G r a p h M o d e l U t i l i t i e s . g e t R e l a t i v e C o o r d i n a t e s (( NodeCell ) cell
));
}
1860
return gr a ph i ca l Ob j ec t ;
G ra p hi c al O bj e ct g ra p hi c al O bj ec t = c r e a t e K I E L E l e m e n t F o r ( cell ) ;
/**
* Calls c r e a t e K I E L E l e m e n t F o r ( GraphCell ) and initializes the new
* G ra p hi c al O bj e ct with the layout information ( coordinates ) .
* @param cell .
* @param parentCell .
* @return .
*/
private G ra p hi c al O bj e ct c r e a t e K I E L E l e m e n t F o r ( final GraphCell cell ,
final GraphCell parentCell ) {
}
g ra p hi c al O bj e ct = new Transition () ;
} else if ( cell . getClass () == W e a k A bort ionCell . class ) {
g ra p hi c al O bj e ct = new WeakAbortion () ;
} else if ( cell . getClass () == D e l i m i te rLi ne Cel l . class ) {
g ra p hi c al O bj e ct = new DelimiterLine () ;
}
nodesToCells . put ( graphicalObject , cell ) ;
);
);
// 1. Create a KIEL - transition object ...
Transition transition ;
if ( sourceNode instanceof InitialState ) {
transition = new InitialArc () ;
} else if ( sourceNode instanceof DynamicChoice ) {
transition = new C o n d i t i o n a l T r a n s i t i o n () ;
} else if ( sourceNode instanceof Suspend ) {
transition = new Suspension () ;
} else if ( type == 0) {
transition = new No rm alT er min at ion () ;
} else if ( type == 1) {
transition = new WeakAbortion () ;
} else if ( type == 2) {
transition = new StrongAbortion () ;
} else {
transition = new Transition () ;
}
transition . setSource ( sourceNode ) ;
Node targetNode = ( Node ) MyGraphConstants . g e t Gr a ph i c a l O b j e c t (
(( GraphCell ) (( DefaultPort ) target ) . getParent () ) . getAttributes ()
if ((( DefaultGrap hCell ) source ) . getParent () . getParent ()
!= (( DefaultGraphCell ) target ) . getParent () . getParent () ) {
throw new Exception ( ResourceBundle . getString (
" i n t e r l e v e l T r a n s i t i o n s N o t A l l o w e d ") ) ;
} else if (! acceptsSource ( null , source ) ) {
throw new Exception ( ResourceBundle . getString (
" source NotAllowed ") ) ;
} else if (! acceptsTarget ( null , target ) ) {
throw new Exception ( ResourceBundle . getString (
" target NotAllowed ") ) ;
} else if ((( DefaultGraphCe ll ) source ) . getParent ()
instanceof InitialStateCel l
&& getEdges ( this , (( Defaul tGraphCell ) source ) . getParent () ,
false ) . length > 0) {
throw new Exception ( ResourceBundle . getString (
" h a s A l r e a d y O u t g o i n g T r a n s i t i o n ") ) ;
}
// following algorithm relies on the KIEL structure
// @TODO Do not use the KIEL structure !
Node sourceNode = ( Node ) MyGraphConstants . g e t Gr a ph i c a l O b j e c t (
(( GraphCell ) (( DefaultPort ) source ) . getParent () ) . getAttributes ()
* @param target .
* @param type .
* @param line .
* @param location .
* @throws Exception If source or target are not valid .
*/
public void addTransition ( final Port source , final Port target ,
final int type , final int line , final Point2D location )
throws Exception {
A. Java-Programm-Quelltext
1910
1900
1890
1880
1870
1920
;
;
1930
Map transportMap = new HashMap () ;
transportMap . put ( transitionCell , newAttributes ) ;
ConnectionSet cs = new ConnectionSet (
}
if ( line == 0) {
Gra phCon stan ts . setLineStyle (
newAttributes , Graph Cons tants . STYLE_SPLINE ) ;
} else if ( line == 1) {
Gra phCon stan ts . setLineStyle (
newAttributes , Graph Cons tants . STYLE_BEZIER ) ;
} else if ( line == 2) {
Gra phCon stan ts . setLineStyle (
newAttributes , Graph Cons tants . STYLE_ORTHO GONAL ) ;
}
points . add ( new AttributeMap . S e r i a l i z a b l e P o i n t 2 D (
sourceBounds . getX () , sourceBounds . getY () ) ) ;
Gra phCon stan ts . setPoints ( newAttributes , points ) ;
1970
1960
points . add ( new AttributeMap . S e r i a l i z a b l e P o i n t 2 D (
1950
sourceBounds . getX () + sourceBounds . getWidth () + loopX ,
sourceBounds . getY () + sourceBounds . getHeight () / 2 + loopY ) )
if ( source == target ) {
Rectangle2D sourceBounds = Gra phConstants . getBounds (
(( D e f a u l t G r a p h C e l l ) (( DefaultPort ) source ) . getParent () )
1940
. getAttributes () ) ;
final int loopX = 50;
final int loopY = 25;
List points = new ArrayList () ;
points . add ( new AttributeMap . S e r i a l i z a b l e P o i n t 2 D (
sourceBounds . getX () , sourceBounds . getY () ) ) ;
points . add ( new AttributeMap . S e r i a l i z a b l e P o i n t 2 D (
sourceBounds . getX () + sourceBounds . getWidth () + loopX ,
sourceBounds . getY () + sourceBounds . getHeight () / 2 - loopY ) )
AttributeMap newAttributes = new AttributeMap () ;
M y G r a p h C o n s t a n t s . s e t T r a n s i t i o n A t t r i b u t e s ( newAttributes ,
transition ) ;
Tra nsiti onCe ll t rans ition Cell =
( Tr ansi tionC ell ) c r e a t e G r a p h C e l lF o r ( transition ) ;
// 2. Transform to JGraph - tr ansi tionCell ...
C o m p o s i t e S t a t e C e l l t r a n s i t i o n C e l l P a r e n t = ( C o mp o si t e St a te C e ll )
(( DefaultPort ) source ) . getParent () . getParent () ;
kielView . s e t L a y o u t I n f o r m a t i o n ( transition , new E d g e L a y o u t I n f o r m a t i o n
() ) ;
transition . setTarget ( targetNode ) ;
transition . setPriority (0) ;
transition . setPriority (
M y G r a p h M o d e l U t i l i t i e s . g e t H i g h e s t P r io r it y ( sourceNode ) + 1) ;
insert ( new Object []{ transitionCell } , transportMap , cs ,
parentMap , null ) ;
;
AttributeMap aMap = new AttributeMap () ;
aTransition . getPriority () . setValue ( i + 1) ;
}
}) ;
for ( int i = 0; i < o u t g o i n g T r a n s i t i o n s . size () ; i ++) {
Transition aTransition = ( Transition ) o u t g o i n g T r a n s i t i o n s . get ( i )
int result = (( Transition ) o1 ) . getPriority () . getValue ()
- (( Transition ) o2 ) . getPriority () . getValue () ;
if ( result == 0 && o1 != o2 ) {
if ( o1 == transition ) {
return -1;
} else if ( o2 == transition ) {
return 1;
}
}
return result ;
ArrayList o u t g o i n g T r a n s i t i o n s =
( ArrayList ) transition . getSource () . g e t O u t g o i n g T r a n s i t i o n s () ;
Collections . sort ( outgoingTransitions , new Comparator () {
public int compare ( final Object o1 , final Object o2 ) {
GraphConstants . setExtraLabels ( map ,
new Object []{" <" + transition . getPriority () . getValue () + " >"}) ;
AttributeMap map = new AttributeMap () ;
transportMap . put ( transitionCell , map ) ;
transition . getPriority () . setValue ( value ) ;
final Transition transition = ( Transition ) MyGraphConsta n t s
. g et G ra p h ic a lO b j ec t ( transitionCell . getAttributes () ) ;
Map transportMap = new HashMap () ;
/**
* .
* @param transitionCell .
* @param value .
*/
public void c h a n g e T r a n s i t i o n P r i o r i t y ( final TransitionCell transitionCell
,
final int value ) {
}
transitionCell , source , target ) ;
ParentMap parentMap = new ParentMap () ;
parentMap . addEntry ( transitionCell , t r a n s i t i o n C e l l P a r e n t ) ;
A.4. Der Quelltext
165
166
2010
2000
1990
1980
() ;
2050
2070
2060
aGraph . g e t O v e r v i e w G r a p h () . g e t S e l ect io nMo de l () . clearSelection () ;
new M o r p h i n g L a y o u t e r ( aGraph , listener , true )
. c o l l a p s e C o m p o s i t e S t a t e ( cell , newBounds ) ;
p r o c e s s I s C o l l a p s e d ( cell , aGraph , false ) ;
edit ( transportMap , null , null , null ) ;
//...
Dimension d = M y G r a p h M o d e l U t i l i t i e s . g e t I n i t i a l D i m e n s i o n O f (
ORState . class ) ;
Rectangle2D newBounds = new Rectangle2D . Double (
exBounds . getX () , exBounds . getY () , d . width , d . height ) ;
exBounds . setRect (
a G r a p h L a y o u t C a c h e . getMapping ( cell , false ) . getBounds () ) ;
M y G r a p h C o n s t a n t s . s e t E x p a n d e d B o u nd s ( newAttributes , exBounds ) ;
// set expanded bounds attribute ...
Rectangle2D exBounds = new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D
// change collapsed attribute ...
M y G r a p h C o n s t a n t s . setCollapsed ( newAttributes ,
! M y G r a p h C o n s t a n t s . isCollapsed ( cell . getAttributes () ) ) ;
Map transportMap = new HashMap () ;
AttributeMap newAttributes = new AttributeMap () ;
transportMap . put ( cell , newAttributes ) ;
if (! M y G r a p h C o n s t a n t s . isCollapsed ( cell . getAttributes () ) ) {
/**
* Toggles the collapsed state of the given cell . An expanding or
collapsing
2030
* is done through the M o r p h i n g L a y o u t e r . " Create space " mechanisms are
not
* implemented here but in the M o r p h i n g La youter !
* @param aGraph .
* @param cell .
* @param a G r a p h L a y o u t C a c h e for the exact current bounds .
* @param listener .
*/
public void flipCollapsed ( final MyJGraph aGraph ,
final C o m p o s i t e S t a t e C e l l cell , final GraphLayoutCach e
2040
aGraphLayoutCache ,
final M o r p h i n g L a y o u t e r . MyListener listener ) {
}
" >"}) ;
}
edit ( transportMap , null , null , null ) ;
2020
transportMap . put ( getGraphCell ( aTransition ) , aMap ) ;
Gra phCo nstan ts . s etEx traLa bels ( aMap ,
new Object []{" <" + aTransition . getPriority () . getValue () +
}
}
}
/**
* Is called by the flipCollapsed () method recursively . " Create space "
* mechanisms are not implemented here but in the Morphi n g L a y o u t e r !
* @param aGraph .
* @param cell .
* @param defaultDelta .
* @param aG ra phL ay out Ca che .
* @param listener .
* @param doExpand .
*/
private void expand ( final MyJGraph aGraph ,
aGraph . g e t G r a p h L a y o u t C a c h e () . collapse (
new Object []{ cell }) ;
aGraph . getOvervi ewGraph () . g e t G r a p h L a y o u t C a c h e () . collapse (
new Object []{ cell }) ;
/**
* .
* @param cell .
* @param aGraph .
*/
private void hideContents ( final C o mp o s it e St a t eC e ll cell ,
final MyJGraph aGraph ) {
if ( MyGr aphConstants . isCollapsed ( cell . getAttributes () ) ) {
}
for ( int i = 0; wholeStatechart && i < cell . getChildCount () ; i ++) {
if ( cell . getChildAt ( i ) instanceof C o mp o si t e St a te C e l l ) {
p r oc e ss I sC o l la p se d (
( Co m p os i te S t at e Ce l l ) cell . getChildAt ( i ) , aGraph ,
wholeStatechart ) ;
}
}
hideContents ( cell , aGraph ) ;
/**
* .
* @param cell .
* @param aGraph .
* @param wholeStatechart .
*/
public void p r oc e s sI s Co l l ap s ed ( final C om p os i t eS t at e C el l cell ,
final MyJGraph aGraph ,
final boolean wholeStatechart ) {
}
;
} else {
expand ( aGraph , cell ,
new Point2D . Double (0 , 0) , aGraphLayoutCache , listener , true )
A. Java-Programm-Quelltext
2120
2110
2100
2090
2080
// NEW
C o m p o s i t e S t a t e C e l l cell ,
Point2D defaultDelta ,
G r a p h L a y o u t C a c h e aGraphLayoutCache ,
M o r p h i n g L a y o u t e r . MyListener listener ,
boolean doExpand ) {
2130
M y G r a p h C o n s t a n t s . s e t E x p a n d e dBo un ds ( newAttributes2 ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
newBounds . getX () , newBounds . getY () ,
new M o r p h i n g L a y o u t e r ( aGraph , listener , true )
. e x p a n d C o m p o s i t e S t a t e ( cell , newBounds . getBounds () ) ;
} else {
Map transportMap2 = new HashMap () ;
AttributeMap new Attr ibute s2 = new AttributeMap () ;
transportMap2 . put ( cell , newAttributes2 ) ;
if ( doExpand ) {
Gra phCo nstan ts . setBounds ( newAttributes , newBounds ) ;
edit ( transportMap , null , null , null ) ;
2180
2170
2150
// change collapsed attribute ...
if ( doExpand ) {
M y G r a p h C o n s t a n t s . setCollapsed ( newAttributes , false ) ;
}
lastBounds =
M y G r a p h C o n s t a n t s . g e t E x p a n d e dBo un ds ( cell . getAttributes () ) ;
if ( lastBounds == null ) {
lastBounds = newBounds ;
} else {
newBounds = new Rectangle2D . Double (
2160
newBounds . getX () ,
newBounds . getY () ,
lastBounds . getWidth () ,
lastBounds . getHeight () ) ;
}
Map transportMap = new HashMap () ;
AttributeMap newAttributes = new AttributeMap () ;
transportMap . put ( cell , newAttributes ) ;
if ( M y G r a p h C o n s t a n t s . isCollapsed ( cell . getAttributes () ) ) {
if ( doExpand ) {
aGraph . g e t G r a p h L a y o u t C a c h e () . expand (
new Object []{ cell }) ;
aGraph . g e t O v e r v i e w G r a p h () . g e t G r a p h L a y o u t C a c h e () . expand (
new Object []{ cell }) ;
aGraph . g e t O v e r v i e w G r a p h () . g e t S e l ect io nMo de l () . clearSelection () ;
}
Rectangle2D newBounds =
2140
g r a p h L a y o u t C a c h e . getMapping ( cell , false ) . getBounds () ;
Gra phCo nstan ts . getBounds ( cell . getAttributes () ) ;
Rectangle2D lastBounds = newBounds ;
final
final
final
final
final
lastBounds . getWidth () , lastBounds . getHeight () ) ) ;
edit ( transportMap2 , null , null , null ) ;
}
transportMap = new Hashtable () ;
newAttributes = new AttributeMap () ;
transportMap . put ( cell . getChildAt ( i ) , newAttributes ) ;
GraphConstants . setPoints ( newAttributes , newPoints ) ;
edit ( transportMap , null , null , null ) ;
Point2D point = ( Point2D ) points . get ( pCount ) ;
newPoints . add ( new AttributeMap . S e r i a l i z a b l e P o i n t 2 D (
point . getX () + delta . getX () ,
point . getY () + delta . getY () ) ) ;
// now expand all children
if ( cell . getChildAt ( i ) instanceof C o mp o si t e St a te C e ll ) {
C o mp o si t eS t a te C el l child =
( Co m p os i te S t at e Ce l l ) cell . getChildAt ( i ) ;
if (! MyGraphConstant s . isCollapsed ( child . getAttributes () ) ) {
expand ( aGraph , child , delta , aGraphLayoutCache ,
listener , doExpand ) ;
}
} else if ( cell . getChildAt ( i ) instanceof Transition Cell ) {
List points = GraphConstants . getPoints (
(( TransitionCell ) cell . getChildAt ( i ) ) . getAttributes () ) ;
List newPoints = new ArrayList () ;
for ( int pCount = 0; pCount < points . size () ; pCount ++) {
if ( newBounds != null ) { // == null for DefaultPorts
newBounds = new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
newBounds . getX () + delta . getX () ,
newBounds . getY () + delta . getY () ,
newBounds . getWidth () ,
newBounds . getHeight () ) ;
GraphConstants . setBounds ( newAttributes , newBounds ) ;
}
edit ( transportMap , null , null , null ) ;
// contents have to be moved to the new pos
newBounds = GraphConstants . getBounds ((( Defaul tGraphC e l l ) cell
. getChildAt ( i ) ) . getAttributes () ) . getBounds2D () ;
Map transportMap = new Hashtable () ;
AttributeMap newAttributes = new AttributeMap () ;
transportMap . put ( cell . getChildAt ( i ) , newAttributes ) ;
// Now check the children ...
for ( int i = 0; i < cell . getChildCount () ; i ++) {
final Point2D delta = new Point2D . Double (
defaultDelta . getX () + newBounds . getX () - lastBounds . getX () ,
defaultDelta . getY () + newBounds . getY () - lastBounds . getY () ) ;
}
}
A.4. Der Quelltext
167
168
2230
2220
2210
2200
2190
}
}
slashFound = labelString . indexOf ("/") != -1;
if ( slashFound ) {
effectPart = labelString . substring (
labelString . indexOf ("/") + 1) . trim () ;
}
// Cut off starting "#"...
flag = labelString . startsWith ("#") ;
if ( flag ) {
labelString = labelString . substring (
labelString . indexOf ("#") + 1) . trim () ;
}
// Cut off obsolete ending "/"...
if ( labelString . trim () . endsWith ("/") ) {
labelString = labelString . substring (
labelString . length () - 1) ;
}
labelString = labelString . trim () ;
String triggerPart = null ;
String conditionPart = null ;
String effectPart = null ;
boolean flag = false ;
boolean slashFound = false ;
String labelString = ( String ) tr ansitionCell . getUserObject () ;
if ( labelString == null ) {
labelString = "";
}
logFile . log (0 , " labelString :" + labelString ) ;
// labelString has this format :
// # trigger { condition } / effect
// /
// trigger
// { condition }
// trigger { condition }
String c u r r e n t U s e r O b j e c t = a C u r r e n t U s e rO b je c t ;
2280
2270
2260
2250
/**
* .
* @param tran siti onCel l .
2240
* @param a C u r r e n t U s e r O b j e c t .
* @throws C o m p o u n d L a b e l E x c e p t i o n .
public void p o s t E d i t T r a n s i t i o n L a b e l ( final DefaultGraphCell
transitionCell ,
final String a C u r r e n t U s e r O b j e c t ) throws C o m p o u n d L a b e l E x c e p t i o n {
}
*/
/*
/**
* .
* @param transitionCell .
* @param triggerPart .
* @param conditionPart .
* @param effectPart .
* @param isImmediate .
* @param a C ur r e nt U se r O bj e ct .
* @throws C o m p o u n d L a b e l E x c e p t i o n .
*/
public void s e tT r a ns i ti o n La b el ( final Defaul tGraphCell transitionCell ,
final String triggerPart ,
final String conditionPart , final String effectPart ,
final boolean isImmediate , final String a C ur r e nt U se r O b j e c t )
throws C o m p o u n d L a b e l E x c e p t i o n {
}
StringTokenizer st = new StringTokenizer ( labelString ) ;
while ( st . hasMoreTokens () ) {
String token = st . nextToken () ;
if ( token . equals ("#") ) {
flag = true ;
} else if ( token . startsWith ("{") && token . endsWith ("}") ) {
conditionPart = token ;
} else if ( token . equals ("/") ) {
slashFound = true ;
} else if ( slashFound ) {
effectPart = token ;
} else {
triggerPart = token ;
}
}
// Create the objects ...
s et T r an s it i o nL a be l ( transitionCell , null , triggerPart , conditionPart ,
effectPart , flag , c urr en tUs er Obj ec t ) ;
if ( conditionPart != null ) {
triggerPart = labelString . substring (
0 , labelString . indexOf ("{") ) . trim () ;
} else if ( slashFound ) {
triggerPart = labelString . substring (
0 , labelString . indexOf ("/") ) . trim () ;
} else {
triggerPart = labelString ;
}
if ( labelString . indexOf ("{") != -1 && labelString . indexOf ("}") !=
-1) {
conditionPart = labelString . substring (
labelString . indexOf ("{") , labelString . indexOf ("}") + 1) ;
}
A. Java-Programm-Quelltext
2330
2320
2310
2300
2290
/**
}
2360
2350
2340
c u r r e n t U s e r O b j e c t = compoundLabel . toString () ;
logFile . log (0 , " set new CompoundLabel : "
+ compoundLabel . toString () ) ;
} finally {
AttributeMap newAttributes = new AttributeMap () ;
Gra phCo nstan ts . setValue ( newAttributes , cu rr ent Us erO bj ect ) ;
Map transportMap = new HashMap () ;
transportMap . put ( transitionCell , newAttributes ) ;
edit ( transportMap , null , null , null ) ;
}
2380
// Use the old label layout ...
if ( transition . getLabel () != null ) {
L a b e l L a y o u t I n f o r m a t i o n layout =
kielView . g e t L a y o u t I n f o r m a t i o n ( transition . getLabel () ) ;
if ( layout != null ) {
kielView . put ( compoundLabel . getID () , layout ) ;
}
2370
}
transition . setLabel ( compoundLabel ) ;
updateKielTransitionLabelsPosition (
( T ransi tion Cell ) transitionCell , null ) ;
Transition transition =
( Transition ) M y G r a p h C o n s t a n t s . g e t Gr a p hi c al O b je c t (
tra nsit ionCe ll . getAttributes () ) ;
C o m p o u n d L a b e l P a r s e r . setStateChart ( g e t C u r r e n t S t a t e C h a r t () ) ;
C o m p o u n d L a b e l P a r s e r . s e t C o m p o s i t e S t a te (
( C ompos iteSt ate ) transition . getSource () . getParent () ) ;
CompoundLabel compoundLabel = new CompoundLabel () ;
try {
if ( triggerPart != null && triggerPart . length () > 0) {
logFile . log (2 , " Trigger part : " + triggerPart ) ;
compoundLabel . setTrigger (
CompoundLabelParser . parseDelayExpression (
triggerPart , isImmediate ) ) ;
}
if ( conditionPart != null && conditionPart . length () > 0) {
logFile . log (2 , " Condition part : " + conditionPart ) ;
compoundLabel . setCondition (
CompoundLabelParser . parseBooleanExpression (
conditionPart ) ) ;
}
if ( effectPart != null && effectPart . length () > 0) {
logFile . log (2 , " Effect part : " + effectPart ) ;
compoundLabel . setEffect (
C o m p o u n d L a b e l P a r s e r . parseActions ( effectPart ) ) ;
}
String c u r r e n t U s e r O b j e c t = a C u r r e n t Us e rO b je c t ;
// calculate the label position ...
Point2D offset = M y G r a p h M o d e l U t i l i t i e s . calculateOffset (
transition . getSource () , kielView ) ;
NodeCell sourceCell = ( NodeCell ) (( DefaultPort )
(( TransitionCell ) transitionCell ) . getSource () )
. getParent () ;
NodeCell targetCell = ( NodeCell ) (( DefaultPort )
(( TransitionCell ) transitionCell ) . getTarget () )
if ( transition . getLabel () == null
|| transition . getLabel () . toString () . length () == 0) {
return ;
}
L a b e l L a y o u t I n f o r m a t i o n layout =
kielView . g e t L a y o u t I n f o r m a t i o n ( transition . getLabel () ) ;
if ( layout == null ) {
layout = new L a b e l L a y o u t I n f o r m a t i o n () ;
kielView . s e t L a y o u t I n f o r m a t i o n ( transition . getLabel () , layout ) ;
} else if ( onlyOnCreate ) {
return ;
}
final boolean onlyOnCreate = newLab elPosition == null ;
Transition transition = ( Transition ) MyGraphConstants
. g et G ra p h ic a lO b j ec t ( transitionCell . getAttributes () ) ;
/**
* Update the position if no layout Info is available ( the label is new
!) .
* @param transitionCell .
* @param newLabelPosition onCreate = newPosition == null . Coordinates
are
* Coordinates are not used !
*/
private void u p d a t e K i e l T r a n s i t i o n L a b e l P o s i t i o n (
final TransitionCell transitionCell ,
final Point2D newLabelPosition ) {
}
updateKielTransitionPriorityLabelPosition (
transitionCell ) ;
updateKielTransitionLabelPosition (
transitionCell , newLabelPos ition ) ;
* Update the position if no layout Info is available ( the label is new
!) .
* @param transitionCell .
* @param newLabelPosition onCreate = newPosition == null . Coordinates
are
* Coordinates are not used !
*/
public void u p d a t e K i e l T r a n s i t i o n L a b e l s P o s i t i o n (
final TransitionCell transitionCell ,
final Point2D newLabelPosition ) {
A.4. Der Quelltext
169
170
2440
2430
2420
2410
2400
2390
2480
L a b e l L a y o u t I n f o r m a t i o n layout =
kielView . g e t L a y o u t I n f o r m a t i o n ( transition . getPriority () ) ;
if ( layout == null ) {
layout = new L a b e l L a y o u t I n f o r m a t i o n () ;
kielView . s e t L a y o u t I n f o r m a t i o n ( transition . getPriority () , layout ) ;
}
// calculate the label position ...
if ( g r a p h L a y o u t C a c h e . getMapping ( transitionCell , false ) == null ) {
System . out . println (" mapping is empty ") ;
2490
return ;
}
Rectangle2D start = g r a p h L a y o u t C a c h e . getMapping ( transitionCell ,
false )
Transition transition = ( Transition ) MyGraphConstants
. g e t G r a p h i c a l O b j e c t ( tra nsit ionCell . getAttributes () ) ;
2470
/**
* Update the position if no layout Info is available ( the label is new
!) .
* @param tran siti onCel l .
*/
private void u p d a t e K i e l T r a n s i t i o n P r i o r i t y L a b e l P o s i t i o n (
final T rans ition Cell tra nsit ionCe ll ) {
}
. getParent () ;
if ( sourceCell != targetCell ) {
Rectangle2D sourceBounds = Gra phConstants . getBounds (
sourceCell . getAttributes () ) ;
Rectangle2D targetBounds = Gra phConstants . getBounds (
targetCell . getAttributes () ) ;
layout . se tCen terPo int ( new Point (
( int ) ( sourceBounds . getCenterX ()
+ ( targetBounds . getCenterX ()
- sourceBounds . getCenterX () ) / 2.0 - offset . getX () ) , 2450
( int ) ( sourceBounds . getCenterY ()
+ ( targetBounds . getCenterY ()
- sourceBounds . getCenterY () ) / 2.0 - offset . getY () ) ) ) ;
} else {
List points = G raph Const ants . getPoints (
tra nsit ionCe ll . getAttributes () ) ;
if ( points . size () > 1) {
layout . se tCent erPo int ( new Point (
( int ) ((( Point2D ) points . get (1) ) . getX ()
- offset . getX () ) ,
2460
( int ) ((( Point2D ) points . get (1) ) . getY ()
- offset . getY () ) ) ) ;
}
}
layout . setWidth (
Properties . getWidth ( Properties . getLabelFont () ,
transition . getLabel () + "") ) ;
layout . setHeight ( Properties . g e t L a b e lFontSize () ) ;
if ( cell . getChildAt ( i ) instanceof RegionCell
for ( int i = 0; i < cell . getChildCount () ; i ++) {
Map transportMap = new HashMap () ;
if ( oldBounds . getWidth () == newBounds . getWidth ()
&& oldBounds . getHeight () == newBounds . getHeight () ) {
return ;
}
Rectangle2D newBounds = GraphConstants . getBounds ( cell . getAttributes
() ) ;
/**
* .
* @param cell .
* @param oldBounds .
*/
public void a n d S t a t e C e l l E n l a r g e d ( final ANDStateCell cell ,
final Rectangle2D oldBounds ) {
/**
* .
* @param cell .
* @param label .
*/
public void setNodeLabel ( final NodeCell cell , final String label ) {
AttributeMap newAttributes = new AttributeMap () ;
GraphConstants . setValue ( newAttributes , label ) ;
Map transportMap = new HashMap () ;
transportMap . put ( cell , newAttributes ) ;
edit ( transportMap , null , null , null ) ;
}
}
() ) ;
if ( start . isEmpty () ) {
System . out . println (" is empty ") ;
return ;
}
System . out . println (" intersection :" + start ) ;
Point2D offset = M y G r a p h M o d e l U t i l i t i e s . calculateOffs e t (
transition . getSource () , kielView ) ;
layout . setCenterPoint ( new Point (
( int ) ( start . getX () - offset . getX () ) ,
( int ) ( start . getY () - offset . getY () ) ) ) ;
layout . setWidth (
Properties . getWidth ( Properties . getLabelFont () ,
" <" + transition . getPriority () . getValue () + " >") ) ;
layout . setHeight ( Properties . getL abelFontSize () ) ;
. getBounds () . getBounds2D () . cr e a te I nt e r se c ti o n (
graphLayo utCache . getMapping (
getSourceVertex ( this , transitionCell ) , false ) . getBounds
A. Java-Programm-Quelltext
2540
2530
2520
2510
2500
;
;
;
}
}
}
}
AttributeMap newAttributes = new AttributeMap () ;
Gra phCo nstan ts . setBounds ( newAttributes , changedBounds ) ;
transportMap . put ( cell . getChildAt ( i ) , newAttributes ) ;
changedBounds . setHeight ( childsBounds . getHeight ()
+ newBounds . getHeight () - oldBounds . getHeight () )
2590
}
// lower edge changed ?
} else if ( oldBounds . getHeight () != newBounds . getHeight () ) {
if ( matches ( oldBounds . getY () + oldBounds . getHeight () ,
childsBounds . getY () + childsBounds . getHeight () ) ) {
changedBounds . setY ( childsBounds . getY ()
+ newBounds . getY () - oldBounds . getY () ) ;
changedBounds . setHeight ( childsBounds . getHeight ()
+ newBounds . getHeight () - oldBounds . getHeight2580
() )
2570
changedBounds . setWidth ( childsBounds . getWidth ()
+ newBounds . getWidth () - oldBounds . getWidth () ) ;
}
// upper edge changed ?
if ( oldBounds . getY () != newBounds . getY () ) {
if ( matches ( oldBounds . getY ()
+ Properties . g e t C o m p o s i t e S t a t e H e a d e r H e i g h t () ,
childsBounds . getY () ) ) {
}
// left edge changed ?
if ( oldBounds . getX () != newBounds . getX () ) {
if ( matches ( oldBounds . getX () , childsBounds . getX () ) ) {
changedBounds . setX ( newBounds . getX () ) ;
changedBounds . setWidth ( childsBounds . getWidth ()
+ newBounds . getWidth () - oldBounds . getWidth ()2560
);
}
// right edge changed ?
} else if ( oldBounds . getWidth () != newBounds . getWidth () ) {
if ( matches ( oldBounds . getX () + oldBounds . getWidth () ,
childsBounds . getX () + childsBounds . getWidth () ) ) {
AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D changedBounds
= new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
childsBounds . getX () , childsBounds . getY () ,
childsBounds . getWidth () , childsBounds . getHeight () ) ;
2550
Rectangle2D childsBounds = GraphConstants . getBounds (
(( D e f a u l t G r a p h C e l l ) cell . getChildAt ( i ) ) . getAttributes () )
|| cell . getChildAt ( i ) instanceof D el imi te rLi ne Cel l ) {
edit ( transportMap , null , null , null ) ;
changedBounds . setX ( oldBounds . getX () ) ;
isOutside = true ;
}
AttributeMap newAttributes = new AttributeMap () ;
GraphConstants . setBounds ( newAttributes , changedBounds ) ;
transportMap . put ( cell , newAttributes ) ;
edit ( transportMap , null , null , null ) ;
}
if ( newBounds . getX () < parentsBounds . getX ()
|| newBounds . getX () > parentsBounds . getX ()
+ parentsBounds . getWidth () ) {
}
} else {
changedBounds . setY ( oldBounds . getY () ) ;
changedBounds . setY ( oldBounds . getY () ) ;
isOutside = true ;
if ( newBounds . getY () < parentsBounds . getY ()
+ Properties . g e t C o m p o s i t e S t a t e H e a d e r H e i g h t ()
|| newBounds . getY () > parentsBounds . getY ()
+ parentsBounds . getHeight () ) {
if ( isHorizontal ) {
changedBounds . setX ( oldBounds . getX () ) ;
Rectangle2D newBounds = GraphConstants . getBounds ( cell . getAttributes
() ) ;
Rectangle2D parentsBounds = GraphConstants . getBounds (
(( DefaultGraphCe ll ) cell . getParent () ) . getAttributes () ) ;
final boolean isHorizontal =
newBounds . getWidth () > newBounds . getHeight () ;
Map transportMap = new HashMap () ;
// Correct coordinates . Horizontal delimiter lines cannot change
// their start . x coordinate ! and they cannot leave their parent
AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D changedBounds
= new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
newBounds . getX () , newBounds . getY () ,
newBounds . getWidth () , newBounds . getHeight () ) ;
boolean isOutside = false ;
/**
* .
* @param cell .
* @param oldBounds .
* @param aG rap hL ayo ut Cac he .
*/
public void d e l i m i t e r L i n e C e l l M o v e d ( final Del im ite rL ine Ce ll cell ,
final Rectangle2D oldBounds ,
final GraphL ayoutCache aG rap hL ayo ut Cac he ) {
}
A.4. Der Quelltext
171
172
2640
2630
2620
2610
2600
{
{
2650
2690
Rectangle2D childsBounds = GraphConstants . getBounds (
(( D e f a u l t G r a p h C e l l ) cell . getParent ()
2700
}
}
newAttributes = new AttributeMap () ;
Gra phCo nstan ts . setBounds ( newAttributes , changedBounds ) ;
transportMap . put ( cell . getParent () . getChildAt ( i ) ,
newAttributes ) ;
} else if ( cell . getParent () . getChildAt ( i ) instanceof RegionCell )
changedBounds . setWidth (
changedBounds . getWidth ()
- oldBounds . getX () + newBounds . getX () ) ;
if ( isHorizontal && ! c h i l d I s Hor iz ont al ) {
if ( matches ( oldBounds . getY () , childsBounds . getY () ) ) {
changedBounds . setY ( newBounds . getY () ) ;
2670
changedBounds . setHeight (
changedBounds . getHeight ()
+ oldBounds . getY () - newBounds . getY () ) ;
} else if ( matches ( oldBounds . getY () ,
childsBounds . getY ()
+ childsBounds . getHeight () ) ) {
changedBounds . setHeight (
changedBounds . getHeight ()
- oldBounds . getY () + newBounds . getY () ) ;
}
} else if (! isHorizontal && chi ld Is Hor iz ont al ) {
if ( matches ( oldBounds . getX () , childsBounds . getX () ) ) {2680
changedBounds . setX ( newBounds . getX () ) ;
changedBounds . setWidth (
changedBounds . getWidth ()
+ oldBounds . getX () - newBounds . getX () ) ;
} else if ( matches ( oldBounds . getX () ,
childsBounds . getX () + childsBounds . getWidth () ) )
boolean c h i l d I s H o r i z o n t a l =
childsBounds . getWidth () > childsBounds . getHeight () ;
Rectangle2D childsBounds = GraphConstants . getBounds (
(( D e f a u l t G r a p h C e l l ) cell . getParent ()
2660
. getChildAt ( i ) ) . getAttributes () ) ;
changedBounds = new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
childsBounds . getX () , childsBounds . getY () ,
childsBounds . getWidth () , childsBounds . getHeight () ) ;
if ( cell . getParent () . getChildAt ( i ) instanceof Del im ite rL ine Ce ll
&& cell . getParent () . getChildAt ( i ) != cell ) {
if ( isOutside ) {
return ;
}
for ( int i = 0; i < cell . getParent () . getChildCount () ; i ++) {
}
}
newAttributes = new AttributeMap () ;
GraphConstants . setBounds ( newAttributes , changedBounds ) ;
transportMap . put ( cell . getParent () . getChildAt ( i ) ,
newAttributes ) ;
changedBounds . setX ( newBounds . getX () ) ;
changedBounds . setWidth ( childsBounds . getWidth ()
+ oldBounds . getX () - newBounds . getX () ) ;
changedBounds . setWidth ( childsBounds . getWidth ()
+ newBounds . getX () - oldBounds . getX () ) ;
// right region ?
} else if ( matches ( oldBounds . getX () , childsBounds . getX ()
}
} else {
// vertical delimiter ...
// left region ?
if ( matches ( oldBounds . getX () ,
childsBounds . getX () + childsBounds . getWidth () ) ) {
changedBounds . setY ( newBounds . getY () ) ;
changedBounds . setHeight ( childsBounds . getHeight ()
+ oldBounds . getY () - newBounds . getY () ) ;
changeParent (
( Default GraphCell ) cell . getParent ()
. getChildAt ( i ) . getChildAt ( childCount ) ,
aG ra phL ay out Ca che ) ;
for ( int i = 0; i < cell . getParent () . getChildCount () ; i ++) {
if ( cell . getParent () . getChildAt ( i ) instanceof RegionCell ) {
for ( int childCount = 0;
childCount < cell . getParent () . getChildAt ( i )
. getChildCount () ; childCount ++) {
}
}
edit ( transportMap , null , null , null ) ;
)) {
)) {
changedBounds . setHeight ( childsBounds . getHeight ()
+ newBounds . getY () - oldBounds . getY () ) ;
// lower region ?
} else if ( matches ( oldBounds . getY () , childsBounds . getY ()
. getChildAt ( i ) ) . getAttributes () ) ;
changedBounds = new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
childsBounds . getX () , childsBounds . getY () ,
childsBounds . getWidth () , childsBounds . getHeight () ) ;
if ( isHorizontal ) { // horizontal delimiter ...
// upper region ?
if ( matches ( oldBounds . getY () ,
childsBounds . getY ()
+ childsBounds . getHeight () ) ) {
A. Java-Programm-Quelltext
}
}
}
}
}
A.4. Der Quelltext
173
174
50
40
30
20
10
kiel . dataStructure . ANDState ;
kiel . dataStructure . Choice ;
kiel . dataStructure . Com posit eSta te ;
kiel . dataStructure . DeepHistory ;
kiel . dataStructure . DynamicChoice ;
kiel . dataStructure . FinalANDState ;
kiel . dataStructure . FinalORState ;
kiel . dataStructure . F i n a l S i m p l e S t a t e ;
kiel . dataStructure . FinalState ;
kiel . dataStructure . ForkConnector ;
kiel . dataStructure . History ;
kiel . dataStructure . InitialState ;
kiel . dataStructure . Join ;
kiel . dataStructure . Junction ;
kiel . dataStructure . Node ;
kiel . dataStructure . ORState ;
kiel . dataStructure . Region ;
kiel . dataStructure . SimpleState ;
kiel . dataStructure . State ;
kiel . dataStructure . Suspend ;
kiel . dataStructure . SynchState ;
kiel . dataStructure . Transition ;
kiel . editor . graph . ANDStateCell ;
kiel . editor . graph . D e l i m i t e r L i n e C e l l ;
kiel . editor . graph . G r a p h i c a l O b j e c t C e l l ;
kiel . editor . graph . M y G r a p h C o n s t a n t s ;
kiel . editor . graph . NodeCell ;
kiel . editor . graph . ORStateCell ;
kiel . editor . graph . Trans itio nCell ;
kiel . editor . resources . Preferences ;
kiel . g r a p h i c a l I n f o r m a t i o n s . E d g e L a y o u t I n f o r m a t i o n ;
kiel . g r a p h i c a l I n f o r m a t i o n s . LinetoPath ;
kiel . g r a p h i c a l I n f o r m a t i o n s . N o d e L a y o u t I n f o r m a t i o n ;
kiel . g r a p h i c a l I n f o r m a t i o n s . PathElement ;
kiel . g r a p h i c a l I n f o r m a t i o n s . Point ;
kiel . g r a p h i c a l I n f o r m a t i o n s . Properties ;
kiel . g r a p h i c a l I n f o r m a t i o n s . View ;
kiel . util . EdgeHelper ;
kiel . util . L i n e s D o N o t I n t e r s e c t E x c e p t i o n ;
kiel . util . LogFile ;
java . awt . Dimension ;
java . awt . geom . Point2D ;
java . awt . geom . Rectangle2D ;
java . util . ArrayList ;
java . util . Iterator ;
java . util . List ;
import org . jgraph . graph . AttributeMap ;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
package kiel . editor ;
kiel.editor.MyGraphModelUtilities
100
90
80
70
60
org . jgraph . graph . CellView ;
org . jgraph . graph . Defaul tGraphCell ;
org . jgraph . graph . GraphCell ;
org . jgraph . graph . GraphConstants ;
org . jgraph . graph . GraphL ayoutCache ;
org . jgraph . graph . ParentMap ;
org . jgraph . graph . PortView ;
/**
* @param node .
* @param aKielView .
/**
* .
* @param kielPoint .
* @param offset .
* @param result .
*/
static void addPoint ( final Point kielPoint , final Point2D offset ,
final List result ) {
if ( kielPoint != null ) {
Point2D jgraphPoint = new AttributeMap . S e r i a l i z a b l e P o i n t 2 D (
kielPoint . getX () + offset . getX () ,
kielPoint . getY () + offset . getY () ) ;
debug ( true , " Add a point to jgraph : " + jgraphPoint , null ) ;
if (! jgraphPoint . equals ( TransitionCell . DUMMY_POINT )
&& ! result . contains ( jgraphPoint ) ) {
result . add ( jgraphPoint ) ;
}
}
}
/**
*
*/
private M y G r a p h M o d e l U t i l i t i e s () {
}
/**
* The logging handle . Prints logs to standard out .
*/
private static LogFile logFile = new LogFile (" Editor " , 2) ;
/**
* Contains static methods mainly used by MyGraphModel .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.20 $ last modified $Date : 2005/07/27 22:20:49 $
*/
public final class M y G r a p h M o d e l U t i l i t i e s {
import
import
import
import
import
import
import
A. Java-Programm-Quelltext
150
140
130
120
110
//
//
//
//
180
Point2D offset = ca l cu l at e Of f se t ( transition . getSource () , view ) ;
ArrayList result = new ArrayList () ;
E d g e L a y o u t I n f o r m a t i o n layout =
view . g e t L a y o u t I n f o r m a t i o n (( Transition ) transition ) ;
190
if ( layout != null ) {
ArrayList points = layout . g e t A l l P a th E le m e nt s () ;
debug ( true , " create JGraphPoints from these original kiel points
:" ,
null ) ;
debug ( true , "" , points ) ;
for ( int i = 0; i < points . size () ; i ++) {
addPoint ((( PathElement ) points . get ( i ) ) . getTargetPoint () ,
offset , result ) ;
addPoint ((( PathElement ) points . get ( i ) ) . getContro lPoint1
200
() ,
offset , result ) ;
addPoint ((( PathElement ) points . get ( i ) ) . getContro lPoint2
() ,
offset , result ) ;
}
debug ( true , " c o n v e r t T r a n s i t i o n P o i n t s K i e l T o J G r a p h ..........." , null ) ;
/**
* Transforms the KIEL transition points of the given transition to
* JGraph transition points .
* @param transition .
* @param view .
* @return .
*/
public static ArrayList c o n v e r t T r a n s i t i o n P o i n t s K i e l T o J G r a p h (
final Transition transition , final View view ) {
* @return .
*/
public static Point2D c a lc u la t eO ff s et ( final Node node ,
final View aKielView ) {
if ( node . getParent () == null ) {
return new AttributeMap . S e r i a l i z a b l e P o i n t 2 D (
Preferences . g e t I n i t i a l G r a p h O f f s e t () ,
160
Preferences . g e t I n i t i a l G r a p h O f f s e t () ) ;
// Root ist etwas versetzt
} else {
Point2D parentOffset = ca l cu l at eOffset (
node . getParent () ,
aKielView ) ;
N o d e L a y o u t I n f o r m a t i o n layout = aKielView . g e t L a y o u t I n f o r m a t i o n (
node
. getParent () ) ;
return new AttributeMap . S e r i a l i z a b l e P o i n t 2 D ( parentOffset . getX ()
170
+ layout . getXPos () ,
parentOffset . getY () + layout . getYPos () ) ;
}
}
//
//
//
;
try {
if ( GraphConstants . getLineStyle ( cell . getAttributes () )
== GraphConstants . STYLE_O RTHOGONAL ) {
// 2. Create Path - Elements ......
debug ( debug , " New KIEL points :" , kielPoints ) ;
}
}
debug ( debug , " Old KIEL points :" , kielView . g e t L a y o u t I n f o r m a t i o n (
transition ) . ge t A ll P at h E le m en t s () ) ;
kielPoints . add ( new kiel . g r a p h i c a l I n f o r m a t i o n s . Point (
( int ) ((( Point2D ) jgraphPoints . get ( i ) ) . getX ()
- parentBounds . getX () ) ,
( int ) ((( Point2D ) jgraphPoints . get ( i ) ) . getY ()
- parentBounds . getY () ) ) ) ;
if (! TransitionCell . DUMMY_POINT . equals ( jgraphPoints . get ( i ) ) ) {
ArrayList kielPoints = new ArrayList () ;
for ( int i = 1; i < jgraphPoints . size () - 1; i ++) {
// first and last are DUMMY_POINTs or the end points
ArrayList jgraphPoints =
( ArrayList ) GraphConstants . getPoints ( cell . getAttributes () ) ;
boolean debug = true ;
debug ( debug , " JGRAPH Points :" , jgraphPoints ) ;
debug ( true , " c o n v e r t T r a n s i t i o n P o i n t s J G r a p h T o K i e l ..........." , null ) ;
// 1. Create KIEL - Points .......
Rectangle2D parentBounds = GraphConstants . getBounds (
(( DefaultGraphCe ll ) cell . getParent () ) . getAttributes () ) ;
debug ( true , " Parent :" + cell . getParent () + ":" + parentBounds , null )
/**
* .
* @param cell .
* @param kielView just for debug
* @param transition just for debug
* @return .
*/
public static ArrayList c o n v e r t T r a n s i t i o n P o i n t s J G r a p h T o K i e l (
final TransitionCell cell , final View kielView ,
final Transition transition ) {
}
}
if ( result . size () == 0) {
result . add ( TransitionCell . DUMMY_POINT ) ;
result . add ( TransitionCell . DUMMY_POINT ) ;
}
debug ( true , " Created JGraph Points :" , result ) ;
return result ;
A.4. Der Quelltext
175
176
250
240
230
220
210
//
//
//
//
//
//
//
//
//
}
300
290
/**
* Creates KIEL datastructure objects , for example : given ANDState . class
as
* nodeClass will return an ANDState object . This could easily done
310
* with java reflection as well , but this techique is generally avoided
in
/**
* .
* @param debug .
* @param msg .
* @param list .
*/
private static void debug ( final boolean debug , final String msg ,
final ArrayList list ) {
if (! debug ) {
return ;
}
System . out . println ( msg ) ;
for ( int i = 0; list != null && i < list . size () ; i ++) {
System . out . println ( list . get ( i ) ) ;
}
}
if ( allKielPoints . size () > 2 && allKielPoints . get (
allKielPoints . size () - 1) instanceof LinetoPath ) {
allKielPoints . remove ( allKielPoints . size () - 1) ;
}
280
if ( allKielPoints . size () > 2 && allKielPoints . get (1)
instanceof LinetoPath ) {
allKielPoints . remove (1) ;
}
debug ( debug , " New points corrected :" , kielView . g e t L a y o u t I n f o r m a t i o n (
transition ) . g e t A l l P a t h E l e m e n t s () ) ;
return kielPoints ;
// 3. Correct Path - Elements ......
ArrayList allKielPoints = kielView . g e t L a y o u t I n f o r m a t i o n (
transition ) . g e t A l l P a t h E l e m e n t s () ;
kielView . s e t L a y o u t I n f o r m a t i o n ( transition ,
EdgeHelper . co n ve r tP o lyPath ( kielPoints , transition
. getSource () , transition . getTarget () , kielView ) )260
;
} else {
kielView . s e t L a y o u t I n f o r m a t i o n ( transition ,
EdgeHelper . c o n v e r t S p l i n eP ath ( kielPoints , transition
. getSource () , transition . getTarget () , kielView ) ) ;
}
} catch ( L i n e s D o N o t I n t e r s e c t E x c e p t i o n e ) {
e . p ri n tS t ac k Tr a ce () ;
}
debug ( debug , " New points after c o nv ertPolyPath :" , kielView
. g e t L a y o u t I n f o r m a t i o n ( transition ) . ge t A ll P at h E le m en t s () ) ;
270
Node node = null ;
if ( nodeClass == ANDState . class ) {
node = new ANDState () ;
} else if ( nodeClass == Choice . class ) {
node = new Choice () ;
} else if ( nodeClass == DeepHistory . class ) {
node = new DeepHistory () ;
} else if ( nodeClass == DynamicChoice . class ) {
node = new DynamicChoice () ;
} else if ( nodeClass == FinalANDState . class ) {
node = new FinalANDState () ;
} else if ( nodeClass == FinalORState . class ) {
node = new FinalORState () ;
} else if ( nodeClass == FinalSi mpleState . class ) {
node = new Final SimpleState () ;
} else if ( nodeClass == FinalState . class ) {
node = new FinalState () ;
} else if ( nodeClass == ForkConnector . class ) {
node = new ForkConnector () ;
} else if ( nodeClass == History . class ) {
node = new History () ;
} else if ( nodeClass == InitialState . class ) {
node = new InitialState () ;
} else if ( nodeClass == Join . class ) {
node = new Join () ;
} else if ( nodeClass == Junction . class ) {
node = new Junction () ;
} else if ( nodeClass == ORState . class ) {
node = new ORState () ;
} else if ( nodeClass == Region . class ) {
node = new Region () ;
} else if ( nodeClass == SimpleState . class ) {
node = new SimpleState () ;
} else if ( nodeClass == State . class ) {
node = new State () ;
} else if ( nodeClass == Suspend . class ) {
node = new Suspend () ;
} else if ( nodeClass == SynchState . class ) {
node = new SynchState () ;
} else {
logFile . log (2 , " Unexpected kiel type :" + nodeClass
+ " instantiate dynamically ...") ;
try {
node = ( Node ) nodeClass . newInstance () ;
} catch ( I n s t a n t i a t i o n E x c e p t i o n e ) {
e . printStackTrace () ;
} catch ( I l l e g a l A c c e s s E x c e p t i o n e ) {
e . printStackTrace () ;
* the editor code .
* @param nodeClass .
* @return .
*/
static Node cr ea teK IE LNo de For ( final Class nodeClass ) {
A. Java-Programm-Quelltext
360
350
340
330
320
410
400
390
380
370
/**
* The initial dimension is used for the node creation . It is stored in
the
* user Preferences .
* TODO What is with subclasses ?
}
Transition [] transitions = ( Transition []) node .
g e t O u t g o i n g T r a n s i t i o n s ()
. toArray ( new Transition [0]) ;
int maxPriority = 0;
for ( int i = 0; i < transitions . length ; i ++) {
if ( transitions [ i ]. getPriority () . getValue () > maxPriority ) {
maxPriority = transitions [ i ]. getPriority () . getValue () ;
}
}
return maxPriority ;
/**
* Returns the highest priority number of the given node ’ s outgoing
* transitions .
* @param node .
* @return .
*/
static int g e t H i g h e s t P r i o r i t y ( final Node node ) {
}
Rectangle2D bounds = Gr aphCo nsta nts . getBounds (
(( D e f a u l t G r a p h C e l l ) cell ) . getAttributes () ) ;
if ( u s e D e f a u l t B o u n d s F o r C o l l a p s e d S t a t e s
&& M y G r a p h C o n s t a n t s . isCollapsed (
(( D e f a u l t G r a p h C e l l ) cell ) . getAttributes () ) ) {
bounds = bounds . getBounds2D () ;
bounds . setRect (
bounds . getX () ,
bounds . getY () ,
Properties . g e t D e f a u l t C o m p o s i t e S t a t e S i z e () . getWidth () ,
Properties . g e t D e f a u l t C o m p o s i t e S t a t e S i z e () . getHeight () ) ;
}
return bounds ;
/**
* Helper method .
* @param cell .
* @param u s e D e f a u l t B o u n d s F o r C o l l a p s e d S t a t e s .
* @return .
*/
static Rectangle2D getBoundsOf ( final Object cell ,
final boolean u s e D e f a u l t B o u n d s F o r C o l l a p s e d S t a t e s ) {
}
}
}
return node ;
/**
* JGraph stores absolute coordinates . This method returns the relative
* coordinates , relative to its parent . This method just subracts the
given
* cell ’ s coordinates from its parent ’ s coordinates .
}
if ( elementClass == SimpleState . class ) {
return new Dimension (
Preferences . getDefaultState () . width ,
Preferences . getDefaultState () . height ) ;
} else if ( elementClass == FinalSimp leState . class ) {
return new Dimension (
Preferences . getDefaultNode () . width ,
Preferences . getDefaultNode () . height ) ;
} else if ( elementClass == InitialState . class ) {
return new Dimension (
Preferences . getDefaultNode () . width ,
Preferences . getDefaultNode () . height ) ;
} else if ( elementClass == Suspend . class ) {
return new Dimension (
Preferences . getDefaultNode () . width ,
Preferences . getDefaultNode () . height ) ;
} else if ( elementClass == DynamicChoice . class ) {
return new Dimension (
Preferences . getDefaultNode () . width ,
Preferences . getDefaultNode () . height ) ;
} else if ( elementClass == History . class ) {
return new Dimension (
Preferences . getDefaultNode () . width ,
Preferences . getDefaultNode () . height ) ;
} else if ( elementClass == DeepHistory . class ) {
return new Dimension (
Preferences . getDefaultNode () . width ,
Preferences . getDefaultNode () . height ) ;
} else if ( elementClass == ORState . class ) {
return new Dimension (
Properties . g e t D e f a u l t C o m p o s i t e S t a t e S i z e () . width ,
Properties . g e t D e f a u l t C o m p o s i t e S t a t e S i z e () . height ) ;
} else if ( elementClass == FinalState . class ) {
return new Dimension (
Preferences . getDefaultState () . width ,
Preferences . getDefaultState () . height ) ;
} else {
return new Dimension (
Preferences . getDefaultNode () . width ,
Preferences . getDefaultNode () . height ) ;
}
* @param elementClass .
* @return .
*/
public static Dimension g e t I n i t i a l D i m e n s i o n O f ( final Class elementClass )
{
A.4. Der Quelltext
177
178
460
450
440
430
420
490
480
470
}
/**
* Returns the smallest node of the given viewClass , containing the
given
* bounds . Never returns a PortView !
* @param viewClass .
* @param bounds .
* @param g r a p h L a y o u t C a c h e .
* @param c h e c k F o r C o n t a i n s if true then use Rectangle . contains () else 500
use
* Rectangle . intersect () .
* @param excludedCell .
* @return .
*/
public static CellView g e t S m a l l e s t V i e w O f T y p e ( final Class viewClass ,
final Rectangle2D bounds , final G r a phLa youtCache graphLayoutCache ,
final boolean checkForContains ,
final D e f a u l t G r a p h C e l l excludedCell ) {
510
CellView [] views = g r a p h L a y o u t C a c h e . getCellViews () ;
CellView n e w S m a l l e s t P a r e n t = null ;
CellView excludedView = null ;
if ( excludedCell != null ) {
excludedView = g r a p h L a y o u t C a c h e . getMapping ( excludedCell , false ) ;
}
for ( int i = 0; i < views . length ; i ++) {
if ( views [ i ] instanceof PortView || views [ i ] == excludedView ) {
NodeCell parent ;
if ( cell instanceof NodeCell ) {
parent = ( NodeCell ) (( NodeCell ) cell ) . getParent () ;
} else {
parent = ( NodeCell ) (( D e l i m i t e r Lin eC ell ) cell ) . getParent () ;
}
Rectangle2D parentBounds = null ;
if ( parent == null ) {
parentBounds = new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
Preferences . g e t I n i t i a l G r a p h O f f s e t () ,
Preferences . g e t I n i t i a l G r a p h O f f s e t () , 0 , 0) ;
} else {
parentBounds = Grap hCons tant s . getBounds (
parent . getAttributes () ) . getBounds () ;
}
return new kiel . g r a p h i c a l I n f o r m a t i o n s . Point (
( int ) ( bounds . getX () - parentBounds . getX () ) ,
( int ) ( bounds . getY () - parentBounds . getY () ) ) ;
Rectangle2D bounds = Gr aphCo nsta nts . getBounds (
cell . getAttributes () ) . getBounds () ;
* @param cell .
* @return .
*/
static kiel . g r a p h i c a l I n f o r m a t i o n s . Point g e t R e l a t i v e C o o r d i n a t e s (
final G r a p h i c a l O b j e c t C e l l cell ) {
//
//
}
}
}
return n ew Sma ll est Pa ren t ;
if ( ne wSm al les tP are nt == null ) {
ne wS mal le stP ar ent = views [ i ];
} else if ( n ew Sma ll est Pa re nt . getBounds () . getWidth ()
* ne wSm al les tP are nt . getBounds () . getHeight ()
> views [ i ]. getBounds () . getWidth ()
* views [ i ]. getBounds () . getHeight () ) {
ne wS mal le stP ar ent = views [ i ];
}
|| (! checkForContain s
&& views [ i ]. getBounds () . intersects ( bounds ) ) ) {
if ( cell instanceof ORStateCell || cell instanceof ANDStateCell ) {
validArea . setRect (
validArea . getX () ,
validArea . getY ()
+ Properties . g e t C o m p o s i t e S t a t e H e a d e r H e i g h t () ,
+ Properties . getUpperOffset (( State ) MyGraphC o n s t a n t s
. g et G ra p h ic a lO b j ec t ( cell . getAttributes () ) ) ,
validArea . getWidth () ,
validArea . getHeight ()
- Properties . g e t C o m p o s i t e S t a t e H e a d e r H e i g h t () ) ;
- Properties . getUpperOffset (( State ) MyGraphC o n s t a n t s
Rectangle2D validArea = getBoundsOf ( cell , false ) . getBounds2D () ;
validArea . setRect (
validArea . getX () + Preferences . g e t Va l id A r ea B or d e r () ,
validArea . getY () + Preferences . g e t Va l id A r ea B or d e r () ,
validArea . getWidth () - 2 * Preferences . g et V al i d A r e a B o r d e r () ,
validArea . getHeight () - 2 * Preferences . g e tV a li d A r e a B o r d e r () ) ;
/**
* Returns the valid area of a composite state , means : where can we
place a
* child ? There are two calculations , one for ANDStates and ORStates (
don ’ t
* place within the header ) and Regions .
* TODO could we replace Preferences . ge t Va l i dA r ea B o rd e r () with
* Preferences . g e t I n t e r s e c t i o n S e n s i t i v i t y () ?
* @param cell .
* @return .
*/
public static Rectangle2D getValidArea ( final DefaultGrap h C e l l cell ) {
}
))
continue ;
}
if ( viewClass . isInstance ( views [ i ]) ) {
if (
( checkFor Contains && views [ i ]. getBounds () . contains ( bounds
A. Java-Programm-Quelltext
540
530
520
560
550
ParentMap . Entry entry = ( ParentMap . Entry ) entries . next () ;
if ( entry . getChild () instanceof NodeCell
&& entry . getParent () != null ) {
// can be null to remove a parent
570
Node child = ( Node ) M y G r a p h Constants . g et G r ap h ic a lO b j ec t (
(( GraphCell ) entry . getChild () ) . getAttributes () ) ;
Node currentParent = child . getParent () ;
Node newParent = ( Node ) M y G raphConstants . g e tG r ap h i ca l Ob j e ct (
(( GraphCell ) entry . getParent () ) . getAttributes () ) ;
// remove from old Parent ...
if ( currentParent instanceof CompositeState ) {
(( Com posit eSta te ) currentParent ) . removeSubnode ( child ) ;
}
// add to new Parent ...
/**
* According to the information stored in the parent map the KIEL
* datastructure is updated .
* @param pm .
*/
static void u p d a t e K i e l P a r e n t ( final ParentMap pm ) {
if ( pm == null ) {
return ;
}
Iterator entries = pm . entries () ;
while ( entries . hasNext () ) {
}
. g e t G r a p h i c a l O b j e c t ( cell . getAttributes () ) ) ) ;
}
return validArea ;
}
}
}
}
.") ;
}
}
Node [] children = ( Node []) (( CompositeState ) node ) . getSubnodes ()
. toArray ( new Node [0]) ;
for ( int i = 0; children != null && i < children . length ; i ++) {
if ( children [ i ]. getParent () != node ) {
children [ i ]. setParent (( CompositeState ) node ) ;
logFile . log (2 , " Editor corrected Parent Child relation
/**
* Checks if the MyGraphModel and the FileInterface did its job well : -)
* TODO this method should be deleted . Everything already works fine !
* @param node .
*/
static void u p d a t e K i e l P a r e n t C h i l d R e l a t i o n ( final Node node ) {
if ( node instanceof CompositeState
&& (( CompositeState ) node ) . getSubnodes () != null ) {
}
}
if ( newParent instanceof CompositeState
&& !(( CompositeState ) newParent ) . getSubnodes ()
. contains ( child ) ) {
(( CompositeState ) newParent ) . addSubnode ( child ) ;
}
A.4. Der Quelltext
179
180
50
40
30
20
10
java . awt . BasicStroke ;
java . awt . Color ;
java . awt . Graphics ;
java . awt . Graphics2D ;
java . awt . Image ;
java . awt . Stroke ;
java . awt . geom . Point2D ;
java . awt . geom . Rectangle2D ;
java . awt . print . PageFormat ;
java . awt . print . Printable ;
java . util . ArrayList ;
java . util . Arrays ;
javax . swing . J C h e c k B o x M e n u I t e m ;
javax . swing . JComponent ;
javax . swing . JMenu ;
javax . swing . JMenuItem ;
javax . swing . JPopupMenu ;
kiel . dataStructure . StateChart ;
kiel . editor . controller . A c t i o n A d d L o o p T r a n s i t i o n ;
kiel . editor . controller . A c t i o n E d i t C o l l a p s e d ;
kiel . editor . controller . A c t i o n E d i t C o n v e r t T o B e z i e r ;
kiel . editor . controller . A c t i o n E d i t C o n v e r t F l i p F i n a l A t t r i b u t e ;
kiel . editor . controller . A c t i o n E d i t C o n v e r t T o N o r m a l T r a n s i t i o n ;
kiel . editor . controller . A c t i o n E d i t C o n v e r t T o O R S t a t e ;
kiel . editor . controller . A c t i o n E d i t C o n v e r t T o O r t h o g o n a l ;
kiel . editor . controller . A c t i o n E d i t C o n v e r t T o S i m p l e S t a t e ;
kiel . editor . controller . A c t i o n E d i t C o n v e r t T o S p l i n e ;
kiel . editor . controller . A c t i o n E d i t C o n v e r t T o S t r o n g A b o r t i o n ;
kiel . editor . controller . A c t i o n E d i t C o n v e r t T o W e a k A b o r t i o n ;
kiel . editor . controller . ActionEditCut ;
kiel . editor . controller . Ac tionE ditE dit ;
kiel . editor . controller . Ac t io n Ed i tP a ste ;
kiel . editor . controller . A c t i o n E d i t R e m ove ;
kiel . editor . controller . A c t i o n E d i t S t a t e D o A c t i o n s ;
kiel . editor . controller . A c t i o n E d i t S t a t e E n t r y A c t i o n s ;
kiel . editor . controller . A c t i o n E d i t S t a t e E v e n t s ;
kiel . editor . controller . A c t i o n E d i t S t a t e E x i t A c t i o n s ;
kiel . editor . controller . A c t i o n E d i t S t a t e V a r i a b l e s ;
kiel . editor . controller . A c t i o n E d i t T r a n s i t i o n P r i o r i t y ;
kiel . editor . controller . EditorAction ;
kiel . editor . controller . EditorActions ;
kiel . editor . controller . M y M a r q u e e H a n d ler ;
kiel . editor . graph . ANDStateCell ;
kiel . editor . graph . C o m p o s i t e S t a t e C e l l ;
kiel . editor . graph . C o n d i t i o n a l T r a n s i t i o n C e l l ;
kiel . editor . graph . D e l i m i t e r L i n e C e l l ;
kiel . editor . graph . D e l i m i t e r L i n e V i e w ;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
package kiel . editor ;
kiel.editor.MyJGraph
100
90
80
70
60
org . jgraph . JGraph ;
org . jgraph . event . GraphModelEvent ;
org . jgraph . event . G ra p hM o d el L is t e ne r ;
org . jgraph . event . G r a p h S e l e c t i o n E v e n t ;
org . jgraph . event . G r a p h S e l e c t i o n L i s t e n e r ;
org . jgraph . graph . CellView ;
org . jgraph . graph . DefaultEdge ;
org . jgraph . graph . Defaul tGraphCell ;
org . jgraph . graph . Def au ltG ra phM od el ;
org . jgraph . graph . DefaultPort ;
org . jgraph . graph . GraphCell ;
org . jgraph . graph . GraphConstants ;
org . jgraph . graph . GraphL ayoutCache ;
org . jgraph . graph . GraphModel ;
org . jgraph . graph . PortRenderer ;
org . jgraph . graph . PortView ;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
/**
* MyJGraph represents the graph drawing area of the editor component .
* MyJGraph customizes the JGraph framework for the use of statecharts .
Mainly
* MyJGraph introduces different KIEL - specific diagram elements . Next ,
MyJGraph
* differs from JGraph in that it contains a overview graph , displayed as
* different layer , and that it contains an undo manager . Many properties of
* MyJGraph can be adjusted through the Preferences class .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.88 $ last modified $Date : 2005/08/01 17:41:30 $
*/
public final class MyJGraph extends JGraph
implements Preferences . Listener , Printable {
kiel . editor . graph . InitialArcCell ;
kiel . editor . graph . InitialStateCell ;
kiel . editor . graph . NodeCell ;
kiel . editor . graph . N o r m a l T e r m i n a t i o n C e l l ;
kiel . editor . graph . ORStateCell ;
kiel . editor . graph . RegionCell ;
kiel . editor . graph . SimpleStateCell ;
kiel . editor . graph . StateCell ;
kiel . editor . graph . S t ro n gA b o rt i on C e ll ;
kiel . editor . graph . SuspensionCell ;
kiel . editor . graph . TransitionCell ;
kiel . editor . graph . WeakAbortionCell ;
kiel . editor . resources . Preferences ;
kiel . editor . resources . ResourceLoader ;
kiel . g r a p h i c a l I n f o r m a t i o n s . Properties ;
kiel . g r a p h i c a l I n f o r m a t i o n s . View ;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
A. Java-Programm-Quelltext
150
140
130
120
110
/**
* The minus - image showed in the upper left corner of an Or - state and
/**
* The plus - image showed in the upper left corner of an Or - state and
* And - State , indicating that this state is collapsed . Used for the
* overview graph .
*/
private static final Image P LU S _I M AG E _G RAY =
Res ource Load er . get (" plusgray . gif ") . getImage () ;
200
/**
* The minus - image showed in the upper left corner of an Or - state and
* And - State indicating that this state is expanded . Used for the main
* graph .
190
*/
private static final Image MINUS_IMAGE =
Res ource Load er . get (" minus . gif ") . getImage () ;
/**
* The plus - image showed in the upper left corner of an Or - state and 180
* And - State , indicating that this state is collapsed . Used for the main
* graph .
*/
private static final Image PLUS_IMAGE =
Res ource Load er . get (" plus . gif ") . getImage () ;
/**
* This reference is filled for overview graphs since a overview graph
* needs to know which cell is currently selected .
*/
private MyJGraph mainGraph ;
170
/**
* @see # overviewGraph
* @return .
*/
public MyJGraph g e t O v e r v i e w G r a p h () {
return overviewGraph ;
}
/**
* This instance variable is only filled for the " main " - MyJGraph object .
* A MyJGraph object , which contains an overviewGraph , is called a " main
"* MyJGraph object . The overview graph is not a " main " - MyJGraph object ,
* consequently it does not have an overviewGraph object itself . (= No
* recursion !) . The overview graph has the same content as its
* " main " - MyJGraph , but it is scaled in a way that it always fits the 160
* window size !
*/
private final MyJGraph overviewGraph ;
/**
* Returns the main color for drawing states . it returns gray ( depending
on
* the Preferences ) for the overview
* graph , returns red for an incomplete main graph element and returns
* black for a complete element in the main graph .
* @param view .
* @return .
*/
public Color getViewsBlack ( final CellView view ) {
if ( overviewGraph == null ) {
return Preferences . getOverviewColo r () ;
} else {
if (!( view . getCell () instanceof NodeCell )
|| isComplete (( DefaultGraphCe ll ) view . getCell () ) ) {
return Color . BLACK ;
} else {
return getViewsRed () ;
}
}
}
/**
* Returns the either the black minus image ( for the main graph ) or the
* grayscaled minus image for the overview graph .
* @return .
*/
public Image getMinusImage () {
if ( overviewGraph == null ) {
return MINUS_IMA GE_GRAY ;
} else {
return MINUS_IMAGE ;
}
}
/**
* Returns the either the black plus image ( for the main graph ) or the
* grayscaled plus image for the overview graph .
* @return .
*/
public Image getPlusImage () {
if ( overviewGraph == null ) {
return PLUS_IMAGE_GRAY ;
} else {
return PLUS_IMAGE ;
}
}
* And - State indicating that this state is expanded . Used for the
overview
* graph .
*/
private static final Image MINUS_ IMAGE_GRAY =
ResourceLoader . get (" minusgray . gif ") . getImage () ;
A.4. Der Quelltext
181
182
250
240
230
220
210
/**
}
int count = 0;
if (!( cell instanceof C o m p o s i t e S t a t eC e l l ) ) {
return 0;
} else {
Object [] children =
(( C o m p o s i t e S t a t e C e l l ) cell ) . getChildren () . toArray () ;
for ( int i = 0; i < children . length ; i ++) {
if ( childClass . isInstance ( children [ i ]) ) {
count ++;
}
}
return count ;
}
/**
*
* @param cell .
* @param childClass .
* @return .
*/
private static int contains ( final GraphCell cell ,
final Class childClass ) {
300
290
260
/**
*
* @param cell .
* @return .
*/
private static boolean isComplete ( final Defaul tGraphCell cell ) {
if ( cell instanceof ORStateCell ) {
return contains ( cell , I n i t i a l S t ateCell . class ) == 1
&& ( cell . getParent () == null /* is root state */
|| h a s I n c o m i n g T r a n s i t i o n s ( cell ) ) ;
} else if ( cell instanceof ANDStateCell ) {
for ( int i = 0; i < cell . getChildCount () ; i ++) {
270
if (! isComplete (( D e f a u l t G r a phCell ) cell . getChildAt ( i ) ) ) {
return false ;
}
}
return h a s I n c o m i n g T r a n s i t i o n s ( cell ) ;
} else if ( cell instanceof RegionCell ) {
return contains ( cell , I n i t i a l S t ateCell . class ) == 1;
} else if ( cell instanceof Si m pl e St ateCell ) {
return h a s I n c o m i n g T r a n s i t i o n s ( cell ) ;
280
} else if ( cell instanceof I n i t i a l S tateCell ) {
return h a s O u t g o i n g T r a n s i t i o n s ( cell ) ;
} else {
return true ;
}
}
/**
* returns dark green for a main graph element and gray ( depending on
the
* Preferences ) for an overview graph element .
* @return .
*/
public Color getViewsGreen () {
if ( overviewGraph == null ) {
return Preferences . getOverviewColor () ;
/**
*
* @param cell .
* @return .
*/
private static boolean h a s O u t g o i n g T r a n s i t i o n s ( final Defa u l t G r a p h C e l l
cell ) {
if ( cell . getParent () == null ) {
return false ;
}
for ( int i = 0; i < cell . getParent () . getChildCount () ; i ++) {
if ( cell . getParent () . getChildAt ( i ) instanceof Tr ansi tionC ell ) {
TransitionCell transition =
( TransitionCell ) cell . getParent () . getChildAt ( i ) ;
if ((( DefaultPort ) transition . getSource () ) . getParent ()
== cell ) {
return true ;
}
}
}
return false ;
}
*
* @param cell .
* @return .
*/
private static boolean h a s I n c o m i n g T r a n s i t i o n s ( final Defa u l t G r a p h C e l l
cell ) {
if ( cell . getParent () == null ) {
return false ;
}
for ( int i = 0; i < cell . getParent () . getChildCount () ; i ++) {
if ( cell . getParent () . getChildAt ( i ) instanceof Tr ansi tionC ell ) {
TransitionCell transition =
( TransitionCell ) cell . getParent () . getChildAt ( i ) ;
if ((( DefaultPort ) transition . getTarget () ) . getParent ()
== cell ) {
return true ;
}
}
}
return false ;
}
A. Java-Programm-Quelltext
360
350
340
330
320
310
390
380
370
/**
*
*/
private static final float MITER_LIMIT = 10;
/**
*
*/
private static final float [] DASH_PHASE = new float [] {5 f , 5 f };
410
/**
* returns yellow for a main graph element and gray ( depending on the
* Preferences ) for an overview graph element .
* @return .
*/
public Color get View sYell ow () {
400
if ( overviewGraph == null ) {
return Preferences . g e t O v e r v i e w C ol or () ;
} else {
return Color . YELLOW ;
}
}
/**
* returns gray for a main graph element and gray ( depending on the
* Preferences ) for an overview graph element .
* @return .
*/
public Color getViewsGray () {
if ( overviewGraph == null ) {
return Preferences . g e t O v e r v i e w C ol or () ;
} else {
return Color . GRAY ;
}
}
/**
* returns red for a main graph element and gray ( depending on the
* Preferences ) for an overview graph element .
* @return .
*/
public Color getViewsRed () {
if ( overviewGraph == null ) {
return Preferences . g e t O v e r v i e w C ol or () ;
} else {
return Color . RED ;
}
}
}
} else {
return Color . GREEN . darker () ;
}
if ( view instanceof Del im ite rL ine Vi ew ) {
return S T R O K E _ H I G H L I G H T _ D E L I M I T E R ;
} else {
return S T R O K E _ H I G H L I G H T _ N O D E ;
}
} else {
if ( view instanceof Del im ite rL ine Vi ew ) {
return STROKE_DE LIMITER ;
} else {
/**
* Returns the main color for drawing states . it returns gray ( depending
on
* the Preferences ) for the overview
* graph , returns red for an incomplete main graph element and returns
* black for a complete element in the main graph .
* @param view .
* @return .
*/
public Stroke getStroke ( final CellView view ) {
if (( overviewGraph == null
&& Arrays . asList ( mainGraph . get Se lec ti onC el ls () )
. contains ( view . getCell () ) )
|| ( overviewGraph != null
&& Arrays . asList ( get Se lec ti onC el ls () )
. contains ( view . getCell () ) ) ) {
/**
*
*/
private static final BasicStroke STROKE_NODE =
new BasicStroke ( Properties . getLineWidth () ) ;
/**
*
*/
private static final BasicStroke STROKE_DEL IMITER =
new BasicStroke ( Properties . getLineWidth () ,
BasicStroke . CAP_BUTT , BasicStroke . JOIN_MITER , MITER_LIMIT ,
DASH_PHASE , 0.0 f ) ;
/**
*
*/
private static final BasicStroke S T R O K E _ H I G H L I G H T _ N O D E =
new BasicStroke ( Properties . getLineWidth () + 1) ;
/**
*
*/
private static final BasicStroke S T R O K E _ H I G H L I G H T _ D E L I M I T E R =
new BasicStroke ( Properties . getLineWidth () + 1 ,
BasicStroke . CAP_BUTT , BasicStroke . JOIN_MITER , MITER_LIMIT ,
DASH_PHASE , 0.0 f ) ;
A.4. Der Quelltext
183
184
460
450
440
430
420
}
return STROKE_NODE ;
470
480
setOpaque ( false ) ;
s et P or t sV i si b le ( true ) ; // Make Ports Visible by Default
s e t I n v o k e s S t o p C e l l E d i t i n g ( true ) ; // Accept edits if click on
background
s e t G r a p h L a y o u t C a c h e ( new G r a p h L a y o u t Cache (
super ( model ) ;
Preferences . addListener ( this ) ;
/**
* Returns an instance of < code > MyJGraph </ code > which displays the
* specified data model .
* @param model .
* @param isMainGraph .
*/
MyJGraph ( final GraphModel model , final boolean isMainGraph ) {
520
510
/**
* Updates all Preferences dependent properties of the graph drawing
area .
490
* @see kiel . editor . resources . Preferences . Listener # pr e f er e nc e s Ch a ng e d ()
*/
public void p r e f e r e n c e s C h a n g e d () {
if ( overviewGraph != null ) {
set Grid Enabl ed ( Preferences . ge tGridEnabled () ) ;
set Grid Visib le ( Preferences . ge tGridVisible () ) ;
// TODO Should be a property ...
final int gridColor = 170;
setGridColor ( new Color ( gridColor , gridColor , gridColor ) ) ;
setGridSize ( Preferences . getGridSize () ) ;
500
setTolerance ( Preferences . g e t C e l l S e l e c t i o n T o l e r a n c e () ) ;
set Hand leCol or ( Preferences . ge t GuiColorDark () ) ;
setHandleSize ( Preferences . g e t S i zeH an dle Si ze () ) ;
set Hand leCol or ( Preferences . g e t S i z e Ha n dl e C ol o r () ) ;
}
}
/**
* @see # undoManager
* @return .
*/
public U n d o C l u s t e r M a n a g e r g e t U n d o C l u s t e r M a n a g e r () {
return undoManager ;
}
/**
* Stores the Undo / Redo history and can perform undo and redo steps .
*/
private final U n d o C l u s t e r M a n a g e r undoManager = new U n do C lu s t er M an a g er () ;
}
}
//
/**
* @see # popup
* @return .
*/
public boolean isPopupVisible () {
return popup . isVisible () ;
}
/**
* Updates the popup menu and its content , depending on which kind
* of diagram element is selected .
* @param x x - coordinate .
* @param y y - coordinate .
/**
* The Graph ’ s popup menu .
*/
private JPopupMenu popup = new JPopupMenu () ;
/**
* This is the hook for our own GraphUI class .
* @see javax . swing . JComponent # updateUI ()
*/
public void updateUI () {
setUI ( new MyBasicGraphUI () ) ;
(( MyBasicGraphUI ) getUI () ) . addEditListener ( this ) ;
}
}
getModel () , new M y D e f a u l t C e l l V i e w F a c t o r y () , true ) ) ;
g e t G r a p h L a y o u t C a c h e () . s e t S e l e c t s L o c a l I n s e r t e d C e l l s ( false ) ;
if ( isMainGraph ) {
se tM arq ue eHa nd ler ( new MyM arqueeHandler ( this ) ) ;
overviewGraph = new MyJGraph ( getModel () , false ) ;
overviewGraph . mainGraph = this ;
overviewGraph . setPortsVisible ( false ) ;
// Paint the current selected cell in the overview !
ge tS ele ct ion Mo del () . a d d G r a p h S e l e c t i o n L i s t e n e r (
new G r a p h S e l e c t i o n L i s t e n e r () {
public void valueChanged ( final G r a p h S e l e c t i o n E v e n t e ) {
if ( e . isAddedCell () ) {
overviewGraph . repaint () ;
}
}
}
);
} else {
overviewGraph = null ;
}
PortView . renderer = new PortRenderer () {
{
setForeground ( Preferences . getPortColor () ) ;
}
};
p re f e re n ce s C ha n ge d () ;
A. Java-Programm-Quelltext
570
560
550
540
530
if ( selected != null ) {
if (!( selected instanceof D e l i m i te rLi ne Ce ll )
/* && !( selected instanceof RegionCell ) */) {
items . add ( Utils . c re a te JM e nu Item ( ActionEditEdit . class ) ) ;
}
if ( selected instanceof StateCell ) {
items . add ( Utils . c re a te JM e nu Item (
A c t i o n E d i t S t a t e E n t r y A c t i o n s . class ) ) ;
items . add ( Utils . c re a te JM e nu Item (
A c t i o n E d i t S t a t e D o A c t i o n s . class ) ) ;
items . add ( Utils . c re a te JM e nu Item (
A c t i o n E d i t S t a t e E x i t A c t i o n s . class ) ) ;
if ( selected instanceof C o m p o si t eS t a te C el l ) {
items . add ( Utils . c re a te J MenuItem (
A c t i o n E d i t S t a t e E v e n t s . class ) ) ;
items . add ( Utils . c re a te J MenuItem (
final GraphCell selected = ( GraphCell ) getS electionCell () ;
ArrayList items = new ArrayList () ;
/**
* Returns all popup or menu items for the selected element .
* @return .
*/
public ArrayList g e t M e n u I t e m s F o r S e l e c t e d () {
/**
*.
* @param aLayouterMenu .
*/
public void s et L ay o ut e rM e nu ( final JMenu aLayouterMenu ) {
layouterMenu = aLayouterMenu ;
}
/**
*
*/
private JMenu layouterMenu ;
}
popup . removeAll () ;
ArrayList allItems = g e t M e n u I t e m s F o r S e l e c t e d () ;
for ( int i = 0; i < allItems . size () ; i ++) {
if ( allItems . get ( i ) instanceof JComponent ) {
popup . add (( JComponent ) allItems . get ( i ) ) ;
} else {
popup . add (( EditorAction ) allItems . get ( i ) ) ;
}
}
popup . show ( this , x , y ) ;
*/
public void showPopup ( final int x , final int y ) {
630
620
610
600
590
580
//
}
A c t i o n E d i t S t a t e V a r i a b l e s . class ) ) ;
items . add ( Utils . createJMenuItem ( ActionEditCut . class ) ) ;
if ( selected instanceof C o mp o si t e St a te C e ll
&& !( selected instanceof RegionCell ) ) {
items . add ( new JPopupMenu . Separator () ) ;
items . add ( g e t M e n u I t e m C o l l a p s e d () ) ;
items . add ( new JPopupMenu . Separator () ) ;
}
if ( selected instanceof SimpleStateCell ) {
items . add ( Utils . createJMenuItem (
A c t i o n E d i t C o n v e r t T o O R S t a t e . class ) ) ;
}
if ( selected instanceof NodeCell
&& ! h a s O u t g o i n g T r a n s i t i o n s (
( Default GraphCell ) selected ) ) {
items . add ( Utils . createJMenuItem (
A c t i o n E d i t C o n v e r t F l i p F i n a l A t t r i b u t e . class ) ) ;
}
if ( selected . getClass () == ORStateCell . class ) {
if ((( ORStateCell ) selected ) . getChildCount () == 1) {
items . add ( Utils . createJMenuItem (
A c t i o n E d i t C o n v e r t T o S i m p l e S t a t e . class ) ) ;
}
}
if ( selected instanceof NodeCell ) {
items . add ( Utils . createJMenuItem (
A c t i o n A d d L o o p T r a n s i t i o n . class ) ) ;
}
if ( EditorActions . get ( ActionEditPaste . class ) . isEnabled ()
&& (( ActionEditCut ) EditorActions . get ( ActionEditCut . class ) )
. get Cu rre nt Cut Ce ll () != null ) {
items . add ( Utils . createJMenuItem ( ActionEditPaste . class ) ) ;
}
if ( selected != null ) {
if ( selected instanceof ANDStateCell
|| selected instanceof ORStateCell ) {
items . add ( layouterMenu ) ;
}
if ( getMyGraphModel () . getRootCell () != selected ) {
}
items . add ( EditorActions . get ( A c t i o n F i l e P r o p e r t i e s . class ) ) ;
if (!( selected instanceof RegionCell ) ) {
items . add ( new JPopupMenu . Separator () ) ;
items . add ( Utils . createJMenuItem ( ActionE ditRemove . class ) ) ;
}
items . add ( new JPopupMenu . Separator () ) ;
if ( EditorActions . get ( ActionEditCut . class ) . isEnabled ()
&& !( selected instanceof TransitionCell )
&& !( selected instanceof D eli mi ter Li neC el l )
&& !( selected instanceof RegionCell ) ) {
}
A.4. Der Quelltext
185
186
680
670
660
650
640
/**
/**
* This menu item always reflects the collapsed state of the currently
730
* selected state .
*/
private JMenuItem m e n u I t e m C o l l a p s e d =
new J C h e c k B o x M e n u I t e m ( EditorActions . get ( A c t i o n E d i t C o l l a p s e d . class ) ) ;
}
710
if (!( selected instanceof N o r m a l T e r m i n a t i o n C e l l ) ) {
items . add ( Utils . c re ateJMenuItem (
A c t i o n E d i t C o n v e r t T o N o r m a l T r a n s i t i o n . class ) ) ;
}
if (!( selected instanceof WeakAbort ionCell ) ) {
items . add ( Utils . c re ateJMenuItem (
A c t i o n E d i t C o n v e r t T o W e a k A b o r t i o n . class ) ) ;
}
if (!( selected instanceof St r o ng A bo r t io n Ce l l ) ) {
items . add ( Utils . c re ateJMenuItem (
A c t i o n E d i t C o n v e r t T o S t r o n g A b o r t i o n . class ) ) ;720
}
items . add ( Utils . c re a te J MenuItem (
A c t i o n E d i t C o n v e r t T o O r t h o g o n a l . class ) ) ;
}
items . add ( new JPopupMenu . Separator () ) ;
if (!( selected instanceof C o n d i t i o n a l T r a n s i t i o n C e l l )
&& !( selected instanceof InitialArcCell )
&& !( selected instanceof SuspensionCell ) ) {
}
if ( G raph Const ants . getLineStyle ( selected . getAttributes () ) 700
!= Gr aphC onsta nts . S T Y L E _ORTHOGONAL ) {
items . add ( Utils . c re a te J MenuItem (
A c t i o n E d i t C o n v e r t T o B e z i e r . class ) ) ;
}
}
}
return items ;
) {
) {
}
}
if ( selected instanceof DefaultEdge ) {
items . add ( Utils . cr e at e JM e nu Item (
A c t i o n E d i t T r a n s i t i o n P r i o r i t y . class ) ) ;
if ( G raph Const ants . getLineStyle (
selected . getAttributes () ) != GraphConstants . STYLE_SPLINE
690
items . add ( Utils . c re a te J MenuItem (
A c t i o n E d i t C o n v e r t T o S p l i n e . class ) ) ;
}
if ( G raph Const ants . getLineStyle (
selected . getAttributes () ) != GraphConstants . STYLE_BEZIER
/**
* @see kiel . util . main . KielComponent # g e t C u r r e n t S t a t e C h a r t ()
*/
public StateChart g e t C u r r e n t S t a t e C h a r t () {
if ( getMyGraphModel () != null ) {
return getMyGraphModel () . g e t C u r r e n t S t a t e C h a r t () ;
} else {
return null ;
}
}
/**
* Casts the current Model to MyGraphModel . If the current model is not
a
* MyGraphModel then null is returned
* @return .
*/
public synchronized MyGraphModel getMyGraphModel () {
if ( getModel () instanceof MyGraphModel ) {
return (( MyGraphModel ) getModel () ) ;
} else {
return null ;
}
}
/**
* @see # cur re ntP op upP oi nt
* @return .
*/
public Point2D g e t C u r r e n t P o p u p P o i n t () {
return c ur ren tP opu pP oin t ;
}
/**
* @see # cur re ntP op upP oi nt
* @param a C ur r en t P op u pP o i nt The cu rre nt Pop up Poi nt to set .
*/
public void s e t C u r r e n t P o p u p P o i n t ( final Point2D aC u r re n tP o p u p P o i n t ) {
this . cu rr ent Po pup Po int = a C ur r e nt P op u p Po i nt ;
}
/**
* Returns the coordinates of the last popup trigger , used for the popup
* menu and for placing a new state .
*/
private Point2D c urr en tPo pu pPo in t ;
* @return the menu item reflecting the collapsed state of the currently
* selected state
*/
public JMenuItem g e t M e n u I t e m C o l l a p s e d () {
return m en uIt em Col la pse d ;
}
A. Java-Programm-Quelltext
780
770
760
750
740
790
}) ;
}
if (! g e t U n d o C l u s t e r M a n a g e r () . i s U n d o M a n a g e r I n P r o g r e s s () ) {
g e t G r a p h L a y o u t C a c h e () . setVisible ( e . getChange ()
. getInserted () , true ) ;
830
if (! i s S e t t i n g M o d e l C o m p l e t e d ) {
g e t U n d o C l u s t e r M a n a g e r () . d i s c a r d C u r r e n t C l u s t e r () ;
i s S e t t i n g M o d e l C o m p l e t e d = true ;
}
u p d a t e O v e r v i e w G r a p h S c a l e () ;
}
public void graphChanged ( final GraphModelEvent e ) {
model . a d d G r a p h M o d e l L i s t e n e r ( new G r a p hM o d el L is t e ne r () {
}
810
if ( g e t U n d o C l u s t e r M a n a g e r () != null && g e t U n d o C l u s t e r M a n a g e r ()
. g etUnd oMan ager () != null ) {
g e t U n d o C l u s t e r M a n a g e r () . clear () ;
model . a d d U n d o a b l e E d i t L i s t e n e r ( g e t U n d o C l u s t e r M a n a g e r ()
. g etUnd oMan ager () ) ;
}
820
u p d a t e O v e r v i e w G r a p h S c a l e () ;
overviewGraph . setModel ( model ) ;
if ( overviewGraph != null ) {
/**
* Don ’ t call directly but always through editor . setModel () .
* @see org . jgraph . JGraph # setModel ( org . jgraph . graph . GraphModel )
*/
public void setModel ( final GraphModel model ) {
i s S e t t i n g M o d e l C o m p l e t e d = false ;
super . setModel ( model ) ;
/**
* After setting the model the cells have set visible , but that action800
* should not belog to the new edit cluster .
*/
private boolean i s S e t t i n g M o d e l C o m p l e t e d ;
/**
* @see kiel . util . main . KielComponent # getCurrentView ()
*/
public View getC urren tVie w () {
if ( g et M yG r ap h Mo d el () != null ) {
return ge t My G ra p hM o de l () . getC urrentView () ;
} else {
return null ;
}
}
double pageWidth = pageFormat . g et Ima ge abl eW idt h () ;
double pageHeight = pageFormat . g et I m ag e ab l e He i gh t () ;
int cols = ( int ) ( this . getWidth () / pageWidth ) + 1;
int rows = ( int ) ( this . getHeight () / pageHeight ) + 1;
int pageCount = cols * rows ;
double xScale = pageWidth / this . getWidth () ;
double yScale = pageHeight / this . getHeight () ;
double oldScale = getScale () ;
try {
// turn off double buffering of graph so we don ’ t get bitmap
printed
se tD oub le Buf fe red ( false ) ;
/**
* @see java . awt . print . Printable # print ( java . awt . Graphics ,
* java . awt . print . PageFormat , int )
*/
public int print ( final Graphics g , final PageFormat pageFormat ,
final int page ) {
/**
* The overview graph should always fit the window size . So this method
is
* called whenever the graph has changed or when a new model is set or
when
* the window has been resized .
*/
public void u p d a t e O v e r v i e w G r a p h S c a l e () {
if ( overviewGraph != null && getMyGraphModel () != null ) {
Rectangle2D bounds = GraphConstants . getBounds (
getMyGraphModel () . getRootCell () . getAttributes () ) ;
final int roundingTip = 20;
double scaleFact orWidth =
( overviewGraph . getWidth () - roundingTip ) / bounds . getWidth ()
;
double s ca leF ac tor He igh t =
( overviewGraph . getHeight () - roundingTip ) / bounds . getHeight
() ;
if ( Math . min ( scaleFactorWidth , sc al eFa ct orH ei ght ) < 1) {
overviewGraph . setScale (
Math . min ( scaleFactorWidth , sca le Fac to rHe ig ht ) ) ;
} else {
overviewGraph . setScale (1) ;
}
}
}
}
if ( g e t G r a p h L a y o u t C a c h e () != null ) {
g e t G r a p h L a y o u t C a c h e () . setVisible (
De fa ult Gr aph Mo del . getDescendants ( getModel () , getRoots () )
. toArray () , true ) ;
}
A.4. Der Quelltext
187
188
850
840
double tx = 0.0;
double ty = 0.0;
final double half = 0.5;
if ( xScale > scale ) {
tx = half * ( xScale - scale ) * this . getWidth () ;
} else {
ty = half * ( yScale - scale ) * this . getHeight () ;
}
(( Graphics2D ) g ) . translate (( int ) pageFormat . getImageableX () ,
( int ) pageFormat . getImageableY () ) ;
(( Graphics2D ) g ) . translate ( tx , ty ) ;
(( Graphics2D ) g ) . scale ( scale , scale ) ;
double scale = Math . min ( xScale , yScale ) ;
860
}
}
if ( page >= pageCount ) {
return NO_SUCH_PAGE ;
this . paint ( g ) ;
} finally {
// turn double buffering back on
se tD oub le Buf fe red ( true ) ;
setScale ( oldScale ) ;
}
return PAGE_EXISTS ;
}
A. Java-Programm-Quelltext
javax . swing . JButton ;
javax . swing . JDialog ;
javax . swing . JFrame ;
javax . swing . JLabel ;
javax . swing . JPanel ;
javax . swing . JScrollPane ;
javax . swing . JTable ;
50
Preferences . addListener ( this ) ;
/**
* @param owner the parent frame for the dialog
*
*/
public P r e f e r e n c e s D i a l o g ( final JFrame owner ) {
super ( owner , "" , true ) ;
100
30
40
/**
* Displays the user preferences . If the user has never saved his
preferences
* to disk , then the default preferences will be shown , but in any case the
* current preferences will be shown , that means , the user can change
* preferences in this dialog and these changes are applied immediately . but
* if the user does not select save , then these changes will be lost when
* exiting the application . An object of this class holds a reference to the
* loaded preferences and a reference to the default preferences . when the
* user changes a value , then the correctness of that value will be checked
* the next time this value is applied . for most of the values this is will80
* be done immediately . if the check failed ( for example , the user typed in
* 3 ,4 instead of 3.4) then the wrong value is overwritten with the default
* preferences value .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.22 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class P r e f e r e n c e s D i a l o g extends JDialog
90
implements Preferences . Listener {
60
70
import kiel . editor . resources . Preferences ;
import kiel . editor . resources . Reso urce Bundl e ;
import
import
import
import
import
import
import
java . awt . BorderLayout ;
java . awt . Dimension ;
java . awt . FlowLayout ;
java . awt . Toolkit ;
java . awt . event . ActionEvent ;
java . awt . event . Acti onLis tene r ;
20
10
import
import
import
import
import
import
package kiel . editor ;
kiel.editor.PreferencesDialog
p re f e re n ce s C ha n ge d () ;
/**
* Creates a table with dynamically read translated Preferences keys and
* values .
* @return .
*/
private JScrollPane createTable () {
/**
* @see # currentTable
*/
private JPanel c u rr e nt B u tt o nP a n el ;
/**
* the current table is stored for removing it to reflect immediately .
* the change the preferences language
*/
private JScrollPane currentTable ;
/**
* whenever the user presses the " save " button , the data will be saved
to
* disk only if the user changed a value beforehand .
*/
private boolean somethingCha nged ;
/**
* .
*/
private JLabel headerLabel = new JLabel () ;
}
getContentPane () . add ( headerPanel , " North ") ;
JPanel headerPanel = Utils . createJPanel ( new BorderLayout () , false ) ;
headerPanel . setPref erredSize ( new Dimension (0 , headerHight ) ) ;
headerLabel . setOpaque ( false ) ;
headerPanel . add ( headerLabel ) ;
getContentPane () . setLayout ( new BorderLayout () ) ;
Dimension d = Toolkit . g et Def au ltT oo lki t () . getScreenSize () ;
final int dialogSize = 400;
final int headerHight = 32;
setBounds (
( d . width - dialogSize ) / 2 ,
( d . height - dialogSize ) / 2 ,
dialogSize ,
dialogSize ) ;
s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . DISPOSE_ON_CLOS E ) ;
A.4. Der Quelltext
189
190
140
130
120
110
);
}
}
}
180
s o m e t h i n g C h a n g e d = true ;
}
Preferences . setProperty ( keys [ row ] , ( String ) value ) ;
super . setValueAt ( value , row , col ) ;
if (! Preferences . getProperty ( keys [ row ]) . equals ( value
public void setValueAt ( final Object value , final int row
170
final int col ) {
get Colu mnMod el () . getColumn (1) . s etP re fer re dW idt h ( column1 )
160
s e t A u t o R e s i z e M o d e ( JTable . AUTO_RESIZE_OFF ) ;
final int column0 = 244;
final int column1 = 130;
get Colu mnMod el () . getColumn (0) . s etP re fe rre dW idt h ( column0 )
150
/**
* Whenever the user changes the language , the whole table and button
panel
* have to created again .
* @see kiel . editor . resources . Preferences . Listener # pr e f er e nc e s Ch a ng e d ()
*/
public void p r e f e r e n c e s C h a n g e d () {
190
if ( currentTable != null ) {
get Conte ntPa ne () . remove ( currentTable ) ;
get Conte ntPa ne () . remove ( c u r r e n t Bu t t on P an e l ) ;
}
setTitle ( R esou rceBu ndle . getString (" Pre fe ren ce sDi al og ") ) ;
headerLabel . setText ( getTitle () ) ;
ge tCont entP ane () . add ( createTable () , " Center ") ;
}
)) {
,
;
;
{
final String [] keys =
( String []) Preferences . keySet () . toArray ( new String [0]) ;
Object [][] data = new Object [ keys . length ][2];
for ( int i = 0; i < data . length ; i ++) {
data [ i ] = new String [] {
Res ourc eBund le . getString ( keys [ i ]) ,
Preferences . getProperty ( keys [ i ]) };
}
return currentTable = new JScrollPane (
new JTable ( data , new String []{
Res ourc eBund le . getString (" preferencesKey ") ,
Res ourc eBund le . getString (" p referencesValu e ") }) {
}
}
JButton cancelButton = new JButton ( ResourceBundle . getString (" Cancel
") ) ;
cancelButton . a ddA ct ion Li ste ne r ( new ActionListener () {
public void actionPerformed ( final ActionEvent e ) {
dispose () ;
}
}) ;
cancelButton . setOpaque ( false ) ;
c ur r e nt B ut t o nP a ne l . add ( cancelButton ) ;
return cu r re n t Bu t to n P an e l ;
JButton okButton =
new JButton ( ResourceBundle . getString (" ActionFileSa ve ") ) ;
okButton . add Ac tio nL ist en er ( new ActionListener () {
public void actionPerformed ( final ActionEvent e ) {
if ( so methingChanged ) {
Preferences . store () ;
}
dispose () ;
}
}) ;
okButton . setOpaque ( false ) ;
c ur r e nt B ut t o nP a ne l . add ( okButton ) ;
JButton resetButton =
new JButton ( ResourceBundle . getString (" defaultValues ") ) ;
resetButton . add Ac tio nL ist en er ( new ActionListener () {
public void actionPerformed ( final ActionEvent e ) {
Preferences . setDef aultValues () ;
dispose () ;
}
}) ;
resetButton . setOpaque ( false ) ;
c ur r e nt B ut t o nP a ne l . add ( resetButton ) ;
/**
* creates the button panel with cancel and save button .
* @return .
*/
private JPanel cr eat eB utt on Pan el () {
final int gap = 6;
c ur r e nt B ut t o nP a ne l =
Utils . createJPanel ( new FlowLayout ( FlowLayout . RIGHT , gap , gap ) ) ;
}
getContentPane () . add ( cre at eBu tt onP an el () , " South ") ;
validate () ;
repaint () ;
A. Java-Programm-Quelltext
50
/**
* The given current redoable edit steps .
*/
private EditStep [] r e d o a b l e E d i t S t e p s ;
100
40
/**
* The given current undoable edit steps .
*/
private EditStep [] u n d o a b l e E d i t S t e p s ;
/**
* This dialog displays all undo / redo steps as well as the whole edit step
* history .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.21 $ last modified $Date : 2005/07/25 11:44:37 $
*/
90
public final class Trac eLog Dialo g extends JDialog {
80
70
30
javax . swing . JButton ;
javax . swing . JDialog ;
javax . swing . JFileChooser ;
javax . swing . JFrame ;
javax . swing . JLabel ;
javax . swing . JPanel ;
javax . swing . JScrollPane ;
javax . swing . JTabbedPane ;
javax . swing . JTable ;
javax . swing . table . D e f a u l t T a b l e C e l l R e n d e r e r ;
import
import
import
import
import
import
import
import
import
import
60
import kiel . editor . resources . Preferences ;
import kiel . editor . resources . Reso urce Bundl e ;
import kiel . editor . resources . Reso urce Loade r ;
20
10
java . awt . BorderLayout ;
java . awt . Component ;
java . awt . Container ;
java . awt . Dimension ;
java . awt . FlowLayout ;
java . awt . Toolkit ;
java . awt . event . ActionEvent ;
java . awt . event . Acti onLis tene r ;
java . io . F i l e N o t F o u n d E x c e p t i o n ;
java . io . F i l e O u t p u t S t r e a m ;
java . io . PrintWriter ;
java . text . S i m p l e D a t e F o r m a t ;
java . util . Date ;
import
import
import
import
import
import
import
import
import
import
import
import
import
package kiel . editor ;
kiel.editor.TraceLogDialog
}
;
getContentPane () . add ( headerPanel , " North ") ;
getContentPane () . add ( createContent () , " Center ") ;
getContentPane () . add ( cre at eBu tt onP an el () , " South ") ;
JPanel headerPanel = Utils . createJPanel ( new BorderLayout () , false ) ;
headerPanel . setPref erredSize ( new Dimension (0 , headerHight ) ) ;
JLabel label = new JLabel (" Trace Log Dialog ") ;
label . setOpaque ( false ) ;
headerPanel . add ( label ) ;
getContentPane () . setLayout ( new BorderLayout () ) ;
final int dialogSize = 400;
final int headerHight = 32;
Dimension d = Toolkit . g et Def au ltT oo lki t () . getScreenSize () ;
setBounds (
( d . width - dialogSize ) / 2 ,
( d . height - dialogSize ) / 2 ,
dialogSize ,
dialogSize ) ;
s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . DISPOSE_ON_CLOS E ) ;
un do abl eE dit St eps = a n A l l U n d o a b l e E d i t S t e p s ;
re do abl eE dit St eps = a n A l l R e d o a b l e E d i t S t e p s ;
allEditSteps = anAllEditSteps ;
editor = anEditor ;
super ( anEditor . getKielFrame () . getJFrame () , " Trace Log Dialog " , true )
/**
* Creates a dialog with size 400 x400 with a tabbed pane inside .
* @param anEditor .
* @param a n A l l U n d o a b l e E d i t S t e p s .
* @param a n A l l R e d o a b l e E d i t S t e p s .
* @param anAllEditSteps .
*/
public TraceLogDialog ( final Editor anEditor ,
final EditStep [] anAllUndoableEditSteps ,
final EditStep [] anAllRedoableEditSteps ,
final EditStep [] anAllEditSteps ) {
/**
* .
*/
private Editor editor ;
/**
* The given all edit steps ( complet history ) .
*/
private EditStep [] allEditSteps ;
A.4. Der Quelltext
191
192
150
140
130
120
110
180
Object [][] data =
new Object [ u n d o a b l e E d i t S t e p s . length + r edo ab leE di tSt ep s . length
][];
for ( int i = 0; i < u n d o a b l e E d i t S t e ps . length ; i ++) {
data [ i ] = new String [] {
190
formatTime ( u n d o a b l e E d i t S t e p s [ i ]) ,
formatAction ( u n d o a b l e E d i t S t ep s [ i ]) };
}
for ( int i = 0; i < r e d o a b l e E d i t S t e ps . length ; i ++) {
data [ u n d o a b l e E d i t S t e p s . length + i ] = new String [] {
formatTime ( r e d o a b l e E d i t S t e p s [ r ed oab le Ed itS te ps . length - i 1]) ,
formatAction (
r e d o a b l e E d i t S t e p s [ r e d o a ble Ed itS te ps . length - i - 1]) };
200
}
JTable table = new JTable ( data , new String []{
Res ourc eBund le . getString (" time ") ,
Res ourc eBund le . getString (" editStep ") }) ;
/**
* Creates the Tabbed pane with its content .
* @return .
*/
private JTabbedPane createContent () {
/**
*
*/
private JTabbedPane tabPane = new JTabbedPane () ;
160
/**
* Reads the class name associated to the edit step , cuts it , and
returns
* the translation of the cutted name via the ResourceBundle .
* @param editStep .
* @return .
*/
private String formatAction ( final EditStep editStep ) {
return Re sour ceBun dle . getString (
editStep . ge t Ed i to r Ac t io n () . getClass () . getName () . substring (
170
editStep . ge t Ed i to r Ac t io n () . getClass () . getName () . lastIndexOf ( ’. ’)
+ 1) ) ;
}
/**
* Formats the time of the iven edit step in HH : mm : ss .
* @param editStep .
* @return .
*/
private String formatTime ( final EditStep editStep ) {
return new S i m p l e D a t e F o r m a t (" HH : mm : ss ") . format (
new Date ( editStep . g e t C u r r e n t T i m e M i l l i s () ) ) ;
}
return tabPane ;
data = new Object [ allEditSteps . length ][];
for ( int i = 0; i < data . length ; i ++) {
data [ i ] = new String [] {
formatTime ( allEditSteps [ i ]) ,
formatAction ( allEditSteps [ i ]) ,
ResourceBundle . getString ( allEditSteps [ i ]. getType () ) };
}
currentTable = new JScrollPane (
new JTable ( data , new String []{
ResourceBundle . getString (" time ") ,
ResourceBundle . getString (" editStep ") ,
ResourceBundle . getString (" editStepType ") }) ) ;
tabPane . insertTab (
ResourceBundle . getString (" allEditSteps ") ,
ResourceLoader . get (" Edit16 . gif ") ,
currentTable ,
ResourceBundle . getString (" t o o l t i p A l l E d i t S t e p s ") , 1) ;
/**
* Creates the button panel with the export and cancel button .
* @return .
*/
private JPanel cr eat eB utt on Pa nel () {
final int gap = 6;
JPanel cu r re n t Bu t to n P an e l =
}
}
isSelected , hasFocus , row , column ) ;
if ( row < und oa ble Ed itS te ps . length ) {
c . setBackground ( Preferences . getG uiColorL i g h t () ) ;
} else {
c . setBackground ( Preferences . getGuiColorD a rk () ) ;
}
return c ;
Component c = super . g e t T a b l e C e l l R e n d e r e r C o m p o n e n t ( table ,
}) ;
JScrollPane currentTable = new JScrollPane ( table ) ;
tabPane . insertTab (
ResourceBundle . getString (" undoSteps ") ,
ResourceLoader . get (" Undo16 . gif ") ,
currentTable ,
ResourceBundle . getString (" tooltipUndoSte ps ") , 0) ;
value ,
table . s et D ef a u lt R en d e re r ( Object . class , new D e f a u l t T a b l e C e l l R e n d e r e r
() {
public Component g e t T a b l e C e l l R e n d e r e r C o m p o n e n t ( final JTable
table ,
final Object value , final boolean isSelected ,
final boolean hasFocus , final int row , final int column ) {
A. Java-Programm-Quelltext
240
230
220
210
Utils . createJPanel ( new FlowLayout ( FlowLayout . RIGHT , gap , gap ) ) ;
JButton okButton =
new JButton ( Re sour ceBun dle . getString (" ActionFileEx port ") ) ;
okButton . a d d A c t i o n L i s t e n e r ( new Ac tionListener () {
250
public void a c ti o nP e rf o rm e d ( final ActionEvent e ) {
JFileChooser chooser = new JFileChooser (
Res ourc eBund le . getString (" T r a ce L og S a ve D ia l o g ") ) ;
s e t C a n c e l B u t t o n T e x t ( chooser ,
Res ourc eBund le . getString (" Cancel ") ) ;
int answer = chooser . showDialog (
Tra ceLo gDial og . this . getOwner () ,
Res ourc eBund le . getString (" ActionFileSave ") ) ;
if ( answer == JFileChooser . APPROVE_OPTION ) {
try {
PrintWriter out = new PrintWriter ( new
260
FileOutputStream (
chooser . g et S el e ctedFile () ) , true ) ;
if ( tabPane . g e t S e l e ctedIn dex () == 0) {
for ( int i = 0; i < un doa bl eEd it Ste ps . length ; i
++) {
out . println (
formatTime ( un do abl eE dit St ep s [ i ])
+ Preferences . g e t T r a c e L o g S e p a r a t o r ()
+ formatAction ( un doa bl eEd it Ste ps [ i ]) ) ;
}
for ( int i = 0; i < re doa bl eEd it Ste ps . length ; 270
i
++) {
out . println (
formatTime ( re do abl eE dit St ep s [ i ])
+ Preferences . g e t T r a c e L o g S e p a r a t o r ()
+ formatAction ( re doa bl eEd it Ste ps [ i ]) ) ;
}
} else {
for ( int i = 0; i < allEditSteps . length ; i ++) {
out . println (
formatTime ( allEditSteps [ i ])
+ Preferences . g e t T r a c e L o g S e p a r a t o r () 280
+ formatAction ( allEditSteps [ i ])
+ Preferences . g e t T r a c e L o g S e p a r a t o r ()
+ Reso urceBundle . getString (
allEditSteps [ i ]. getType () ) ) ;
}
}
out . close () ;
} catch ( F i l e N o t F o u n d E x c e p t i o n ex ) {
}
}
for ( int i = 0; i < c . getComponents () . length ; i ++) {
if ( c . getComponents () [ i ] instanceof JButton ) {
if (" Cancel ". equals ((( JButton ) c . getComponents () [ i ]) . getText
() )
|| " Abbrechen ". equals (
(( JButton ) c . getComponents () [ i ]) . getText () ) ) {
(( JButton ) c . getComponents () [ i ]) . setText ( text ) ;
}
} else if ( c . getComponents () [ i ] instanceof Container ) {
s e t C a n c e l B u t t o n T e x t (( Container ) c . getComponents () [ i ] , text ) ;
}
}
/**
* Workaround for setting the cancel button text of a component that
* has a " Abbrechen " or " Cancel " button .
* @param c e . g . a JFileChooser object
* @param text the text for the cancel button
*/
private static void s e t C a n c e l B u t t o n T e x t ( final Container c ,
final String text ) {
}
}
}) ;
okButton . setOpaque ( false ) ;
c ur r e nt B ut t o nP a ne l . add ( okButton ) ;
JButton cancelButton = new JButton ( ResourceBundle . getString (" Cancel
") ) ;
cancelButton . a ddA ct ion Li ste ne r ( new ActionListener () {
public void actionPerformed ( final ActionEvent e ) {
dispose () ;
}
}) ;
cancelButton . setOpaque ( false ) ;
c ur r e nt B ut t o nP a ne l . add ( cancelButton ) ;
return cu r r en t Bu t t on P an e l ;
}
}
dispose () ;
editor . getKielFrame () . handleException (
ResourceBundle . getString (" ErrorOnSaving ") ,
false , ex ) ;
A.4. Der Quelltext
193
194
40
30
20
10
50
kiel . editor . controller . Ac tionE ditR edo ;
kiel . editor . controller . Ac tionE ditU ndo ;
kiel . editor . controller . EditorAction ;
kiel . editor . controller . EditorActions ;
kiel . util . LogFile ;
60
/**
* .
*/
/**
* The G r a p h U n d o M a n a g e r object for handling undo operations as
GraphModel
* change steps .
*/
private UndoManager undoManager ;
90
/**
* The U n d o C l u s t e r M a n a g e r manages the the EditorActions , the user edit steps
.
* The G r a p h U n d o M a n a g e r manages the GraphModel change steps . The
* U n d o C l u s t e r M a n a g e r wraps the G r a p h U n d o M a nager to cluster and wrap the
* GraphModel change steps . That means , the GraphModel change steps during
an
70
* EditorAction step have to be counted and this count , wrapped into an
* EditStep object , has to be stored on a stack . When the user wants to
* perform an undo , he calls U n d o C l u s t e r M a n a ge r . undo () , which takes an
EditStep
* containing a count n from the stack , and calls n times
* G r a p h U n d o M a n a g e r . undo () . The same with redo steps .
* The U n d o C l u s t e r M a n a g e r also provides a Slider object , unfortunately this
* slider currently just acts as visible component without working features
: -(
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
80
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.43 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class U n d o C l u s t e r M a n a g e r {
import org . jgraph . graph . G r a p h U n d o M a n a g e r ;
import
import
import
import
import
/**
* Initializes the slider and performs a clear () call .
*
*/
U nd o C lu s te r Ma n a ge r () {
getSlider () . setMinimum (0) ;
getSlider () . setMaximum (0) ;
getSlider () . a dd Cha ng eLi st ene r ( s l i d e r C h a n g e L i s t e n e r ) ;
/**
* The s l i d e r C h a n g e L i s t e n e r should not react , when the slider is
adjusted
* inside the Un d oC l u st e rM a n ag e r .
*/
private boolean updateSlider = true ;
/**
* The s l i d e r C h a n g e L i s t e n e r reacts on using the slider knob to perform
undo
* or redo steps .
*/
private ChangeListener s l i d e r C h a n g e L i s t e n e r = new Change List ener () {
public void stateChanged ( final ChangeEvent e ) {
if (! updateSlider ) {
return ;
}
if ( u n d o a b l e E d i t H a p p e n e d C l u s t e r s . size () > getSlider () . getValue ()
) {
while ( u n d o a b l e E d i t H a p p e n e d C l u s t e r s . size ()
> getSlider () . getValue () ) {
undo () ;
}
} else {
while ( u n d o a b l e E d i t H a p p e n e d C l u s t e r s . size ()
+ r e d o a b l e E d i t H a p p e n e d C l u s t e r s . size ()
> getSlider () . getValue () ) {
redo () ;
}
}
}
};
/**
* .
* @param aListener .
*/
void setListener ( final U n d o C l u s t e r M a n a g e r L i s t e n e r aListener ) {
listener = aListener ;
}
javax . swing . JSlider ;
javax . swing . event . ChangeEvent ;
javax . swing . event . Chang eLis tener ;
javax . swing . event . U n d o a b l e E d i t E v e n t ;
javax . swing . undo . UndoManager ;
import java . util . Stack ;
import
import
import
import
import
private U n d o C l u s t e r M a n a g e r L i s t e n e r listener ;
package kiel . editor ;
kiel.editor.UndoClusterManager
A. Java-Programm-Quelltext
140
130
120
110
100
clear () ;
180
170
160
150
/**
* Update Undo / Redo Button State and slider dependent on the undo and 190
redo
* stack .
*/
private void u p d a t e H i s t o r y B u t t o n s A n d S l i d e r () {
EditorActions . get ( Act ionEd itUn do . class ) . setEnabled (
! u n d o a b l e E d i t H a p p e n e d C l u s t e r s . isEmpty () ) ;
EditorActions . get ( Act ionEd itRe do . class ) . setEnabled (
! r e d o a b l e E d i t H a p p e n e d C l u s t e r s . isEmpty () ) ;
/**
*
* @return the content of the redo EditStep stack
*/
public EditStep [] g e t A l l R e d o a b l e E d i t S t e p s A s c e n d i n g () {
return ( EditStep []) r e d o a b l e E d i t H a p p e n e d C l u s t e r s . toArray (
new EditStep [0]) ;
}
/**
*
* @return the content of the undo EditStep stack
*/
public EditStep [] g e t A l l U n d o a b l e E d i t S t e p s A s c e n d i n g () {
return ( EditStep []) u n d o a b l e E d i t H a p p e n e d C l u s t e r s . toArray (
new EditStep [0]) ;
}
/**
* @see # slider
* @return .
*/
JSlider getSlider () {
return slider ;
}
/**
* The slider displaying the current relation between undo and redo
steps .
*/
private final JSlider slider = Utils . createJSlider () ;
/**
*
* @return the UndoManager responsible for GraphModel change steps
*/
UndoManager g etUnd oMan ager () {
return undoManager ;
}
}
/**
* Process the whole undo stack .
*
}
}
};
undoManager . setLimit ( Integer . MAX_VALUE ) ;
u p d a t e H i s t o r y B u t t o n s A n d S l i d e r () ;
super . u n d o a b l e E d i t H a p p e n e d ( e ) ;
u p d a t e H i s t o r y B u t t o n s A n d S l i d e r () ; // Update Toolbar
u n d o a b l e E d i t H a p p e n e d C o u n t ++;
public void u n d o a b l e E d i t H a p p e n e d ( final U ndo ab leE di tE v e n t e ) {
if ( i s U n d o M a n a g e r I n P r o g r e s s () ) {
return ;
}
/**
* clears the whole GraphModel undo history by destroying the old
* Gr aphUndoManager . With this also the EditStep undo and redo stacks
have
* to be cleared .
*
*/
void clear () {
r e d o a b l e E d i t H a p p e n e d C l u s t e r s . clear () ;
u n d o a b l e E d i t H a p p e n e d C l u s t e r s . clear () ;
u n d o a b l e E d i t H a p p e n e d C o u n t = 0;
undoManager = new GraphUndoM anager () {
/**
* the undo EditStep stack .
*/
private final Stack u n d o a b l e E d i t H a p p e n e d C l u s t e r s = new Stack () ;
/**
* the count of GraphModel change steps of the current EditStep .
*/
private int u n d o a b l e E d i t H a p p e n e d C o u n t ;
}
if ( listener != null ) {
listener . stackChanged (
u n d o a b l e E d i t H a p p e n e d C l u s t e r s . size () ,
r e d o a b l e E d i t H a p p e n e d C l u s t e r s . size () ) ;
}
updateSlider = false ;
getSlider () . setMinimum (0) ;
getSlider () . setMaximum ( u n d o a b l e E d i t H a p p e n e d C l u s t e r s . size ()
+ r e d o a b l e E d i t H a p p e n e d C l u s t e r s . size () ) ;
getSlider () . setValue ( u n d o a b l e E d i t H a p p e n e d C l u s t e r s . size () ) ;
updateSlider = true ;
A.4. Der Quelltext
195
196
250
240
230
220
210
200
280
270
260
/**
* Perform one EditorAction EditStep undo .
/**
* The logging handle . Prints logs to standard out .
*/
private LogFile logFile = new LogFile (" Editor " , 2) ;
300
/**
* Perform an undo and do not put this EditStep on the redo stack , so
this
290
* step will be lost = non redoable .
*/
public void n on R ed o ab l eU n do () {
undo () ;
if (! r e d o a b l e E d i t H a p p e n e d C l u s t e r s . isEmpty () ) {
r e d o a b l e E d i t H a p p e n e d C l u s t e r s . pop () ;
}
}
/**
* Perform one EditorAction EditStep redo .
*/
public void redo () {
if ( r e d o a b l e E d i t H a p p e n e d C l u s t e r s . isEmpty () ) {
return ;
}
i s U n d o M a n a g e r I n P r o g r e s s = true ;
int count = (( EditStep ) u n d o a b l e E d i t H a p p e n e d C l u s t e r s
. push ( r e d o a b l e E d i t H a p p e n e d C l u s t e r s . pop () ) ) . getCount () ;
for ( int i = 0; i < count ; i ++) {
// Redo the last Change to the Model or the View
undoManager . redo () ;
}
i s U n d o M a n a g e r I n P r o g r e s s = false ;
u p d a t e H i s t o r y B u t t o n s A n d S l i d e r () ;
}
/**
* Redo the whole undo stack .
*
*/
public void redoAll () {
while (! r e d o a b l e E d i t H a p p e n e d C l u s t e r s . isEmpty () ) {
redo () ;
}
}
*/
public void undoAll () {
while (! u n d o a b l e E d i t H a p p e n e d C l u s t e r s . isEmpty () ) {
undo () ;
}
}
/**
* Throw away the information how many GraphModel change steps have been
* done in the current EditStep . This method should only be called if
the
* undo steps on the GraphModel are done by someone else , for example ,
when
* the JGraph framework does them internally .
*/
public void d i s c a r d C u r r e n t C l u s t e r () {
s e t U n d o C l u s t e r S t a r t () ;
}
/**
* Tells the U n do C l us t er M a na g er to start counting the GraphModel change
* steps because an EditorAction has just begun .
*/
public void s e t U n d o C l u st e r S t a r t () {
u n d o a b l e E d i t H a p p e n e d C o u n t = 0;
}
/**
* @return @see inProgress
*/
boolean i s U n d o M a n a g e r I n P r o g r e s s () {
return i s U n d o M a n a g e r I n P r o g r e s s ;
}
/**
* is true whenever the Un d oC l u st e rM a n ag e r . undo () or redo () method is
* processed .
*/
private boolean i s U n d o M a n a g e r I n P r o g r e s s ;
*/
public void undo () {
if ( u n d o a b l e E d i t H a p p e n e d C l u s t e r s . isEmpty () ) {
return ;
}
i s U n d o M a n a g e r I n P r o g r e s s = true ;
int count = (( EditStep ) r e d o a b l e E d i t H a p p e n e d C l u s t e r s
. push ( u n d o a b l e E d i t H a p p e n e d C l u s t e r s . pop () ) ) . getCount () ;
for ( int i = 0; i < count ; i ++) {
// Undo the last Change to the Model or the View
try {
undoManager . undo () ;
} catch ( N u l l P o i n t e r E x c e p t i o n e ) {
logFile . log (1 ,
" Un d o Cl u st e r Ma n ag e r . undo () Already reported JGraph - bug ")
;
}
}
i s U n d o M a n a g e r I n P r o g r e s s = false ;
u p d a t e H i s t o r y B u t t o n s A n d S l i d e r () ;
}
A. Java-Programm-Quelltext
320
310
/**
* Tells the U n d o C l u s t e r M a n a g e r that the current EditorAction ( EditStep
330
)
* has ended . So , a new EditStep object will be created and put on the
undo
* stack .
* @param editorAction .
*/
public void s e t U n d o C l u s t e r E n d ( final EditorAction editorAction ) {
if ( u n d o a b l e E d i t H a p p e n e d C o u n t > 0) {
u n d o a b l e E d i t H a p p e n e d C l u s t e r s . push ( new EditStep (
undoableEditHappenedCount , editorAction ,
EditStep . T YP E _S U CC E SS F UL ) ) ;
340
u n d o a b l e E d i t H a p p e n e d C o u n t = 0;
r e d o a b l e E d i t H a p p e n e d C l u s t e r s . clear () ;
/**
* the redo EditStep stack .
*/
private final Stack r e d o a b l e E d i t H a p p e n e d C l u s t e r s = new Stack () ;
}
}
u p d a t e H i s t o r y B u t t o n s A n d S l i d e r () ;
/**
*
* @return true if the undo stack is not empty
*/
public boolean canUndo () {
return ! u n d o a b l e E d i t H a p p e n e d C l u s t e r s . isEmpty () ;
}
/**
*
* @return true if the redo stack is not empty
*/
public boolean canRedo () {
return ! r e d o a b l e E d i t H a p p e n e d C l u s t e r s . isEmpty () ;
}
}
A.4. Der Quelltext
197
198
50
40
30
20
10
javax . swing . Abst ract Butto n ;
javax . swing . Action ;
javax . swing . JButton ;
javax . swing . JComboBox ;
javax . swing . JComponent ;
javax . swing . JDialog ;
javax . swing . JLabel ;
javax . swing . JMenu ;
javax . swing . JMenuBar ;
javax . swing . JMenuItem ;
javax . swing . JPanel ;
javax . swing . JScrollBar ;
javax . swing . JScrollPane ;
javax . swing . JSlider ;
javax . swing . JSplitPane ;
javax . swing . JTabbedPane ;
javax . swing . JToggleButton ;
javax . swing . JToolBar ;
javax . swing . KeyStroke ;
javax . swing . event . M o u s e I n p u t L i s t e n e r ;
javax . swing . plaf . ButtonUI ;
javax . swing . plaf . metal . MetalButtonUI ;
javax . swing . plaf . metal . M e t a l T o g g l e B u t t o n U I ;
javax . swing . plaf . metal . Me talTo olBa rUI ;
kiel . editor . controller . EditorActions ;
kiel . editor . resources . Preferences ;
kiel . editor . resources . Reso urce Bundl e ;
kiel . editor . resources . Reso urce Loade r ;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
90
80
70
60
100
/**
* Defines a special look & feel for some swing classes , providing two color
* gradient background paints , and provides a Splitpane and TabbedPane with
java . awt . BorderLayout ;
java . awt . Color ;
java . awt . Component ;
java . awt . Container ;
java . awt . GradientPaint ;
java . awt . Graphics ;
java . awt . Graphics2D ;
java . awt . LayoutManager ;
java . awt . Paint ;
java . awt . event . Cont ainer Even t ;
java . awt . event . C o n t a i n e r L i s t e n e r ;
java . awt . event . KeyEvent ;
java . awt . event . MouseEvent ;
java . awt . event . WindowEvent ;
java . awt . event . Wind owLis tene r ;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
package kiel . editor ;
kiel.editor.Utils
if ( topToBottom ) {
(( Graphics2D ) g ) . setPaint ( new GradientPaint (0 , 0 ,
light , 0 , c . getSize () . height , dark , true ) ) ;
} else {
(( Graphics2D ) g ) . setPaint ( new GradientPaint (0 , 0 ,
dark , c . getSize () . width , 0 , light , true ) ) ;
}
Paint oldPaint = (( Graphics2D ) g ) . getPaint () ;
/**
*
* @param c .
* @param g .
* @param topToBottom .
* @param light .
* @param dark .
*/
private static void paintComponent ( final JComponent c , final Graphics g ,
final boolean topToBottom , final Color light , final Color dark ) {
}
paintComponent (
c,
g,
topToBottom ,
Preferences . getGui ColorLight () ,
Preferences . getGuiColorDark () ) ;
/**
*
* @param c .
* @param g .
* @param topToBottom .
*/
private static void paintComponent ( final JComponent c , final Graphics g ,
final boolean topToBottom ) {
/**
* Not for instantiation .
*
*/
private Utils () { }
* floatable ( draggable ) child components .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.42 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class Utils {
A. Java-Programm-Quelltext
150
140
130
120
110
/**
*
* @see kiel . editor . resources . Preferences . Listener #
* p r e f e r e n c e s C h a n g e d ()
*/
public void p r e f e r e n c e s C h a n g e d () {
setText ( Resou rceB undle . getString ( title ) ) ;
/**
*
*
*/
MyMenu () {
setOpaque ( false ) ;
Preferences . addListener ( this ) ;
p r e f e r e n c e s C h a n g e d () ;
}
/**
*
* @author <a href =" mailto : flu @inf ormatik . uni - kiel . de " >
* Florian Luepke </a >
*/
class MyMenu extends JMenu implements Preferences . Listener {
/**
*
* @param title .
* @param shortcut .
* @return .
*/
public static JMenu createJMenu ( final String title , final String
shortcut ) {
/**
* .
* @param title .
* @param shortcut .
* @param icon .
* @return .
*/
public static JMenu createJMenu ( final String title , final String
shortcut ,
final String icon ) {
JMenu menu = createJMenu ( title , shortcut ) ;
menu . setOpaque ( true ) ;
menu . setIcon ( Re sourc eLoa der . get ( icon ) ) ;
return menu ;
}
}
(( Graphics2D ) g ) . fillRect (0 , 0 , c . getSize () . width , c . getSize () .
height ) ;
(( Graphics2D ) g ) . setPaint ( oldPaint ) ;
200
190
180
170
160
}
}
}
return new MyMenu () ;
if ( shortcut != null ) {
setMnemonic ( ResourceBundle . getString ( shortcut ) . charAt (0)
/**
*
* @return .
*/
public static JToolBar createJToolBar () {
return new JToolBar () {
protected void paintComponent ( final Graphics g ) {
Utils . paintComponent ( this , g , true ) ;
}
/**
*
* @return .
*/
public static JSlider createJSlider () {
return new JSlider () {
{
setOpaque ( false ) ;
for ( int i = 0; i < ge tCo mp one nt Cou nt () ; i ++) {
if ( getComponent ( i ) instanceof JComponent ) {
(( JComponent ) getComponent ( i ) ) . setOpaque ( false ) ;
}
}
}
};
}
/**
*
* @param items .
* @return .
*/
public static JComboBox createJComboBox ( final String [] items ) {
return new JComboBox ( items ) {
{
setOpaque ( false ) ;
for ( int i = 0; i < ge tCo mp one nt Cou nt () ; i ++) {
if ( getComponent ( i ) instanceof JComponent ) {
(( JComponent ) getComponent ( i ) ) . setOpaque ( false ) ;
}
}
(( JComponent ) getRenderer () ) . setOpaque ( false ) ;
}
};
}
}
);
A.4. Der Quelltext
199
200
260
250
240
230
220
210
};
/**
*
* @return .
*/
public static JLabel createJLabel () {
return new JLabel () {
protected void pai ntCo mpone nt ( final Graphics g ) {
Utils . p aintC ompo nent ( this , g , true ) ;
super . p aintC ompo nent ( g ) ;
}
/**
*
* @param layout .
* @param topToBottom .
* @return .
*/
public static JPanel createJPanel ( final LayoutManager layout ,
final boolean topToBottom ) {
return new JPanel ( layout ) {
protected void pai ntCo mpone nt ( final Graphics g ) {
Utils . p aintC ompo nent ( this , g , topToBottom ) ;
}
};
}
/**
*
* @param layout .
* @return .
*/
public static JPanel createJPanel ( final LayoutManager layout ) {
return new JPanel ( layout ) {
protected void pai ntCo mpone nt ( final Graphics g ) {
Utils . p aintC ompo nent ( this , g , true ) ;
}
};
}
/**
*
* @param topToBottom .
* @return .
*/
public static JToolBar cre ateJ ToolB ar ( final boolean topToBottom ) {
return new JToolBar () {
protected void pai ntCo mpone nt ( final Graphics g ) {
Utils . p aintC ompo nent ( this , g , topToBottom ) ;
}
};
}
}
310
300
290
280
270
};
/**
*
/**
*
* @see javax . swing . AbstractButton # setText ( java . lang . String )
*/
public void setText ( final String text ) { }
/**
*
* @param action .
*/
MyJButton ( final Action action ) {
super ( action ) ;
setOpaque ( false ) ;
setFocusPainted ( false ) ;
Preferences . addListener ( this ) ;
p re f er e n ce s Ch a n ge d () ;
}
/**
*
* @author <a href =" mailto : [email protected] . uni - kiel . de " >
* Florian Luepke </a >
*/
final class MyJButton extends JButton implements Preferences .
Listener {
/**
*
* @param action .
* @param tooltip .
* @return .
*/
public static JButton createJButton ( final Action action ,
final String tooltip ) {
/**
*
* @return .
*/
public static JLabel c r e a t e J L a b e l H o r i z o n t a l () {
return new JLabel () {
protected void paintComponent ( final Graphics g ) {
Utils . paintComponent ( this , g , false ) ;
super . paintComponent ( g ) ;
}
};
}
}
A. Java-Programm-Quelltext
360
350
340
330
320
}
return new MyJButton ( action ) ;
/**
*
* @param action .
/**
*
* @author <a href =" mailto : flu @inf ormatik . uni - kiel . de " >
* Florian Luepke </a >
*/
final class My J To g gl e Bu t to n extends JToggleButton
implements Preferences . Listener {
/**
*
* @param action .
* @param tooltip .
* @return .
*/
public static JToggleButton c r e a t e J T o g g l e B u t t o n ( final Action action ,
final String tooltip ) {
}
}
/**
*
* @see kiel . editor . resources . Preferences . Listener #
* p r e f e r e n c e s C h a n g e d ()
*/
public void p r e f e r e n c e s C h a n g e d () {
set Tool TipTe xt ( Resou rceB undle . getString ( tooltip ) ) ;
}
}
}) ;
Utils . p aint Compo nent ( MyJButton . this , g , true ,
Preferences . g e t G u i B u t t o n C o l o r S e l e c t e d L i g h t () ,
Preferences . g e t G u i B u t t o n C o l o r S e l e c t e d D a r k () ) ;
/**
*
* @see javax . swing . plaf . basic . BasicButtonUI #
* p a i n t B u t t o n P r e s s e d ( java . awt . Graphics ,
* javax . swing . Ab stra ctButton )
*/
protected void p a i n t B u t t o nP r e ss e d ( final Graphics g ,
final A bstr actBu tton b ) {
* @see javax . swing . Abs tract Button # setUI ( javax . swing . plaf .
ButtonUI )
*/
public void setUI ( final ButtonUI ui ) {
super . setUI ( new MetalButtonUI () {
410
400
390
380
370
}
}
return new MyJToggleButton ( action ) ;
/**
*
* @return .
}
}) ;
/**
*
* @see kiel . editor . resources . Preferences . Listener #
* p r ef e re n c es C ha n g ed ()
*/
public void p r ef e re n c es C ha n g ed () {
setToolTipText ( ResourceBundle . getString ( tooltip ) ) ;
}
}
Utils . paintComponent ( MyJToggleButton . this , g , true ,
Preferences . g e t G u i B u t t o n C o l o r S e l e c t e d L i g h t () ,
Preferences . g e t G u i B u t t o n C o l o r S e l e c t e d D a r k () ) ;
super . setUI ( new M e t a l T o g g l e B u t t o n U I () {
/**
*
* @see javax . swing . plaf . basic . BasicButtonUI #
* p a in t Bu t t on P re s s ed ( java . awt . Graphics ,
* javax . swing . AbstractButton )
*/
protected void pa i nt B u tt o nP r es s e d ( final Graphics g ,
final AbstractButton b ) {
/**
*
* @see javax . swing . AbstractButton # setUI ( javax . swing . plaf .
ButtonUI )
*/
public void setUI ( final ButtonUI ui ) {
/**
*
* @see javax . swing . AbstractButton # setText ( java . lang . String )
*/
public void setText ( final String text ) { }
*/
MyJToggleButton ( final Action action ) {
super ( action ) ;
setOpaque ( false ) ;
setFocusPainted ( false ) ;
Preferences . addListener ( this ) ;
p r ef e re n ce s C ha n ge d () ;
}
A.4. Der Quelltext
201
202
470
460
450
440
430
420
480
/**
*
* @param orientation .
*/
MyScrollBar ( final int orientation ) {
super ( orientation ) ;
setOpaque ( false ) ;
}
/**
*
* @author <a href =" mailto : flu @inf ormatik . uni - kiel . de " >
* Florian Luepke </a >
*/
final class MyScrollBar extends JScrollPane . ScrollBar {
/**
* A completely non opaque component .
* @param view .
*/
MyJScrollPane ( final Component view ) {
super ( view ) ;
setOpaque ( false ) ;
for ( int i = 0; i < g e t C o m p o n e n t Cou nt () ; i ++) {
if ( getComponent ( i ) instanceof JComponent ) {
(( JComponent ) getComponent ( i ) ) . setOpaque ( false ) ;
}
}
}
520
510
500
490
/**
*
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </
a>
*/
public static class MyJScrollPane extends JScrollPane {
/**
*
* @param view .
* @return .
*/
public static JScrollPane c r e a t e J S c r o l l P an e ( final Component view ) {
return new MyJScrollPane ( view ) ;
}
*/
public static JMenuBar cre ateJ MenuB ar () {
return new JMenuBar () {
protected void pai ntCo mpone nt ( final Graphics g ) {
Utils . p aintC ompo nent ( this , g , false ) ;
}
};
}
super . mousePressed ( e ) ;
if ( toolbar . getParent () instanceof JTabbedPane ) {
protected M o us e In p ut L i st e ne r c r e a t e D o c k i n g L i s t e n e r () {
return new DockingListener ( toolBar ) {
public void mousePressed ( final MouseEvent e ) {
private JTabbedPane myParent ;
private String tabTitle ;
private int tabIndex ;
final JToolBar toolbar = Utils . createJToolBar ( false ) ;
toolbar . setUI ( new MetalToolBarUI () {
/**
*
* @param source .
* @return .
*/
public static JComponent c r e a t e F l o a t a b l e C o m p o n e n t F o r T a b b e d P a n e (
final JComponent source ) {
}
/**
*
* @see javax . swing . JScrollPane # c r e a t e V e r t i c a l S c r o l l B a r ()
*/
public final JScrollBar c r e a t e V e r t i c a l S c r o l l B a r () {
return new MyScrollBar ( JScrollBar . VERTICAL ) ;
}
/**
*
* @see javax . swing . JScrollPane # c r e a t e H o r i z o n t a l S c r o l l B a r ()
*/
public final JScrollBar c r e a t e H o r i z o n t a l S c r o l l B a r () {
return new MyScrollBar ( JScrollBar . HORIZONTAL ) ;
}
}
/**
*
* @see javax . swing . JComponent # paintComponent ( java . awt . Graphics )
*/
protected void paintComponent ( final Graphics g ) {
Utils . paintComponent (
this ,
g,
orientation == JScrollBar . HORIZONTAL ,
Preferences . getGu iColorLight () ,
Preferences . getGu iColorLight () ) ;
super . paintComponent ( g ) ;
}
A. Java-Programm-Quelltext
570
560
550
540
530
final JPanel root = new JPanel ( new BorderLayout () ) ;
final JToolBar toolbar = Utils . cre ateJToolBar ( false ) ;
toolbar . setUI ( new Metal Tool BarUI () {
/**
*
* @param source .
* @return .
*/
public static JComponent c r e a t e F l o a t a b l e C o m p o n e n t F o r S p l i t P a n e (
final JComponent source ) {
}
}) ;
toolbar . setLayout ( new BorderLayout () ) ;
toolbar . add ( source , " Center ") ;
return toolbar ;
};
}
protected Windo wLis tener c r e a t e F r a m e L i s t e n e r () {
return new FrameListener () {
public void windowClosing ( final WindowEvent w ) {
super . windowClosing ( w ) ;
if ( tabIndex > myParent . getTabCount () ) {
tabIndex = myParent . getTabCount () ;
}
myParent . add ( toolbar , tabTitle , tabIndex ) ;
}
};
}
}
parent = parent . getParent () ;
}
if ( parent instanceof JDialog ) {
(( JDialog ) parent ) . setTitle ( tabTitle ) ;
(( JDialog ) parent ) . setResizable ( true ) ;
}
}
public void mouseReleased ( final MouseEvent e ) {
super . mouseReleased ( e ) ;
Container parent = toolbar . getParent () ;
while (!( parent instanceof JDialog )
&& parent . getParent () != null ) {
630
620
610
600
590
myParent = ( JTabbedPane ) toolbar . getParent () ; 580
}
for ( int i = 0; myParent != null
&& i < myParent . getTabCount () ; i ++) {
if ( myParent . g etComponentAt ( i ) == toolbar ) {
tabTitle = myParent . getTitleAt ( i ) ;
tabIndex = i ;
}
}
if ( source instanceof JTabbedPane ) {
final JTabbedPane tabPane = ( JTabbedPane ) source ;
// when the last tab is removed , then the tab pane should become
// invisible and vice versa .
}) ;
toolbar . setLayout ( new BorderLayout () ) ;
root . add ( toolbar , " Center ") ;
toolbar . add ( source , " Center ") ;
}
};
}
protected WindowListener c r e a t e F r a m e L i s t e n e r () {
return new FrameListener () {
public void windowClosing ( final WindowEvent w ) {
super . windowClosing ( w ) ;
myParent . s et D iv i d er L oc a t io n ( l a s t D i v i d e r L o c a t i o n ) ;
}
};
}
parent = parent . getParent () ;
}
if ( parent instanceof JDialog ) {
(( JDialog ) parent ) . setResizable ( true ) ;
isFirstDr agEvent = true ;
}
protected M o us e In p ut L i st e ne r c r e a t e D o c k i n g L i s t e n e r () {
return new DockingListener ( toolBar ) {
private boolean isFirstDragEv ent = true ;
public void mouseDragged ( final MouseEvent e ) {
super . mouseDragged ( e ) ;
if ( isFi rstDragEvent ) {
myParent = ( JSplitPane ) root . getParent () ;
if ( myParent . ge t D iv i de r L oc a ti o n () > 0) {
lastDividerLocation =
myParent . g et D iv i d er L oc a t io n () ;
}
if ( myParent . getTopComponent () == root ) {
myParent . s et D i vi d er L o ca t io n (0) ;
} else {
myParent . s et D i vi d er L o ca t io n (1.0) ;
}
isFirstDr agEvent = false ;
}
}
public void mouseReleased ( final MouseEvent e ) {
super . mouseReleased ( e ) ;
Container parent = toolbar . getParent () ;
while (!( parent instanceof JDialog )
&& parent . getParent () != null ) {
private JSplitPane myParent ;
private int l a s t D i v i d e r L o c a t i o n ;
A.4. Der Quelltext
203
204
670
660
650
640
}
}) ;
}
return root ;
. getParent () ;
}
if ( parent != null ) {
l a s t D i v i d e r L o c a t i o n = parent . ge t Di v i de r Lo c a ti o n () ;
}
if ( tabPane . getTabCount () == 0) {
if ( parent . g et T op C omponent ()
== tabPane . getParent () . getParent () ) {
700
parent . s e t D i v i d e r L oc a ti o n (0) ;
} else {
parent . s e t D i v i d e r L oc a ti o n (1.0) ;
}
}
690
parent = ( JSplitPane ) tabPane . getParent () . getParent
710
/**
* Translates the values returned by the current Resource bundle to the
}
()
public void c o m p o n e n t R e m o v e d ( final ContainerEvent e ) {
if ( tabPane . getParent () != null
&& tabPane . getParent () . getParent () != null ) {
public void comp onent Adde d ( final ContainerEvent e ) {
if ( tabPane . getTabCount () == 1) {
680
if ( parent != null ) {
parent . s e t D i v i d e r L oc a ti o n ( l a s t D i v i d e r L o c a t i o n ) ;
}
}
}
private JSplitPane parent ;
private int l a s t D i v i d e r L o c a ti o n ;
tabPane . a d d C o n t a i n e r L i s t e n e r ( new C on tai ne rLi st ene r () {
}
/**
* Convinience method for setting an accelerator .
* @param actionClass for which action a menu item should be created .
* @return a new menu item .
*/
public static JMenuItem createJMenuItem ( final Class actionClass ) {
return addAccelerator ( new JMenuItem ( EditorActions . get (
actionClass ) ) ) ;
}
}
}
return mi ;
c = KeyEvent . VK_F1
+ Integer . parseInt ( accelerator . substring (2) ) - 1;
} else if ( accelerator . equals ("0 DEL ") ) {
c = KeyEvent . VK_DELETE ;
}
mi . setAccelerator ( KeyStroke . getKeyStroke (c ,
Integer . parseInt ( accelerator . substring (0 , 1) ) ) ) ;
final int fKeyMinLength = 3;
final int fKeyMaxLength = 4;
if (! accelerator . startsWith (" acceleratorFor ") ) {
int c = accelerator . charAt (1) ;
if ( c == ’+ ’) {
c = KeyEvent . VK_PLUS ;
} else if ( c == ’F ’ && accelerator . length () >= fKeyMinLength
&& accelerator . length () <= fKeyMaxLength ) {
String accelerator = ResourceBundle . getString (" accele rator For "
+ mi . getAction () . getClass () . getName () . substring (
mi . getAction () . getClass () . getName () . lastIndexOf ( ’. ’) + 1) ) ;
* correct accelerator .
* @param mi the menu item to which an accelerator should be attached .
* @return a new menu item object .
*/
public static JMenuItem addAccelerator ( final JMenuItem mi ) {
A. Java-Programm-Quelltext
20
10
30
/**
* Searches in the selected cell for the first port child .
*
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
/**
* Creates an object with the connect . gif image .
*/
A c t i o n A d d L o o p T r a n s i t i o n () {
super (" connect . gif ") ;
}
50
/**
* Defines the edit step " add loop transition ".
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
40
* @version $Revision : 1.22 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class A c t i o n A d d L o o p T r a n s i t i o n extends EditorAction {
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import org . jgraph . graph . Port ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionAddLoopTransition
}
protected void doAction ( final ActionEvent e ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . s e t U n d o Cl u s t e r S t a r t ()
;
DefaultGra phCell cell =
( Defaul tGraphCell ) getEditor () . getGraph () . getSelecti o n C e l l () ;
if ( cell != null ) {
for ( int i = 0; i < cell . getChildCount () ; i ++) {
if ( cell . getChildAt ( i ) instanceof Port ) {
try {
getEditor () . getGraph () . getMyGraphModel () .
addTransition (
( Port ) cell . getChildAt ( i ) ,
( Port ) cell . getChildAt ( i ) ,
getEditor () . g e t C u r r e n t T r a n s i t i o n T y p e () ,
getEditor () . g e t C u r r e n t T r a n s i t i o n L i n e () ,
getEditor () . getGraph () . g e t C u r r e n t P o p u p P o i n t () ) ;
} catch ( Exception ex ) {
getEditor () . getKielFrame () . handleExcepti on (
ex . getMessage () , false , ex ) ;
}
break ;
}
}
}
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . se tU ndo Cl u s t e r E n d (
this ) ;
}
A.4. Der Quelltext
205
206
10
20
/**
* Creates an object with an connecton . gif image .
*/
A c t i o n A d d T r a n s i t i o n T o g g l e () {
/**
* Defines the edit step " toggle transition mode on / off ".
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 30
* @version $Revision : 1.15 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class A c t i o n A d d T r a n s i t i o n T o g g l e extends EditorAction {
import kiel . editor . resources . Reso urce Loade r ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionAddTransitionToggle
}
super (" connecton . gif ") ;
/**
* Toggles the image and calls JGraph . setPortsVisible () .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . getGraph () . setPortsVisible (
! getEditor () . getGraph () . isPortsVisible () ) ;
if ( getEditor () . getGraph () . isPortsVisible () ) {
putValue ( SMALL_ICON , ResourceLoader . get (" connecton . gif ") ) ;
} else {
putValue ( SMALL_ICON , ResourceLoader . get (" connectoff . gif ") ) ;
}
}
}
A. Java-Programm-Quelltext
40
30
20
10
kiel . editor . M o r p h i n g L a y o u t e r ;
kiel . editor . graph . C o m p o s i t e S t a t e C e l l ;
kiel . editor . graph . M y G r a p h C o n s t a n t s ;
kiel . editor . graph . RegionCell ;
kiel . editor . resources . Reso urce Bundl e ;
60
50
;
boolean isCollapsed = M y G r a p h C o nstants . isCollapsed (
if ( selected instanceof C o m p o s i t e S t a te C e ll ) {
D e f a u l t G r a p h C e l l selected =
( D e f a u l t G r a p h C e l l ) getEditor () . getGraph () . getSelectionCell () ;
90
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . s e t U n d o C l u s t e r S t a r t ()
/**
* Calls MyGraphModel . flipCollapsed () .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
/**
* This action does not have any image since it will be represented by
* a checkbox .
*/
A c t i o n E d i t C o l l a p s e d () {
super ( null ) ;
80
}
/**
* Defines the edit step " collapse " for collapsing or expanding the
currently
* selected node .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.26 $ last modified $Date : 2005/08/01 17:53:17 $
*/
70
public final class A c t i o n E d i t C o l l a p s e d extends EditorAction
implements M o r p h i n g L a y o u t e r . MyListener {
import
import
import
import
import
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import org . jgraph . graph . G raphC onst ants ;
import java . awt . event . ActionEvent ;
import java . awt . geom . Rectangle2D ;
package kiel . editor . controller ;
kiel.editor.controller.ActionEditCollapsed
}
}
getEditor () . getGraph () . g e t G r a p h L a y o u t C a c h e () , this ) ;
/**
* Terminates the current undo cluster .
* @see kiel . editor . MorphingLayouter . MyListener # morphingF in i s h e d ()
*/
public void m orphingFinished () {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . se tU ndo Cl u s t e r E n d (
this ) ;
}
}
() ,
}
}
getEditor () . getGraph () . getMyGraphModel () . flipCollapsed (
getEditor () . getGraph () ,
( C om p os i t eS t at e C el l ) getEditor () . getGraph () . get S e l e c t i o n C e l l
getEditor () . getKielFrame () . handleException (
ResourceBundle . getString (" notEnoughSpace ") ,
false , null ) ;
return ;
Rectangle2D parentsBounds =
GraphConstants . getBounds (
(( DefaultGraphCel l ) selected . getParent () )
. getAttributes () ) ;
Rectangle2D selectedBounds =
GraphConstants . getBounds (
selected . getAttributes () ) ;
Rectangle2D expandedBounds =
MyGraphCon stants . g et Exp an ded Bo und s (
selected . getAttributes () ) . getBounds2D () ;
expandedBounds . setRect (
selectedBounds . getX () ,
selectedBounds . getY () ,
expandedBounds . getWidth () ,
expandedBounds . getHeight () ) ;
if (( selected . getParent () instanceof RegionCell
&& ! parentsBounds . contains ( expandedBounds ) )
// intersect or contain ...
|| getEditor () . getGraph () . getMyGraphModel () . intersect (
selected , expandedBounds , true , null , true ) ) {
// check if enough space for expanding is available ...
if ( isCollapsed ) {
selected . getAttributes () ) ;
A.4. Der Quelltext
207
208
30
20
10
kiel . editor . graph . ANDStateCell ;
kiel . editor . graph . F i n a l A N D S t a t e C e l l ;
kiel . editor . graph . F i n a l O R S t a t e C e l l ;
kiel . editor . graph . F i n a l S i m p l e S t a t e C e l l ;
kiel . editor . graph . ORStateCell ;
kiel . editor . graph . S im p le S ta t eC e ll ;
40
/**
* Creates an object with an F i n a l S i m p l eState . gif image .
*/
A c t i o n E d i t C o n v e r t F l i p F i n a l A t t r i b u t e () {
super (" F i n a l S i m p l e S t a t e . gif ") ;
}
60
/**
* Converts the currently selected node to a FinalState . If it is an ORState
, it
* will become an FinalORState , if it was a SimpleState , it will become an
* FinalSimpleState .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
50
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.1 $ last modified $Date : 2005/04/27 17:00:34 $
*/
public final class A c t i o n E d i t C o n v e r t F l i p F i n a l A t t r i b u t e extends EditorAction
{
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import
import
import
import
import
import
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
}
/**
* Calls MyGraphModel . convert () .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . s e t U n d o C l u s t e r S t a r t ()
;
DefaultGra phCell selectedCell =
( Defaul tGraphCell ) getEditor () . getGraph () . getSel e c t i o n C e l l () ;
if ( selectedCell instanceof FinalORStateCell ) {
getEditor () . getGraph () . getMyGraphModel () . convert (
selectedCell , ORStateCell . class ) ;
} else if ( selectedCell instanceof Fi nal AN DSt at eCe ll ) {
getEditor () . getGraph () . getMyGraphModel () . convert (
selectedCell , ANDStateCell . class ) ;
} else if ( selectedCell instanceof F i n a l S i m p l e S t a t e C e l l ) {
getEditor () . getGraph () . getMyGraphModel () . convert (
selectedCell , SimpleStateCell . class ) ;
} else if ( selectedCell instanceof ORStateCell ) {
getEditor () . getGraph () . getMyGraphModel () . convert (
selectedCell , FinalO RStateCell . class ) ;
} else if ( selectedCell instanceof ANDStateCell ) {
getEditor () . getGraph () . getMyGraphModel () . convert (
selectedCell , Fin al AND St ate Ce ll . class ) ;
} else if ( selectedCell instanceof SimpleStateCell ) {
getEditor () . getGraph () . getMyGraphModel () . convert (
selectedCell , F i n a l S i m p l e S t a t e C e l l . class ) ;
}
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . se tU n d o C l u s t e r E n d (
this ) ;
}
kiel.editor.controller.ActionEditConvertFlipFinalAttribute
A. Java-Programm-Quelltext
10
20
/**
* Creates an object with an edge . gif image .
*/
/**
* Converts the currently selected transition to a bezier curve .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
30
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.16 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class A c t i o n E d i t C o n v e r t T o B e z i e r extends EditorAction {
import org . jgraph . graph . GraphCell ;
import org . jgraph . graph . G raphC onst ants ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionEditConvertToBezier
}
/**
* Calls MyGraphModel . changeLineStyle () .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . s e t U n d o C l u s t e r S t a r t ()
;
getEditor () . getGraph () . getMyGraphModel () . changeLineStyle (
( GraphCell ) getEditor () . getGraph () . getSelectionCell () ,
GraphConstants . STYLE_BEZIER ) ;
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . se tU ndo Cl u s t e r E n d (
this ) ;
}
A c t i o n E d i t C o n v e r t T o B e z i e r () {
super (" edge . gif ") ;
}
A.4. Der Quelltext
209
210
10
20
/**
* Creates an object with an arrow . gif image .
/**
* Converts the currently selected transition to a NormalTran sition .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p30
>
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.16 $ last modified $Date : 2005/03/08 15:49:19 $
*/
public final class A c t i o n E d i t C o n v e r t T o N o r m a l T r a n s i t i o n extends EditorAction
{
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import kiel . editor . graph . N o r m a l T e r m i n a t i o n C e l l ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
}
/**
* Calls MyGraphModel . convert () .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . s e t U n d o C l u s t e r S t a r t ()
;
getEditor () . getGraph () . getMyGraphModel () . convert (
( Defaul tGraphCell ) getEditor () . getGraph () . getSel e c t i o n C e l l () ,
N o r m a l T e r m i n a t i o n C e l l . class ) ;
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . se tU n d o C l u s t e r E n d (
this ) ;
}
*/
A c t i o n E d i t C o n v e r t T o N o r m a l T r a n s i t i o n () {
super (" arrow . gif ") ;
}
kiel.editor.controller.ActionEditConvertToNormalTransition
A. Java-Programm-Quelltext
20
10
/**
* Creates an object with an OrState . gif image .
*/
/**
30
* Converts the currently selected node to an ORState .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.16 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class A c t i o n E d i t C o n v e r t T o O R S t a t e extends EditorAction {
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import kiel . editor . graph . ORStateCell ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionEditConvertToORState
}
/**
* Calls MyGraphModel . convert () .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . s e t U n d o C l u s t e r S t a r t ()
;
getEditor () . getGraph () . getMyGraphModel () . convert (
( Defaul tGraphCell ) getEditor () . getGraph () . getSelect i o n C e l l () ,
ORStateCell . class ) ;
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . se tU ndo C l u s t e r E n d (
this ) ;
}
A c t i o n E d i t C o n v e r t T o O R S t a t e () {
super (" OrState . gif ") ;
}
A.4. Der Quelltext
211
212
10
20
/**
* Creates an object with an edge . gif image .
*/
/**
* Converts the currently selected transition to an orthogonal type .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
30
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.16 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class A c t i o n E d i t C o n v e r t T o O r t h o g o n a l extends EditorAction {
import org . jgraph . graph . GraphCell ;
import org . jgraph . graph . G raphC onst ants ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
}
/**
* Calls MyGraphModel . changeLineStyle () .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . s e t U n d o C l u s t e r S t a r t ()
;
getEditor () . getGraph () . getMyGraphModel () . changeLineS ty l e (
( GraphCell ) getEditor () . getGraph () . g etSelectionC e l l () ,
GraphConstants . ST YLE_ORTHOGONAL ) ;
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . se tU n d o C l u s t e r E n d (
this ) ;
}
A c t i o n E d i t C o n v e r t T o O r t h o g o n a l () {
super (" edge . gif ") ;
}
kiel.editor.controller.ActionEditConvertToOrthogonal
A. Java-Programm-Quelltext
20
10
/**
* Creates an object with an SimpleState . gif image .
*/
/**
30
* Converts the currently selected node to an SimpleState .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.1 $ last modified $Date : 2005/04/01 23:56:02 $
*/
public final class A c t i o n E d i t C o n v e r t T o S i m p l e S t a t e extends EditorAction {
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import kiel . editor . graph . S im p le S ta t eC e ll ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
}
/**
* Calls MyGraphModel . convert () .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . s e t U n d o C l u s t e r S t a r t ()
;
getEditor () . getGraph () . getMyGraphModel () . convert (
( Defaul tGraphCell ) getEditor () . getGraph () . getSelect i o n C e l l () ,
SimpleStateCell . class ) ;
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . se tU ndo C l u s t e r E n d (
this ) ;
}
A c t i o n E d i t C o n v e r t T o S i m p l e S t a t e () {
super (" SimpleState . gif ") ;
}
kiel.editor.controller.ActionEditConvertToSimpleState
A.4. Der Quelltext
213
214
10
20
/**
* Creates an object with an edge . gif image .
*/
/**
* Converts the currently selected transition to an orthogonal type .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
30
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.16 $ last modified $Date : 2005/03/08 15:49:19 $
*/
public final class A c t i o n E d i t C o n v e r t T o S p l i n e extends EditorAction {
import org . jgraph . graph . GraphCell ;
import org . jgraph . graph . G raphC onst ants ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionEditConvertToSpline
}
/**
* Calls MyGraphModel . changeLineStyle () .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . s e t U n d o C l u s t e r S t a r t ()
;
getEditor () . getGraph () . getMyGraphModel () . changeLineS ty l e (
( GraphCell ) getEditor () . getGraph () . g etSelectionC e l l () ,
GraphConstants . STYLE_SPLINE ) ;
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . se tU n d o C l u s t e r E n d (
this ) ;
}
A c t i o n E d i t C o n v e r t T o S p l i n e () {
super (" edge . gif ") ;
}
A. Java-Programm-Quelltext
20
10
/**
* Creates an object with an arrow . gif image .
*/
/**
30
* Converts the currently selected transition to a StrongAbortion .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.16 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class A c t i o n E d i t C o n v e r t T o S t r o n g A b o r t i o n extends EditorAction {
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import kiel . editor . graph . S t r o n g A b o r t i o n C e l l ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
}
/**
* Calls MyGraphModel . convert () .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . s e t U n d o C l u s t e r S t a r t ()
;
getEditor () . getGraph () . getMyGraphModel () . convert (
( Defaul tGraphCell ) getEditor () . getGraph () . getSelect i o n C e l l () ,
S tr o n gA b or t i on C el l . class ) ;
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . se tU ndo C l u s t e r E n d (
this ) ;
}
A c t i o n E d i t C o n v e r t T o S t r o n g A b o r t i o n () {
super (" arrow . gif ") ;
}
kiel.editor.controller.ActionEditConvertToStrongAbortion
A.4. Der Quelltext
215
216
20
10
/**
* Creates an object with an arrow . gif image .
*/
/**
30
* Converts the currently selected transition to a WeakAbortion .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.17 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class A c t i o n E d i t C o n v e r t T o W e a k A b o r t i o n extends EditorAction {
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import kiel . editor . graph . W e a k A b o r t i o n C e l l ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
}
/**
* Calls MyGraphModel . convert () .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . s e t U n d o C l u s t e r S t a r t ()
;
getEditor () . getGraph () . getMyGraphModel () . convert (
( Defaul tGraphCell ) getEditor () . getGraph () . getSel e c t i o n C e l l () ,
WeakAbort ionCell . class ) ;
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . se tU n d o C l u s t e r E n d (
this ) ;
}
A c t i o n E d i t C o n v e r t T o W e a k A b o r t i o n () {
super (" arrow . gif ") ;
}
kiel.editor.controller.ActionEditConvertToWeak Abortion
A. Java-Programm-Quelltext
20
10
/**
* Creates an object with an Copy16 . gif image .
*/
Ac tionE ditCo py () {
/**
* Wraps the swing . T ra n sf e rH a nd l er . CopyAction .
*/
private Action copy ;
50
}
/**
* Currently permits the given value < code > true </ code >.
* @see javax . swing . Action # setEnabled ( boolean )
*/
public void setEnabled ( final boolean b ) {
if (! b ) {
super . setEnabled ( b ) ;
}
}
/**
* Nothin implemented yet .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
// TODO Implement !
}
copy = new EventRedirector ( action ) ;
/**
* Uses the swing . Tr a ns f er H an d le r and implements the well known
* C &P - functionality .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 40
* @version $Revision : 1.13 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class Acti onEd itCop y extends EditorAction {
;
}
30
super (" Copy16 . gif ") ;
setEnabled ( false ) ;
Action action = javax . swing . TransferHandler . getCopyAction () ;
action . putValue ( Action . SMALL_ICON , ResourceLoader . get (" Copy16 . gif ") )
import kiel . editor . resources . Reso urce Loade r ;
import javax . swing . Action ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionEditCopy
A.4. Der Quelltext
217
218
30
20
10
40
/**
* @see # c urre ntCut Cell .
* @return .
*/
/**
* @see # c urre ntCut Cell .
* @param cell .
*/
public void s e t C u r r e n t C u t C e l l ( final D e f aultGraphC ell cell ) {
cur rentC utCe ll = cell ;
}
/**
* The currently cut cell has to be stored until the paste action is
* performed .
*/
private D e f a u l t G r a p h C e l l curr entC utCel l ;
70
60
/**
50
* Uses the swing . Tr a ns f er H an d le r and implements the well known
* C &P - functionality .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.17 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class ActionEditCut extends EditorAction {
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import kiel . editor . resources . Reso urce Loade r ;
import javax . swing . Action ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionEditCut
}
/**
* Calls JGraphModel . remove () and delegates the actionPe r fo r me d () to the
* cut object .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r ()
. s e t U n d o C l u s t e r S t a r t () ;
currentCutCell = ( Defa ultGraphCell ) getEditor () . getGraph ()
. getSel ectionCell () ;
getEditor () . getGraph () . getModel () . remove (
new Object []{ currentCutCell }) ;
cut . actionPerformed ( e ) ;
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . se tU n d o C l u s t e r E n d (
this ) ;
}
/**
* Creates an object with an Cut16 . gif image .
*/
ActionEditCut () {
super (" Cut16 . gif ") ;
Action action = javax . swing . TransferHandler . getCutAction () ;
action . putValue ( Action . SMALL_ICON , ResourceLoader . get (" Cut16 . gif ") ) ;
cut = new EditorAction . EventRedirector ( action ) ;
}
/**
* Wraps the swing . TransferHandler . CutAction .
*/
private Action cut ;
public DefaultG raphCell get Cu rre nt Cut Ce ll () {
return currentCutCell ;
}
A. Java-Programm-Quelltext
50
40
30
20
10
javax . swing . JCheckBox ;
javax . swing . JLabel ;
javax . swing . JOptionPane ;
javax . swing . JPanel ;
javax . swing . JTextField ;
javax . swing . tree . D e f a u l t M u t a b l e T r e e N o d e ;
kiel . dataStructure . CompoundLabel ;
kiel . dataStructure . Transition ;
kiel . editor . graph . M y G r a p h C o n s t a n t s ;
kiel . editor . graph . NodeCell ;
kiel . editor . graph . Tran sitio nCell ;
kiel . editor . resources . Reso urce Bundl e ;
kiel . util . C o m p o u n d L a b e l E x c e p t i o n ;
70
60
90
/**
* Calls the JGraph . s t a r t E d i t i n g A t C e l l () to open a textfield on a node .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . s e t U n d o C l u s t e r S t a r t ()
;
100
/**
* Store the current userObject of the selected graph cell .
*/
private String c u r r e n t U s e r O b j e c t ;
/**
* Starts the text editor in a graph cell .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.20 $ last modified $Date : 2005/07/27 09:42:14 $
*/
public final class Acti onEd itEdi t extends EditorAction {
80
/**
* Creates an object with an Edit16 . gif image .
*/
Ac tionE ditEd it () {
super (" Edit16 . gif ") ;
}
import
import
import
import
import
import
import
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import
import
import
import
import
import
import java . awt . GridLayout ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionEditEdit
);
if ( transition . getLabel () instanceof CompoundLabel ) {
CompoundLabel label = ( CompoundLabel ) transition . getLabel () ;
if ( label . getCondition () != null ) {
t ex t F ie l dC o n di t io n . setText ( label . getCondition () + "") ;
}
if ( label . getEffect () != null ) {
textFieldEffect . setText ( label . getEffect () + "") ;
}
if ( label . getTrigger () != null ) {
ch ec kBo xI mme di ate . setSelected ( label . getTrigger ()
. isImmediate () ) ;
if (! label . getTrigger () . isImmediate () ) {
textFieldT rigger . setText ( label . getTrigger () + "") ;
} else if (( label . getTrigger () + "") . length () > 2) {
textFieldT rigger . setText (
label . getTrigger () . toString () . substring (2) ) ;
}
}
}
final int cols = 5;
JPanel p = new JPanel ( new GridLayout (2 , cols ) ) ;
p . add ( new JLabel (" Immediate :
") ) ;
p . add ( new JLabel (" Trigger :
") ) ;
p . add ( new JLabel (" Condition :
") ) ;
p . add ( new JLabel (" Action :
") ) ;
p . add ( ch ec kBo xI mme di ate ) ;
p . add ( textFieldTrigge r ) ;
p . add ( t e x tF i el d Co n d it i on ) ;
p . add ( textFieldEffect ) ;
int answer = JOptionPane . showOptionDi alog (
getEditor () . getKielFrame () . getJFrame () ,
p , ResourceBundle . getString (" e d i t T r a n s i t i o n L a b e l ") ,
JOptionPane . OK_CANCEL_OPTION ,
JOptionPane . QUESTION_MESSAGE ,
null , new Object [] {
JTextField textFieldTrigg er = new JTextField () ;
JTextField t e x tF i el d C on d it i o n = new JTextField () ;
JTextField textFieldEffect = new JTextField () ;
JCheckBox ch eck Bo xIm me dia te = new JCheckBox () ;
if ( selected instanceof TransitionCell ) {
Transition transition = ( Transition )
MyGraphCons tants . ge t G ra p hi c a lO b je c t ( selected . getAttributes ()
final Defaul tGraphCell selected =
( Defaul tGraphCell ) getEditor () . getGraph () . getSelecti o n C e l l () ;
cu rr ent Us erO bj ect = ( String ) (( D e f a u l t M u t a b l e T r e e N o d e ) getEditor ()
. getGraph () . getSelectionCell () ) . getUserObject () ;
A.4. Der Quelltext
219
220
130
120
110
int answer = JOptionPane . s h o w O p tionD ialog (
getEditor () . getKielFrame () . getJFrame () ,
textFieldLabel , Res ourc eBundle . getString (" editNodeLabel ") ,
JOptionPane . OK_CANCEL_OPTION ,
JOptionPane . QUESTION_MESSAGE ,
null , new Object [] {
Res ourc eBund le . getString (" OK ") ,
Res ourc eBund le . getString (" Cancel ") } ,
Res ourc eBund le . getString (" OK ") ) ;
160
if ( answer == 0) {
getEditor () . getGraph () . g et M yGraphModel ()
Res ourc eBund le . getString (" OK ") ,
Res ourc eBund le . getString (" Cancel ") } ,
Res ourc eBund le . getString (" OK ") ) ;
if ( answer == 0) {
try {
getEditor () . getGraph () . getMyGraphModel ()
. setTransitionLabel (
selected ,
t e x t F i e l d T r i g g e r . getText () ,
140
t e x t F i e l d C o n d i t io n . getText () ,
t ex t Fi e ld E ff e ct . getText () ,
c h e c k B o x I m m e d i a te . isSelected () ,
c u r r e n t U s e r O b j e ct ) ;
} catch ( C o m p o u n d L a b e l E x c e p t i o n ex ) {
getEditor () . getKielFrame () . handleException (
ex . getMessage () , false , ex ) ;
}
}
} else {
150
JTextField tex tFie ldLab el = new JTextField ( cu rre nt Use rO bje ct ) ;
}
}
*/
if ( selected instanceof TransitionCell ) {
try {
getEditor () . getGraph () . getMyGraphModel ()
. p o s t E d i t T r a n s i t i o n L a b e l ( selected , cu rre n t U s e r O b j e c t ) ;
} catch ( C o m p o u n d L a b e l E x c e p t i o n e ) {
getEditor () . getKielFrame () . handleException (
e . getMessage () , false , e ) ;
}
}
getEditor () . getLogFile () . log (0 , " EditingStopped ActionE ditEd it ") ;
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . se tU n d o C l u s t e r E n d (
this ) ;
final Def aultGraphCell selected =
( Default GraphCell ) getEditor () . getGraph () . getSel e c t i o n C e l l () ;
/**
* Is called to terminate the current undo cluster .
* @see kiel . editor . EditListener # editingStopped ()
public void editingStopped () {
}
. setNodeLabel (( NodeCell ) selected ,
textFieldLabel . getText () ) ;
}
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . se tU n d o C l u s t e r E n d (
this ) ;
}
A. Java-Programm-Quelltext
20
10
/**
* Creates an object with an Find16 . gif image .
*/
Ac tionE ditFi nd () {
super (" Find16 . gif ") ;
setEnabled ( false ) ;
40
/**
* Represents a search action , but is not implemented yet . the idea is to
* provide a search function for viewing nodes .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 30
* @version $Revision : 1.14 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class Acti onEd itFin d extends EditorAction {
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionEditFind
}
/**
* Permits true value .
* @see javax . swing . Action # setEnabled ( boolean )
*/
public void setEnabled ( final boolean b ) {
if (! b ) {
super . setEnabled ( b ) ;
}
}
/**
* TODO Not implemented yet .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
}
}
A.4. Der Quelltext
221
222
30
20
10
40
}
60
/**
* Creates an object with an Paste16 . gif image .
*/
A ct i on E di t Pa s te () {
super (" Paste16 . gif ") ;
Action action = javax . swing . T ra n sf e rHandler . getPasteAction () ;
action . putValue ( Action . SMALL_ICON , ResourceLoader . get (" Paste16 . gif ")
);
paste = new Ev e nt R ed i re c to r ( action ) ;
/**
* The wrapped paste action object .
*/
private Action paste ;
50
/**
* The Paste part of a Copy & Paste action .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.17 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class A c ti o nE d it P as t e extends EditorAction {
import org . jgraph . graph . AttributeMap ;
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import org . jgraph . graph . G raphC onst ants ;
import kiel . editor . resources . Reso urce Loade r ;
import javax . swing . Action ;
import java . awt . event . ActionEvent ;
import java . awt . geom . Rectangle2D ;
package kiel . editor . controller ;
kiel.editor.controller.ActionEditPaste
}
}
DefaultGra phCell currentCutCell = (( ActionEditCut ) EditorActions . get
ActionEditCut . class ) ) . g et Cur re ntC ut Cel l () ;
if ( currentCutCell != null ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r ()
. s e t U n d o C l u s t e r S t a r t () ;
paste . actionPerformed ( e ) ;
Rectangle2D bounds =
GraphConstants . getBounds ( currentCutCell . getAttributes () ) ;
GraphConstants . setBounds ( currentCutCell
. getAttributes () , new AttributeMap .
SerializableRectangle2D (
getEditor () . getGraph () . g e t C u r r e n t P o p u p P o i n t () . getX ()
,
getEditor () . getGraph () . g e t C u r r e n t P o p u p P o i n t () . getY ()
,
( int ) bounds . getWidth () ,
( int ) bounds . getHeight () ) ) ;
getEditor () . getGraph () . getMyGraphModel () . insert (
new Object []{ currentCutCell } , null ,
null , null , null ) ;
getEditor () . getGraph () . getMyGraphModel () . changeParent (
currentCutCell , getEditor () . getGraph () . g e t G r a p h L a y o u t C a c h e ()
);
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r ()
. set Un doC lu ste rE nd ( this ) ;
}
(
/**
* Pastes in the cut node .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
A. Java-Programm-Quelltext
10
20
/**
* Represents the Redo function . Takes the last undo action from the stack
and
* re - executes it .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.13 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class Acti onEd itRed o extends EditorAction {
30
/**
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionEditRedo
}
/**
* Delegates to the U n do C lu s t er M an a g er .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . redo () ;
}
* Creates an object with an Redo16 . gif image .
*/
ActionEditRedo () {
super (" Redo16 . gif ") ;
setEnabled ( false ) ;
}
A.4. Der Quelltext
223
224
20
10
/**
* Creates an object with an Delete16 . gif image .
*/
A c t i o n E d i t R e m o v e () {
super (" Delete16 . gif ") ;
setEnabled ( false ) ;
40
/**
* Represents the DELETE action , triggered by a menu item or by pressing the
* DEL key .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 30
* @version $Revision : 1.14 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class A c t i o n E d i t R e m o v e extends EditorAction {
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionEditRemove
}
}
if (! getEditor () . getGraph () . isSelectionEmpty () ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r ()
. s e t U n d o C l u s t e r S t a r t () ;
Object [] cells = getEditor () . getGraph () . g et Sel ec t i o n C e l l s () ;
cells = getEditor () . getGraph () . getDescendants ( cells ) ;
getEditor () . getGraph () . getModel () . remove ( cells ) ;
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r ()
. set Un doC lu ste rE nd ( this ) ;
}
/**
* Calls JGraph . remove () . Deletes the selected node and its children .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
}
A. Java-Programm-Quelltext
20
10
}
/**
* Selects all child nodes of the selected cells .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
// TODO does not work , take care of mouse clicks destroying the
// selection
Object [] roots = getEditor () . getGraph () . g et Sel ec tio nC ell s () ;
ArrayList children = new ArrayList () ;
children . addAll (
Arrays . asList ( getEditor () . getGraph () . getDescendants ( roots ) ) ) ;
for ( int i = 0; i < roots . length ; i ++) {
children . remove ( roots [ i ]) ;
}
getEditor () . getGraph () . set Se lec ti on Cel ls ( children . toArray () ) ;
}
import java . awt . event . ActionEvent ;
import java . util . ArrayList ;
import java . util . Arrays ;
/**
* Creates an object with an group . gif image .
*/
A c t i o n E d i t S e l e c t A l l () {
super (" group . gif ") ;
40
/**
* Selects all children of the currently selected node and desects the
* currently selected node .
30
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.13 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class A c t i o n E d i t S e l e c t A l l extends EditorAction {
}
package kiel . editor . controller ;
kiel.editor.controller.ActionEditSelectAll
A.4. Der Quelltext
225
226
30
20
10
40
/**
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
/**
* Creates an object with an Edit16 . gif image .
*/
A c t i o n E d i t S t a t e C h a r t I n p u t E v e n t s () {
super (" Edit16 . gif ") ;
}
60
/**
* Shows an edit dialog to change the state ’ s events .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
50
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.5 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class A c t i o n E d i t S t a t e C h a r t I n p u t E v e n t s extends EditorAction {
import kiel . dataStructure . StateChart ;
import kiel . dataStructure . eventexp . Event ;
import kiel . editor . resources . Reso urce Bundl e ;
import javax . swing . JOptionPane ;
import javax . swing . JTextField ;
import java . awt . event . ActionEvent ;
import java . util . ArrayList ;
package kiel . editor . controller ;
}
}
);
()
kiel.editor.controller.ActionEditStateChartInputEvents
}
getEditor () . getGraph () . repaint () ;
getEditor () . getLogFile () . log (0 ,
" Parsed events : " + statechart . getInputEv ents () ) ;
} catch ( Exception ex ) {
getEditor () . getKielFrame () . handleException (
ex . getMessage () , false , ex ) ;
}
. parseSignals ( textField . getText () ) . toArray ( new Event [0])
final int columns = 50;
JTextField textField = new JTextField ( eventsText , columns ) ;
int answer = JOptionPane . showOptionDia log (
getEditor () . getKielFrame () . getJFrame () ,
textField ,
ResourceBundle . getString (" e d i t S t a t e c h a r t I n p u t E v e n t s ") ,
JOptionPane . OK_CANCEL_OPTION ,
JOptionPane . QUESTION_MESSAGE ,
null , new Object [] {
ResourceBundle . getString (" OK ") ,
ResourceBundle . getString (" Cancel ") } ,
ResourceBundle . getString (" OK ") ) ;
if ( answer == 0) {
try {
statechart . setInputEvents (( Event []) getEditor () . getKielFrame
StateChart statechart = getEditor () . getGraph () . getMy Gr a ph M od e l ()
. g e t C u r r e n t S t a t e C h a r t () ;
ArrayList events = statechart . getInputEvents () ;
String eventsText = events . toString () ;
eventsText = eventsText . substring (1 , eventsText . length () - 1) ;
A. Java-Programm-Quelltext
30
20
10
40
/**
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
/**
* Creates an object with an Edit16 . gif image .
*/
A c t i o n E d i t S t a t e C h a r t O u t p u t E v e n t s () {
super (" Edit16 . gif ") ;
}
60
/**
* Shows an edit dialog to change the state ’ s events .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
50
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.5 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class A c t i o n E d i t S t a t e C h a r t O u t p u t E v e n t s extends EditorAction {
import kiel . dataStructure . StateChart ;
import kiel . dataStructure . eventexp . Event ;
import kiel . editor . resources . Reso urce Bundl e ;
import javax . swing . JOptionPane ;
import javax . swing . JTextField ;
import java . awt . event . ActionEvent ;
import java . util . ArrayList ;
package kiel . editor . controller ;
}
}
final int columns = 50;
JTextField textField = new JTextField ( eventsText , columns ) ;
int answer = JOptionPane . showOptionDi alog (
getEditor () . getKielFrame () . getJFrame () ,
textField ,
ResourceBundle . getString (" e d i t S t a t e c h a r t O u t p u t E v e n t s ") ,
JOptionPane . OK_CANCEL_OPTION ,
JOptionPane . QUESTION_MESSAGE ,
null , new Object [] {
ResourceBundle . getString (" OK ") ,
ResourceBundle . getString (" Cancel ") } ,
ResourceBundle . getString (" OK ") ) ;
if ( answer == 0) {
try {
statechart . setOutputEvents (( Event []) getEditor () .
getKielFrame ()
. parseSignals ( textField . getText () ) . toArray ( new Event [0])
);
getEditor () . getGraph () . repaint () ;
getEditor () . getLogFile () . log (0 ,
" Parsed events : " + statechart . getOutputEvent s () ) ;
} catch ( Exception ex ) {
getEditor () . getKielFrame () . handleException (
ex . getMessage () , false , ex ) ;
}
}
StateChart statechart = getEditor () . getGraph () . getMyGraph M od e l ()
. g e t C u r r e n t S t a t e C h a r t () ;
ArrayList events = statechart . getOutputEvents () ;
String eventsText = events . toString () ;
eventsText = eventsText . substring (1 , eventsText . length () - 1) ;
kiel.editor.controller.ActionEditStateChartOutputEvents
A.4. Der Quelltext
227
228
40
30
20
10
kiel . dataStructure . Com posit eSta te ;
kiel . dataStructure . State ;
kiel . dataStructure . action . Actions ;
kiel . editor . graph . M y G r a p h C o n s t a n t s ;
kiel . editor . resources . Reso urce Bundl e ;
kiel . util . C o m p o u n d L a b e l E x c e p t i o n ;
kiel . util . C o m p o u n d L a b e l P a r s e r ;
50
70
State state = ( State ) M y G r a p h C o n s t a nts
. g e t G r a p h i c a l O b j e c t ((( D e f a u l t G r aphCell ) getEditor () . getGraph () 80
/**
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
/**
* Creates an object with an Edit16 . gif image .
*/
A c t i o n E d i t S t a t e D o A c t i o n s () {
super (" Edit16 . gif ") ;
}
/**
60
* Shows an edit dialog to change the state ’ s do actions .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.15 $ last modified $Date : 2005/07/14 15:27:55 $
*/
public final class A c t i o n E d i t S t a t e D o A c t i o n s extends EditorAction {
import
import
import
import
import
import
import
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import javax . swing . JOptionPane ;
import javax . swing . JTextField ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionEditStateDoActions
}
}
}
));
;
}
getEditor () . getGraph () . repaint () ;
} catch ( C o m p o u n d L a b e l E x c e p t i o n ex ) {
getEditor () . getKielFrame () . handleException (
ex . getMessage () , false , ex ) ;
}
} else {
C o m p o u n d L a b e l P a r s e r . set Co mpo si teS ta te (
( CompositeState ) state ) ;
}
if ( textfield . getText () . trim () . length () == 0) {
state . setDoActivity ( new Actions () ) ;
} else {
state . setDoActivity (
C o m p o u n d L a b e l P a r s e r . parseActions ( textfield . getText ()
final int columns = 50;
JTextField textfield = new JTextField ( actionsText , columns ) ;
int answer = JOptionPane . showOptionDia log (
getEditor () . getKielFrame () . getJFrame () ,
textfield ,
ResourceBundle . getString (" E d i t S t a t e D o A c t i v i t i e s ") ,
JOptionPane . OK_CANCEL_OPTION ,
JOptionPane . QUESTION_MESSAGE ,
null , new Object [] {
ResourceBundle . getString (" OK ") ,
ResourceBundle . getString (" Cancel ") } ,
ResourceBundle . getString (" OK ") ) ;
if ( answer == 0) {
try {
C o m p o u n d L a b e l P a r s e r . setStateChart (
getEditor () . g e t C u r r e n t S t a t e C h a r t () ) ;
if ( state . getParent () != null ) {
C o m p o u n d L a b e l P a r s e r . set Co mpo si teS ta te ( state . getParent () )
. getSel ectionCell () ) . getAttributes () ) ;
String actionsText = state . getDoActivity () . toString () ;
A. Java-Programm-Quelltext
40
30
20
10
kiel . dataStructure . Com posit eSta te ;
kiel . dataStructure . State ;
kiel . dataStructure . action . Actions ;
kiel . editor . graph . M y G r a p h C o n s t a n t s ;
kiel . editor . resources . Reso urce Bundl e ;
kiel . util . C o m p o u n d L a b e l E x c e p t i o n ;
kiel . util . C o m p o u n d L a b e l P a r s e r ;
50
70
State state = ( State ) M y G r a p h C o n s t a nts
. g e t G r a p h i c a l O b j e c t ((( D e f a u l t G r aphCell ) getEditor () . getGraph () 80
/**
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
/**
* Creates an object with an Edit16 . gif image .
*/
A c t i o n E d i t S t a t e E n t r y A c t i o n s () {
super (" Edit16 . gif ") ;
}
/**
60
* Shows an edit dialog to change the state ’ s entry actions .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.15 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class A c t i o n E d i t S t a t e E n t r y A c t i o n s extends EditorAction {
import
import
import
import
import
import
import
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import javax . swing . JOptionPane ;
import javax . swing . JTextField ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
}
kiel.editor.controller.ActionEditStateEntryActions
}
}
));
;
}
getEditor () . getGraph () . repaint () ;
} catch ( C o m p o u n d L a b e l E x c e p t i o n ex ) {
getEditor () . getKielFrame () . handleException (
ex . getMessage () , false , ex ) ;
}
} else {
C o m p o u n d L a b e l P a r s e r . set Co mpo si teS ta te (
( CompositeState ) state ) ;
}
if ( textfield . getText () . trim () . length () == 0) {
state . setEntry ( new Actions () ) ;
} else {
state . setEntry (
C o m p o u n d L a b e l P a r s e r . parseActions ( textfield . getText ()
final int columns = 50;
JTextField textfield = new JTextField ( actionsText , columns ) ;
int answer = JOptionPane . showOptionDi alog (
getEditor () . getKielFrame () . getJFrame () ,
textfield ,
ResourceBundle . getString (" e d i tO n En t r yA c ti o n s ") ,
JOptionPane . OK_CANCEL_OPTION ,
JOptionPane . QUESTION_MESSAGE ,
null , new Object [] {
ResourceBundle . getString (" OK ") ,
ResourceBundle . getString (" Cancel ") } ,
ResourceBundle . getString (" OK ") ) ;
if ( answer == 0) {
try {
C o m p o u n d L a b e l P a r s e r . setStateChart (
getEditor () . g e t C u r r e n t S t a t e C h a r t () ) ;
if ( state . getParent () != null ) {
C o m p o u n d L a b e l P a r s e r . set Co mpo si teS ta te ( state . getParent () )
. getSe lectionCell () ) . getAttributes () ) ;
String actionsText = state . getEntry () . toString () ;
A.4. Der Quelltext
229
230
40
30
20
10
kiel . dataStructure . Com posit eSta te ;
kiel . dataStructure . eventexp . Event ;
kiel . dataStructure . eventexp . IntegerSignal ;
kiel . dataStructure . intexp . I n t e g e r E x p r ess io n ;
kiel . editor . graph . M y G r a p h C o n s t a n t s ;
kiel . editor . resources . Reso urce Bundl e ;
60
50
String eventsText = "";
for ( int i = 0; i < state . g etLo calEvents () . size () ; i ++) {
Com posit eSta te state = ( Co mpos iteSt ate ) MyGraphConst ants
. g e t G r a p h i c a l O b j e c t ((( D e f a u l t G r aphCell ) getEditor () . getGraph ()
. g e t S e l e c t i o n C e l l () ) . getAttributes () ) ;
/**
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
/**
* Creates an object with an Edit16 . gif image .
*/
A c t i o n E d i t S t a t e E v e n t s () {
super (" Edit16 . gif ") ;
}
90
80
/**
* Shows an edit dialog to change the state ’ s events .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.16 $ last modified $Date : 2005/07/21 16:47:53 $
*/
70
public final class A c t i o n E d i t S t a t e E v e n t s extends EditorAction {
import
import
import
import
import
import
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import javax . swing . JOptionPane ;
import javax . swing . JTextField ;
import java . awt . event . ActionEvent ;
import java . util . Collection ;
package kiel . editor . controller ;
kiel.editor.controller.ActionEditStateEvents
}
}
final int columns = 50;
JTextField textField = new JTextField ( eventsText , columns ) ;
int answer = JOptionPane . showOptionDia log (
getEditor () . getKielFrame () . getJFrame () ,
textField ,
ResourceBundle . getString (" E d i t S t a t e c h a r t E v e n t s ") ,
JOptionPane . OK_CANCEL_OPTION ,
JOptionPane . QUESTION_MESSAGE ,
null , new Object [] {
ResourceBundle . getString (" OK ") ,
ResourceBundle . getString (" Cancel ") } ,
ResourceBundle . getString (" OK ") ) ;
if ( answer == 0) {
try {
Collection newLocalEvents = getEditor () . getKielFrame ()
. parseSignals ( textField . getText () ) ;
state . getLocalEvents () . clear () ;
state . addLocalEvents ( newLocalEvents ) ;
getEditor () . getGraph () . repaint () ;
getEditor () . getLogFile () . log (0 ,
" Parsed events : " + newLocalEvents ) ;
} catch ( Exception ex ) {
getEditor () . getKielFrame () . handleException (
ex . getMessage () , false , ex ) ;
}
}
}
if ( event instanceof IntegerSignal ) {
In te ger Ex pre ss ion expr =
(( IntegerSignal ) event ) . getInitialValue () ;
if ( expr != null ) {
eventsText += " := " + expr . toIntExpString () ;
}
eventsText += " : integer ";
}
if ( i < state . getLocalEvents () . size () - 1) {
eventsText += " , ";
}
Event event = ( Event ) state . getLocalEvents () . get ( i ) ;
eventsText += event . getName () ;
A. Java-Programm-Quelltext
40
30
20
10
kiel . dataStructure . Com posit eSta te ;
kiel . dataStructure . State ;
kiel . dataStructure . action . Actions ;
kiel . editor . graph . M y G r a p h C o n s t a n t s ;
kiel . editor . resources . Reso urce Bundl e ;
kiel . util . C o m p o u n d L a b e l E x c e p t i o n ;
kiel . util . C o m p o u n d L a b e l P a r s e r ;
50
70
State state = ( State ) M y G r a p h C o n s t a nts
. g e t G r a p h i c a l O b j e c t ((( D e f a u l t G r aphCell ) getEditor () . getGraph () 80
/**
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
/**
* Creates an object with an Edit16 . gif image .
*/
A c t i o n E d i t S t a t e E x i t A c t i o n s () {
super (" Edit16 . gif ") ;
}
/**
60
* Shows an edit dialog to change the state ’ s exit actions .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.15 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class A c t i o n E d i t S t a t e E x i t A c t i o n s extends EditorAction {
import
import
import
import
import
import
import
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import javax . swing . JOptionPane ;
import javax . swing . JTextField ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionEditStateExitActions
}
}
}
));
;
}
getEditor () . getGraph () . repaint () ;
} catch ( C o m p o u n d L a b e l E x c e p t i o n ex ) {
getEditor () . getKielFrame () . handleException (
ex . getMessage () , false , ex ) ;
}
} else {
C o m p o u n d L a b e l P a r s e r . set Co mpo si teS ta te (
( CompositeState ) state ) ;
}
if ( textfield . getText () . trim () . length () == 0) {
state . setExit ( new Actions () ) ;
} else {
state . setExit (
C o m p o u n d L a b e l P a r s e r . parseActions ( textfield . getText ()
final int columns = 50;
JTextField textfield = new JTextField ( actionsText , columns ) ;
int answer = JOptionPane . showOptionDi alog (
getEditor () . getKielFrame () . getJFrame () ,
textfield ,
ResourceBundle . getString (" e dit On Exi tA cti on s ") ,
JOptionPane . OK_CANCEL_OPTION ,
JOptionPane . QUESTION_MESSAGE ,
null , new Object [] {
ResourceBundle . getString (" OK ") ,
ResourceBundle . getString (" Cancel ") } ,
ResourceBundle . getString (" OK ") ) ;
if ( answer == 0) {
try {
C o m p o u n d L a b e l P a r s e r . setStateChart (
getEditor () . g e t C u r r e n t S t a t e C h a r t () ) ;
if ( state . getParent () != null ) {
C o m p o u n d L a b e l P a r s e r . set Co mpo si teS ta te ( state . getParent () )
. getSe lectionCell () ) . getAttributes () ) ;
String actionsText = state . getExit () . toString () ;
A.4. Der Quelltext
231
232
50
40
30
20
10
kiel . dataStructure . Com posit eSta te ;
kiel . dataStructure . Str ingVa riab le ;
kiel . dataStructure . Variable ;
kiel . dataStructure . boolexp . B o o l e a n E x p res si on ;
kiel . dataStructure . boolexp . Bo o le a nV a riable ;
kiel . dataStructure . doubleexp . D o u b l e E xpressi on ;
kiel . dataStructure . doubleexp . Dou bleVariable ;
kiel . dataStructure . floatexp . F lo a tE x pression ;
kiel . dataStructure . floatexp . FloatVariable ;
kiel . dataStructure . intexp . I n t e g e r E x p r ess io n ;
kiel . dataStructure . intexp . I n te g er V ar iable ;
kiel . editor . graph . M y G r a p h C o n s t a n t s ;
kiel . editor . resources . Reso urce Bundl e ;
70
60
90
Com posit eSta te state = ( Co mpos iteSt ate ) MyGraphConst ants
. g e t G r a p h i c a l O b j e c t ((( D e f a u l t G r aphCell ) getEditor () . getGraph ()100
. g e t S e l e c t i o n C e l l () ) . getAttributes () ) ;
/**
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
/**
* Creates an object with an Edit16 . gif image .
*/
A c t i o n E d i t S t a t e V a r i a b l e s () {
super (" Edit16 . gif ") ;
}
/**
* Shows an edit dialog to change the state ’ s variables .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
80
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.19 $ last modified $Date : 2005/07/21 16:47:53 $
*/
public final class A c t i o n E d i t S t a t e V a r i a b l e s extends EditorAction {
import
import
import
import
import
import
import
import
import
import
import
import
import
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import javax . swing . JOptionPane ;
import javax . swing . JTextField ;
import java . awt . event . ActionEvent ;
import java . util . Collection ;
import java . util . St r in g To k en i ze r ;
package kiel . editor . controller ;
kiel.editor.controller.ActionEditStateVariables
final int columns = 50;
JTextField textfield = new JTextField ( variablesText , columns ) ;
int answer = JOptionPane . showOptionDia log (
getEditor () . getKielFrame () . getJFrame () ,
textfield ,
ResourceBundle . getString (" E d i t S t a t e c h a r t V a r i a b l e s ") ,
JOptionPane . OK_CANCEL_OPTION ,
JOptionPane . QUESTION_MESSAGE ,
null , new Object [] {
}
if ( v instanceof BooleanVariable ) {
Bo ol ean Ex pre ss ion expr =
(( BooleanVariable ) v ) . getInitialValue () ;
if ( expr != null ) {
variablesText += " := " + expr . toString () ;
}
variablesText += " : boolean ";
} else if ( v instanceof DoubleVariable ) {
DoubleExpre ssion expr =
(( DoubleVariable ) v ) . getInitialValue () ;
if ( expr != null ) {
variablesText += " := " + expr . to Do ubl eE x p S t r i n g () ;
}
variablesText += " : double ";
} else if ( v instanceof FloatVariable ) {
FloatExpression expr =
(( FloatVariable ) v ) . getInitialValue () ;
if ( expr != null ) {
variablesText += " := " + expr . toFloatEx p S t r i n g () ;
}
variablesText += " : float ";
} else if ( v instanceof IntegerVariable ) {
In te ger Ex pre ss ion expr =
(( IntegerVariable ) v ) . getInitialValue () ;
if ( expr != null ) {
variablesText += " := " + expr . toIntExpStri ng () ;
}
variablesText += " : integer ";
} else if ( v instanceof StringVariable ) {
variablesText += " : string ";
}
if ( i < state . getVariables () . size () - 1) {
variablesText += " , ";
}
Variable v = ( Variable ) state . getVariables () . get ( i ) ;
variablesText += v . getName () ;
String variablesText = "";
for ( int i = 0; i < state . getVariables () . size () ; i ++) {
A. Java-Programm-Quelltext
110
Res ourc eBund le . getString (" OK ") ,
Res ourc eBund le . getString (" Cancel ") } ,
Res ourc eBund le . getString (" OK ") ) ;
if ( answer == 0) {
try {
S tr i ng T ok e ni z er st =
new S tr i ng T ok e ni z er ( textfield . getText () , " ,") ;
variablesText = "";
while ( st . hasMoreTokens () ) {
String aVariable = st . nextToken () ;
if ( aVariable . indexOf (":") == -1) {
aVariable += " : integer ";
}
variablesText += aVariable ;
if ( st . hasMoreTokens () ) {
variablesText += " , ";
130
120
}
}
}
}
}
getEditor () . getLogFile () . log (0 ,
" Parse variables : " + variablesText ) ;
Collection newVariables = getEditor () . getKielFrame ()
. parseVariables ( variablesText ) ;
state . getVariables () . clear () ;
state . getVariables () . addAll ( newVariables ) ;
getEditor () . getGraph () . repaint () ;
} catch ( Exception ex ) {
getEditor () . getKielFrame () . handleException (
ex . getMessage () , false , ex ) ;
}
A.4. Der Quelltext
233
234
30
20
10
kiel . dataStructure . Transition ;
kiel . editor . graph . M y G r a p h C o n s t a n t s ;
kiel . editor . graph . Trans itio nCell ;
kiel . editor . resources . Reso urce Bundl e ;
40
/**
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
/**
* Creates an object with an Edit16 . gif image .
*/
A c t i o n E d i t T r a n s i t i o n P r i o r i t y () {
super (" Edit16 . gif ") ;
}
60
/**
* Shows an edit dialog to change the state ’ s events .
50
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.3 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class A c t i o n E d i t T r a n s i t i o n P r i o r i t y extends EditorAction {
import
import
import
import
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import javax . swing . JOptionPane ;
import javax . swing . JTextField ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
}
kiel.editor.controller.ActionEditTransitionPriority
}
JTextField textField = new JTextField (
transition . getPriority () . getValue () + "" , 2) ;
int answer = JOptionPane . showOptionDia log (
getEditor () . getKielFrame () . getJFrame () ,
textField ,
ResourceBundle . getString (" e d i t T r a n s i t i o n P r i o r i t y ") ,
JOptionPane . OK_CANCEL_OPTION ,
JOptionPane . QUESTION_MESSAGE ,
null , new Object [] {
ResourceBundle . getString (" OK ") ,
ResourceBundle . getString (" Cancel ") } ,
ResourceBundle . getString (" OK ") ) ;
if ( answer == 0) {
try {
getEditor () . getGraph () . getMyGraphModel ()
. changeTransitionPriority (
(( TransitionCell ) getEditor () . getGraph ()
. getSelec tionCell () ) ,
Integer . parseInt ( textField . getText () ) ) ;
getEditor () . getGraph () . repaint () ;
} catch ( N u m b e r F o r m a t E x c e p t i o n ex ) {
getEditor () . getKielFrame () . handleException (
ex . getMessage () , false , ex ) ;
}
}
Transition transition = ( Transition ) MyGraphConstant s
. g et G ra p h ic a lO b j ec t ((( DefaultGraphCell ) getEditor () . getGraph ()
. getSe lectionCell () ) . getAttributes () ) ;
protected void doAction ( final ActionEvent e ) {
A. Java-Programm-Quelltext
10
/**
* Creates an object with an Undo16 . gif image .
30
20
/**
* Implements the undo feature .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.13 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class Acti onEd itUnd o extends EditorAction {
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionEditUndo
}
/**
* Delegates to the U n do C lu s t er M an a g er .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . undo () ;
}
*/
ActionEditUndo () {
super (" Undo16 . gif ") ;
setEnabled ( false ) ;
}
A.4. Der Quelltext
235
236
50
40
30
20
10
java . awt . Alp haCom posi te ;
java . awt . Color ;
java . awt . Dimension ;
java . awt . Graphics ;
java . awt . Graphics2D ;
java . awt . Image ;
java . awt . Transparency ;
java . awt . color . ColorSpace ;
java . awt . event . ActionEvent ;
java . awt . geom . Rectangle2D ;
java . awt . image . BufferedImage ;
java . awt . image . ColorModel ;
java . awt . image . C o m p o n e n t C o l o r M o d e l ;
java . awt . image . DataBuffer ;
java . awt . image . F i l t e r e d I m a g e S o u r c e ;
java . io . B y t e A r r a y O u t p u t S t r e a m ;
java . io . File ;
java . io . F i l e O u t p u t S t r e a m ;
java . io . IOException ;
/**
* Creates an object with an Export16 . gif image .
*/
A c t i o n F i l e E x p o r t () {
super (" Export16 . gif ") ;
}
100
}
int answer = fileChooser . showDialog ( getEditor ()
. getKielFrame () . getJFrame () , ResourceBundl e
. getString (" save ") ) ;
if ( answer == JFileChooser . APPROVE_OPTION ) {
File selectedFile = fileChooser . getSelectedFi l e () ;
FileOutputS tream fos = null ;
// Find the filter ...
int filterIndex = 0;
for ( int filterCount = 0;
filterCount < filters . length ; filterCount ++) {
if ( filters [ filterCount ] == fileChooser
. getFileFilter () ) {
};
fileChooser . a d d C h o o s a b l e F i l e F i l t e r ( filters [ i ]) ;
public String getDescription () {
return description [ ii ];
}
}
return f != null
&& f . getName () . toLowerCase () . endsWith (
suffix [ ii ]) ;
public boolean accept ( final File f ) {
try {
JFileChooser fileChooser = new JFileChooser (
getEditor () . getKielFrame () . g e t F i l e I n t e r f a c e S a v e D i r () ) ;
fileChooser . setDialogType ( JFileChooser . SAVE_DIALOG ) ;
final String [] suffix = new String []{". gif " , ". eps "};
final String [] description = new String []{
ResourceBundle . getString (" GIF_ - _ G r a p h i c s _ I n t e r c h a n g e _ F o r m a t
") ,
ResourceBundle . getString (" EPS_ - _ E n c a p s u l a t e d _ P o s t s c r i p t ") };
FileFilter [] filters = new FileFilter [ suffix . length ];
for ( int i = 0; i < filters . length ; i ++) {
final int ii = i ;
filters [ i ] = new FileFilter () {
final boolean isPortsVisible = getEditor () . getGraph () . isP ortsV isib le
() ;
getEditor () . getGraph () . setPortsVisible ( false ) ;
import com . eteks . filter . W e b 2 1 6 C o l o r s F i l t e r ;
80
70
60
/**
* Opens a file chooser dialog and provides the types GIF and EPS .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
/**
* Provides the export formats GIF and EPS in a file chooser dialog box .
* The code is taken from the JGraph framework .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 90
* @version $Revision : 1.24 $ last modified $Date : 2005/08/01 17:53:29 $
*/
public final class A c t i o n F i l e E x p o r t extends EditorAction {
import Acme . JPM . Encoders . GifEncoder ;
import org . jgraph . JGraph ;
import org . jibble . epsgraphics . EpsGraphics2D ;
import kiel . editor . resources . Reso urce Bundl e ;
import javax . swing . JFileChooser ;
import javax . swing . Repa intM anage r ;
import javax . swing . filechooser . FileFilter ;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
package kiel . editor . controller ;
kiel.editor.controller.ActionFileExport
A. Java-Programm-Quelltext
150
140
130
120
110
//
180
170
160
/**
* @see java . awt . Graphics # setXORMode ( java . awt . Color )
*/
public void setXORMode ( final Color c1 ) {
m e t h o d N o t S u p p o r t e d () ;
/**
* @param g this .
*/
public My E ps G ra p hi c s2 D ( final M y Ep s Graphics2D g ) {
super ( g ) ;
}
200
/**
* Extends EpsGraphics2D in order to suppress the stack trace dump
* at every setXORMode () - call .
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </
a>
*/
static class M y Ep s Gr a ph i cs 2 D extends EpsGraphics2D {
/**
190
*
*/
public My E ps G ra p hi c s2 D () {
// nothing
}
}
}
} catch ( IOException ex ) {
getEditor () . getKielFrame () . h an d leException (
ex . getMessage () , true , ex ) ;
}
getEditor () . getGraph () . s et P or t sV i si ble ( isPortsVisible ) ;
filterIndex = filterCount ;
}
}
if (! selectedFile . toString () . toLowerCase () . endsWith (
suffix [ filterIndex ]) ) {
selectedFile = new File ( selectedFile
+ suffix [ filterIndex ]) ;
}
fos = new F i l e O u t p u t S t r e a m ( selectedFile ) ;
if ( filterIndex == 0) {
saveGIF ( fos ) ;
} else if ( filterIndex == 1) {
saveEPS ( fos ) ;
}
if ( fos != null ) {
// Write to file
fos . flush () ;
fos . close () ;
}
}
getEditor () . getGraph () . set Se lec ti on Cel ls ( null ) ;
final int i = 5;
fos . write (
convertToGif ( toImage ( getEditor () . getGraph () , i ) ) ) ;
/**
* Handles converting to GIF .
* @param fos .
* @throws IOException .
*/
private void saveGIF ( final FileOu tputStream fos ) throws IOException {
}
MyEpsGraphics2D graphics = new MyEpsGraphics2D () ;
graphics . setColor ( getEditor () . getGraph () . getBackground () ) ;
Rectangle2D bounds = getEditor () . getGraph () . getCellBounds (
getEditor () . getGraph () . getDescendants (
getEditor () . getGraph () . getRoots () ) ) ;
getEditor () . getGraph () . toScreen ( bounds ) ;
Dimension d = bounds . getBounds () . getSize () ;
final int ten = 10;
final int five = 5;
graphics . fillRect (0 , 0 , d . width + ten , d . height + ten ) ;
graphics . translate ( - bounds . getX () + five , - bounds . getY () + five ) ;
Object [] selection = getEditor () . getGraph () . get Se lec ti o n C e l l s () ;
boolean gridVisible = getEditor () . getGraph () . isGridVisible () ;
boolean doubleBuffered = getEditor () . getGraph ()
. isDou bleBuffered () ;
getEditor () . getGraph () . setGridVisible ( false ) ;
getEditor () . getGraph () . set Do ubl eB uf fer ed ( false ) ;
getEditor () . getGraph () . clearSelection () ;
getEditor () . getGraph () . paint ( graphics ) ;
getEditor () . getGraph () . set Se lec ti on Cel ls ( selection ) ;
getEditor () . getGraph () . setGridVisible ( gridVisible ) ;
getEditor () . getGraph () . set Do ubl eB uf fer ed ( doubleBuffered ) ;
fos . write ( graphics . toString () . getBytes () ) ;
/**
* Handles converting to EPS .
* @param fos .
* @throws IOException .
*/
private void saveEPS ( final FileOu tputStream fos ) throws IOException {
}
/**
* @see java . awt . Graphics # create ()
*/
public Graphics create () {
return new MyEpsGraphics2D ( this ) ;
}
}
A.4. Der Quelltext
237
238
240
230
220
210
bounds
. getY () + inset ) ) ;
boolean tmp = graph . i s D o u b l e B u f fered () ;
Rep aint Manag er curre ntMa nager = RepaintManager
. c urren tMan ager ( graph ) ;
} else {
graphics . setComposite ( A lphaComposite . getInstance (
Al phaCo mpos ite . CLEAR , 0.0 f ) ) ;
graphics . fillRect (0 , 0 , img . getWidth () , img . getHeight () ) ; 270
graphics . setComposite ( A lphaComposite . SrcOver ) ;
}
graphics . translate (( int ) ( - bounds . getX () + inset ) , ( int ) ( -
/**
* Taken from jgraph addons JG r ap h Ut i li ties .
* @param graph .
* @param inset .
* @return .
*/
public static BufferedImage toImage ( final JGraph graph , final int inset )
{
250
Object [] cells = graph . getRoots () ;
Rectangle2D bounds = graph . getCellBounds ( cells ) ;
if ( bounds != null ) {
graph . toScreen ( bounds ) ;
ColorSpace cs = ColorSpace . getInstance ( ColorSpace . CS_sRGB ) ;
ColorModel cm = new C o m p o n e n t C o l o r M o d e l ( cs , false , true ,
Transparency . OPAQUE , DataBuffer . TYPE_BYTE ) ;
BufferedImage img = new BufferedImage (( int ) bounds . getWidth () +
2
* inset , ( int ) bounds . getHeight () + 2 * inset ,
260
BufferedImage . TYPE_INT_ARGB ) ;
Graphics2D graphics = img . creat eGraphics () ;
if ( graph . isOpaque () ) {
graphics . setColor ( graph . getBackground () ) ;
graphics . fillRect (0 , 0 , img . getWidth () , img . getHeight () ) ;
}
}
return null ;
}
Graphics oGrf = oImgBuffer . getGraphics () ;
B y t e A r r a y O u t p u t S t r e a m oOut = null ;
try {
oOut = new B y t e A r r a y O u t p u t S t r e a m () ;
new GifEncoder ( oImgBuffer , oOut ) . encode () ;
} catch ( IOException e ) {
// GifEncoder throws IOException when GIF contains too many
// colors
// if this happens , filter image to reduce number of colors
final F i l t e r e d I m a g e S o u r c e filter = new F i l t e r e d I m a g e S o u r c e (
oImgBuffer . getSource () , new We b 21 6 C ol o rs F i l t e r () ) ;
oOut = new B y t e A r r a y O u t p u t S t r e a m () ;
new GifEncoder ( filter , oOut ) . encode () ;
}
return oOut . toByteArray () ;
/**
* Converts Image to GIF - encoded data , reducing the number of colors if
* needed Taken from JGraphPad . FileExportGIF .
*
* @param oImgBuffer .
* @return .
* @throws IOException .
*/
public static byte [] convertToGif ( final Image oImgBuffer )
throws IOException {
}
currentManager . s e t D o u b l e B u f f e r i n g E n a b l e d ( false ) ;
graph . paint ( graphics ) ;
currentManager . s e t D o u b l e B u f f e r i n g E n a b l e d ( true ) ;
return img ;
A. Java-Programm-Quelltext
10
20
/**
* Creates an object with an New16 . gif image .
/**
* Creates a new data model for a Esterel Studio statechart .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 30
* @version $Revision : 1.16 $ last modified $Date : 2005/08/02 18:51:48 $
*/
public final class A c t i o n F i l e N e w E s t e r e l S t u d i o extends EditorAction {
import kiel . editor . MyGraphModel ;
import kiel . editor . resources . Reso urce Bundl e ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionFileNewEsterelStudio
}
/**
* sets a new MyGraphModel object .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . setModel ( new MyGraphModel (
ResourceBundle . getString (" A c t i o n F i l e N e w E s t e r e l S t u d i o ") ,
getEditor () . getGraph () . g e t G r a p h L a y o u t C a c h e () ) ) ;
getEditor () . getKielFrame () . setCurrentFile ( null ) ;
}
*/
A c t i o n F i l e N e w E s t e r e l S t u d i o () {
super (" New16 . gif ") ;
}
A.4. Der Quelltext
239
240
10
20
/**
* Creates an object with an New16 . gif image .
/**
* Creates a new data model for a Esterel Studio statechart .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 30
* @version $Revision : 1.17 $ last modified $Date : 2005/08/02 18:52:04 $
*/
public final class A c t i o n F i l e N e w M a t l a b extends EditorAction {
import kiel . editor . MyGraphModel ;
import kiel . editor . resources . Reso urce Bundl e ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionFileNewMatlab
}
/**
* sets a new MyGraphModel object .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . setModel ( new MyGraphModel (
ResourceBundle . getString (" A c t i o n F i l e N e w M a t l a b ") ,
getEditor () . getGraph () . g e t G r a p h L a y o u t C a c h e () ) ) ;
getEditor () . getKielFrame () . setCurrentFile ( null ) ;
}
*/
A c t i o n F i l e N e w M a t l a b () {
super (" New16 . gif ") ;
}
A. Java-Programm-Quelltext
10
20
/**
/**
* Opens the preferences dialog .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.13 $ last modified $Date : 2005/06/22 15:19:58 $
*/
30
public final class A c t i o n F i l e P r e f e r e n c e s extends EditorAction {
import kiel . editor . P r e f e r e n c e s D i a l o g ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionFilePreferences
}
/**
* Opens the preferences dialog .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
new Pr efe re nce sD ial og ( getEditor () . getKielFrame () . getJFrame () )
. setVisible ( true ) ;
}
* Creates an object with an Preferences16 . gif image .
*/
A c t i o n F i l e P r e f e r e n c e s () {
super (" Preferences16 . gif ") ;
}
A.4. Der Quelltext
241
242
20
10
}
/**
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
PrinterJob printJob = PrinterJob . getPrinterJob () ;
printJob . setPrintable ( getEditor () . getGraph () ) ;
printJob . pageDialog ( new PageFormat () ) ;
if ( printJob . printDialog () ) {
try {
printJob . print () ;
} catch ( PrinterException ex ) {
getEditor () . getKielFrame () . handleException (
ex . getMessage () , true , ex ) ;
}
}
}
import
import
import
import
/**
* Creates an object with an Print16 . gif image .
*/
A ct i on F il e Pr i nt () {
super (" Print16 . gif ") ;
40
/**
* Should implement the print feature , but is not implemented yet .
30
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.16 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class A c ti o nF i le P ri n t extends EditorAction {
java . awt . event . ActionEvent ;
java . awt . print . PageFormat ;
java . awt . print . P r i n t e r E x c e p t i o n ;
java . awt . print . PrinterJob ;
}
package kiel . editor . controller ;
kiel.editor.controller.ActionFilePrint
A. Java-Programm-Quelltext
20
10
/**
/**
* Creates an object with an Save16 . gif image .
*/
Ac tionF ileSa ve () {
super (" Save16 . gif ") ;
}
40
/**
* Saves the current statechart to file . If no filename is associated to the
* current statechart , then this Action delegates to ActionFileSaveAs .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p30
>
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.19 $ last modified $Date : 2005/06/13 21:05:15 $
*/
public final class Acti onFi leSav e extends EditorAction {
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionFileSave
}
* Opens the file save dialog as provided by the KIEL - FileInterface .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
if ( getEditor () . getKielFrame () . getCurrentFile () != null ) {
try {
getEditor () . getKielFrame () . w r i t e S t a t e Ch a r t F i l e (
getEditor () . getGraph () . getMyGraphModel ()
. g e t C u r r e n t S t a t e C h a r t () ,
getEditor () . getGraph () . getMyGraphModel ()
. getCurrentView () ) ;
} catch ( Exception ex ) {
getEditor () . getKielFrame () . handleException (
ex . getMessage () , false , ex ) ;
}
} else {
EditorActions . get ( ActionFileSav eAs . class ) . actionPer fo r me d ( e ) ;
}
}
A.4. Der Quelltext
243
244
20
10
/**
/**
* Creates an object with an SaveAs16 . gif image .
*/
A c t i o n F i l e S a v e A s () {
super (" SaveAs16 . gif ") ;
}
40
/**
* Saves the current statechart to file by opening the file save dialog .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 30
* @version $Revision : 1.16 $ last modified $Date : 2005/06/13 21:05:21 $
*/
public final class A c t i o n F i l e S a v e A s extends EditorAction {
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionFileSaveAs
}
}
try {
getEditor () . getKielFrame () . w r i t e S t a t e C h a r t F i l e W i t h S a v e D i a l o g (
getEditor () . getGraph () . getMyGraphModel () .
g e t C u r r e n t S t a t e C h a r t () ,
getEditor () . getGraph () . getMyGraphModel () . get Curr entVi ew () ) ;
if ( getEditor () . getKielFrame () . ge tS tat ec har tF ile () != null ) {
getEditor () . getKielFrame () . setCurrentFile (
getEditor () . getKielFrame () . ge tSt at ech ar t F i l e () ) ;
}
} catch ( Exception ex ) {
getEditor () . getKielFrame () . handleException (
ex . getMessage () , false , ex ) ;
}
* Saves the current statechart to file by opening the file save dialog .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
A. Java-Programm-Quelltext
50
40
30
20
10
/**
* Called by a subclass setting a coordinate of the bounds variable .
* @param newX .
*/
protected void setX ( final double newX ) {
bounds . setRect ( newX , bounds . getY () , bounds . getWidth () ,
bounds . getHeight () ) ;
}
/**
* See bounds .
* @return .
*/
protected Rectangle2D getBounds () {
return bounds ;
}
/**
* The target bounds of the currently selected diagram elements .
*/
private Rectangle2D bounds ;
/**
* Creates an A c t i o n F o r m a t A l i g n object .
* @param iconName .
*/
A c t i o n F o r m a t A l i g n ( final String iconName ) {
super ( iconName ) ;
}
100
90
80
60
/**
* The superclass for all align features . The subclasses set some
coordinates
* and then the doAction () method of this class is performed .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.18 $ last modified $Date : 2005/07/25 11:44:36 $
*/
70
abstract class A c t i o n F o r m a t A l i g n extends EditorAction {
import org . jgraph . graph . AttributeMap ;
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import org . jgraph . graph . G raphC onst ants ;
import java . awt . event . ActionEvent ;
import java . awt . geom . Rectangle2D ;
import java . util . Hashtable ;
package kiel . editor . controller ;
kiel.editor.controller.ActionFormatAlign
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r ()
. s e t U n d o C l u s t e r S t a r t () ;
Hashtable transportMap = new Hashtable () ;
Object [] allSelectedCells = getEditor () . getGraph ()
. get Se lec ti onC el ls () ;
Rectangle2D firstBounds = GraphConstants
. getBounds ((( DefaultGraph Cell ) allS electedCells [0])
. getAttributes () ) ;
for ( int i = 0; i < allS electedCells . length ; i ++) {
bounds = GraphConstants . getBounds (
/**
* Sets the bounds for the selected cells .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
/**
* Implements the method calls to manipulate the target bounds .
* @param firstBounds .
*/
protected abstract void se tN ewC oo rdi na tes ( final Rectangle2D firstBounds )
;
/**
* Called by a subclass setting a coordinate of the bounds variable .
* @param newHeight .
*/
protected void setHeight ( final double newHeight ) {
bounds . setRect ( bounds . getX () , bounds . getY () ,
bounds . getWidth () , newHeight ) ;
}
/**
* Called by a subclass setting a coordinate of the bounds variable .
* @param newWidth .
*/
protected void setWidth ( final double newWidth ) {
bounds . setRect ( bounds . getX () , bounds . getY () ,
newWidth , bounds . getHeight () ) ;
}
/**
* Called by a subclass setting a coordinate of the bounds variable .
* @param newY .
*/
protected void setY ( final double newY ) {
bounds . setRect ( bounds . getX () , newY ,
bounds . getWidth () , bounds . getHeight () ) ;
}
A.4. Der Quelltext
245
(( D e f a u l t G r a p h C e l l ) a l l Sel ectedCells [ i ])
. getAttributes () ) . getBounds () ;
s e t N e w C o o r d i n a t e s ( firstBounds ) ;
110
AttributeMap newAttributes = new AttributeMap () ;
Gra phCo nstan ts . setBounds (
newAttributes , new AttributeMap () . createRect ( bounds ) ) ;
transportMap . put ( a l l S e l e c t e d C e l ls [ i ] , newAttributes ) ;
}
}
}
getEditor () . getGraph () . getMyGraphModel () . edit ( transportMap ,
null , null , null ) ;
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . se tU n d o C l u s t e r E n d (
this ) ;
A. Java-Programm-Quelltext
246
10
/**
* Creates an object with an AlignBottom16 . gif image .
30
20
/**
* Aligns the selected cells on the bottom border of the first selected cell
.
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.12 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class A c t i o n F o r m a t A l i g n B o t t o m extends Ac tio nF orm at Ali gn {
import java . awt . geom . Rectangle2D ;
package kiel . editor . controller ;
kiel.editor.controller.ActionFormatAlignBottom
}
/**
* Set y - coordinate .
* @see kiel . editor . controller . A cti on For ma tAl ig n
* # se tN ewC oo rdi na tes ( java . awt . geom . Rectangle2D )
*/
protected void s etN ew Coo rd ina te s ( final Rectangle2D firstBounds ) {
setY (( firstBounds . getY ()
+ firstBounds . getHeight ()
- getBounds () . getHeight () ) ) ;
}
*/
A c t i o n F o r m a t A l i g n B o t t o m () {
super (" AlignBottom16 . gif ") ;
}
A.4. Der Quelltext
247
248
10
/**
* Creates an object with an AlignCenter16 . gif image .
import java . awt . geom . Rectangle2D ;
20
/**
* Aligns the selected cells , so that all cells ’ center points lie
* on the same horizontal line .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class A c t i o n F o r m a t A l i g n C e n t e r H o r i z o n t a l extends
30
ActionFormatAlign {
package kiel . editor . controller ;
}
/**
* Sets the y - coordinate .
* @see kiel . editor . controller . A ct ion Fo rma tA lig n
* # s etN ew Coo rd ina te s ( java . awt . geom . Rectangle2D )
*/
protected void s etN ew Coo rd ina te s ( final Rectangle2D firstBounds ) {
setY ((( firstBounds . getY ()
+ firstBounds . getHeight () / 2)
- getBounds () . getHeight () / 2) ) ;
}
*/
A c t i o n F o r m a t A l i g n C e n t e r H o r i z o n t a l () {
super (" AlignCenter16 . gif ") ;
}
kiel.editor.controller.ActionFormatAlignCenterHorizontal
A. Java-Programm-Quelltext
10
20
/**
* Aligns the selected cells , so that all cells ’ center points lie
* on the same vertical line .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class A c t i o n F o r m a t A l i g n C e n t e r V e r t i c a l extends Ac ti onF or mat Al ign
{
30
/**
import java . awt . geom . Rectangle2D ;
package kiel . editor . controller ;
}
/**
* Sets the x - coordinate .
* @see kiel . editor . controller . A cti on For ma tAl ig n
* # se tN ewC oo rdi na tes ( java . awt . geom . Rectangle2D )
*/
protected void s etN ew Coo rd ina te s ( final Rectangle2D firstBounds ) {
setX ((( firstBounds . getX () + firstBounds . getWidth () / 2)
- getBounds () . getWidth () / 2) ) ;
}
* Creates an object with an AlignCenter16 . gif image .
*/
A c t i o n F o r m a t A l i g n C e n t e r V e r t i c a l () {
super (" AlignCenter16 . gif ") ;
}
kiel.editor.controller.ActionFormatAlignCenterVertical
A.4. Der Quelltext
249
250
10
/**
30
20
/**
* Sets all selected cells width to the first selected cells ’ width .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.12 $ last modified $Date : 2005/03/08 15:49:19 $
*/
public final class A c t i o n F o r m a t A l i g n J u s t i f y H o r i z o n t a l
extends A c t i o n F o r m a t A l i g n {
import java . awt . geom . Rectangle2D ;
package kiel . editor . controller ;
}
/**
* Sets the width .
* @see kiel . editor . controller . A ct ion Fo rma tA lig n
* # s etN ew Coo rd ina te s ( java . awt . geom . Rectangle2D )
*/
protected void s etN ew Coo rd ina te s ( final Rectangle2D firstBounds ) {
setWidth ( firstBounds . getWidth () ) ;
}
* Creates an object with an A l i g n J u s t i f y H o r i z o n t a l 1 6 . gif image .
*/
A c t i o n F o r m a t A l i g n J u s t i f y H o r i z o n t a l () {
super (" A l i g n J u s t i f y H o r i z o n t a l 1 6 . gif ") ;
}
kiel.editor.controller.ActionFormatAlignJustifyHorizontal
A. Java-Programm-Quelltext
10
/**
/**
20
* Sets all selected cells width to the first selected cells ’ height .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class A c t i o n F o r m a t A l i g n J u s t i f y V e r t i c a l extends
ActionFormatAlign {
import java . awt . geom . Rectangle2D ;
package kiel . editor . controller ;
}
/**
* Sets the height .
* @see kiel . editor . controller . A cti on For ma tAl ig n
* # se tN ewC oo rdi na tes ( java . awt . geom . Rectangle2D )
*/
protected void s etN ew Coo rd ina te s ( final Rectangle2D firstBounds ) {
setHeight ( firstBounds . getHeight () ) ;
}
* Creates an object with an A l i g n J u s t i f y V e r t i c a l 1 6 . gif image .
*/
A c t i o n F o r m a t A l i g n J u s t i f y V e r t i c a l () {
super (" A l i g n J u s t i f y V e r t i c a l 1 6 . gif ") ;
}
kiel.editor.controller.ActionFormatAlignJustifyVertical
A.4. Der Quelltext
251
252
10
/**
* Creates an object with an AlignLeft16 . gif image .
20
/**
* Aligns the selected cells on the left border of the first selected cell .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class A c t i o n F o r m a t A l i g n L e f t extends Ac ti on For ma tAl ig n {
import java . awt . geom . Rectangle2D ;
package kiel . editor . controller ;
kiel.editor.controller.ActionFormatAlignLeft
}
/**
* Sets the x - coordinate .
* @see kiel . editor . controller . A ct ion Fo rma tA lig n
* # s etN ew Coo rd ina te s ( java . awt . geom . Rectangle2D )
*/
protected void s etN ew Coo rd ina te s ( final Rectangle2D firstBounds ) {
setX ( firstBounds . getX () ) ;
}
*/
A c t i o n F o r m a t A l i g n L e f t () {
super (" AlignLeft16 . gif ") ;
}
A. Java-Programm-Quelltext
10
/**
* Creates an object with an AlignRight16 . gif image .
*/
30
import java . awt . geom . Rectangle2D ;
20
/**
* Aligns the selected cells on the right border of the first selected cell .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/03/08 15:49:19 $
*/
public final class A c t i o n F o r m a t A l i g n R i g h t extends A ct ion Fo rma tA lig n {
package kiel . editor . controller ;
kiel.editor.controller.ActionFormatAlignRight
}
/**
* Sets the x - coordinate .
* @see kiel . editor . controller . A cti on For ma tAl ig n
* # se tN ewC oo rdi na tes ( java . awt . geom . Rectangle2D )
*/
protected void s etN ew Coo rd ina te s ( final Rectangle2D firstBounds ) {
setX (( firstBounds . getX ()
+ firstBounds . getWidth ()
- getBounds () . getWidth () ) ) ;
}
A c t i o n F o r m a t A l i g n R i g h t () {
super (" AlignRight16 . gif ") ;
}
A.4. Der Quelltext
253
254
10
/**
* Creates an object with an AlignTop16 . gif image .
20
/**
* Aligns the selected cells on the top border of the first selected cell .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class A c t i o n F o r m a t A l i g n T o p extends Ac tio nF orm at Ali gn {
import java . awt . geom . Rectangle2D ;
package kiel . editor . controller ;
kiel.editor.controller.ActionFormatAlignTop
}
/**
* Sets the y - coordinate .
* @see kiel . editor . controller . A ct ion Fo rma tA lig n
* # s etN ew Coo rd ina te s ( java . awt . geom . Rectangle2D )
*/
protected void s etN ew Coo rd ina te s ( final Rectangle2D firstBounds ) {
setY ( firstBounds . getY () ) ;
}
*/
A c t i o n F o r m a t A l i g n T o p () {
super (" AlignTop16 . gif ") ;
}
A. Java-Programm-Quelltext
10
/**
* Creates an object with an Zoom16 . gif image .
20
/**
* Sets the scale factor to 1.0 , means no zoom at all .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.14 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class A c t i o n F o r m a t Z o o m 1 0 0 extends EditorAction {
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionFormatZoom
}
/**
* Sets the zoom factor to 1.0.
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . getGraph () . setScale (1.0) ;
}
*/
A c t i o n F o r m a t Z o o m 1 0 0 () {
super (" Zoom16 . gif ") ;
}
A.4. Der Quelltext
255
256
10
20
/**
/**
* Sets the zoom factor by multiplying it with the preferences zoom in
factor .
* That defines steps with relative value .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 30
* @version $Revision : 1.14 $ last modified $Date : 2005/03/08 15:49:19 $
*/
public final class A c t i o n F o r m a t Z o o m I n extends EditorAction {
import kiel . editor . resources . Preferences ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionFormatZoomIn
}
/**
* Sets the zoom factor by multiplying it with the preferences zoom in
* factor . That defines steps with relative value .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . getGraph () . setScale ( Preferences . getZoomI nF a ct o r ()
* getEditor () . getGraph () . getScale () ) ;
}
* Creates an object with an ZoomIn16 . gif image .
*/
A ct i o nF o rm a t Zo o mI n () {
super (" ZoomIn16 . gif ") ;
}
A. Java-Programm-Quelltext
10
20
/**
/**
* Sets the zoom factor by multiplying it with the preferences zoom out
factor .
* That defines steps with relative value .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 30
* @version $Revision : 1.14 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class A c t i o n F o r m a t Z o o m O u t extends EditorAction {
import kiel . editor . resources . Preferences ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionFormatZoomOut
}
/**
* Sets the zoom factor by multiplying it with the preferences zoom in
* factor .
* That defines steps with relative value .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
getEditor () . getGraph () . setScale ( getEditor () . getGraph () . getScale ()
* Preferences . getZoom OutFactor () ) ;
}
* Creates an object with an ZoomOut16 . gif image .
*/
A c t i o n F o r m a t Z o o m O u t () {
super (" ZoomOut16 . gif ") ;
}
A.4. Der Quelltext
257
258
50
40
30
20
10
kiel . dataStructure . Com posit eSta te ;
kiel . dataStructure . Region ;
kiel . dataStructure . StateChart ;
kiel . editor . M o r p h i n g L a y o u t e r ;
kiel . g r a p h i c a l I n f o r m a t i o n s . L a b e l L a y o u t I n f o r m a t i o n ;
kiel . g r a p h i c a l I n f o r m a t i o n s . View ;
kiel . util . main . KielLayouter ;
60
/**
* The layouter name as defined by the layouter package , provided by the
* Handler .
*/
private KielLayouter layouter ;
80
/**
* Creates an object with an layout . gif image .
* @param aLayouterName .
*/
public ActionLayout ( final String aLayouterName ) {
super ( aLayouterName , " layout . gif ") ;
layouter = getEditor () . getKielFrame ()
. g e t K i e l L a y o u t e r B y N a m e ( aLayouterName ) ;
}
90
/**
* Just calls layout ( State ) .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
layout ( getEditor () . getGraph () . ge t My GraphModel () . g e t C u r r e n t S t a t e C h a r t
()
. getRootNode () ) ;
}
100
/**
* Layouts the current statechart with the given layouter from the layouter
* package .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
70
* @version $Revision : 1.31 $ last modified $Date : 2005/07/15 20:25:02 $
*/
public class ActionLayout extends EditorAction
implements M o r p h i n g L a y o u t e r . MyListener {
import
import
import
import
import
import
import
import java . awt . event . ActionEvent ;
import java . util . Iterator ;
package kiel . editor . controller ;
kiel.editor.controller.ActionLayout
/* If the user didnt not want to layout the whole statechart ( the
* root state ) then the layouter . getStaticView () does not contain
* the layouts of all elements , so it has to be filled up .
*/
if ( layouter . getStaticView () != null ) {
// can be null if " Original layout " is chosen ...
Iterator keys = getEditor () . getCurrentView () . getAllKeys () ;
while ( keys . hasNext () ) {
String id = ( String ) keys . next () ;
if (! layouter . getStaticView () . containsId ( id ) ) {
layouter . getStaticView () . put ( id , getEditor ()
. getCurrentView () . getById ( id ) ) ;
}
}
// the selected state ’ s position ( which has to be layouted )
// should not change !
layouter . getStaticView () . g e t L a y o u t I n f o r m a t i o n ( state )
. set Up per Le ftP oi nt (
getEditor () . getCurrentView () . g e t L a y o u t I n f o r m a t i o n ( state )
. g et Upp er Lef tP oin t () ) ;
if ( state instanceof Region ) {
layouter . getStaticView () . g e t L a y o u t I n f o r m a t i o n ( state )
. setWidth (
getEditor () . getCurrentView () . g e t L a y o u t I n f o r m a t i o n (
state )
. getWidth () ) ;
layouter . getStaticView () . g e t L a y o u t I n f o r m a t i o n ( state )
// getGraph () . setModel ( new KielGraphModel ( chart ,
// layouter . getStaticView () , new
// GraphLayo utCache ( getGraph () ) ) ) ;
/**
* Layouts the given state with the morphing algorithm .
* @param state .
*/
protected final void layout ( final CompositeState state ) {
StateChart chart = new StateChart () ;
chart . setRootNode ( state ) ;
try {
layouter . setStatechart ( chart ) ;
} catch ( Exception e ) {
getEditor () . getKielFrame () . handleException (
e . getMessage () , false , e ) ;
return ;
}
if ( layouter . getStaticView () == null ) {
layouter . layoutView ( View . g et I ni t i al i ze d V ie w ( chart ) ) ;
} else {
layouter . layoutView ( layouter . getStaticView () ) ;
}
A. Java-Programm-Quelltext
110
state )
}
}
getEditor () . ge tCur rentV iew () . put (
id , layouter . getStaticView () . getById ( id ) ) ;
. getHeight () ) ;
}
// Take the layouted transition label layout informations ...
keys = layouter . getStaticView () . getAllKeys () ;
while ( keys . hasNext () ) {
String id = ( String ) keys . next () ;
if ( layouter . getStaticView () . getById ( id )
instanceof L a b e l L a y o u t I n f o r m a t i o n ) {
130
120
. setHeight (
getEditor () . ge tCur rentView () . g e t L a y o u t I n f o r m a t i o n (
}
}
/**
* Calls U nd o Cl u s te r Ma n a ge r . s et Und oC lus te rEn d () .
* @see kiel . editor . MorphingLayouter . MyListener # morphingF ini s h e d ()
*/
public final void morp hingFinished () {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . se tU ndo C l u s t e r E n d (
this ) ;
}
}
// now do the layout !
new MorphingLayouter (
getEditor () . getGraph () ,
this , true ) . applyNewView ( layouter . getStaticView () ) ;
A.4. Der Quelltext
259
260
20
10
kiel . dataStructure . Com posit eSta te ;
kiel . editor . graph . C o m p o s i t e S t a t e C e l l ;
kiel . editor . graph . M y G r a p h C o n s t a n t s ;
kiel . editor . resources . Reso urce Bundl e ;
30
/**
* Layouts the selected state with the given layouter from the layouter
package .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.14 $ last modified $Date : 2005/07/14 15:27:55 $
*/
public final class A c t i o n L a y o u t S e l e c t e d S t a t e extends ActionLayout {
40
/**
* Creates an object with an connecton . gif image .
* @param aLayouterName .
*/
import
import
import
import
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionLayoutSelectedState
}
}
if ( yes ) {
getEditor () . g e t C u r r e n t S t a t e C h a r t () ; // just for update !
layout (( CompositeState ) MyGraph Constants . g et G r ap h i c a l O b j e c t (
(( C o m po s it e S ta t eC e l l ) getEditor () . getGraph () .
getSelecti onCell () )
. getAttributes () ) ) ;
}
/**
* Calls layout () with the selected state .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
boolean yes = getEditor () . getKielFrame () . ask (
ResourceBundle . getString (" partialLayout ") ) ;
public A c t i o n L a y o u t S e l e c t e d S t a t e ( final String aLayouterName ) {
super ( aLayouterName ) ;
}
A. Java-Programm-Quelltext
10
20
/**
* Creates an object with no image since it will be represented by a
/**
* Toggles showing the graph ’ s grid .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.5 $ last modified $Date : 2005/03/08 15:49:19 $
30
*/
public final class Acti onVi ewGri d extends EditorAction {
import kiel . editor . resources . Preferences ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionViewGrid
}
/**
* Toggles the showGrid preference . All Preferences - Listeners will
* receive a Preferences - changed message .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
Preferences . toggleShowGrid () ;
}
* checkbox .
*/
ActionViewGrid () {
super (" grid . gif ") ;
}
A.4. Der Quelltext
261
262
10
20
/**
* Creates an object with no image since it will be represented by a
/**
* Toggles showing the overview graph .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.13 $ last modified $Date : 2005/03/08 15:49:18 $
*/
30
public final class A c t i o n V i e w O v e r v i e w extends EditorAction {
import kiel . editor . resources . Preferences ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionViewOverview
}
/**
* Toggles the sho wO ver vi ewL ay er preference . All Preferences - Listeners
will
* receive a Preferences - changed message .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
Preferences . t o g g l e S h o w O v e r v i e w L a y e r () ;
}
* checkbox .
*/
A ct i o nV i ew O v er v ie w () {
super ( null ) ;
}
A. Java-Programm-Quelltext
50
40
30
20
10
/**
* Is called when the play button should flip its icon .
*/
protected static void f l i p P l a y P a u s e I c o n () {
showPlayIcon = ! showPlayIcon ;
if ( showPlayIcon ) {
EditorActions . get ( A c t i o n V i e w R e p l a y P l a y . class ) . putValue (
/**
* Is true if the playing mode is fast .
*/
private static boolean playFast ;
/**
* Is true if the playing direction is forward .
*/
private static boolean forward ;
/**
* Is true if the animation is playing currently .
*/
private static boolean isPlaying ;
/**
* See showPlayIcon .
* @return .
*/
protected static boolean is ShowP layI con () {
return showPlayIcon ;
}
90
80
/**
* Is the play icon currently shown ? False means the pause icon is shown
70
*/
private static boolean showPlayIcon = true ;
/**
* Provides the " Media - Player " feature regarding the user edit step history60
.
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.15 $ last modified $Date : 2005/03/08 15:49:19 $
*/
abstract class A c t i o n V i e w R e p l a y extends EditorAction {
import kiel . editor . resources . Preferences ;
import kiel . editor . resources . Reso urce Loade r ;
import javax . swing . Action ;
package kiel . editor . controller ;
kiel.editor.controller.ActionViewReplay
;
;
} else {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . undo ()
if ( isPlaying ) {
return ;
}
if ( forward && ! getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r ()
. canRedo () ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . undoAll () ;
}
if (! forward && ! getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r ()
. canUndo () ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . redoAll () ;
}
new Thread () {
public void run () {
isPlaying = true ;
while (! showPlayIcon
&&
(( forward && getEditor () . getGraph ()
. g e t U n d o C l u s t e r M a n a g e r () . canRedo ()
|| (! forward && getEditor () . getGraph ()
. g e t U n d o C l u s t e r M a n a g e r () . canUndo () ) ) ) ) {
if ( forward ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . redo ()
forward = aForward ;
playFast = aPlayFast ;
/**
* Starts playing the animation .
* @param aForward .
* @param aPlayFast .
*/
protected static void play ( final boolean aForward , final boolean
aPlayFast ) {
/**
* Creates an object with an connecton . gif image .
* @param iconName .
*/
ActionView Replay ( final String iconName ) {
super ( iconName ) ;
}
}
Action . SMALL_ICON , ResourceLoader . get (" Play16 . gif ") ) ;
} else {
EditorActions . get ( A c t i o n V i e w R e p l a y P l a y . class ) . putValue (
Action . SMALL_ICON , ResourceLoader . get (" Pause16 . gif ") ) ;
}
A.4. Der Quelltext
263
264
110
100
try {
if ( playFast ) {
sleep ( Preferences . g e t R e p l a y S t e p T i m e F a s t () ) ;
} else {
sleep ( Preferences . g et Rep la ySt ep Tim e () ) ;
}
} catch ( I n t e r r u p t e d E x c e p t i o n e ) {
getEditor () . getKielFrame () . handleException (
e . getMessage () , true , e ) ;
}
}
120
}
}
}
} . start () ;
}
if (! getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . canRedo ()
|| ! getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r ()
. canUndo () ) {
fl ip Pla yP aus eI con () ;
}
isPlaying = false ;
A. Java-Programm-Quelltext
10
/**
* Creates an object with an FastForward16 . gif image .
*/
30
import java . awt . event . ActionEvent ;
20
/**
* Starts playing in fast forward mode . See superclass for more details .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.13 $ last modified $Date : 2005/03/08 15:49:19 $
*/
public final class A c t i o n V i e w R e p l a y F a s t F o r w a r d extends ActionViewReplay {
package kiel . editor . controller ;
}
kiel.editor.controller.ActionViewReplayFastForward
/**
* Flips the play button icon and starts playing .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
if ( isShowPlayIcon () ) {
fl ip Pla yP aus eI co n () ;
}
play ( true , true ) ;
}
A c t i o n V i e w R e p l a y F a s t F o r w a r d () {
super (" FastForward16 . gif ") ;
}
A.4. Der Quelltext
265
266
10
/**
* Creates an object with an Play16 . gif image .
*/
30
import java . awt . event . ActionEvent ;
20
/**
* Starts playing in normal forward mode . See superclass for more details .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.13 $ last modified $Date : 2005/03/08 15:49:19 $
*/
public final class A c t i o n V i e w R e p l a y P l a y extends Ac tionViewReplay {
package kiel . editor . controller ;
kiel.editor.controller.ActionViewReplayPlay
}
/**
* Flips the play button icon and starts playing .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
fl ip Pla yP aus eI con () ;
if (! isShowPlayIcon () ) {
play ( true , false ) ;
}
}
A c t i o n V i e w R e p l a y P l a y () {
super (" Play16 . gif ") ;
}
A. Java-Programm-Quelltext
10
/**
* Creates an object with an Rewind16 . gif image .
*/
30
import java . awt . event . ActionEvent ;
20
/**
* Starts playing in normal backward mode . See superclass for more details .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.13 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class A c t i o n V i e w R e p l a y R e w i n d extends ActionVi ewReplay {
package kiel . editor . controller ;
kiel.editor.controller.ActionViewReplayRewind
}
/**
* Flips the play button icon and starts playing .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
if ( isShowPlayIcon () ) {
fl ip Pla yP aus eI co n () ;
}
play ( false , true ) ;
}
A c t i o n V i e w R e p l a y R e w i n d () {
super (" Rewind16 . gif ") ;
}
A.4. Der Quelltext
267
268
10
20
/**
* Starts playing one step in backward mode . See superclass for more details
.
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.15 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class A c t i o n V i e w R e p l a y S t e p B a c k extends ActionViewReplay {
30
/**
* Creates an object with an StepBack16 . gif image .
*/
A c t i o n V i e w R e p l a y S t e p B a c k () {
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionViewReplayStepBack
}
super (" StepBack16 . gif ") ;
/**
* Flips the play button icon and does one step backward (= one undo
step ) .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
if (! isShowPlayIcon () ) {
fl ip Pla yP aus eI con () ;
}
if ( getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . canUndo () ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . undo () ;
}
}
}
A. Java-Programm-Quelltext
10
20
/**
* Starts playing one step in forward mode . See superclass for more details .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.15 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class A c t i o n V i e w R e p l a y S t e p F o r w a r d extends ActionViewReplay {
30
/**
* Creates an object with an StepForward16 . gif image .
*/
A c t i o n V i e w R e p l a y S t e p F o r w a r d () {
super (" StepForward16 . gif ") ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
}
kiel.editor.controller.ActionViewReplayStepForward
/**
* Flips the play button icon and does one step forward (= one redo step
).
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
if (! isShowPlayIcon () ) {
fl ip Pla yP aus eI co n () ;
}
if ( getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . canRedo () ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . redo () ;
}
}
}
A.4. Der Quelltext
269
270
20
10
/**
* Creates an object with an NavStop16 . gif image .
*/
A c t i o n V i e w R e p l a y S t o p () {
super (" NavStop16 . gif ") ;
}
40
/**
30
* Stops playing the Replay . See superclass for more details .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.16 $ last modified $Date : 2005/03/08 15:49:19 $
*/
public final class A c t i o n V i e w R e p l a y S t o p extends Ac tionViewReplay {
import kiel . editor . resources . Preferences ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionViewReplayStop
}
/**
* Stops the playing and does an redoAll () .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
if (! isShowPlayIcon () ) {
fl ip Pla yP aus eI con () ;
try {
Thread . sleep ( Preferences . ge tRe pl ayS te pT ime () ) ;
} catch ( I n t e r r u p t e d E x c e p t i o n ex ) {
getEditor () . getKielFrame () . handleException (
ex . getMessage () , true , ex ) ;
}
}
new Thread () {
public void run () {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . redoAll () ;
}
} . start () ;
}
A. Java-Programm-Quelltext
10
20
/**
* Creates an object with an History16 . gif image .
*/
A c t i o n V i e w R e p l a y T r a c e L o g () {
/**
* Opens the trace log dialog .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 30
* @version $Revision : 1.16 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class A c t i o n V i e w R e p l a y T r a c e L o g extends EditorAction {
import kiel . editor . Trac eLog Dialo g ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionViewReplayTraceLog
}
super (" History16 . gif ") ;
/**
* Opens the trace log dialog .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
new TraceLogDialog (
getEditor () ,
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r ()
. g e t A l l U n d o a b l e E d i t S t e p s A s c e n d i n g () ,
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r ()
. g e t A l l R e d o a b l e E d i t S t e p s A s c e n d i n g () ,
EditorAction . getTraceLog () ) . setVisible ( true ) ;
}
}
A.4. Der Quelltext
271
272
10
20
/**
/**
* Toggles the preference " s h o w C o m p o s i t e S t a t e E v e n t s " for displaying the
* state ’ s variables .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
30
* @version $Revision : 1.6 $ last modified $Date : 2005/03/08 15:49:19 $
*/
public final class A c t i o n V i e w S h o w C o m p o s i t e S t a t e E v e n t s extends EditorAction {
import kiel . editor . resources . Preferences ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
}
/**
* Toggles the preference " s h o w C o m p o s i t e S t a t e E v e n t s " for displaying the
* state ’ s events .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
Preferences . t o g g l e S h o w C o m p o s i t e S t a t e E v e n t s () ;
}
* Creates an object with an group . gif image .
*/
A c t i o n V i e w S h o w C o m p o s i t e S t a t e E v e n t s () {
super (" History16 . gif ") ;
}
kiel.editor.controller.ActionViewShowCompositeStateEvents
A. Java-Programm-Quelltext
10
20
/**
* Toggles the preference " s h o w C o m p o s i t e S t a t e V a r i a b l e s " for displaying the
* state ’ s variables .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.6 $ last modified $Date : 2005/03/08 15:49:19 $
30
*/
public final class A c t i o n V i e w S h o w C o m p o s i t e S t a t e V a r i a b l e s extends
EditorAction {
import kiel . editor . resources . Preferences ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
}
/**
* Toggles the preference " showStateActions " for displaying the
* state ’ s variables .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
Preferences . t o g g l e S h o w C o m p o s i t e S t a t e V a r i a b l e s () ;
}
/**
* Creates an object with an group . gif image .
*/
A c t i o n V i e w S h o w C o m p o s i t e S t a t e V a r i a b l e s () {
super (" History16 . gif ") ;
}
kiel.editor.controller.ActionViewShowCompositeStateVariables
A.4. Der Quelltext
273
274
10
20
/**
/**
* Toggles the preference " s h o w S t a t e A c t i o n s " for displaying the
* entry - , do - and exit - activities .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
30
* @version $Revision : 1.6 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class A c t i o n V i e w S h o w S t a t e A c t i o n s extends EditorAction {
import kiel . editor . resources . Preferences ;
import java . awt . event . ActionEvent ;
package kiel . editor . controller ;
kiel.editor.controller.ActionViewShowStateActions
}
/**
* Toggles the preference " showStateActi ons " for displaying the
* entry - , do - and exit - activities .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected void doAction ( final ActionEvent e ) {
Preferences . t o g g l e S h o w S t a t e A c t i o n s () ;
}
* Creates an object with an group . gif image .
*/
A c t i o n V i e w S h o w S t a t e A c t i o n s () {
super (" History16 . gif ") ;
}
A. Java-Programm-Quelltext
50
40
30
20
10
kiel . editor . EditStep ;
kiel . editor . Editor ;
kiel . editor . resources . Preferences ;
kiel . editor . resources . Reso urce Bundl e ;
kiel . editor . resources . Reso urce Loade r ;
60
/**
* Has to be called by the Editor to set the reference to itself .
* @param anEditor .
*/
/**
* Reference to the editor , mainly used to get access to the graph .
* TODO Should be replaced by a reference to the graph and the kiel
frame .
*/
private static Editor editor ;
/**
* @see # TRACELOG
* @return .
*/
public static final EditStep [] getTraceLog () {
return ( EditStep []) TRACELOG . toArray ( new EditStep [0]) ;
}
100
90
/**
* The list of EditorStep objects describing which user edit steps have
* been done in which order .
*/
80
protected static final ArrayList TRACELOG = new ArrayList () ;
/**
* The superclass for all user edit steps . Will add every EditorAction call
* to the TraceLog .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
70
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.18 $ last modified $Date : 2005/08/01 17:47:28 $
*/
public abstract class EditorAction extends AbstractAction
implements Preferences . Listener {
import
import
import
import
import
import javax . swing . Abst ract Actio n ;
import javax . swing . Action ;
import javax . swing . ImageIcon ;
import java . awt . event . ActionEvent ;
import java . util . ArrayList ;
package kiel . editor . controller ;
kiel.editor.controller.EditorAction
/**
* The single " entry point " for starting the action .
* @see java . awt . event . ActionListener # actionPerformed (
/**
* The main action to be performed . This method is called just by
* actionPerformed () .
* @param e .
*/
protected abstract void doAction ( final ActionEvent e ) ;
/**
* Does not add the created object to the preferences listener list .
* @param name .
* @param iconName .
*/
protected EditorAction ( final String name , final String iconName ) {
super ( name , ResourceLoader . get ( iconName ) ) ;
}
/**
* Changes the Action . NAME according to the changes in the Preferences
* class .
* @see kiel . editor . resources . Preferences . Listener # pr e fe r e nc e s C h a n g e d ()
*/
public final void p re f e re n ce s C ha n ge d () {
putValue ( Action . NAME , ResourceBundle . getString ( getClass () . getName ()
. substring ( getClass () . getName () . lastIndexOf ( ’. ’) + 1) ) ) ;
}
/**
* Adds the created object to the preferences listener list .
* @param iconName .
*/
protected EditorAction ( final String iconName ) {
super ( null , ResourceLoader . get ( iconName ) ) ;
Preferences . addListener ( this ) ;
p re f e re n ce s C ha n ge d () ;
}
/**
* See editor .
* @return .
*/
protected static final Editor getEditor () {
return editor ;
}
public static final void initialize ( final Editor anEditor ) {
editor = anEditor ;
}
A.4. Der Quelltext
275
276
120
110
/**
/**
* The wrapped action .
*/
private Action action ;
/**
* This will change the source of the actionevent to graph . This class
* is taken from the examples of the JGraph framework .
130
*/
final class Ev e nt R ed i re c to r extends AbstractAction {
* java . awt . event . ActionEvent )
*/
public final void a ct i on P er f or m ed ( final ActionEvent e ) {
TRACELOG . add ( new EditStep (0 , this , EditStep . TYPE_START ) ) ;
doAction ( e ) ;
}
}
}
/**
* Redirect the Actionevent .
* @see java . awt . event . ActionListener # actionPerforme d (
* java . awt . event . ActionEvent )
*/
public void actionPerformed ( final ActionEvent e ) {
action . actionPerformed ( new ActionEvent ( getEditor () . getGraph () ,
e . getID () , e . getActionCom mand () , e . getModifiers () ) ) ;
}
* Construct the " Wrapper " Action .
* @param a .
*/
public EventRedirector ( final Action a ) {
super ("" , ( ImageIcon ) a . getValue ( Action . SMALL_ICON ) ) ;
this . action = a ;
}
A. Java-Programm-Quelltext
20
10
30
/**
* Returns the EditorAction and creates it if not yet done .
* @param actionClass The action class
* @return The action class
*/
public static EditorAction get ( final Class actionClass ) {
/**
* The cache containing all EditorActions . Mapping class --- object
*/
private static Hashtable cache = new Hashtable () ;
50
/**
* Thats the cache for all EditorAction objects . It creates and returns
* EditorActions . Every EditorAction is a
* singleton , that makes it easy to enable or disable some EditorActions ,
* that means the corresponding menuItems are then disabled or enabled .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
40
* @version $Revision : 1.12 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class EditorActions {
import java . util . Hashtable ;
package kiel . editor . controller ;
kiel.editor.controller.EditorActions
}
/**
* This class is not for instantiation .
*/
private EditorActions () { }
/**
* for convenience .
* @return .
*/
public ActionEditCut get ActionEditCut () {
return ( ActionEditCut ) get ( ActionEditCut . class ) ;
}
}
EditorAction instance = ( EditorAction ) cache . get ( actionClass ) ;
if ( instance == null ) {
try {
instance = ( EditorAction ) actionClass . newInstance () ;
cache . put ( actionClass , instance ) ;
} catch ( I n s t a n t i a t i o n E x c e p t i o n e ) {
e . printStackTrace () ;
} catch ( I l l e g a l A c c e s s E x c e p t i o n e ) {
e . printStackTrace () ;
}
}
return instance ;
A.4. Der Quelltext
277
278
40
30
20
10
java . awt . Cursor ;
java . awt . Point ;
java . awt . Toolkit ;
java . awt . event . ActionEvent ;
java . awt . geom . Point2D ;
50
/**
100
/**
* This is true , if i s Va l id P os i ti o n () returns true and if the requested
* operation is valid , means : moving a transition for example is
* disallowed !
*/
private boolean isModeEnabled = true ;
/**
* Thats the yellow warning cursor . This is not used yet .
private static final Cursor CURS OR_W ARNING = Toolkit . get De fau lt Too lk it ()
. c r e a t e C u s t o m C u r s o r ( Res ourc eLoader . get (" attention . gif ") . getImage
() ,
90
new Point (0 , 0) , " Warning ") ;
*/
/**
* Thats the red cross cursor !
*/
private static final Cursor C U R S O R _ F O R B IDDEN = Toolkit . ge tD ef aul tT ool ki80
t
()
. c r e a t e C u s t o m C u r s o r ( Res ourc eLoader . get (" stop . gif ") . getImage () ,
new Point (0 , 0) , " Forbidden ") ;
60
/**
* This class represents an editor state . we distinguish between the
* Select state , the add transition state and the add node state . All these
* states are represented as toggle buttons in the menu bar , only one per
* time selected . This class is not just the superclass of all EditorModes ,
* it also contains some code that has to be processed in every state , that
* is displaying the current mouse position coordinates for example . In each
* mode we have to check if the operation is generally enabled and if an
* intersection currently occurs . Depending on that , this class sets the
* cursor , a red cross or a cursor representing the mode .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p70
>
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.19 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public abstract class EditorMode extends EditorAction {
import kiel . editor . resources . Reso urce Loade r ;
import
import
import
import
import
package kiel . editor . controller ;
kiel.editor.controller.EditorMode
/**
* Calls a done () on the last EditorMode and sets this object as
* current EditorMode ( EditorMode . setCurrent () ) .
*
*/
public void start () {
if ( EditorModes . getCurrent () != null ) {
EditorModes . getCurrent () . done () ;
}
EditorModes . setCurrent ( this ) ;
/**
* Creates an EditorMode .
* @param iconName .
*/
protected EditorMode ( final String iconName ) {
super ( iconName ) ;
}
/**
* See isIntersects .
* @return .
*/
protected final boolean isIntersects () {
return isIntersects ;
}
/**
* See myCursor .
* @param newMyCursor .
*/
protected final void setMyCursor ( final Cursor newMyCursor ) {
myCursor = newMyCursor ;
}
/**
* See myCursor .
* @return .
*/
protected final Cursor getMyCursor () {
return myCursor ;
}
/**
* Holds a reference to the EditorMode dependent cursor .
*/
private Cursor myCursor = Cursor . getDefault Cursor () ;
* Does a node currently intersects another node ?
*/
private boolean isIntersects = false ;
A. Java-Programm-Quelltext
140
130
120
110
150
/**
* See isModeEnabled .
* @return .
*/
protected final boolean isModeEnabled () {
/**
* Sets the red cross cursor or the EditorMode dependent cursor .
* @param b .
*/
private void s e t C u r s o r E n a b l e d ( final boolean b ) {
if ( b ) {
getEditor () . getGraph () . setCursor ( myCursor ) ;
} else {
getEditor () . getGraph () . setCursor ( CURS OR_FORBIDDEN ) ;
}
}
/**
* Sets the current cursor as well .
* @param b .
*/
protected final void set ModeE nabl ed ( final boolean b ) {
isModeEnabled = b ;
s e t C u r s o r E n a b l e d ( isModeEnabled () && ! isIntersects () ) ;
}
/**
* Sets the current cursor as well .
* @param b .
*/
protected final void setIntersects ( final boolean b ) {
isIntersects = b ;
s e t C u r s o r E n a b l e d ( isModeEnabled () && ! isIntersects () ) ;
}
190
180
170
160
/**
* Is called when this EditorMode is replaced by the " next " EditorMode .
*/
public abstract void done () ;
}
if ( EditorModes . getCurrent () == EditorModes . get (
E d i t o r M o d e S e l e c t O r D r a g O r R e s i z e O r F l i p E x p a n d . class ) ) {
getEditor () . s e t S e l e c t i o n B u t t o n S e l e c t e d () ;
}
}
return isModeEnabled ;
/**
* Does nothing .
* @param p .
*/
public void mouseReleased ( final Point2D p ) {
}
/**
* Does nothing .
* @param p .
* @param isControlDown .
*/
public void mousePressed ( final Point2D p , final boolean isControlDown ) {
}
/**
* Sets the cursor position coordinates .
* @param p .
*/
public void mouseDragged ( final Point2D p ) {
getEditor () . s e t L a b e l C u r s o r P o s i t i o n ( p ) ;
}
/**
* Sets the cursor position coordinates .
* @param p .
* @author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </
a>
*/
public void mouseMoved ( final Point2D p ) {
getEditor () . s e t L a b e l C u r s o r P o s i t i o n ( p ) ;
}
/**
* Just calls start () .
* @see kiel . editor . controller . EditorAction # doAction (
* java . awt . event . ActionEvent )
*/
protected final void doAction ( final ActionEvent e ) {
start () ;
}
}
A.4. Der Quelltext
279
280
30
20
10
kiel . dataStructure . DeepHistory ;
kiel . editor . graph . D ee p Hi s to r yC e ll ;
kiel . editor . graph . ORStateCell ;
kiel . editor . graph . RegionCell ;
kiel . editor . resources . Preferences ;
kiel . g r a p h i c a l I n f o r m a t i o n s . Properties ;
50
40
/**
* Returns true if the selected state is an ANDState or ORState .
* @see kiel . editor . controller . E d i t o r M o deA dd Nod e # isValidPosition (
* java . awt . geom . Point2D )
*/
protected boolean i s Va l id P os i ti o n ( final Point2D p ) {
/**
* Creates an object with an DeepHistory . gif image .
*/
E d i t o r M o d e A d d D e e p H i s t o r y () {
super (" DeepHistory . gif " , DeepHistory . class ) ;
}
70
/**
* The state in which the user can add a DeepHistory .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 60
* @version $Revision : 1.21 $ last modified $Date : 2005/07/27 09:42:14 $
*/
public final class E d i t o r M o d e A d d D e e p H i s t o r y extends Ed it orM od eAd dN ode {
import
import
import
import
import
import
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import org . jgraph . graph . GraphCell ;
import org . jgraph . graph . G raphC onst ants ;
import java . awt . geom . Point2D ;
import java . awt . geom . Rectangle2D ;
package kiel . editor . controller ;
kiel.editor.controller.EditorModeAddDeepHistory
}
/**
* @see kiel . editor . controller . E di tor Mo deA dd Nod e # useNode En l ar g er ()
*/
protected boolean useNodeEnlarger () {
return false ;
}
}
getEditor () . getGraph () . getMyGraphModel () . addNode (
getNodeClass () ,
GraphConstants . getBounds (
(( DefaultGraphC ell ) cell ) . getAttributes () ) . getX ()
+ Preferences . g e t P l a c e O f D e e p H i s t o r y () . x
+ Preferences . g e t I n t e r s e c t i o n S e n s i t i v i t y () ,
GraphConstants . getBounds (
(( DefaultGraphC ell ) cell ) . getAttributes () ) . getY ()
+ Preferences . g e t P l a c e O f D e e p H i s t o r y () . y
+ Properties . g e t C o m p o s i t e S t a t e H e a d e r H e i g h t () ,
getEditor () . getGraph () . g e t G r a p h L a y o u t C a c h e () ) ;
// has to be placed in the upper left corner
Object cell = getEditor () . getGraph () . getMyGraphModel ()
. g e t S m a l l e s t C e l l O f T y p e ( GraphCell . class ,
new Rectangle2D . Double ( p . getX () , p . getY () , 1 , 1) , false ) ;
/**
* Calls MyGraphModel . add () .
* @see kiel . editor . controller . E dit or Mod eA ddN od e # doPlaceAction (
* java . awt . geom . Point2D )
*/
protected void doPlaceAction ( final Point2D p ) {
}
// is allowed only once in each ANDState and ORState
return getEditor () . getGraph () . getMyGraphModel () . canBeAdded (
DeepHistoryCell . class , p ,
new Class []{ RegionCell . class , ORStateCell . class } , true ) ;
A. Java-Programm-Quelltext
40
30
20
10
kiel . editor . M y G r a p h M o d e l U t i l i t i e s ;
kiel . editor . graph . C o m p o s i t e S t a t e C e l l ;
kiel . editor . graph . M y G r a p h C o n s t a n t s ;
kiel . editor . graph . NodeCell ;
60
50
90
80
C o m p o s i t e S t a t e C e l l cell = ( C o m p o s i t e St a te C e ll ) getEditor () . getGraph
100
()
/**
* Returns true if the selected state is not the root state or if the .
* cursor is not in the valid area of the selected state
* @see kiel . editor . controller . E d i t o r M o deA dd Nod e # isValidPosition (
* java . awt . geom . Point2D )
*/
protected final boolean i s Va l id P os i ti o n ( final Point2D p ) {
/**
* Depending on the subclass . We could have used here polymorphism as
well .
*/
private boolean isHorizontal ;
}
super ( cursorFilename , null ) ;
isHorizontal = anIs Horiz onta l ;
/**
* Creates an EditorMode object .
* @param curs orFi lenam e .
* @param anIs Hori zonta l .
*/
E d i t o r M o d e A d d D e l i m i t e r ( final String cursorFilename ,
final boolean anI sHori zont al ) {
/**
* The state in which the user can add a Delimiter .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.25 $ last modified $Date : 2005/07/27 09:42:14 $
70
*/
public abstract class E d i t o r M o d e A d d D e l i m i t e r extends E di tor Mo deA dd Nod e {
import org . jgraph . graph . AttributeMap ;
import org . jgraph . graph . GraphCell ;
import org . jgraph . graph . G raphC onst ants ;
import
import
import
import
import java . awt . geom . Point2D ;
import java . awt . geom . Rectangle2D ;
package kiel . editor . controller ;
kiel.editor.controller.EditorModeAddDelimiter
/**
* @see kiel . editor . controller . E dit or Mod eA ddN od e # useNodeEnlar g er ()
}
if ( isHorizontal ) {
getEditor () . getGraph () . getMyGraphModel () . addDelimiter (p ,
new Point2D . Double ( p . getX () + 1 , p . getY () ) ) ;
} else {
getEditor () . getGraph () . getMyGraphModel () . addDelimiter (p ,
new Point2D . Double ( p . getX () , p . getY () + 1) ) ;
}
/**
* Calls MyGraphModel . addDelimiter () .
* @see kiel . editor . controller . E dit or Mod eA ddN od e # doPlaceAction (
* java . awt . geom . Point2D )
*/
protected final void doPlaceAction ( final Point2D p ) {
}
. getMyGraphModel () . g e t S m a l l e s t C e l l O f T y p e (
C om p os i t eS t at e C el l . class ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
p . getX () , p . getY () , 1 , 1) , true ) ;
if ( cell == null
|| getEditor () . getGraph () . getMyGraphModel () . getRootCell ()
== cell
|| MyGraphC onstants . isCollapsed ( cell . getAttributes () )
|| ! M y G r a p h M o d e l U t i l i t i e s . getValidArea ( cell ) . contains ( p ) ) {
return false ;
} else {
GraphCell [] children = ( GraphCell []) (( C om p os i t eS t at e C e l l ) cell )
. getChildren () . toArray ( new GraphCell [0]) ;
for ( int i = 0; i < children . length ; i ++) {
if ( children [ i ] instanceof NodeCell ) {
Rectangle2D bounds = GraphConstants . getBounds (
children [ i ]. getAttributes () ) . getBounds () ;
if (( isHorizontal
&& bounds . getY () < p . getY ()
&& bounds . getY ()
+ bounds . getHeight () > p . getY () )
|| (! isHorizontal
&& bounds . getX () < p . getX ()
&& bounds . getX ()
+ bounds . getWidth () > p . getX () ) ) {
return false ;
}
}
}
}
return true ;
A.4. Der Quelltext
281
*/
protected final boolean u s eN o de E nl a rg e r () {
return false ;
}
}
A. Java-Programm-Quelltext
282
10
/**
/**
20
* The state in which the user can add a DeepHistory .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.13 $ last modified $Date : 2005/03/08 15:49:19 $
*/
public final class E d i t o r M o d e A d d D y n a m i c C h o i c e extends Edi to rMo de Add No de {
import kiel . dataStructure . DynamicChoice ;
package kiel . editor . controller ;
kiel.editor.controller.EditorModeAddDynamicChoice
}
/**
* @see kiel . editor . controller . E dit or Mod eA ddN od e # useNodeEnl ar g er ()
*/
protected boolean useNodeEnlarger () {
return true ;
}
* Creates an object with an DynamicChoice . gif image .
*/
E d i t o r M o d e A d d D y n a m i c C h o i c e () {
super (" DynamicChoice . gif " , DynamicChoice . class ) ;
}
A.4. Der Quelltext
283
284
10
/**
/**
20
* The state in which the user can add a DeepHistory .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.13 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class E d i t o r M o d e A d d F i n a l S i m p l e S t a t e extends Edi to rMo de Add No de {
import kiel . dataStructure . F i n a l S i m p l e S t a t e ;
package kiel . editor . controller ;
}
/**
* @see kiel . editor . controller . E di tor Mo deA dd Nod e # useNode En l ar g er ()
*/
protected boolean useNodeEnlarger () {
return true ;
}
* Creates an object with an Fi nalSimpleState . gif image .
*/
E d i t o r M o d e A d d F i n a l S i m p l e S t a t e () {
super (" FinalSimpleState . gif " , F inalSimpleState . class ) ;
}
kiel.editor.controller.EditorModeAddFinalSimpleState
A. Java-Programm-Quelltext
10
/**
/**
20
* The state in which the user can add a DeepHistory .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.13 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class E d i t o r M o d e A d d H i s t o r y extends Ed ito rM ode Ad dNo de {
import kiel . dataStructure . History ;
package kiel . editor . controller ;
kiel.editor.controller.EditorModeAddHistory
}
/**
* @see kiel . editor . controller . E dit or Mod eA ddN od e # useNodeEnlar g er ()
*/
protected boolean useNodeEnlarger () {
return true ;
}
* Creates an object with an History . gif image .
*/
E d i t o r M o d e A d d H i s t o r y () {
super (" History . gif " , History . class ) ;
}
A.4. Der Quelltext
285
286
10
/**
* Creates an object with an H o r i z o n t a l D e l i m i t e r . gif image .
*/
E d i t o r M o d e A d d H o r i z o n t a l D e l i m i t e r () {
super (" H o r i z o n t a l D e l i m i t e r . gif " , true ) ;
}
/**
* The state in which the user can add a horizontal delimiter line .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.14 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class E d i t o r M o d e A d d H o r i z o n t a l D e l i m i t e r
}
extends E d i t o r M o d e A d d D e l i m i t e r {
package kiel . editor . controller ;
kiel.editor.controller.EditorModeAddHorizontalDelimiter
A. Java-Programm-Quelltext
20
10
/**
* Creates an object with an InitialState . gif image .
*/
E d i t o r M o d e A d d I n i t i a l S t a t e () {
super (" InitialState . gif " , InitialState . class ) ;
/**
* The state in which the user can add a DeepHistory .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.14 $ last modified $Date : 2005/03/08 15:49:18 $
*/
40
public final class E d i t o r M o d e A d d I n i t i a l S t a t e extends E di tor Mo deA dd Nod e {
30
}
/**
* @see kiel . editor . controller . E dit or Mod eA ddN od e # useNodeEnl ar g er ()
*/
protected boolean useNodeEnlarger () {
return true ;
}
}
// at most one time in each ORState and Region
return getEditor () . getGraph () . getMyGraphModel () . canBeAdded (
InitialStat eCell . class , p ,
new Class []{ RegionCell . class , ORStateCell . class } , false ) ;
/**
* Returns true if the selected node is a Region or ORState .
* @see kiel . editor . controller . E dit or Mod eA ddN od e # isValidPos it i on (
* java . awt . geom . Point2D )
*/
protected boolean isValidPosition ( final Point2D p ) {
kiel . dataStructure . InitialState ;
kiel . editor . graph . I n i t i a l S t a t e C e l l ;
kiel . editor . graph . ORStateCell ;
kiel . editor . graph . RegionCell ;
import java . awt . geom . Point2D ;
import
import
import
import
}
package kiel . editor . controller ;
kiel.editor.controller.EditorModeAddInitialState
A.4. Der Quelltext
287
288
40
30
20
10
java . awt . Point ;
java . awt . Rectangle ;
java . awt . Toolkit ;
java . awt . geom . Point2D ;
java . awt . geom . Rectangle2D ;
kiel . dataStructure . State ;
kiel . editor . EditStep ;
kiel . editor . M o r p h i n g L a y o u t e r ;
kiel . editor . M y G r a p h M o d e l U t i l i t i e s ;
kiel . editor . graph . C o m p o s i t e S t a t e C e l l ;
kiel . editor . graph . M y G r a p h C o n s t a n t s ;
kiel . editor . graph . NodeCell ;
kiel . editor . graph . ORStateCell ;
kiel . editor . graph . RegionCell ;
kiel . editor . resources . Preferences ;
kiel . editor . resources . Reso urce Loade r ;
kiel . g r a p h i c a l I n f o r m a t i o n s . Properties ;
70
60
50
90
/**
* Each E d i t o r M o d e A d d N o d e object will create a node of a particular type
.
*/
private final Class nodeClass ;
/**
* The handler for the editor layout mechanism for " creating editor
space ".
* This class does not contain the algorithm but the call to the
* M o r p h i n g L a y o u t e r which contains that layouting information
*/
private final NodeEnlarger nodeEnlarger = new NodeEnlarger () ;
/**
* The state in which the user can add a node .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p80
>
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.40 $ last modified $Date : 2005/07/27 09:42:14 $
*/
public abstract class E d i t o r M o d e A d d N o d e extends EditorMode {
import org . jgraph . graph . AttributeMap ;
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
import org . jgraph . graph . G raphC onst ants ;
import
import
import
import
import
import
import
import
import
import
import
import
import javax . swing . Action ;
import javax . swing . ImageIcon ;
import
import
import
import
import
package kiel . editor . controller ;
kiel.editor.controller.EditorModeAddNode
}
}
new Point (0 , 0) ,
( String ) getValue ( Action . NAME ) ) ) ;
/**
* Sets the appropriate cursor and delegates this call to the node
enlarger .
* @see kiel . editor . controller . EditorMode # start ()
*/
public final void start () {
super . start () ;
getEditor () . getGraph () . setCursor ( getMyCursor () ) ;
getEditor () . getGraph () . setPortsVisible ( true ) ;
EditorActions . get ( A c t i o n A d d T r a n s i t i o n T o g g l e . class ) . doAction ( null ) ;
}
() ,
if ( icon != null ) {
setMyCursor ( Toolkit . ge tD efa ul tTo ol kit ()
. c re a te C u st o mC u rs o r ( icon . getImage () ,
new Point (0 , 0) ,
( String ) getValue ( Action . NAME ) ) ) ;
} else {
setMyCursor ( Toolkit . ge tD efa ul tTo ol kit ()
. c re a te C u st o mC u rs o r (
ResourceLoader . get ( cursorFilenam e ) . getImage
ImageIcon icon = ResourceLoader . get (
cursorFilename . substring (0 , cursorFilename . lastIndexOf (".") )
+ " AndCursor . gif ") ;
if ( cursorFilename != null ) {
super ( cursorFilename ) ;
this . nodeClass = aNodeClass ;
/**
* Creates an object with the appropriate cursor .
* @param cursorFilename .
* @param aNodeClass .
*/
protected Edi to rM ode Ad dNo de ( final String cursorFilename ,
final Class aNodeClass ) {
/**
* See nodeClass .
* @return .
*/
protected final Class getNodeClass () {
return nodeClass ;
}
A. Java-Programm-Quelltext
150
140
130
120
110
100
EditorActions . get ( A c t i o n A d d T r a n s i t i o n T o g g l e . class ) . setEnabled ( false )
nodeEnlarger . start () ;
/**
* Calls the doPlaceAction () if isModeEnabled and not isIntersects .
* Switches then to the Select - EditorMode .
* @see kiel . editor . controller . EditorMode
* # mouseReleased ( java . awt . geom . Point2D )
*/
public final void mouseReleased ( final Point2D p ) {
super . mouseReleased ( p ) ;
if ( isModeEnabled () && ! isIntersects () ) {
doPlaceAction ( p ) ;
/**
* Just calls MyGraphModel . add () .
* @param p .
*/
protected void doPlaceAction ( final Point2D p ) {
Point2D snapPoint = getEditor () . getGraph () . snap ( p ) ;
getEditor () . getGraph () . g et M yG r ap h Mo del () . addNode (
nodeClass , snapPoint . getX () , snapPoint . getY () ,
getEditor () . getGraph () . g e t G r a p h L a y o u t C a c h e () ) ;
}
}
// no limit for Co m po s it e St a te s
Point2D snapPoint = getEditor () . getGraph () . snap ( p ) ;
Object cell = getEditor () . getGraph () . getMyGraphModel ()
. g e t S m a l l e s t C e l l O f T y p e ( NodeCell . class ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
snapPoint . getX () , snapPoint . getY () , 1 , 1) , true ) ;
return cell instanceof C o m p o s i t e S t a t e Ce l l
&& ! M y G r a p h C o n s t a n t s . isCollapsed (
(( D e f a u l t G r a p h C e l l ) cell ) . getAttributes () ) ;
/**
* Returns true if the currently selected state is a CompositeState .
* @param p .
* @return .
*/
protected boolean i s Va l id P os i ti o n ( final Point2D p ) {
200
190
180
170
/**
* Delegates to the node enlarger .
* @see kiel . editor . controller . EditorMode # done ()
160
*/
public final void done () {
EditorActions . get ( A c t i o n A d d T r a n s i t i o n T o g g l e . class ) . doAction ( null ) ;
EditorActions . get ( A c t i o n A d d T r a n s i t i o n T o g g l e . class ) . setEnabled ( true ) ;
nodeEnlarger . done () ;
}
}
;
super . mousePressed (p , isControlDown ) ;
c u r r e n t l y S e l e c t e d C o m p o s i t e S t a t e = ( C o mp o s it e St a t eC e ll ) getEditor ()
. getGraph () . getMyGraphModel () . g e t S m a l l e s t C e l l O f T y p e (
/**
* Sets the c u r r e n t l y S e l e c t e d C o m p o s i t e S t a t e and starts the undo cluster .
* Then delegates the call to the Node enlarger .
* @see kiel . editor . controller . EditorMode
* # mousePressed ( java . awt . geom . Point2D , boolean )
*/
public final void mousePressed ( final Point2D p ,
final boolean isControlDown ) {
/**
* If the action has been done successfully , that means , mouse released
* when the red cross was not visible , then the edit cluster can be
* terminated , otherwise it will be discarded .
*/
private boolean a c t i o n S u c c e s s f u l D o n e ;
/**
* Has mouseReleased () already been called ? The current
* edit step cluster can be finished only if there are none left .
*/
private boolean m o u s e I s A l r e a d y R e l e a s e d ;
/**
* how many Morphin gLayouter calls have not been finished yet ? The
current
* edit step cluster can be finished only if there are none left .
*/
private int p e n d i n g M o r p h i n g R e q u e s t s C o u n t ;
/**
* See c u r r e n t l y S e l e c t e d C o m p o s i t e S t a t e .
* @return .
*/
protected static C o mp o si t e St a te C e ll g e t C u r r e n t l y S e l e c t e d C o m p o s i t e S t a t e ()
{
return c u r r e n t l y S e l e c t e d C o m p o s i t e S t a t e ;
}
/**
* Reference to the currently selected state .
*/
private static C o mp o si t e St a te C e ll c u r r e n t l y S e l e c t e d C o m p o s i t e S t a t e ;
}
a c t i o n S u c c e s s f u l D o n e = true ;
}
m o u s e I s A l r e a d y R e l e a s e d = true ;
t e r m i n a t e E d i t C l u s t e r () ;
EditorModes . get ( E d i t o r M o d e S e l e c t O r D r a g O r R e s i z e O r F l i p E x p a n d . class )
. start () ;
A.4. Der Quelltext
289
290
250
240
230
220
210
nodeEnlarger . mousePressed ( p ) ;
p e n d i n g M o r p h i n g R e q u e s t s C o u n t = 0;
m o u s e I s A l r e a d y R e l e a s e d = false ;
a c t i o n S u c c e s s f u l D o n e = false ;
/**
*
* @param newNodeBounds .
* @return .
*/
/**
* .
* @return .
*/
protected abstract boolean u se N od e En l ar ger () ;
/**
* Just sets the cursor .
* @see kiel . editor . controller . EditorMode
* # mouseMoved ( java . awt . geom . Point2D )
*/
public final void mouseMoved ( final Point2D p ) {
super . mouseMoved ( p ) ;
// Check if allowed to place
se tMode Enab led ( i sV a li d Po s it i on ( p ) ) ;
setIntersects (
! w i l l E n l a r g e T a r g e t P a r e n t ( g e t N e w NodeBounds ( p ) )
&& getEditor () . getGraph () . ge t My GraphModel () . intersect (
nodeClass , p . getX () , p . getY () ) ) ;
}
300
290
/**
270
* Sets the cursor and delegates the call to the NodeEnlarger .
* @see kiel . editor . controller . EditorMode
* # mouseDragged ( java . awt . geom . Point2D )
*/
public final void mouseDragged ( final Point2D p ) {
super . mouseDragged ( p ) ;
// Check if allowed to place
se tMode Enab led ( i sV a li d Po s it i on ( p ) ) ;
setIntersects ( getEditor () . getGraph () . getMyGraphModel () . intersect (
280
nodeClass ,
p . getX () , p . getY () ) ) ;
nodeEnlarger . mouseDragged ( p ) ;
}
}
;
260
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . s e t U n d o C l u s t e r S t a r t ()
C o m p o s i t e S t a t e C e l l . class ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
p . getX () , p . getY () , 1 , 1) , false ) ;
/**
* The initial bounds of the currently selected Compos iteSt ate
* have to be stored .
*/
/**
* Handles " create space !" requests while choosing a place to create
* a new node . This class does not implement any layout algorithms but
just
* calls the MorphingLayouter who implements those layout mechanisms .
* @author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </
a>
*/
private final class NodeEnlarger implements Morp hingLayo u t e r . MyListener
{
/**
*
* @param upperLeft .
* @return .
*/
private Rectangle2D getNewNod eBounds ( final Point2D upperLeft ) {
final int se ns iti vi tyF ac tor = 2;
return new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
upperLeft . getX () - Preferences . g e t I n t e r s e c t i o n S e n s i t i v i t y () ,
upperLeft . getY () - Preferences . g e t I n t e r s e c t i o n S e n s i t i v i t y () ,
// TODO Why 2 times Preferences . getGridSize () ??
M y G r a p h M o d e l U t i l i t i e s . g e t I n i t i a l D i m e n s i o n O f ( nodeClass )
. width
+ se nsi ti vit yF act or * Preferences . g e t I n t e r s e c t i o n S e n s i t i v i t y
()
+ se nsi ti vit yF act or * Preferences . getGridSize () ,
M y G r a p h M o d e l U t i l i t i e s . g e t I n i t i a l D i m e n s i o n O f ( nodeClass )
. height
+ se nsi ti vit yF act or * Preferences . g e t I n t e r s e c t i o n S e n s i t i v i t y
()
+ se nsi ti vit yF act or * Preferences . getGridSize () ) ;
}
}
DefaultGra phCell currentNode =
( Default GraphCell ) getEditor () . getGraph () . getMyGr a ph M od el ()
. g e t S m a l l e s t C e l l O f T y p e ( Co m po s i te S ta t e Ce l l . class ,
new Rectangle (
( int ) newNodeBounds . getX () ,
( int ) newNodeBounds . getY () , 1 , 1) , false ) ;
return
Preferences . get La you tO nIn se rt ()
&& currentNode instanceof ORStateCell
&& getEditor () . getGraph () . getMyGraphModel () . intersect (
currentNode , newNodeBounds , false ) ;
private boolean w i l l E n l a r g e T a r g e t P a r e n t (
final Rectangle2D newNodeBounds ) {
A. Java-Programm-Quelltext
350
340
330
320
310
()
/**
* Calls the M o r p h i n g L a y o u t e r depending on the Preferences .
/**
* Just sets the JGraph . moveable attribute to true . Don ’ t really
* know why .
* @see kiel . editor . controller . EditorMode # done ()
*/
public void done () {
getEditor () . getGraph () . setMoveable ( true ) ;
}
/**
* Just sets the JGraph . moveable attribute to false . Don ’ t really
* know why .
* @see kiel . editor . controller . EditorMode # start ()
*/
public void start () {
getEditor () . getGraph () . setMoveable ( false ) ;
}
/**
* Just delegates the call to the NodeEnlarger .
* @see kiel . editor . controller . EditorMode
* # mouseDragged ( java . awt . geom . Point2D )
*/
public void mouseDragged ( final Point2D p ) {
e n l a r g e T a r g e t P a r e n t (p , false ) ;
}
}
. getAttributes () ) . getBounds2D () ;
} else {
i n i t i a l B o u n d s O f C u r r e n t l y S e l e c t e d C o m p o s i t e S t a t e = null ;
}
if (!( E d i t o r M o d e A d d N o d e . g e t C u r r e n t l y S e l e c t e d C o m p o s i t e S t a t e ()
instanceof RegionCell ) ) {
e n l a r g e T a r g e t P a r e n t (p , true ) ;
}
400
390
380
private Rectangle2D i n i t i a l B o u n d s O f C u r r e n t l y S e l e c t e d C o m p o s i t e S t a t e ;
360
/**
* Sets the initial bounds of the currently selected CompositeState
* and delegates the call to the NodeEnlarger .
* @see kiel . editor . controller . EditorMode
* # mousePressed ( java . awt . geom . Point2D )
*/
public void mousePressed ( final Point2D p ) {
if ( E d i t o r M o d e A d d N o d e . g e t C u r r e n t l y S e l e c t e d C o m p o s i t e S t a t e ()
!= null ) {
370
initialBoundsOfCurrentlySelectedCompositeState =
Gra phCo nstan ts . getBounds (
EditorModeAddNode . getCurrentlySelectedCompositeState
t ar g e tP a re n t Bo u nd s . add ( newStateBounds ) ;
// think of the or state header ...
newStateBounds . add ( new AttributeMap . S e r i a l i z a b l e P o i n t 2 D (
newStateBounds . getX () ,
newStateBounds . getY ()
- Properties . getUpperOffset (
( State ) MyGra phConstants . g et G r ap h ic a l Ob j e c t (
Ed it orM od eAd dN ode
. g e t C u r r e n t l y S e l e c t e d C o m p o s i t e S t a t e ()
. getAttributes () ) ) ) ) ;
//...
EditorModes . getCurrent () . setIntersects ( false ) ;
/**
* Decreases the p e n d i n g M o r p h i n g R e q u e s t s C o u n t and calls
* t e r m i n a t e E d i t C l u s t e r () .
* @see kiel . editor . MorphingLayouter . MyListener # morphing F i n i s h e d ()
*/
public void morphingFinished () {
}
}
p e n d i n g M o r p h i n g R e q u e s t s C o u n t ++;
new MorphingLayouter ( getEditor () . getGraph () , this ,
doMorphing )
. e x p a n d C o m p o s i t e S t a t e (( DefaultGraphCe ll )
Ed it orM od eAd dN ode . g e t C u r r e n t l y S e l e c t e d C o m p o s i t e S t a t e
() ,
t ar g e tP a re n t Bo u nd s ) ;
() ;
// @TODO Calculate needed bounds for the current parent and
// morph ...
Rectangle2D t ar g et P a re n tB o u nd s =
i n i t i a l B o u n d s O f C u r r e n t l y S e l e c t e d C o m p o s i t e S t a t e . getBounds
if ( w i l l E n l a r g e T a r g e t P a r e n t ( newStateBounds ) ) {
Rectangle2D newStateBounds = get NewNodeBounds ( p ) ;
}
// @TODO do the same for dragging after creation
if (! Preferences . get La you tO nIn se rt ()
|| ! isModeEnabled ()
|| ! useNodeEnlarger () ) {
return ;
* @param p .
* @param doMorphing .
*/
private void e n l a r g e T a r g e t P a r e n t ( final Point2D p ,
final boolean doMorphing ) {
A.4. Der Quelltext
291
292
420
410
pen ding Morph ingRe ques tsCou nt - -;
t e r m i n a t e E d i t C l u s t e r () ;
/**
* If the p e n d i n g M o r p h i n g R e q u e s t s C o u n t is 0 and the mouse is already
* released , then if the action was successgfully done , then terminate430
the
* the current edit step cluster otherwise discard the current edit step
* cluster .
*/
private void t e r m i n a t e E d i t C l u s t e r () {
if ( p e n d i n g M o r p h i n g R e q u e s t s C o u n t == 0 && m o u s e I s A l r e a d y R e l e a s e d ) {
}
}
}
}
}
if ( a c t i o n S u c c e s s f u l D o n e ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r ()
. set Un doC lu ste rE nd ( Ed it orM od eAd dN ode . this ) ;
EditorAction . TRACELOG . add (
new EditStep (0 , this , EditStep . TYPE_SUCCE S SF U L ) ) ;
} else {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r ()
. d i s c a r d C u r r e n t C l u s t e r () ;
EditorAction . TRACELOG . add (
new EditStep (0 , this , EditStep . TYPE_CANCELL ED ) ) ;
}
A. Java-Programm-Quelltext
10
/**
/**
20
* The state in which the user can add an or state .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.12 $ last modified $Date : 2005/03/08 15:49:19 $
*/
public final class E d i t o r M o d e A d d O r S t a t e extends Ed ito rM ode Ad dNo de {
import kiel . dataStructure . ORState ;
package kiel . editor . controller ;
kiel.editor.controller.EditorModeAddOrState
}
/**
* @see kiel . editor . controller . E dit or Mod eA ddN od e # useNodeEnlar g er ()
*/
protected boolean useNodeEnlarger () {
return true ;
}
* Creates an object with an OrState . gif image .
*/
E d i t o r M o d e A d d O r S t a t e () {
super (" OrState . gif " , ORState . class ) ;
}
A.4. Der Quelltext
293
294
10
/**
/**
20
* The state in which the user can add a simple state .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.12 $ last modified $Date : 2005/03/08 15:49:18 $
*/
public final class E d i t o r M o d e A d d S i m p l e S t a t e extends Ed it orM od eAd dN ode {
import kiel . dataStructure . SimpleState ;
package kiel . editor . controller ;
kiel.editor.controller.EditorModeAddSimpleState
}
/**
* @see kiel . editor . controller . E di tor Mo deA dd Nod e # useNode En l ar g er ()
*/
protected boolean useNodeEnlarger () {
return true ;
}
* Creates an object with an SimpleState . gif image .
*/
E d i t o r M o d e A d d S i m p l e S t a t e () {
super (" SimpleState . gif " , SimpleState . class ) ;
}
A. Java-Programm-Quelltext
10
/**
/**
20
* The state in which the user can add a suspend .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.12 $ last modified $Date : 2005/03/08 15:49:19 $
*/
public final class E d i t o r M o d e A d d S u s p e n d extends Ed ito rM ode Ad dNo de {
import kiel . dataStructure . Suspend ;
package kiel . editor . controller ;
kiel.editor.controller.EditorModeAddSuspend
}
/**
* @see kiel . editor . controller . E dit or Mod eA ddN od e # useNodeEnlar g er ()
*/
protected boolean useNodeEnlarger () {
return true ;
}
* Creates an object with an Suspend . gif image .
*/
E d i t o r M o d e A d d S u s p e n d () {
super (" Suspend . gif " , Suspend . class ) ;
}
A.4. Der Quelltext
295
296
20
10
30
50
/**
*
* @see kiel . editor . controller . EditorMode # start ()
*/
public void start () {
super . start () ;
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . s e t U n d o C l u s t e r S t a r t ()
;
/**
* Creates an object with no image since it will have no representation
at
* all .
*/
E d i t o r M o d e A d d T r a n s i t i o n () {
super ( null ) ;
}
/**
* The state in which the user can add a transition .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.14 $ last modified $Date : 2005/03/08 15:49:18 $
*/
40
public final class E d i t o r M o d e A d d T r a n s i t i o n extends EditorMode {
import java . awt . geom . Point2D ;
package kiel . editor . controller ;
kiel.editor.controller.EditorModeAddTransition
}
/**
*
* @see kiel . editor . controller . EditorMode # done ()
*/
public void done () {
}
/**
*
* @see kiel . editor . controller . EditorMode # mouseReleased (
* java . awt . geom . Point2D )
*/
public void mouseReleased ( final Point2D p ) {
super . mouseReleased ( p ) ;
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . se tU n d o C l u s t e r E n d (
this ) ;
EditorModes . get ( E d i t o r M o d e S e l e c t O r D r a g O r R e s i z e O r F l i p E x p a n d . class )
. start () ;
}
/**
* @see kiel . editor . controller . E di tor Mo deA dd Nod e # doPlaceAction (
* java . awt . geom . Point2D )
*/
protected void doPlaceAction ( final Point2D p ) {
}
}
A. Java-Programm-Quelltext
10
/**
* Creates an object with an Ver ti cal De lim it er . gif image .
*/
E d i t o r M o d e A d d V e r t i c a l D e l i m i t e r () {
super (" Ve rti ca lDe li mit er . gif " , false ) ;
}
/**
* The state in which the user can add a vertical delimiter .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.12 $ last modified $Date : 2005/03/08 15:49:19 $
*/
public final class E d i t o r M o d e A d d V e r t i c a l D e l i m i t e r
}
extends E d i t o r M o d e A d d D e l i m i t e r {
package kiel . editor . controller ;
kiel.editor.controller.EditorModeAddVerticalDelimiter
A.4. Der Quelltext
297
298
30
20
10
EditorMode instance = ( EditorMode ) cache . get ( actionClass ) ;
if ( instance == null ) {
try {
instance = ( EditorMode ) actionClass . newInstance () ;
cache . put ( actionClass , instance ) ;
} catch ( I n s t a n t i a t i o n E x c e p t i o n e ) {
e . p ri n tS t ac k Tr a ce () ;
} catch ( I l l e g a l A c c e s s E x c e p t i o n e ) {
e . p ri n tS t ac k Tr a ce () ;
/**
* @param actionClass The action class
* @return The action class
*/
public static EditorMode get ( final Class actionClass ) {
/**
* Comment for < code > cache </ code >.
*/
private static Hashtable cache = new Hashtable () ;
60
50
/**
* The editor modes cache .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p40
>
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class EditorModes {
import java . util . Hashtable ;
package kiel . editor . controller ;
kiel.editor.controller.EditorModes
}
/**
* @param anEditorMode .
*/
static void setCurrent ( final EditorMode anEditorMode ) {
currentMode = anEditorMode ;
}
/**
* @return .
*/
public static EditorMode getCurrent () {
return currentMode ;
}
/**
* Comment for < code > currentMode </ code >.
*/
private static EditorMode currentMode =
EditorModes . get ( E d i t o r M o d e S e l e c t O r D r a g O r R e s i z e O r F l i p E x p a n d . class ) ;
}
/**
* .
*/
private EditorModes () {
}
}
}
return instance ;
A. Java-Programm-Quelltext
50
40
30
20
10
80
70
60
/**
* Comment for < code > draggedCell </ code >.
*/
private Object [] selectedCells ;
100
/**
* The state in which the user can select or drag or resize or flip expand
* a state .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p90
>
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.60 $ last modified $Date : 2005/08/02 19:28:13 $
*/
public class E d i t o r M o d e S e l e c t O r D r a g O r R e s i z e O r F l i p E x p a n d extends EditorMode
implements M o r p h i n g L a y o u t e r . MyListener {
org . jgraph . graph . AttributeMap ;
org . jgraph . graph . CellView ;
org . jgraph . graph . D e f a u l t G r a p h C e l l ;
org . jgraph . graph . D e f a u l t G r a p h M o d e l ;
org . jgraph . graph . G raphC onst ants ;
kiel . dataStructure . ANDState ;
kiel . dataStructure . G r ap h ic a lO b je c t ;
kiel . dataStructure . ORState ;
kiel . editor . M o r p h i n g L a y o u t e r ;
kiel . editor . MyGraphModel ;
kiel . editor . M y G r a p h M o d e l U t i l i t i e s ;
kiel . editor . graph . ANDStateCell ;
kiel . editor . graph . C o m p o s i t e S t a t e C e l l ;
kiel . editor . graph . D ee p Hi s to r yC e ll ;
kiel . editor . graph . D e l i m i t e r L i n e C e l l ;
kiel . editor . graph . M y G r a p h C o n s t a n t s ;
kiel . editor . graph . NodeCell ;
kiel . editor . graph . NodeView ;
kiel . editor . graph . ORStateCell ;
kiel . editor . graph . Previewable ;
kiel . editor . graph . P se u do S ta t eC e ll ;
kiel . editor . graph . RegionCell ;
kiel . editor . graph . Tran sitio nCell ;
kiel . editor . resources . Preferences ;
kiel . g r a p h i c a l I n f o r m a t i o n s . Properties ;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
java . awt . Rectangle ;
java . awt . geom . Point2D ;
java . awt . geom . Rectangle2D ;
java . util . Arrays ;
java . util . Iterator ;
import
import
import
import
import
package kiel . editor . controller ;
;
selectedCells = getEditor () . getGraph ()
. get Se lec ti onM od el () . get Se lec ti onC el ls () ;
if ( selectedCells != null ) {
selectedBounds = new Rectangle2D [ selectedCells . length ];
} else {
selectedBounds = null ;
}
for ( int i = 0; selectedCells != null
&& i < selectedCells . length ; i ++) {
// for dragging and resizing mode ...
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . s e t U n d o C l u s t e r S t a r t ()
// This is done * here * because of performance issues
if ( isControlDown ) {
getEditor () . updateMenuEdit () ;
}
// For selection mode ...
a u t o m a t i c S e l e c t i o n E n a b l e d = ! isControlDown ;
/**
* @see kiel . editor . controller . EditorMode
* # mousePressed ( java . awt . geom . Point2D )
*/
public final void mousePressed ( final Point2D p ,
final boolean isControlDown ) {
super . mousePressed (p , isControlDown ) ;
/**
* Creates an object with an cancel . gif image .
*/
E d i t o r M o d e S e l e c t O r D r a g O r R e s i z e O r F l i p E x p a n d () {
super (" cancel . gif ") ;
}
/**
*
*/
private boolean i s D r a g g i n g O r R e s i z i n g ;
/**
*
*/
private boolean a u t o m a t i c S e l e c t i o n E n a b l e d = true ;
/**
*
*/
private Rectangle2D [] selectedBounds ;
kiel.editor.controller.EditorModeSelectOrDragOrResizeOrFlipExpand
A.4. Der Quelltext
299
300
150
140
130
120
110
sel ecte dBoun ds [ i ] = ( Rectangle2D ) GraphConstants . getBounds (
(( D e f a u l t G r a p h C e l l ) selectedCells [ i ]) . getAttributes () ) ;
160
return ;
}
// select the node in which the mouse cursor is or , if exist , a
child
// of this node which intersects the mouse * area *.
CellView toBeSelected = M y G r a p h M o d e l U t i l i t i e s . g e t S m a l l e s t V i e w O f T y p e (
CellView . class , new Rectangle (( int ) p . getX () ,
200
( int ) p . getY () , 1 , 1) ,
getEditor () . getGraph () . g e t G r a p h L a y o u t C a c h e () ,
false , null ) ;
if ( toBeSelected == null ) {
// For selection mode
if (! a u t o m a t i c S e l e c t i o n E n a b l e d
|| !( getEditor () . getGraph () . getModel () instanceof MyGraphModel190
)
|| getEditor () . getGraph () . i sPopupVisible () ) {
// TODO Fix me ! workaround : the cursor of EditorModeS elect ...
// will not be resetted after addDelimiter !
if ( getEditor () != null
&& ( getEditor () . getGraph () . getCursor ()
180
== EditorModes . get (
E d i t o r M o d e A d d H o r i z o n t a l D e l i m i t e r . class ) . getMyCursor () )
|| getEditor () . getGraph () . getCursor ()
== EditorModes . get (
E d i t o r M o d e A d d V e r t i c a l D e l i m i t e r . class ) . getMyCursor () ) {
getEditor () . getLogFile () . log (2 , " correct cursor ") ;
getEditor () . getGraph () . setCursor ( getMyCursor () ) ;
}
Object selectedCell = getEditor () . getGraph () . getSelectionCell () ;
if ( l a s t S e l e c t e d C e l l != selectedCell ) {
l a s t S e l e c t e d C e l l = selectedCell ;
getEditor () . up dateM enuE dit () ;
}
/**
* Handles automatic selection and updating menus on mouse moving events
.
* @see kiel . editor . controller . EditorMode
* # mouseMoved ( java . awt . geom . Point2D )
*/
public final void mouseMoved ( final Point2D p ) {
170
super . mouseMoved ( p ) ;
/**
*
*/
private Object l a s t S e l e c t e d C e l l ;
}
}
//
}
/**
* @param cellClass .
* @return .
*/
private boolean i s S e l e c t e d I n s t a n c e O f ( final Class cellClass ) {
Object [] objects = getEditor () . getGraph () . ge tS ele ct i o n C e l l s () ;
for ( int i = 0; objects != null && i < objects . length ; i ++) {
if ( objects [ i ] != null && cellClass . isInstance ( objects [ i ]) ) {
return true ;
}
}
getEditor () . g e t M e n u I t e m C o l l a p s e d () . setSelected ( isCollapsed ) ;
getEditor () . getGraph () . g e t M e n u I t e m C o l l a p s e d () . setSelected (
isCollapsed ) ;
// Update Button States based on Current Selection
EditorActions . get ( ActionEditCopy . class ) . setEnabled ( cell != null ) ;
EditorActions . get ( ActionEditCut . class ) . setEnabled ( cell != null ) ;
if ( cell != null && cell != getEditor () . getGraph () . g e t S e l e c t i o n C e l l
() ) {
getEditor () . getGraph () . ge tSe le cti on Mod el () . se tSe l e c t i o n C e l l ( cell
);
// update the collapsed checkbox items in the menubar and the
popup
// menu
GraphicalObject go = MyGraphConstan ts . ge t Gr a p hi c a l O b j e c t (
(( DefaultGraphCe ll ) cell ) . getAttributes () ) ;
if ( go instanceof ORState || go instanceof ANDState ) {
final boolean isCollapsed = MyGraphCons tants . isCollapsed (
(( DefaultGraphC ell ) cell ) . getAttributes () ) ;
for ( int i = 0; i < toBeSelected . getChildViews () . length ; i ++) {
if ( toBeSelected . getChildViews () [ i ] instanceof NodeView
&& toBeSelected . getChildViews () [ i ]. getBounds () . intersects (
mouseRectangle ) ) {
toBeSelected = toBeSelected . getChildViews () [ i ];
break ;
}
}
Object cell = toBeSelected . getCell () ;
}
Rectangle2D mouseRectangle = new AttributeMap .
SerializableRectangle2D (
p . getX () - Preferences . g e t S i z e H a n d l e S e n s i t i v i t y () ,
p . getY () - Preferences . g e t S i z e H a n d l e S e n s i t i v i t y () ,
Preferences . g e t S i z e H a n d l e S e n s i t i v i t y () * 2 ,
Preferences . g e t S i z e H a n d l e S e n s i t i v i t y () * 2) ;
toBeSelected = getEditor () . getGraph () . g e t G r a p h L a y o u t C a c h e ()
. getMapping ( getEditor () . getGraph () . getMyGrap h Mo d el ()
. getRootCell () , false ) ;
return ;
A. Java-Programm-Quelltext
250
240
230
220
210
return true ;
}
return false ;
}
if ( selectedViews [ i ] instanceof Previewable
&& (( Previewable ) selectedViews [ i ]) . isResizing () ) {
i s D r a g g i n g O r R e s i z i n g = true ;
set ModeE nabl ed ( true ) ;
setIntersects ( false ) ;
/**
* @see kiel . editor . controller . EditorMode
* # mouseDragged ( java . awt . geom . Point2D )
*/
public final void mouseDragged ( final Point2D p ) {
super . mouseDragged ( p ) ;
}
280
270
260
310
300
290
for ( int i = 0; selectedViews != null && i < selectedViews . length ;
i ++) {
CellView [] selectedViews = getEditor () . getGraph ()
. g e t G r a p h L a y o u t C a c h e () . getMapping ( selectedCells ) ;
/**
*
* @return .
*/
private boolean isResizing () {
/**
*
* @param cell .
* @return .
*/
private static Rectangle2D g e t P r e v i e w B o unds ( final Object cell ) {
CellView view = getEditor () . getGraph ()
. g e t G r a p h L a y o u t C a c h e () . getMapping ( cell , false ) ;
if ( view instanceof Previewable ) {
return (( Previewable ) view ) . g e t PreviewBounds () ;
} else if ( cell != null ) {
getEditor () . getLogFile () . log (2 , cell . getClass () . getName () ) ;
}
return null ;
}
}
}
}
return false ;
[0])
// Check if all children are still in bounds
} else { // IsMoving
if ( selectedCells [0] instanceof ORStateCell
|| selectedCells [0] instanceof ANDStateCell ) {
// ensmall to the valid area
previewBounds . setRect (
previewBounds . getX () ,
previewBounds . getY ()
+ Properties . g e t C o m p o s i t e S t a t e H e a d e r H e i g h t () ,
previewBounds . getWidth () ,
previewBounds . getHeight ()
- Properties . g e t C o m p o s i t e S t a t e H e a d e r H e i g h t () ) ;
}
// and , ensmall to the intersections sensitivity ...
final int sens = Preferences . g e t I n t e r s e c t i o n S e n s i t i v i t y () ;
if (!( selectedCells [0] instanceof ANDStateCell ) ) { // make
previewBounds . setRect (// resizing ANDState possible !
previewBounds . getX () + sens ,
previewBounds . getY () + sens ,
previewBounds . getWidth () - 2 * sens ,
previewBounds . getHeight () - 2 * sens ) ;
}
intersects =
getEditor () . getGraph () . getMyGraphModel () . intersect (
( Default GraphCell ) selectedCells [0] , previewBounds ,
false , null , false )
|| ! getEditor () . getGraph () . getMyGraphModel ()
. a r e A l l C h i l d r e n I n s i d e (( DefaultGraphC ell )
selectedCells [0] , previewBounds ) ;
. getBounds2D () ;
Rectangle2D previewBounds = getPrevi ewBounds ( selectedCells
if ( isResizing ) {
if ( i s S e l e c t e d I n s t a n c e O f ( RegionCell . class ) ) {
setModeEnabled ( false ) ;
} else if ( i s S e l e c t e d I n s t a n c e O f ( DeepHistoryCell . class ) ) {
setModeEnabled ( false ) ;
} else if ( i s S e l e c t e d I n s t a n c e O f ( De li mit er Lin eC ell . class )
&& isResizing () ) {
setModeEnabled ( false ) ;
} else if ( i s D r a g g i n g R o o t O r C h a n g i n g U p p e r L e f t () ) {
setModeEnabled ( false ) ;
} else if ( i s S e l e c t e d I n s t a n c e O f ( TransitionCell . class ) ) {
setModeEnabled ( true ) ;
} else if ( i s S e l e c t e d I n s t a n c e O f ( PseudoStateCell . class )
&& isResizing () ) {
setModeEnabled ( false ) ;
} else if ( selectedCells != null ) {
boolean isResizing = isResizing () ;
boolean intersects = false ;
A.4. Der Quelltext
301
302
360
350
340
330
320
}
370
}
}
setIntersects ( intersects ) ;
}
if ( i s F l i p E x p a n d C o m p o s i t e S t a t e T r i g g e r ( p ) ) {
// resizing in case of adding / deleting transition points
CellView view = getEditor () . getGraph () . g e t G r a p h L a y o u t C a c h e ()
. getMapping ( selectedCells [ i ] , false ) ;
Point2D labelPosition = null ;
if ( view != null ) {
labelPosition = GraphConstants . getLabelPosit i o n (
view . getAttributes () ) ;
}
if ( selectedCells [ i ] instanceof TransitionCell ) {
// or source or target have been moved !!!!!
getEditor () . getGraph () . getMyGraphModel ()
. updateKielTransitionLabelsPosition (
( TransitionCell ) selectedCells [ i ] ,
labelPosition ) ;
} else if ( selectedCells [ i ] instanceof NodeCell ) {
Iterator edges = De fa ult Gr ap hMo de l . getEdges (
getEditor () . getGraph () . getModel () ,
new Object []{ selectedCells [ i ]}) . iterator () ;
while ( edges . hasNext () ) {
getEditor () . getGraph () . getMyGraphModel ()
. updateKielTransitionLabelsPosition (
( TransitionCell ) edges . next () ,
labelPosition ) ;
}
}
// @TODO
410
400
or
for ( int i = 0; selectedCells != null
&& i < selectedCells . length ; i ++) {
// has to be done here , since this is independent from dragging
/**
* @see kiel . editor . controller . EditorMode
* # mouseReleased ( java . awt . geom . Point2D )
*/
public final void mouseReleased ( final Point2D p ) {
super . mouseReleased ( p ) ;
// @TODO
/**
* @author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </
a>
*/
private static final class EditorM odeResize
extends E d i t o r M o d e S e l e c t O r D r a g O r R e s i z e O r F l i p E x p a n d { }
/**
* @author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </
a>
*/
private static final class EditorModeDrag
extends E d i t o r M o d e S e l e c t O r D r a g O r R e s i z e O r F l i p E x p a n d { }
}
D e f a u l t G r a p h C e l l root =
getEditor () . getGraph () . g et M yG r aphModel () . getRootCell () ;
return
getEditor () . getGraph () . g e t S e l e c ti onC el ls () != null
&& getEditor () . getGraph () . g e t S e l e c tio nC ell s () . length > 0
&& root == getEditor () . getGraph () . ge tSe le cti on Cel ls () [0]
&& g e t P r e v i e w B o u n d s ( root ) != null
&& ( g e t P r e v i e w B o u n d s ( root ) . getX ()
!= Preferences . g e t I n i t i a l G r a p h O f f s e t ()
|| g e t P r e v i e w B o u n d s ( root ) . getY ()
!= Preferences . g e t I n i t i a l G r a p h O f f s e t () ) ;
390
if ( i s R o o t C e l l D r a g g e d ) {
intersects = true ;
} else if ( previewBounds != null ) {
380
// Is valid for move only !!
intersects = intersects
|| getEditor () . getGraph () . getMyGraphModel ()
. intersect (( D e f aultGraphCell )
selectedCells [ cellCount ] , previewBounds , true ,
Arrays . asList ( selectedCells ) , false ) ;
} else {
getEditor () . getLogFile () . log (2 , getClass ()
+ ". mouseDragged () : previewBounds == null ") ;
}
}
Rectangle2D previewBounds = getPrevie wBounds (
selectedCells [ cellCount ]) ;
if ( getEditor () . getGraph () . getMyGraphModel ()
. getRootCell () == selectedCells [ i ]) {
i s R o o t C e l l D r a g g ed = true ;
}
/**
* .
* @return .
*/
private boolean i s D r a g g i n g R o o t O r C h a n g i n g U p p e r L e f t () {
}
{
boolean i s R o o t C e l l D r a g g ed = false ;
for ( int i = 0;
! i s R o o t C e l l D r a g g e d && i < selectedCells . length ; i ++)
for ( int cellCount = 0; cellCount < selectedCells . length ;
cellCount ++) {
A. Java-Programm-Quelltext
460
450
440
430
420
);
"
);
470
Object [] edges = MyGraphModel . getEdges (
getEditor () . getGraph () . getModel () ,
// set the parent of all cells and transitions
// that are now inside the dragged / resized cell
CellView view = getEditor () . getGraph ()
. g e t G r a p h L a y o u t C a c h e () . getMapping (
selectedCells [ i ] , false ) ;
if ( view == null ) {
System . out . println (" E d i t o r M o d e S e l e c t O r D r a g O r R e s i z e O r
500
+ " FlipExpand : view is null ") ;
continue ;
}
Object [] newChildren = getEditor () . getGraph ()
. g et M yG ra p hM o de l () . getAllCells ( view . getBounds () ) ;
for ( int newCount = 0; newCount < newChildren . length ;
newCount ++) {
if ((( D e f a u l t G r a p h C ell ) newChildren [ newCount ])
. getParent ()
510
== (( D e f a u l t G r a phCe ll ) selectedCells [ i ])
. getParent () ) {
getEditor () . getGraph () . getMyGraphModel ()
. changeParent (
( D e f a u l t G r a phCell ) newChildren [ newCount ] ,
getEditor () . getGraph () . g e t G r a p h L a y o u t C a c h e ()
480
continue ;
}
if ( selectedCells [ i ] instanceof ANDStateCell ) {
getEditor () . getGraph () . getMyGraphModel ()
. andStateCellEnlarged (
( ANDStateCell ) selectedCells [ i ] ,
sel ecte dBounds [ i ]) ;
}
// set the parent of the dragged / resized cell
getEditor () . getGraph () . getMyGraphModel () . changeParent (
490
( D e f a u l t G r a p h C e l l ) selectedCells [ i ] ,
getEditor () . getGraph () . g e t G r a p h L a y o u t C a c h e () ) ;
if ( selectedCells [ i ] instanceof D eli mi ter Li neC el l ) {
getEditor () . getGraph () . getMyGraphModel ()
. delimiterLineCellMoved (
( D e l i m i t e r L ine Ce ll ) selectedCells [ i ] ,
sel ecte dBounds [ i ] ,
getEditor () . getGraph () . g e t G r a p h L a y o u t C a c h e ()
if ( isModeEnabled () && ! isIntersects () ) {
for ( int i = 0; selectedCells != null
&& i < selectedCells . length ; i ++) {
EditorActions . get ( A c t i o n E d i t C o l l a p s e d . class ) . actionPerformed (
null ) ;
} else if ( i s D r a g g i n g O r R e s i z i n g ) {
}
i s D r a g g i n g O r R e s i z i n g = false ;
EditorModes . get ( E d i t o r M o d e S e l e c t O r D r a g O r R e s i z e O r F l i p E x p a n d . class )
. start () ;
if ( bounds . getX () + Preferences . getFlipArea () . x < p . getX ()
&& p . getX () < bounds . getX () + Preferences . getFlipArea () . x
if ( cell != null && (!( cell instanceof RegionCell ) ) ) {
Rectangle2D bounds = GraphConstants . getBounds (
cell . getAttributes () ) . getBounds2D () ;
C om p o si t eS t a te C el l cell = ( C o mp o si t e St a te C e ll ) getEditor ()
. getGraph () . getMyGraphModel ()
. g e t S m a l l e s t C e l l O f T y p e ( Co m po s i te S ta t e Ce l l . class ,
new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
p . getX () , p . getY () , 1 , 1) , false ) ;
}
if ( getEditor () . getGraph () . getMyGraphModel () == null ) {
return false ;
/**
*
* @param p .
* @return .
*/
private boolean i s F l i p E x p a n d C o m p o s i t e S t a t e T r i g g e r ( final Point2D p ) {
}
}
}
}
if ( i s D r a g g i n g O r R e s i z i n g ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r ()
. s et Und oC lus te rEn d ( new EditorModeDrag () ) ;
} else {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r ()
. s et Und oC lus te rEn d ( new EditorModeResi ze () ) ;
}
if (!( isModeEnabled () && ! isIntersects () ) ) {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r ()
. nonRedoableUndo () ;
}
selectedCells = null ;
}
newChildren [ newCount ] ,
false ) ;
for ( int e = 0; e < edges . length ; e ++) {
getEditor () . getGraph () . getMyGrap h Mo d el ()
. changeParent (
( Default GraphCell ) edges [ e ] ,
getEditor () . getGraph ()
. g e t G r a p h L a y o u t C a c h e () ) ;
}
A.4. Der Quelltext
303
304
530
520
/**
*
* @see kiel . editor . M o r p h i n g L a y o u t e r . MyListener # morphing Finished ()
550
*/
public final void m o r p h i n g F i n i s h e d () {
getEditor () . getGraph () . g e t U n d o C l u s t e r M a n a g e r () . se tU ndo Cl ust er End (
this ) ;
}
}
}
return false ;
+ Preferences . getFlipArea () . width
&& bounds . getY () + Preferences . getFlipArea () . y < p . getY ()
&& p . getY () < bounds . getY () + Preferences . getFlipArea () . y
+ Preferences . getFlipArea () . height ) {
540
return true ;
}
/**
* @see kiel . editor . controller . EditorMode # done ()
*/
public void done () {
}
/**
* @see kiel . editor . controller . EditorMode # start ()
*/
public final void start () {
super . start () ;
getEditor () . getGraph () . setCursor ( getMyCursor () ) ;
}
}
A. Java-Programm-Quelltext
50
40
30
20
10
java . awt . Color ;
java . awt . Cursor ;
java . awt . Graphics ;
java . awt . event . MouseEvent ;
java . awt . geom . Point2D ;
java . awt . geom . Rectangle2D ;
org . jgraph . JGraph ;
org . jgraph . graph . B a s i c M a r q u e e H a n d l e r ;
org . jgraph . graph . G raphC onst ants ;
org . jgraph . graph . Port ;
org . jgraph . graph . PortView ;
60
/**
* Override to Gain Control ( for PopupMenu and ConnectMode ) .
/**
* @param aGraph .
*
*/
public M y M a r q u e e H a n d l e r ( final JGraph aGraph ) {
graph = aGraph ;
}
/**
*
*/
private JGraph graph ;
/**
* Holds the First and the Current Port .
*/
private PortView port , firstPort ;
/**
* Holds the Start and the Current Point .
*/
private Point2D start , current ;
100
90
80
/**
70
* A simple i mplem enta tion of a marquee handler for JGraph .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.15 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class M y M a r q u e e H a n d l e r extends B a s i c M a r q u e e H a n d l e r {
import
import
import
import
import
import kiel . editor . MyGraphModel ;
import
import
import
import
import
import
package kiel . editor . controller ;
kiel.editor.controller.MyMarqueeHandler
/**
* Find Port under Mouse and Repaint Connector .
* @see org . jgraph . graph . B a s i c M a r q u e e H a n d l e r # mouseDragged (
* java . awt . event . MouseEvent )
*/
public void mouseDragged ( final MouseEvent e ) {
// If remembered Start Point is Valid
if ( start != null ) {
// Fetch Graphics from Graph
/**
* Display PopupMenu or Remember Start Location and First Port .
* @see org . jgraph . graph . B a s i c M a r q u e e H a n d l e r # mousePressed (
* java . awt . event . MouseEvent )
*/
public void mousePressed ( final MouseEvent e ) {
if ( e . isPopupTrigger () ) {
return ;
// Else if in ConnectMode and Remembered Port is Valid
} else if ( port != null && graph . isPortsVisible () ) {
// Remember Start Location
start = graph . toScreen ( port . getLocation ( null ) ) ;
// Remember First Port
firstPort = port ;
} else {
// Call Superclass
super . mousePressed ( e ) ;
}
}
* @see org . jgraph . graph . B a s i c M a r q u e e H a n d l e r # i s F o r c e M a r q u e e E v e n t (
* java . awt . event . MouseEvent )
*/
public boolean i s F o r c e M a r q u e e E v e n t ( final MouseEvent e ) {
if ( e . isShiftDown () ) {
return false ;
}
// If Right Mouse Button we want to Display the PopupMenu
if ( e . isPopupTrigger () ) {
// Return Immediately
return true ;
}
// Find and Remember Port
port = getSourcePortAt ( e . getPoint () ) ;
// If Port Found and in ConnectMode (= Ports Visible )
if ( port != null && graph . isPortsVisible () ) {
return true ;
}
// Else Call Superclass
return super . i s F o r c e M a r q u e e E v e n t ( e ) ;
}
A.4. Der Quelltext
305
306
150
140
130
120
110
200
190
180
/**
* Connect the First Port and the Current Port in the Graph or Repaint .
* @see org . jgraph . graph . B a s i c M a r q u e e H a n d l e r # mouseReleased (
210
/**
* Find a Cell at point and Return its first Port as a PortView .
* @param point .
* @return .
*/
protected PortView ge t Ta r ge t Po r tA t ( final Point2D point ) {
// Find a Port View in Model Coordinates and Remember
return graph . getPortViewAt ( point . getX () , point . getY () ) ;
}
/**
*
* @param point .
* @return .
*/
protected PortView ge t So u rc e Po r tA t ( final Point2D point ) {
// Disable jumping
graph . s e t J u m p T o D e f a u l t P o r t ( false ) ;
PortView result ;
try {
// Find a Port View in Model Coordinates and Remember
result = graph . getPortViewAt ( point . getX () , point . getY () ) ;
} finally {
graph . s e t J u m p T o D e f a u l t P o r t ( true ) ;
}
return result ;
}
}
}
// Call Superclass
super . mouseDragged ( e ) ;
Graphics g = graph . getGraphics () ;
// Reset Remembered Port
PortView newPort = g et T ar g et Po r tAt ( e . getPoint () ) ;
160
// Do not flicker ( repaint only on real changes )
if ( newPort == null || newPort != port ) {
// Xor - Paint the old Connector ( Hide old Connector )
pai ntCo nnect or ( Color . black , graph . getBackground () , g ) ;
// If Port was found then Point to Port Location
port = newPort ;
if ( port != null ) {
current = graph . toScreen ( port . getLocation ( null ) ) ;
// Else If no Port was found then Point to Mouse Location
} else {
current = graph . snap ( e . getPoint () ) ;
170
}
// Xor - Paint the new Connector
pai ntCo nnect or ( graph . getBackground () , Color . black , g ) ;
}
/**
* Show Special Cursor if Over Port .
* @see org . jgraph . graph . B a s i c M a r q u e e H a n d l e r # mouseMoved (
* java . awt . event . MouseEvent )
*/
public void mouseMoved ( final MouseEvent e ) {
// Check Mode and Find Port
if ( e != null
&& getSourcePortAt ( e . getPoint () ) != null
&& graph . isPortsVisible () ) {
// Set Cusor on Graph ( Automatically Reset )
graph . setCursor ( new Cursor ( Cursor . HAND_CURSOR ) ) ;
// Consume Event
// Note : This is to signal the BasicGraphUI ’ s
// MouseHandle to stop further event processing .
e . consume () ;
} else {
// Call Superclass
}
// Else Repaint the Graph
} else {
graph . repaint () ;
}
// Reset Global Vars
firstPort = null ;
port = null ;
start = null ;
current = null ;
// Call Superclass
super . mouseReleased ( e ) ;
* java . awt . event . MouseEvent )
*/
public void mouseReleased ( final MouseEvent e ) {
if ( e . isPopupTrigger () && ! e . isShiftDown () ) {
return ;
}
// If Valid Event , Current and First Port
if ( e != null
&& port != null
&& firstPort != null
&& firstPort != port ) {
// Then Establish Connection
try {
(( MyGraphModel ) graph . getModel () ) . addTransition (
( Port ) firstPort . getCell () , ( Port ) port . getCell () ,
EditorAction . getEditor () . g e t C u r r e n t T r a n s i t i o n T y p e () ,
EditorAction . getEditor () . g e t C u r r e n t T r a n s i t i o n L i n e () ,
null ) ;
} catch ( Exception ex ) {
EditorAction . getEditor () . getKielFrame () . handl e Ex c ep t io n (
ex . getMessage () , false , ex ) ;
}
A. Java-Programm-Quelltext
230
220
}
super . mouseMoved ( e ) ;
/**
/**
* Use Xor - Mode on Graphics to Paint Connector .
* @param fg .
* @param bg .
* @param g .
*/
protected void pa intCo nnec tor ( final Color fg , final Color bg ,
final Graphics g ) {
// Set Foreground
g . setColor ( fg ) ;
// Set Xor - Mode Color
g . setXORMode ( bg ) ;
// Highlight the Current Port
paintPort ( graph . getGraphics () ) ;
// If Valid First Port , Start and Current Point
if ( firstPort != null && start != null && current != null ) {
// Then Draw A Line From Start to Current Point
g . drawLine (( int ) start . getX () ,
( int ) start . getY () ,
( int ) current . getX () ,
( int ) current . getY () ) ;
}
}
}
260
250
240
}
* Use the Preview Flag to Draw a Highlighted Port .
* @param g .
*/
protected void paintPort ( final Graphics g ) {
// If Current Port is Valid
if ( port != null ) {
// If Not Floating Port ...
// ... Then use Parent ’ s Bounds
Rectangle2D r ;
if ( GraphConstants . getOffset ( port . getAttributes () ) != null ) {
r = port . getBounds () ;
} else {
r = port . getParentView () . getBounds () ;
}
// Scale from Model to Screen
r = graph . toScreen (( Rectangle2D ) r . clone () ) ;
// Add Space For the Highlight Border
final int border = 3;
r . setFrame (
r . getX () - border ,
r . getY () - border ,
r . getWidth () + border * 2 ,
r . getHeight () + border * 2) ;
// Paint Port in Preview (= Highlight ) Mode
graph . getUI () . paintCell (g , port , r , true ) ;
}
}
A.4. Der Quelltext
307
308
10
/**
* Describes an ANDState in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.12 $ last modified $Date : 2005/03/15 11:52:54 $
*/
package kiel . editor . graph ;
kiel.editor.graph.ANDStateCell
}
/**
* @param userObject .
*/
public ANDStateCell ( final Object userObject ) {
super ( userObject ) ;
}
public class ANDStateCell extends C om p o si t eS t at e C el l {
A. Java-Programm-Quelltext
10
20
/**
* Describes an ANDState in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 30
* @version $Revision : 1.11 $ last modified $Date : 2005/04/01 12:26:33 $
*/
import org . jgraph . graph . G raphC onst ants ;
import kiel . g r a p h i c a l I n f o r m a t i o n s . Properties ;
import java . awt . Graphics ;
import java . awt . Graphics2D ;
package kiel . editor . graph ;
kiel.editor.graph.AndStateRenderer
}
/**
* @see org . jgraph . graph . VertexRenderer # p a i n t S e l e c t i o n B o r d e r (
* java . awt . Graphics )
*/
protected void p a i n t S e l e c t i o n B o r d e r ( final Graphics g ) {
super . p a i n t S e l e c t i o n B o r d e r ( g ) ;
(( Graphics2D ) g ) . setStroke ( getGraph () . getStroke ( getView () ) ) ;
g . drawLine (0 , Properties . g e t C o m p o s i t e S t a t e H e a d e r H e i g h t () ,
getSize () . width - 2 ,
Properties . g e t C o m p o s i t e S t a t e H e a d e r H e i g h t () ) ;
(( Graphics2D ) g ) . setStroke ( GraphConstants . SELECTION_STR O K E ) ;
}
class AndS tateRenderer extends C o m p o s i t e S t a t e R e n d e r e r {
A.4. Der Quelltext
309
310
10
/**
* Describes an ANDState in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.21 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.ANDStateView
}
/**
* @param cell .
*/
public ANDStateView ( final Object cell ) {
super ( cell ) ;
}
public class ANDStateView extends C om p o si t eS t at e V ie w {
A. Java-Programm-Quelltext
50
40
30
20
10
static {
R E N D E R E R _ M A P P I N G . put (
ANDStateView . class , A n d S t a t e R e n derer . class ) ;
R E N D E R E R _ M A P P I N G . put (
80
ChoiceView . class , Ch oiceR ende rer . class ) ;
R E N D E R E R _ M A P P I N G . put (
C o m p o s i t e S t a t e V i e w . class , C o m p o s i t e S t a t e R e n d e r e r . class ) ;
R E N D E R E R _ M A P P I N G . put (
D ee p Hi s to r yV i ew . class , D e e p H i s t o r y R e n d e r e r . class ) ;
R E N D E R E R _ M A P P I N G . put (
D y n a m i c C h o i c e V i e w . class , D y n a m i c C h o i c e R e n d e r e r . class ) ;
R E N D E R E R _ M A P P I N G . put (
F i n a l A N D S t a t e V i e w . class , F i n a l A n d S t a t e R e n d e r e r . class ) ;
R E N D E R E R _ M A P P I N G . put (
F i n a l O R S t a t e V i e w . class , F i n a l O r S t a t e R e n d e r e r . class ) ;
90
R E N D E R E R _ M A P P I N G . put (
F i n a l S i m p l e S t a t e V i e w . class , F i n a l S i m p l e S t a t e R e n d e r e r . class ) ;
R E N D E R E R _ M A P P I N G . put (
Fin alSt ateVi ew . class , F i n a l S t a t eR e nd e r er . class ) ;
R E N D E R E R _ M A P P I N G . put (
HistoryView . class , H is t or y Re n de rer . class ) ;
R E N D E R E R _ M A P P I N G . put (
I n i t i a l S t a t e V i e w . class , I n i t i a l S t a t e R e n d e r e r . class ) ;
R E N D E R E R _ M A P P I N G . put (
NodeView . class , NodeRenderer . class ) ;
100
R E N D E R E R _ M A P P I N G . put (
N o r m a l T e r m i n a t i o n V i e w . class , N o r m a l T e r m i n a t i o n R e n d e r e r . class ) ;
R E N D E R E R _ M A P P I N G . put (
ORStateView . class , O rS t at e Re n de rer . class ) ;
R E N D E R E R _ M A P P I N G . put (
P se u do S ta t eV i ew . class , P s e u d o S t a t e R e n d e r e r . class ) ;
import org . jgraph . graph . C e l l V i e w R e n d e r e r ;
60
/**
* This class defines all the drawing information of the CellView
* classes representing the diagram elements on the view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.21 $ last modified $Date : 2005/07/25 11:44:37 $
*/
public final class C e l l V i e w R e n d e r e r F a c t o r y {
70
/**
*
*/
private static final HashMap R E N D E R E R _ M AP PING = new HashMap () ;
import java . util . HashMap ;
import java . util . Hashtable ;
package kiel . editor . graph ;
kiel.editor.graph.CellViewRendererFactory
}
}
CellViewR enderer instance = ( CellViewRende rer ) cache . get (
rendererClass ) ;
if ( instance == null ) {
try {
instance = ( CellV iewRenderer ) rendererClass . newInstance () ;
cache . put ( rendererClass , instance ) ;
} catch ( I n s t a n t i a t i o n E x c e p t i o n e ) {
e . printStackTrace () ;
} catch ( I l l e g a l A c c e s s E x c e p t i o n e ) {
e . printStackTrace () ;
}
}
return instance ;
Class viewClass = aViewClass ;
Class rendererClass = null ;
while ( rendererClass == null ) {
rendererClass = ( Class ) RENDERER_MAPPIN G . get ( viewClass ) ;
viewClass = viewClass . getSuperclass () ;
}
/**
* @param aViewClass The CellView class
* @return The renderer class
*/
static CellViewRe nderer get ( final Class aViewClass ) {
/**
* Comment for < code > cache </ code >.
*/
private static Hashtable cache = new Hashtable () ;
/**
*
*
*/
private C e l l V i e w R e n d e r e r F a c t o r y () { }
}
RENDERER_ MAPPING . put (
RegionView . class , RegionRenderer . class ) ;
RENDERER_ MAPPING . put (
StateView . class , StateRenderer . class ) ;
RENDERER_ MAPPING . put (
S tr o n gA b or t i on V ie w . class , S t r o n g A b o r t i o n R e n d e r e r . class ) ;
RENDERER_ MAPPING . put (
SuspendView . class , SuspendRenderer . class ) ;
RENDERER_ MAPPING . put (
TransitionView . class , T r an s i ti o nR e nd e r er . class ) ;
RENDERER_ MAPPING . put (
De li mit er Lin eV iew . class , D e l i m i t e r L i n e R e n d e r e r . class ) ;
A.4. Der Quelltext
311
312
10
/**
* Describes a Choice in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/03/15 11:52:54 $
*/
package kiel . editor . graph ;
kiel.editor.graph.ChoiceCell
}
/**
* @param userObject .
*/
public ChoiceCell ( final Object userObject ) {
super ( userObject ) ;
}
public class ChoiceCell extends PseudoStateCell {
A. Java-Programm-Quelltext
10
/**
* Describes a Choice in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.7 $ last modified $Date : 2005/03/15 11:52:53 $
*/
class C hoice Rend erer extends P s e u d o S t a t e R e n d e r e r {
package kiel . editor . graph ;
kiel.editor.graph.ChoiceRenderer
//
}
/**
* @see kiel . editor . graph . P s e u d o S t a t e R e n d e r e r # getMyName ()
*/
protected String getMyName () {
return " C ";
image = ResourceLoader . get (" Dy nam ic Cho ic eGr ey . gif ") . getImage () ;
}
A.4. Der Quelltext
313
314
10
/**
* Describes a Choice in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.17 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.ChoiceView
}
/**
* @param cell .
*/
public ChoiceView ( final Object cell ) {
super ( cell ) ;
}
public class ChoiceView extends PseudoStateView {
A. Java-Programm-Quelltext
10
/**
* Describes a Co mpos iteSt ate in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.12 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.CompositeStateCell
}
/**
* @param userObject .
*/
public Co m p os i te S t at e Ce l l ( final Object userObject ) {
super ( userObject ) ;
}
public class Co m po s i te S ta t e Ce l l extends StateCell {
A.4. Der Quelltext
315
316
30
70
60
20
/**
*
* @see org . jgraph . graph . V ertex Rend erer # p a i n t S e l e c t i o n B o r d e r (
* java . awt . Graphics )
*/
protected void p a i n t S e l e c t i o n B o r d e r ( final Graphics g ) {
super . p a i n t S e l e c t i o n B o r d e r ( g ) ;
boolean isCollapsed = M y G r a p h C o n s t a nts . isCollapsed (
(( D e f a u l t G r a p h C e l l ) getView () . getCell () ) . getAttributes () ) ;
if ( Preferences . g e t S h o w C o l l a p s e B u t t o n s () ) {
if ( isCollapsed ) {
g . drawImage (
getGraph () . getPlusImage () ,
Preferences . g e t C o m p o s i t e S t a t e I m a g e O f f s e t () ,
Preferences . g e t C o m p o s i t e S t a t e I m a g e O f f s e t () ,
null ) ;
50
/**
* Describes a Co mpos iteSt ate in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.13 $ last modified $Date : 2005/07/25 11:44:37 $
*/
class C o m p o s i t e S t a t e R e n d e r e r extends StateRenderer {
40
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
kiel . dataStructure . Com posit eSta te ;
kiel . editor . resources . Preferences ;
kiel . editor . resources . Reso urce Bundl e ;
kiel . g r a p h i c a l I n f o r m a t i o n s . Properties ;
10
import
import
import
import
import java . awt . Graphics ;
package kiel . editor . graph ;
kiel.editor.graph.CompositeStateRenderer
}
}
}
if ( Preferences . g e t S h o w S t a t e A c t i o n s () ) {
CompositeState state = ( CompositeState ) MyGraphC o n s t a n t s
. g et G ra p h ic a lO b j ec t ((( DefaultGraphCell ) getView () . getCell () )
. getAttributes () ) ;
if ( Preferences . g e t S h o w C o m p o s i t e S t a t e V a r i a b l e s () ) {
yOffset = draw ( ResourceBundle . getString (" Variables ")
+ ": " , state . getVariables () , yOffset , g ) ;
}
if ( Preferences . g e t S h o w C o m p o s i t e S t a t e E v e n t s () ) {
yOffset = draw ( ResourceBundle . getString (" Events ")
+ ": " , state . getLocalEvents () , yOffset , g ) ;
}
}
return yOffset ;
int yOffset = initialYOffset
+ Properties . g e t C o m p o s i t e S t a t e H e a d e r H e i g h t () ;
/**
* .
* @see kiel . editor . graph . StateRenderer # d r a w V a r i a b l e s A n d E v e n t s (
* java . awt . Graphics , int )
*/
protected int d r a w V a r i a b l e s A n d E v e n t s ( final Graphics g ,
final int initialYOffset ) {
}
} else {
g . drawImage (
getGraph () . getMinusImage () ,
Preferences . g e t C o m p o s i t e S t a t e I m a g e O f f s e t () ,
Preferences . g e t C o m p o s i t e S t a t e I m a g e O f f s e t () ,
null ) ;
}
A. Java-Programm-Quelltext
10
/**
* Describes a Co mpos iteSt ate in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.19 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.CompositeStateView
}
/**
* @param cell .
*/
public Co m p os i te S t at e Vi e w ( final Object cell ) {
super ( cell ) ;
}
public class Co m po s i te S ta t e Vi e w extends StateView {
A.4. Der Quelltext
317
318
10
/**
*
/**
* Describes a C o n d i t i o n a l T r a n s i t i o n in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 20
* @version $Revision : 1.11 $ last modified $Date : 2005/03/15 11:52:54 $
*/
public class C o n d i t i o n a l T r a n s i t i o n C e l l extends TransitionCell {
package kiel . editor . graph ;
kiel.editor.graph.ConditionalTransitionCell
}
/**
* @param userObject .
*/
public C o n d i t i o n a l T r a n s i t i o n C e l l ( final Object userObject ) {
super ( userObject ) ;
}
*/
public C o n d i t i o n a l T r a n s i t i o n C e l l () {
super () ;
}
A. Java-Programm-Quelltext
10
/**
* Describes a C o n d i t i o n a l T r a n s i t i o n in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.14 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.ConditionalTransitionView
}
/**
* @param cell .
*/
public C o n d i t i o n a l T r a n s i t i o n V i e w ( final Object cell ) {
super ( cell ) ;
}
public class C o n d i t i o n a l T r a n s i t i o n V i e w extends TransitionView {
A.4. Der Quelltext
319
320
10
/**
* Describes a DeepHistory in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/03/15 11:52:54 $
*/
package kiel . editor . graph ;
kiel.editor.graph.DeepHistoryCell
}
/**
* @param userObject .
*/
public DeepHistoryCell ( final Object userObject ) {
super ( userObject ) ;
}
public class DeepHistoryCell extends PseudoStateCell {
A. Java-Programm-Quelltext
10
/**
* Describes a DeepHistory in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.7 $ last modified $Date : 2005/03/15 11:52:54 $
*/
class D e e p H i s t o r y R e n d e r e r extends P s e u d o S t a t e R e n d e r e r {
package kiel . editor . graph ;
kiel.editor.graph.DeepHistoryRenderer
//
}
/**
* @see kiel . editor . graph . P s e u d o S t a t e R e n d e r e r # getMyName ()
*/
protected String getMyName () {
return " H *";
image = ResourceLoader . get (" DeepHistoryGrey . gif ") . getImage () ;
}
A.4. Der Quelltext
321
322
10
/**
* Describes a DeepHistory in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.17 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.DeepHistoryView
}
/**
* @param cell .
*/
public DeepHistoryView ( final Object cell ) {
super ( cell ) ;
}
public class DeepHistoryView extends PseudoStateView {
A. Java-Programm-Quelltext
10
/**
* Describes an ANDState in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.5 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.DelimiterLineCell
}
/**
* @param userObject .
*/
public D el imi te rLi ne Cel l ( final Object userObject ) {
super ( userObject ) ;
}
public class D eli mi ter Li neC el l extends G r a p h i c a l O b j e c t C e l l {
A.4. Der Quelltext
323
324
10
20
/**
30
* Describes an ANDState in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.7 $ last modified $Date : 2005/07/24 20:00:30 $
*/
class D e l i m i t e r L i n e R e n d e r e r extends V erte xRenderer {
import org . jgraph . graph . G raphC onst ants ;
import org . jgraph . graph . V ertex Rend erer ;
import kiel . editor . MyJGraph ;
import java . awt . Graphics ;
import java . awt . Graphics2D ;
package kiel . editor . graph ;
kiel.editor.graph.DelimiterLineRenderer
}
//
/**
* @see org . jgraph . graph . VertexRenderer # p a i n t S e l e c t i o n B o r d e r (
* java . awt . Graphics )
*/
protected void p a i n t S e l e c t i o n B o r d e r ( final Graphics g ) {
super . p a i n t S e l e c t i o n B o r d e r ( g ) ;
g . setColor ((( MyJGraph ) graph ) . getViewsBlack ( view ) ) ;
(( Graphics2D ) g ) . setStroke ( GraphConstants . SELECTION_ S T R O K E ) ;
System . out . println ( getBounds () ) ;
if ( getBounds () . width < getBounds () . height ) {
g . drawLine (0 , 0 , 0 , getBounds () . height ) ;
} else {
g . drawLine (0 , 0 , getBounds () . width , 0) ;
}
}
A. Java-Programm-Quelltext
40
30
20
10
org . jgraph . graph . CellHandle ;
org . jgraph . graph . C e l l V i e w R e n d e r e r ;
org . jgraph . graph . G raphC onst ants ;
org . jgraph . graph . GraphContext ;
org . jgraph . graph . VertexView ;
50
/**
* .
* @param aBounds .
*/
public final void s e t P r e v i e w B o u n d s ( final Rectangle2D aBounds ) {
/**
* Comment for < code > isResizing </ code >.
*/
private boolean isResizing ;
/**
* @param cell .
*/
public D e l i m i t e r L i n e V i e w ( final Object cell ) {
super ( cell ) ;
}
/**
*
* @see org . jgraph . graph . A b s t r a c t C e l l V i e w # getRenderer ()
*/
public final C e l l V i e w R e n d e r e r getRenderer () {
return C e l l V i e w R e n d e r e r F a c t o r y . get ( getClass () ) ;
}
80
70
/**
* Describes an ANDState in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/07/25 11:44:37 $
60
*/
public class D e l i m i t e r L i n e V i e w extends VertexView implements Previewable {
import
import
import
import
import
import java . awt . geom . Rectangle2D ;
package kiel . editor . graph ;
kiel.editor.graph.DelimiterLineView
}
previewBounds = aBounds ;
/**
* .
* @return .
*/
public final Rectangle2D getPreviewBounds () {
return previewBounds ;
}
/**
*
*/
private Rectangle2D previewBounds ;
}
return new MySizeHandle ( this , context ) ;
}
return null ;
/**
* @see org . jgraph . graph . CellView # getHandle ( org . jgraph . graph .
GraphContext )
*/
public final CellHandle getHandle ( final GraphContext context ) {
if ( GraphConstants . isSizeable ( getAll Attributes () )
&& context . getGraph () . isSizeable () ) {
/**
* @return .
*/
public final boolean isResizing () {
return isResizing ;
}
/**
* .
* @param b .
*/
public final void setResizing ( final boolean b ) {
isResizing = b ;
}
}
A.4. Der Quelltext
325
326
10
/**
* Describes a DynamicChoice in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.12 $ last modified $Date : 2005/03/15 11:52:54 $
*/
package kiel . editor . graph ;
kiel.editor.graph.DynamicChoiceCell
}
/**
* @param userObject .
*/
public D yn ami cC hoi ce Cel l ( final Object userObject ) {
super ( userObject ) ;
}
public class D yna mi cCh oi ceC el l extends PseudoStateCell {
A. Java-Programm-Quelltext
10
/**
* Describes a DynamicChoice in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.7 $ last modified $Date : 2005/03/15 11:52:53 $
*/
class D y n a m i c C h o i c e R e n d e r e r extends P s e u d o S t a t e R e n d e r e r {
package kiel . editor . graph ;
kiel.editor.graph.DynamicChoiceRenderer
//
}
/**
* @see kiel . editor . graph . P s e u d o S t a t e R e n d e r e r # getMyName ()
*/
protected String getMyName () {
return " C ";
image = ResourceLoader . get (" Dy nam ic Cho ic eGr ey . gif ") . getImage () ;
}
A.4. Der Quelltext
327
328
10
/**
* Describes a DynamicChoice in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.17 $ last modified $Date : 2005/03/15 11:52:54 $
*/
package kiel . editor . graph ;
kiel.editor.graph.DynamicChoiceView
}
/**
* @param cell .
*/
public D yn ami cC hoi ce Vie w ( final Object cell ) {
super ( cell ) ;
}
public class D yna mi cCh oi ceV ie w extends PseudoStateView {
A. Java-Programm-Quelltext
10
/**
/**
20
* Describes an Edge in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/03/15 11:52:53 $
*/
public abstract class EdgeCell extends DefaultEdge {
import org . jgraph . graph . DefaultEdge ;
package kiel . editor . graph ;
kiel.editor.graph.EdgeCell
}
/**
* @param userObject .
*/
public EdgeCell ( final Object userObject ) {
super ( userObject ) ;
}
*
*/
public EdgeCell () {
super () ;
}
A.4. Der Quelltext
329
330
40
30
20
10
50
70
80
/**
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </
a>
*/
private static class MyEdgeHandle extends EdgeHandle {
/**
* @see org . jgraph . graph . CellView # getHandle ( org . jgraph . graph .
GraphContext )
*/
public final CellHandle getHandle ( final GraphContext context ) {
return new MyEdgeHandle ( this , context ) ;
}
/**
*
* @see org . jgraph . graph . A b s t r a c t C e l l V i ew # getRenderer ()
*/
public C e l l V i e w R e n d e r e r getRenderer () {
return C e l l V i e w R e n d e r e r F a c t o r y . get ( getClass () ) ;
}
/**
* Describes an Edge in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 60
* @version $Revision : 1.18 $ last modified $Date : 2005/07/15 20:25:02 $
*/
public abstract class EdgeView extends org . jgraph . graph . EdgeView {
import org . jgraph . graph . CellHandle ;
import org . jgraph . graph . C e l l V i e w R e n d e r e r ;
import org . jgraph . graph . GraphContext ;
import kiel . editor . resources . Preferences ;
import javax . swing . Swin gUti litie s ;
import java . awt . Graphics ;
import java . awt . event . MouseEvent ;
package kiel . editor . graph ;
kiel.editor.graph.EdgeView
}
/**
* @param cell .
*/
public EdgeView ( final Object cell ) {
super ( cell ) ;
}
}
/**
* @see org . jgraph . graph . EdgeView . EdgeHandle # i sR e mo v e P o i n t E v e n t (
* java . awt . event . MouseEvent )
*/
public boolean i s Re m ov e P oi n tE v en t ( final MouseEvent event ) {
return SwingUtilities . i s Ri g h tM o us e B ut t on ( event )
&& event . isShiftDown () ;
}
/**
* @see org . jgraph . graph . EdgeView . EdgeHandle # isAddPoi n tE v en t (
* java . awt . event . MouseEvent )
*/
public boolean isAddPointEvent ( final MouseEvent event ) {
return SwingUtilities . i s Ri g h tM o us e B ut t on ( event )
&& event . isShiftDown () ;
}
/**
* @see org . jgraph . graph . CellHandle # paint ( java . awt . Graphics )
*/
public void paint ( final Graphics g ) {
if ( Preferences . g e t S i z e H a n d l e V i s i b l e () ) {
super . paint ( g ) ;
}
}
/**
* @param edge .
* @param ctx .
*/
public MyEdgeHandle ( final org . jgraph . graph . EdgeView edge ,
final GraphContext ctx ) {
super ( edge , ctx ) ;
}
A. Java-Programm-Quelltext
10
/**
* Describes a FinalANDState in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.FinalANDStateCell
}
/**
* @param userObject .
*/
public F in alA ND Sta te Cel l ( final Object userObject ) {
super ( userObject ) ;
}
public class F ina lA NDS ta teC el l extends ANDStateCell {
A.4. Der Quelltext
331
332
10
20
/**
* Describes a FinalANDState in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.10 $ last modified $Date : 2005/04/01 12:26:33 $
30
*/
class F i n a l A n d S t a t e R e n d e r e r extends A n d S t a t eRenderer {
import kiel . editor . resources . Preferences ;
import java . awt . Graphics ;
import java . awt . Graphics2D ;
package kiel . editor . graph ;
kiel.editor.graph.FinalANDStateRenderer
}
/**
* @see org . jgraph . graph . VertexRenderer # p a i n t S e l e c t i o n B o r d e r (
* java . awt . Graphics )
*/
protected void p a i n t S e l e c t i o n B o r d e r ( final Graphics g ) {
super . p a i n t S e l e c t i o n B o r d e r ( g ) ;
(( Graphics2D ) g ) . setStroke ( getGraph () . getStroke ( getView () ) ) ;
g . drawRoundRect (
Preferences . g e t F i n a l S t a t e B o r d e r () ,
Preferences . g e t F i n a l S t a t e B o r d e r () ,
getSize () . width - ( Preferences . g e t F i n a l S t a t e B o r d e r () * 2 + 1) ,
getSize () . height - ( Preferences . g e t F i n a l S t a t e B o r d e r () * 2 + 1) ,
Preferences . get Ar cWi dt hHe ig ht () ,
Preferences . get Ar cWi dt hHe ig ht () ) ;
}
A. Java-Programm-Quelltext
10
/**
* Describes a FinalANDState in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.15 $ last modified $Date : 2005/03/15 11:52:54 $
*/
package kiel . editor . graph ;
kiel.editor.graph.FinalANDStateView
}
/**
* @param cell .
*/
public F in alA ND Sta te Vie w ( final Object cell ) {
super ( cell ) ;
}
public class F ina lA NDS ta teV ie w extends ANDStateView {
A.4. Der Quelltext
333
334
10
/**
* Describes a FinalORState in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.FinalORStateCell
}
/**
* @param userObject .
*/
public FinalORS tateCell ( final Object userObject ) {
super ( userObject ) ;
}
public class FinalORState Cell extends ORStateCell {
A. Java-Programm-Quelltext
10
20
/**
* Describes a FinalORState in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.7 $ last modified $Date : 2005/03/15 11:52:54 $
*/
class F i n a l O r S t a t e R e n d e r e r extends Or S ta t eR enderer {
30
import kiel . editor . resources . Preferences ;
import java . awt . Graphics ;
package kiel . editor . graph ;
kiel.editor.graph.FinalORStateRenderer
}
/**
* @see org . jgraph . graph . VertexRenderer # p a i n t S e l e c t i o n B o r d e r (
* java . awt . Graphics )
*/
protected void p a i n t S e l e c t i o n B o r d e r ( final Graphics g ) {
super . p a i n t S e l e c t i o n B o r d e r ( g ) ;
g . drawRoundRect (
Preferences . g e t F i n a l S t a t e B o r d e r () ,
Preferences . g e t F i n a l S t a t e B o r d e r () ,
getSize () . width - ( Preferences . g e t F i n a l S t a t e B o r d e r () * 2 + 1) ,
getSize () . height - ( Preferences . g e t F i n a l S t a t e B o r d e r () * 2 + 1) ,
Preferences . get Ar cWi dt hHe ig ht () ,
Preferences . get Ar cWi dt hHe ig ht () ) ;
}
A.4. Der Quelltext
335
336
10
/**
* Describes a FinalORState in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.15 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.FinalORStateView
}
/**
* @param cell .
*/
public FinalORS tateView ( final Object cell ) {
super ( cell ) ;
}
public class FinalORState View extends ORStateView {
A. Java-Programm-Quelltext
10
/**
* Describes a F i n a l S i m p l e S t a t e in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/03/15 11:52:54 $
*/
package kiel . editor . graph ;
kiel.editor.graph.FinalSimpleStateCell
}
/**
* @param userObject .
*/
public F i n a l S i m p l e S t a t e C e l l ( final Object userObject ) {
super ( userObject ) ;
}
public class F i n a l S i m p l e S t a t e C e l l extends SimpleStateCell {
A.4. Der Quelltext
337
338
10
20
/**
/**
* Describes a F i n a l S i m p l e S t a t e in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
30
* @version $Revision : 1.10 $ last modified $Date : 2005/04/01 12:26:33 $
*/
class F i n a l S i m p l e S t a t e R e n d e r e r extends StateRenderer {
import kiel . editor . resources . Preferences ;
import java . awt . Graphics ;
import java . awt . Graphics2D ;
package kiel . editor . graph ;
kiel.editor.graph.FinalSimpleStateRenderer
}
* @see org . jgraph . graph . VertexRenderer # p a i n t S e l e c t i o n B o r d e r (
* java . awt . Graphics )
*/
protected void p a i n t S e l e c t i o n B o r d e r ( final Graphics g ) {
(( Graphics2D ) g ) . setStroke ( getGraph () . getStroke ( getView () ) ) ;
g . setColor ( getGraph () . getViewsBlack ( getView () ) ) ;
g . drawOval (0 , 0 , getSize () . width - 1 , getSize () . height - 1) ;
g . drawOval (
Preferences . g e t F i n a l S t a t e B o r d e r () ,
Preferences . g e t F i n a l S t a t e B o r d e r () ,
getSize () . width - ( Preferences . g e t F i n a l S t a t e B o r d e r () * 2 + 1) ,
getSize () . height - ( Preferences . g e t F i n a l S t a t e B o r d e r () * 2 + 1) ) ;
final int initialYOffset = 30;
drawActions (g , initialYOffset ) ;
}
A. Java-Programm-Quelltext
10
/**
* Describes a F i n a l S i m p l e S t a t e in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.17 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.FinalSimpleStateView
}
/**
* @param cell .
*/
public F i n a l S i m p l e S t a t e V i e w ( final Object cell ) {
super ( cell ) ;
}
public class F i n a l S i m p l e S t a t e V i e w extends SimpleStateView {
A.4. Der Quelltext
339
340
10
/**
* Describes a FinalState in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.FinalStateCell
}
/**
* @param userObject .
*/
public FinalStateCell ( final Object userObject ) {
super ( userObject ) ;
}
public class FinalStateCell extends StateCell {
A. Java-Programm-Quelltext
10
20
/**
/**
* Describes a FinalState in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
30
* @version $Revision : 1.10 $ last modified $Date : 2005/04/01 12:26:33 $
*/
class F i n a l S t a t e R e n d e r e r extends StateRenderer {
import kiel . editor . resources . Preferences ;
import java . awt . Graphics ;
import java . awt . Graphics2D ;
package kiel . editor . graph ;
kiel.editor.graph.FinalStateRenderer
}
* @see org . jgraph . graph . VertexRenderer # p a i n t S e l e c t i o n B o r d e r (
* java . awt . Graphics )
*/
protected void p a i n t S e l e c t i o n B o r d e r ( final Graphics g ) {
(( Graphics2D ) g ) . setStroke ( getGraph () . getStroke ( getView () ) ) ;
g . setColor ( getGraph () . getViewsBlack ( getView () ) ) ;
g . drawOval (0 , 0 , getSize () . width - 1 , getSize () . height - 1) ;
g . drawOval (
Preferences . g e t F i n a l S t a t e B o r d e r () ,
Preferences . g e t F i n a l S t a t e B o r d e r () ,
getSize () . width - ( Preferences . g e t F i n a l S t a t e B o r d e r () * 2 + 1) ,
getSize () . height - ( Preferences . g e t F i n a l S t a t e B o r d e r () * 2 + 1) ) ;
final int initialYOffset = 30;
drawActions (g , initialYOffset ) ;
}
A.4. Der Quelltext
341
342
10
/**
* Describes a FinalState in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.18 $ last modified $Date : 2005/03/15 11:52:54 $
*/
package kiel . editor . graph ;
kiel.editor.graph.FinalStateView
}
/**
* @param cell .
*/
public FinalStateView ( final Object cell ) {
super ( cell ) ;
}
public class FinalStateView extends StateView {
A. Java-Programm-Quelltext
10
/**
* Describes a ForkConnector in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.ForkConnectorCell
}
/**
* @param userObject .
*/
public F or kCo nn ect or Cel l ( final Object userObject ) {
super ( userObject ) ;
}
public class F ork Co nne ct orC el l extends PseudoStateCell {
A.4. Der Quelltext
343
344
10
/**
* Describes a ForkConnector in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.14 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.ForkConnectorView
}
/**
* @param cell .
*/
public F or kCo nn ect or Vie w ( final Object cell ) {
super ( cell ) ;
}
public class F ork Co nne ct orV ie w extends PseudoStateView {
A. Java-Programm-Quelltext
10
/**
* Describes a Gr a ph i ca l Ob j ec t in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.10 $ last modified $Date : 2005/03/15 11:52:53 $
20
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
package kiel . editor . graph ;
kiel.editor.graph.GraphicalObjectCell
}
/**
* @param userObject .
*/
public G r a p h i c a l O b j e c t C e l l ( final Object userObject ) {
super ( userObject ) ;
}
*/
public class G r a p h i c a l O b j e c t C e l l extends De faultGraphCell {
A.4. Der Quelltext
345
346
10
/**
* Describes a History in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.HistoryCell
}
/**
* @param userObject .
*/
public HistoryCell ( final Object userObject ) {
super ( userObject ) ;
}
public class HistoryCell extends PseudoStateCell {
A. Java-Programm-Quelltext
10
/**
* Describes a History in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.7 $ last modified $Date : 2005/03/15 11:52:53 $
*/
class Hi s to r yR e nd e re r extends P s e u d o S t a t e R e n d e r e r {
package kiel . editor . graph ;
kiel.editor.graph.HistoryRenderer
//
}
/**
* @see kiel . editor . graph . P s e u d o S t a t e R e n d e r e r # getMyName ()
*/
protected String getMyName () {
return " H ";
image = ResourceLoader . get (" HistoryGrey . gif ") . getImage () ;
}
A.4. Der Quelltext
347
348
10
/**
* Describes a History in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.17 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.HistoryView
}
/**
* @param cell .
*/
public HistoryView ( final Object cell ) {
super ( cell ) ;
}
public class HistoryView extends PseudoStateView {
A. Java-Programm-Quelltext
10
/**
*
/**
* Describes an InitialArc in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 20
* @version $Revision : 1.11 $ last modified $Date : 2005/03/15 11:52:53 $
*/
public class Ini tial ArcCe ll extends Tra nsit ionCell {
package kiel . editor . graph ;
kiel.editor.graph.InitialArcCell
}
/**
* @param userObject .
*/
public InitialArcCell ( final Object userObject ) {
super ( userObject ) ;
}
*/
public InitialArcCell () {
super () ;
}
A.4. Der Quelltext
349
350
10
/**
* Describes an InitialArc in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.14 $ last modified $Date : 2005/03/15 11:52:54 $
*/
package kiel . editor . graph ;
kiel.editor.graph.InitialArcView
}
/**
* @param cell .
*/
public InitialArcView ( final Object cell ) {
super ( cell ) ;
}
public class InitialArcView extends TransitionView {
A. Java-Programm-Quelltext
10
/**
* Describes an InitialState in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/03/15 11:52:54 $
*/
package kiel . editor . graph ;
kiel.editor.graph.InitialStateCell
}
/**
* @param userObject .
*/
public InitialS tateCell ( final Object userObject ) {
super ( userObject ) ;
}
public class InitialState Cell extends PseudoStateCell {
A.4. Der Quelltext
351
352
10
/**
* Describes an InitialState in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.7 $ last modified $Date : 2005/03/15 11:52:54 $
*/
class I n i t i a l S t a t e R e n d e r e r extends P s e u d o S t a t e R e n d e r e r {
package kiel . editor . graph ;
kiel.editor.graph.InitialStateRenderer
//
}
/**
* @see kiel . editor . graph . P s e u d o S t a t e R e n d e r e r # getMyName ()
*/
protected String getMyName () {
return " I ";
image = ResourceLoader . get (" Init ialStateGrey . gif ") . getImage () ;
}
A. Java-Programm-Quelltext
10
/**
* Describes an InitialState in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.17 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.InitialStateView
}
/**
* @param cell .
*/
public InitialS tateView ( final Object cell ) {
super ( cell ) ;
}
public class InitialState View extends PseudoStateView {
A.4. Der Quelltext
353
354
10
/**
* Describes a Join in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.JoinCell
}
/**
* @param userObject .
*/
public JoinCell ( final Object userObject ) {
super ( userObject ) ;
}
public class JoinCell extends PseudoStateCell {
A. Java-Programm-Quelltext
10
/**
* Describes a Join in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.14 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.JoinView
}
/**
* @param cell .
*/
public JoinView ( final Object cell ) {
super ( cell ) ;
}
public class JoinView extends PseudoStateView {
A.4. Der Quelltext
355
356
10
/**
* Describes a Junction in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/03/15 11:52:54 $
*/
package kiel . editor . graph ;
kiel.editor.graph.JunctionCell
}
/**
* @param userObject .
*/
public JunctionCell ( final Object userObject ) {
super ( userObject ) ;
}
public class JunctionCell extends PseudoStateCell {
A. Java-Programm-Quelltext
10
/**
* Describes a Junction in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.14 $ last modified $Date : 2005/03/15 11:52:54 $
*/
package kiel . editor . graph ;
kiel.editor.graph.JunctionView
}
/**
* @param cell .
*/
public JunctionView ( final Object cell ) {
super ( cell ) ;
}
public class JunctionView extends PseudoStateView {
A.4. Der Quelltext
357
358
50
40
30
20
10
60
kiel . dataStructure . ANDState ;
kiel . dataStructure . Com posit eSta te ;
kiel . dataStructure . G r ap h ic a lO b je c t ;
kiel . dataStructure . Node ;
kiel . dataStructure . N o r m a l T e r m i n a t i o n ;
kiel . dataStructure . ORState ;
kiel . dataStructure . Region ;
kiel . dataStructure . Str ongAb orti on ;
kiel . dataStructure . Transition ;
kiel . editor . M y G r a p h M o d e l U t i l i t i e s ;
kiel . g r a p h i c a l I n f o r m a t i o n s . C o m p o s i t e S t a t e L a y o u t I n f o r m a t i o n ;
kiel . g r a p h i c a l I n f o r m a t i o n s . N o d e L a y o u t I n f o r m a t i o n ;
kiel . g r a p h i c a l I n f o r m a t i o n s . View ;
80
70
/**
* Comment for < code > EXPANDED_BOUNDS </ code >.
*/
/**
* Comment for < code > GRAPHICAL_OBJECT </ code >.
*/
private static final String G R A P H I C A L _ O BJECT = " GRAPHICAL_OBJECT ";
/**
* Represents a Strong abort arrow begin decoration .
*/
public static final int ARROW_BEGIN = 100;
100
90
/**
* Provides access to the JGraph cells ’ attributes .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.47 $ last modified $Date : 2005/07/25 11:44:37 $
*/
public class M y G r a p h C o n s t a n t s extends Graph Constants {
import org . jgraph . graph . AttributeMap ;
import org . jgraph . graph . G raphC onst ants ;
import
import
import
import
import
import
import
import
import
import
import
import
import
import javax . swing . BorderFactory ;
import javax . swing . Swin gCon stant s ;
/**
* .
* @param map .
* @param graphicalObject .
*/
public static final void s e tG r ap h i ca l Ob j ec t (
final AttributeMap map , final GraphicalObject graphi c al O bj e ct ) {
/**
* @param map .
* @param expandedBounds .
*/
public static final void se tEx pa nde dB oun ds ( final AttributeMap map ,
final Rectangle2D expandedBounds ) {
map . put ( EXPANDED_BOUNDS , expandedBounds ) ;
}
/**
* @param map .
* @return .
*/
public static final Rectangle2D ge tE xpa nd edB ou nds ( final AttributeMap map
) {
return ( Rectangle2D ) map . get ( EXPANDED_BOUNDS ) ;
}
/**
*
* @param map .
* @return .
*/
public static boolean isCollapsed ( final Map map ) {
return map . get ( IS_COLLAPSED ) != null
&& (( Boolean ) map . get ( IS_COLLAPSED ) ) . booleanValue () ;
}
/**
*
* @param map .
* @param b .
*/
public static final void setCollapsed ( final Map map , final boolean b ) {
map . put ( IS_COLLAPSED , new Boolean ( b ) ) ;
}
/**
* .
*/
private static final String IS_COLLAPSED = " IS_COLLAPSED ";
import
import
import
import
import
import
java . awt . Color ;
java . awt . Dimension ;
java . awt . Point ;
java . awt . geom . Point2D ;
java . awt . geom . Rectangle2D ;
java . util . Map ;
private static final String EXPANDED_BOUNDS = " EXPANDED_ BO U ND S ";
package kiel . editor . graph ;
kiel.editor.graph.MyGraphConstants
A. Java-Programm-Quelltext
140
130
120
110
/**
* .
* @param map .
* @param node .
* @param kielView .
*/
public static final void s e t N o d e A t t r i b u t es ( final AttributeMap map ,
final Node node , final View kielView ) {
s e t G r a p h i c a l O b j e c t ( map , node ) ;
if ( node instanceof ORState || node instanceof ANDState ) {
C o m p o s i t e S t a t e L a y o u t I n f o r m a t i o n layout =
( CompositeStateLayoutInformation )
kielView . g e t L a y o u t I n f o r m a t i o n (( CompositeState ) node ) ;
setCollapsed ( map , layout . isCollapsed () ) ;
} else if ( node instanceof Region ) {
// TODO Check if that is ok ( dependent on EStudio - parser )
setCollapsed ( map , false ) ;
}
}
180
170
s e t G r a p h i c a l O b j e c t ( map , transition ) ;
setValue ( map , transition . getLabel () . toString () ) ;
setLineEnd ( map , G raph Const ants . A R RO W_TECHNICAL ) ;
setLineStyle ( map , Graph Cons tants . STYLE_SPLINE ) ;
s e t L a b e l A l o n g E d g e ( map , false ) ;
final int pos = 20;
s e t E x t r a L a b e l P o s i t i o n s ( map , new Point []{ new Point ( pos , pos ) }) ;
160
Gra phCon stan ts . s etEx traLa bels ( map ,
new Object []{" <" + transition . getPriority () . getValue () + " >"}) ;
if ( transition instanceof St rong Abortion
|| transition instanceof N o r m a l Ter mi nat io n ) {
setLineBegin ( map , M y G r a p h C o n s t a nts . ARROW_BEGIN ) ;
}
map . put ( GRAPHICAL_OBJECT , g ra ph i ca l Object ) ;
}
/**
* .
* @param map .
* @param transition .
*/
150
public static final void s e t T r a n s i t i o n A t t r i b u t e s ( final AttributeMap map ,
final Transition transition ) {
}
/**
* @param map .
* @return .
*/
public static final synchronized GraphicalObject ge t Gr a ph i c a l O b j e c t (
final Map map ) {
return ( GraphicalObject ) map . get ( GRAPHICAL_OBJ ECT ) ;
}
}
N o d e L a y o u t I n f o r m a t i o n layout = kielView . g e t L a y o u t I n f o r m a t i o n ( node ) ;
Point2D offset = M y G r a p h M o d e l U t i l i t i e s . calculateOffset ( node ,
kielView ) ;
if ( layout != null ) {
if ( isCollapsed ( map ) ) {
Dimension d = M y G r a p h M o d e l U t i l i t i e s . g e t I n i t i a l D i m e n s i o n O f (
ORState . class ) ;
setBounds ( map , new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
layout . getXPos () + offset . getX () ,
layout . getYPos () + offset . getY () ,
d . getWidth () ,
d . getHeight () ) ) ;
se tE xpa nd edB ou nds ( map , new AttributeMap .
SerializableRectangle2D (
layout . getXPos () + offset . getX () ,
layout . getYPos () + offset . getY () ,
layout . getWidth () ,
layout . getHeight () ) ) ;
} else {
setBounds ( map , new AttributeMap . S e r i a l i z a b l e R e c t a n g l e 2 D (
layout . getXPos () + offset . getX () ,
layout . getYPos () + offset . getY () ,
layout . getWidth () ,
layout . getHeight () ) ) ;
}
}
s e t V e r t i c a l A l i g n m e n t ( map , SwingConstants . TOP ) ;
setBorderColor ( map , Color . black ) ;
setBorder ( map , BorderFactory . c re ate Em pty Bo rd er () ) ;
setBackground ( map , Color . white ) ;
setOpaque ( map , false ) ;
A.4. Der Quelltext
359
360
10
/**
* Describes a Node in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.13 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.NodeCell
}
/**
* @param userObject .
*/
public NodeCell ( final Object userObject ) {
super ( userObject ) ;
}
public class NodeCell extends G r a p h i c a l O b j e c t C e l l {
A. Java-Programm-Quelltext
20
10
30
/**
* .
* @return .
*/
/**
* Describes a Node in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/04/01 12:26:33 $
40
*/
class NodeRenderer extends Vert exRe ndere r {
import org . jgraph . graph . V ertex Rend erer ;
import org . jgraph . graph . VertexView ;
}
/**
*
* @see java . awt . Component # paint ( java . awt . Graphics )
*/
public void paint ( final Graphics g ) {
setFont ( Properties . g e t De s cr i p ti o nF o n t () ) ;
setForeground ((( MyJGraph ) graph ) . getViewsBlack ( view ) ) ;
super . paint ( g ) ;
}
/**
* .
* @return .
*/
protected VertexView getView () {
return view ;
}
import kiel . editor . MyJGraph ;
import kiel . g r a p h i c a l I n f o r m a t i o n s . Properties ;
import java . awt . Graphics ;
protected MyJGraph getGraph () {
return ( MyJGraph ) graph ;
}
package kiel . editor . graph ;
kiel.editor.graph.NodeRenderer
A.4. Der Quelltext
361
362
40
30
20
10
org . jgraph . graph . CellHandle ;
org . jgraph . graph . C e l l V i e w R e n d e r e r ;
org . jgraph . graph . G raphC onst ants ;
org . jgraph . graph . GraphContext ;
org . jgraph . graph . VertexView ;
50
/**
* .
/**
* Comment for < code > isResizing </ code >.
*/
private boolean isResizing ;
/**
* @param cell .
*/
public NodeView ( final Object cell ) {
super ( cell ) ;
}
/**
* @see org . jgraph . graph . CellView # isLeaf ()
*/
public final boolean isLeaf () {
return true ;
}
/**
*
* @see org . jgraph . graph . A b s t r a c t C e l l V i ew # getRenderer ()
*/
public C e l l V i e w R e n d e r e r getRenderer () {
return C e l l V i e w R e n d e r e r F a c t o r y . get ( getClass () ) ;
}
90
80
70
/**
60
* Describes a Node in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.33 $ last modified $Date : 2005/07/25 11:44:37 $
*/
public class NodeView extends VertexView implements Previewable {
import
import
import
import
import
import java . awt . geom . Rectangle2D ;
package kiel . editor . graph ;
kiel.editor.graph.NodeView
}
/**
* .
* @return .
*/
public final Rectangle2D getPreviewBounds () {
return previewBounds ;
}
/**
*
*/
private Rectangle2D previewBounds ;
}
return new MySizeHandle ( this , context ) ;
}
return null ;
/**
* @see org . jgraph . graph . CellView # getHandle ( org . jgraph . graph .
GraphContext )
*/
public final CellHandle getHandle ( final GraphContext context ) {
if ( GraphConstants . isSizeable ( getAllA ttributes () )
&& context . getGraph () . isSizeable () ) {
/**
* @return .
*/
public final boolean isResizing () {
return isResizing ;
}
/**
* .
* @param b .
*/
public final void setResizing ( final boolean b ) {
isResizing = b ;
}
* @param aBounds .
*/
public final void s etPreviewBounds ( final Rectangle2D aBounds ) {
previewBounds = aBounds ;
}
A. Java-Programm-Quelltext
10
/**
*
/**
* Describes a N o r m a l T e r m i n a t i o n in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 20
* @version $Revision : 1.12 $ last modified $Date : 2005/03/15 11:52:54 $
*/
public class N o r m a l T e r m i n a t i o n C e l l extends TransitionCell {
package kiel . editor . graph ;
kiel.editor.graph.NormalTerminationCell
}
/**
* @param userObject .
*/
public N o r m a l T e r m i n a t i o n C e l l ( final Object userObject ) {
super ( userObject ) ;
}
*/
public N o r m a l T e r m i n a t i o n C e l l () {
super () ;
}
A.4. Der Quelltext
363
364
20
10
java . awt . Graphics ;
java . awt . Graphics2D ;
java . awt . Shape ;
java . awt . geom . Ellipse2D ;
java . awt . geom . Point2D ;
30
/**
* @see java . awt . Component # paint ( java . awt . Graphics )
*/
public void paint ( final Graphics g ) {
super . paint ( g ) ;
g . setColor ( getGraph () . getViewsGreen () ) ;
if ( getView () . beginShape != null ) { // TODO Why can be null ??
try {
(( Graphics2D ) g ) . fill ( getView () . beginShape ) ;
50
/**
* Describes a N o r m a l T e r m i n a t i o n in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
40
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.12 $ last modified $Date : 2005/06/13 07:00:19 $
*/
class N o r m a l T e r m i n a t i o n R e n d e r e r extends T r a n s it i o nR e nd e r er {
import kiel . editor . resources . Preferences ;
import
import
import
import
import
package kiel . editor . graph ;
kiel.editor.graph.NormalTerminationRenderer
}
}
}
+ " draw ( Unknown Source ) ") ;
+ " renderPath ( Unknown Source ) ") ;
getLogFile () . log (1 , " at sun . java2d . pipe . D u c t u s S h a p e R e n d e r e r
/**
* @see org . jgraph . graph . EdgeRenderer # createLineEnd ( int , int ,
* java . awt . geom . Point2D , java . awt . geom . Point2D )
*/
protected Shape createLineEnd ( final int size , final int style ,
final Point2D src , final Point2D dst ) {
if ( style == MyGraphCo nstants . ARROW_BEGIN ) {
return new Ellipse2D . Double ( dst . getX () , dst . getY () ,
Preferences . g et L in e E nd D ia m e te r () ,
Preferences . g et L in e E nd D ia m e te r () ) ;
} else {
return super . createLineEnd ( size , style , src , dst ) ;
}
}
}
."
."
g . setColor ( getGraph () . getViewsBlack ( getView () ) ) ;
(( Graphics2D ) g ) . draw ( getView () . beginShape ) ;
} catch ( N u l l P o i n t e r E x c e p t i o n e ) {
getLogFile () . log (1 , " at sun . java2d . pipe . D u c t u s S h a p e R e n d e r e r
A. Java-Programm-Quelltext
10
/**
* Describes a N o r m a l T e r m i n a t i o n in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.19 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.NormalTerminationView
}
/**
* @param cell .
*/
public N o r m a l T e r m i n a t i o n V i e w ( final Object cell ) {
super ( cell ) ;
}
public class N o r m a l T e r m i n a t i o n V i e w extends TransitionView {
A.4. Der Quelltext
365
366
10
/**
* Describes a ORState in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.12 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.ORStateCell
}
/**
* @param userObject .
*/
public ORStateCell ( final Object userObject ) {
super ( userObject ) ;
}
public class ORStateCell extends Co m po s i te S ta t e Ce l l {
A. Java-Programm-Quelltext
10
20
/**
* Describes a ORState in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.9 $ last modified $Date : 2005/03/15 11:52:53 $
*/
import kiel . g r a p h i c a l I n f o r m a t i o n s . Properties ;
import java . awt . Graphics ;
package kiel . editor . graph ;
kiel.editor.graph.ORStateRenderer
}
/**
* @see org . jgraph . graph . VertexRenderer # p a i n t S e l e c t i o n B o r d e r (
* java . awt . Graphics )
*/
protected void p a i n t S e l e c t i o n B o r d e r ( final Graphics g ) {
super . p a i n t S e l e c t i o n B o r d e r ( g ) ;
g . drawLine (0 , Properties . g e t C o m p o s i t e S t a t e H e a d e r H e i g h t () ,
getSize () . width - 2 ,
Properties . g e t C o m p o s i t e S t a t e H e a d e r H e i g h t () ) ;
}
class OrStateRenderer extends C o m p o s i t e S t a t e R e n d e r e r {
A.4. Der Quelltext
367
368
10
/**
* Describes an ORState in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.18 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.ORStateView
}
/**
* @param cell .
*/
public ORStateView ( final Object cell ) {
super ( cell ) ;
}
public class ORStateView extends Co m po s i te S ta t e Vi e w {
A. Java-Programm-Quelltext
10
/**
* Describes a PseudoState in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.13 $ last modified $Date : 2005/03/15 11:52:54 $
*/
package kiel . editor . graph ;
kiel.editor.graph.PseudoStateCell
}
/**
* @param userObject .
*/
public PseudoStateCell ( final Object userObject ) {
super ( userObject ) ;
}
public class PseudoStateCell extends NodeCell {
A.4. Der Quelltext
369
370
30
20
10
java . awt . Color ;
java . awt . Dimension ;
java . awt . Graphics ;
java . awt . Graphics2D ;
50
40
/**
* .
* @return .
*/
protected VertexView getView () {
return view ;
}
/**
* .
* @return .
*/
protected MyJGraph getGraph () {
return ( MyJGraph ) graph ;
}
70
60
/**
* Describes a PseudoState in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.11 $ last modified $Date : 2005/04/01 16:24:06 $
*/
class P s e u d o S t a t e R e n d e r e r extends Ver texRe nderer {
import org . jgraph . graph . V ertex Rend erer ;
import org . jgraph . graph . VertexView ;
import kiel . editor . MyJGraph ;
import kiel . editor . resources . Preferences ;
import
import
import
import
package kiel . editor . graph ;
kiel.editor.graph.PseudoStateRenderer
}
//
//
protected Image image = ResourceLoader . get (" attention . gif ") . getImage
}
g . drawImage ((( PseudoStateView ) view ) . image , 0 , 0 , null ) ;
/**
* @param g .
*/
protected void p a i n t S e l e c t i o n B o r d e r ( final Graphics g ) {
(( Graphics2D ) g ) . setStroke ( getGraph () . getStroke ( getView () ) ) ;
Dimension d = getSize () ; g . setColor (
(( MyJGraph ) graph ) . getViewsBlack ( view ) ) ;
g . drawOval (0 , 0 , d . width - 1 , d . height - 1) ;
g . setColor ( getMyColor () ) ;
g . fillOval (0 , 0 , d . width - 1 , d . height - 1) ;
g . setColor ((( MyJGraph ) graph ) . getViewsBlack ( view ) ) ;
g . drawString ( getMyName () ,
Preferences . g e t P s e u d o S t a t e N a m e O f f s e t () .x ,
Preferences . g e t P s e u d o S t a t e N a m e O f f s e t () . y ) ;
() ;
/**
*
* @return .
*/
protected Color getMyColor () {
return (( MyJGraph ) graph ) . getViewsGray () ;
}
/**
*
* @return .
*/
protected String getMyName () {
return ""; // H , H * , I , S : wird im Kreis angezeigt
}
A. Java-Programm-Quelltext
/**
* @param cell .
*/
public PseudoStateView ( final Object cell ) {
super ( cell ) ;
}
/**
* Describes a PseudoState in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.23 $ last modified $Date : 2005/03/15 11:52:54 $
*/
}
public class PseudoStateView extends NodeView {
package kiel . editor . graph ;
10
kiel.editor.graph.PseudoStateView
A.4. Der Quelltext
371
372
10
/**
* Describes a Region in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.12 $ last modified $Date : 2005/03/15 11:52:54 $
*/
package kiel . editor . graph ;
kiel.editor.graph.RegionCell
}
/**
* @param userObject .
*/
public RegionCell ( final Object userObject ) {
super ( userObject ) ;
}
public class RegionCell extends C o mp o s it e St a t eC e ll {
A. Java-Programm-Quelltext
10
/**
* Describes a Region in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 20
* @version $Revision : 1.8 $ last modified $Date : 2005/03/21 22:53:58 $
*/
import java . awt . Graphics ;
package kiel . editor . graph ;
kiel.editor.graph.RegionRenderer
}
/**
* @see org . jgraph . graph . VertexRenderer # p a i n t S e l e c t i o n B o r d e r (
* java . awt . Graphics )
*/
protected void p a i n t S e l e c t i o n B o r d e r ( final Graphics g ) {
final int initialYOffset = -10;
drawAllLabels (g , initialYOffset ) ;
}
class RegionRenderer extends C o m p o s i t e S t a t e R e n d e r e r {
A.4. Der Quelltext
373
374
10
/**
* Describes a Region in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.17 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.RegionView
}
/**
* @param cell .
*/
public RegionView ( final Object cell ) {
super ( cell ) ;
}
public class RegionView extends C o mp o s it e St a t eV i ew {
A. Java-Programm-Quelltext
10
/**
* Describes a SimpleState in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.12 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.SimpleStateCell
}
/**
* @param userObject .
*/
public SimpleStateCell ( final Object userObject ) {
super ( userObject ) ;
}
public class SimpleStateCell extends StateCell {
A.4. Der Quelltext
375
376
10
/**
* Describes a SimpleState in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.15 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.SimpleStateView
}
/**
* @param cell .
*/
public SimpleStateView ( final Object cell ) {
super ( cell ) ;
}
public class SimpleStateView extends StateView {
A. Java-Programm-Quelltext
10
/**
* Describes a State in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.12 $ last modified $Date : 2005/03/15 11:52:54 $
*/
package kiel . editor . graph ;
kiel.editor.graph.StateCell
}
/**
* @param userObject .
*/
public StateCell ( final Object userObject ) {
super ( userObject ) ;
}
public class StateCell extends NodeCell {
A.4. Der Quelltext
377
378
60
}
/**
* @see org . jgraph . graph . V ertex Rend erer # p a i n t S e l e c t i o n B o r d e r (
* java . awt . Graphics )
*/
protected void p a i n t S e l e c t i o n B o r d e r ( final Graphics g ) {
(( Graphics2D ) g ) . setStroke ( getGraph () . getStroke ( getView () ) ) ;
g . setColor ( getGraph () . getViewsBlack ( getView () ) ) ;
g . drawRoundRect (0 , 0 , getSize () . width - 1 ,
getSize () . height - 1 ,
50
super . g e t R e n d e r e r C o m p o n e n t ( graph , view , sel , focus , preview ) ;
if (!( view instanceof C o m p o s i t e S t a t e Vi e w ) ) {
setText ("") ;
}
return this ;
/**
* @see org . jgraph . graph . C e l l V i e w R e n d e r er # g e t R e n d e r e r C o m p o n e n t (
* org . jgraph . JGraph , org . jgraph . graph . CellView , boolean , boolean ,
boolean )
*/
public Component g e t R e n d e r e r C o m p o n e n t ( final JGraph graph ,
final CellView view , final boolean sel , final boolean focus ,
final boolean preview ) {
90
80
/**
* Describes a State in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p70
>
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.13 $ last modified $Date : 2005/07/14 15:27:56 $
*/
class StateRenderer extends NodeRenderer {
import org . jgraph . JGraph ;
import org . jgraph . graph . CellView ;
import org . jgraph . graph . D e f a u l t G r a p h C e l l ;
kiel . dataStructure . State ;
kiel . editor . resources . Preferences ;
kiel . editor . resources . Reso urce Bundl e ;
kiel . g r a p h i c a l I n f o r m a t i o n s . Properties ;
import
import
import
import
40
30
20
10
java . awt . Component ;
java . awt . Graphics ;
java . awt . Graphics2D ;
java . util . Arrays ;
java . util . List ;
import
import
import
import
import
package kiel . editor . graph ;
kiel.editor.graph.StateRenderer
/**
* .
* @param rowTitle .
* @param elements .
* @param aYOffset .
* @param g .
* @return .
*/
protected int draw ( final String rowTitle , final List elements ,
final int aYOffset , final Graphics g ) {
/**
* .
* @param g .
* @param yOffset .
* @return .
*/
protected int d r a w V a r i a b l e s A n d E v e n t s ( final Graphics g , final int yOffset
) {
return yOffset ;
}
/**
*
* @param g .
* @param initialYOffset .
*/
protected void drawAllLabels ( final Graphics g , final int init ialY Offse t )
{
int yOffset = initialYOffset ;
yOffset = d r a w V a r i a b l e s A n d E v e n t s (g , yOffset ) ;
drawActions (g , yOffset ) ;
}
}
if (!( view instanceof C o m po s it e S ta t eV i e w ) ) {
int offset = Properties . getUpperOffset (( State )
MyGraphCons tants . ge t G ra p hi c a lO b je c t (
(( NodeCell ) view . getCell () ) . getAttributes () ) ) ;
String s = graph . c o n v e r t V a l u e T o S t r i n g ( view ) ;
g . setFont ( Properties . g et D es c r ip t io n F on t () ) ;
g . drawString (
s,
( getWidth () - Properties . getWidth ( g . getFont () , s ) ) / 2 ,
2 + 2 + 2 + offset + ( getHeight () - offset ) / 2) ;
}
Preferences . get Ar cWi dt hHe ig ht () ,
Preferences . get Ar cWi dt hHe ig ht () ) ;
drawAllLabels (g , Properties . getHeight (
Properties . getActivityFont () , " X ") + HEADER_FOOTER ) ;
A. Java-Programm-Quelltext
120
110
100
}
130
if ( elements != null ) {
String e lemen tsStr ing = "";
for ( int i = 0; i < elements . size () ; i ++) {
if ( elements . get ( i ) != null ) {
if ( i > 0) {
ele ments Stri ng += " , ";
}
ele ment sStri ng += elements . get ( i ) ;
}
}
140
if ( e leme ntsSt ring . length () > 0) {
final int xOffset = 10;
g . setFont ( Properties . ge t Ac t ivityFont () ) ;
g . drawString ( rowTitle + elementsString , xOffset , yOffset ) ;
g . drawLine (0 ,
yOffset + HEADER_FOOTER ,
getSize () . width - 2 ,
yOffset + HEADER_FOOTER ) ;
yOffset += Properties . getHeight (
Properties . g e tA c ti v it y Font () , " X ") + 2 * HEADER_FOOTER ;
}
}
return yOffset ;
150
int yOffset = aYOffset ;
}
/**
* .
* @param g .
* @param initialYOffset .
*/
protected void drawActions ( final Graphics g , final int initia lYOff set ) {
int yOffset = initialYOffset ;
if ( Preferences . g e t S h o w S t a t e A c t i o n s () ) {
State state = ( State ) MyGraphC onstants . g et G ra p h ic a lO b j e c t (
(( DefaultGraphC ell ) getView () . getCell () ) . getAttributes () ) ;
yOffset = draw ( ResourceBundle . getString (" On_Entry_Act i on ") + ":
",
Arrays . asList ( state . getEntry () . getActions () ) , yOffset , g ) ;
yOffset = draw ( ResourceBundle . getString (" O n_Inside_ A c t i o n ") + ":
",
Arrays . asList ( state . getDoActivity () . getActions () ) , yOffset ,
g);
yOffset = draw ( ResourceBundle . getString (" On_Exit_Actio n ") + ":
",
Arrays . asList ( state . getExit () . getActions () ) , yOffset , g ) ;
}
}
/**
* .
*/
private static final int HEADER_FOOTER = 3;
A.4. Der Quelltext
379
380
/**
* @param cell .
*/
public StateView ( final Object cell ) {
super ( cell ) ;
}
/**
* Describes a State in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.19 $ last modified $Date : 2005/03/15 11:52:54 $
*/
}
public class StateView extends NodeView {
package kiel . editor . graph ;
10
kiel.editor.graph.StateView
A. Java-Programm-Quelltext
10
/**
*
/**
* Describes a St rong Abort ion in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 20
* @version $Revision : 1.12 $ last modified $Date : 2005/03/15 11:52:53 $
*/
public class S t r o n g A b o r t i o n C e l l extends Tr ansitionCell {
package kiel . editor . graph ;
kiel.editor.graph.StrongAbortionCell
}
/**
* @param userObject .
*/
public St r o ng A bo r t io n Ce l l ( final Object userObject ) {
super ( userObject ) ;
}
*/
public St r o ng A bo r t io n Ce l l () {
super () ;
}
A.4. Der Quelltext
381
382
20
10
java . awt . Graphics ;
java . awt . Graphics2D ;
java . awt . Shape ;
java . awt . geom . Ellipse2D ;
java . awt . geom . Point2D ;
30
/**
* @see java . awt . Component # paint ( java . awt . Graphics )
*/
public void paint ( final Graphics g ) {
super . paint ( g ) ;
g . setColor ( getGraph () . getViewsRed () ) ;
if ( getView () . beginShape != null ) { // TODO Why can be null ??
try {
(( Graphics2D ) g ) . fill ( getView () . beginShape ) ;
50
/**
* Describes a St rong Abort ion in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
40
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.13 $ last modified $Date : 2005/06/13 07:00:19 $
*/
class S t r o n g A b o r t i o n R e n d e r e r extends T r a n s i ti o nR e n de r er {
import kiel . editor . resources . Preferences ;
import
import
import
import
import
package kiel . editor . graph ;
kiel.editor.graph.StrongAbortionRenderer
}
}
}
+ " draw ( Unknown Source ) ") ;
+ " renderPath ( Unknown Source ) ") ;
getLogFile () . log (1 , " at sun . java2d . pipe . D u c t u s S h a p e R e n d e r e r
/**
* @see org . jgraph . graph . EdgeRenderer # createLineEnd ( int , int ,
* java . awt . geom . Point2D , java . awt . geom . Point2D )
*/
protected Shape createLineEnd ( final int size , final int style ,
final Point2D src , final Point2D dst ) {
if ( style == MyGraphCo nstants . ARROW_BEGIN ) {
return new Ellipse2D . Double ( dst . getX () , dst . getY () ,
Preferences . g et L in e E nd D ia m e te r () ,
Preferences . g et L in e E nd D ia m e te r () ) ;
} else {
return super . createLineEnd ( size , style , src , dst ) ;
}
}
}
."
."
g . setColor ( getGraph () . getViewsBlack ( getView () ) ) ;
(( Graphics2D ) g ) . draw ( getView () . beginShape ) ;
} catch ( N u l l P o i n t e r E x c e p t i o n e ) {
getLogFile () . log (1 , " at sun . java2d . pipe . D u c t u s S h a p e R e n d e r e r
A. Java-Programm-Quelltext
10
/**
* Describes a St rong Abort ion in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.20 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.StrongAbortionView
}
/**
* @param cell .
*/
public St r o ng A bo r t io n Vi e w ( final Object cell ) {
super ( cell ) ;
}
public class St r on g A bo r ti o n Vi e w extends TransitionView {
A.4. Der Quelltext
383
384
10
/**
* Describes a Suspend in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.12 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.SuspendCell
}
/**
* @param userObject .
*/
public SuspendCell ( final Object userObject ) {
super ( userObject ) ;
}
public class SuspendCell extends PseudoStateCell {
A. Java-Programm-Quelltext
10
/**
/**
20
* Describes a Suspend in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.8 $ last modified $Date : 2005/04/01 12:33:58 $
*/
class Su s pe n dR e nd e re r extends P s e u d o S t a t e R e n d e r e r {
import java . awt . Color ;
package kiel . editor . graph ;
kiel.editor.graph.SuspendRenderer
}
//
/**
* @see kiel . editor . graph . P s e u d o S t a t e R e n d e r e r # getMyColor ()
*/
protected Color getMyColor () {
return getGraph () . getViewsYellow () ;
}
* @see kiel . editor . graph . P s e u d o S t a t e R e n d e r e r # getMyName ()
*/
protected String getMyName () {
return " S ";
image = ResourceLoader . get (" Suspend . gif ") . getImage () ;
}
A.4. Der Quelltext
385
386
10
/**
* Describes a Suspend in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.18 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.SuspendView
}
/**
* @param cell .
*/
public SuspendView ( final Object cell ) {
super ( cell ) ;
}
public class SuspendView extends PseudoStateView {
A. Java-Programm-Quelltext
10
/**
*
/**
* Describes a Suspension in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 20
* @version $Revision : 1.12 $ last modified $Date : 2005/03/15 11:52:53 $
*/
public class Sus pens ionCe ll extends Tra nsit ionCell {
package kiel . editor . graph ;
kiel.editor.graph.SuspensionCell
}
/**
* @param userObject .
*/
public SuspensionCell ( final Object userObject ) {
super ( userObject ) ;
}
*/
public SuspensionCell () {
super () ;
}
A.4. Der Quelltext
387
388
20
10
java . awt . Graphics ;
java . awt . Graphics2D ;
java . awt . Shape ;
java . awt . geom . Ellipse2D ;
java . awt . geom . Point2D ;
30
/**
* @see java . awt . Component # paint ( java . awt . Graphics )
*/
public void paint ( final Graphics g ) {
super . paint ( g ) ;
if ( getView () . endShape != null ) { // TODO Why can be null ??
try {
g . setColor ( getGraph () . getViewsBlack ( getView () ) ) ;
(( Graphics2D ) g ) . draw ( getView () . endShape ) ;
g . setColor ( getGraph () . getV iewsYellow () ) ;
50
/**
* Describes a Suspension in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p40
>
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.3 $ last modified $Date : 2005/06/13 07:00:18 $
*/
class S u s p e n s i o n R e n d e r e r extends T r a n s i t i o n R e nd e re r {
import kiel . editor . resources . Preferences ;
import
import
import
import
import
package kiel . editor . graph ;
kiel.editor.graph.SuspensionRenderer
}
}
}
+ " draw ( Unknown Source ) ") ;
+ " renderPath ( Unknown Source ) ") ;
getLogFile () . log (1 , " at sun . java2d . pipe . D u c t u s S h a p e R e n d e r e r
/**
* @see org . jgraph . graph . EdgeRenderer # createLineEnd ( int , int ,
* java . awt . geom . Point2D , java . awt . geom . Point2D )
*/
protected Shape createLineEnd ( final int size , final int style ,
final Point2D src , final Point2D dst ) {
Shape shape = super . createLineEnd ( size , style , src , dst ) ;
if ( style != MyGraphCo nstants . ARROW_BEGIN ) {
return new Ellipse2D . Double ( dst . getX () , dst . getY () ,
Preferences . g et L in e E nd D ia m e te r () ,
Preferences . g et L in e E nd D ia m e te r () ) ;
} else {
return shape ;
}
}
}
."
."
(( Graphics2D ) g ) . fill ( getView () . endShape ) ;
} catch ( N u l l P o i n t e r E x c e p t i o n e ) {
getLogFile () . log (1 , " at sun . java2d . pipe . D u c t u s S h a p e R e n d e r e r
A. Java-Programm-Quelltext
10
/**
* Describes a Suspension in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.15 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.SuspensionView
}
/**
* @param cell .
*/
public SuspensionView ( final Object cell ) {
super ( cell ) ;
}
public class SuspensionView extends TransitionView {
A.4. Der Quelltext
389
390
10
/**
* Describes a SynchState in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.12 $ last modified $Date : 2005/03/15 11:52:54 $
*/
package kiel . editor . graph ;
kiel.editor.graph.SynchStateCell
}
/**
* @param userObject .
*/
public SynchStateCell ( final Object userObject ) {
super ( userObject ) ;
}
public class SynchStateCell extends PseudoStateCell {
A. Java-Programm-Quelltext
10
/**
* Describes a SynchState in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.15 $ last modified $Date : 2005/03/15 11:52:53 $
*/
package kiel . editor . graph ;
kiel.editor.graph.SynchStateView
}
/**
* @param cell .
*/
public SynchStateView ( final Object cell ) {
super ( cell ) ;
}
public class SynchStateView extends PseudoStateView {
A.4. Der Quelltext
391
392
30
20
10
40
/**
* @param userObject .
*/
public TransitionCell ( final Object userObject ) {
super ( userObject ) ;
}
/**
* @see org . jgraph . graph . DefaultEdge # checkDefaults ()
*/
protected final void checkDefaults () {
List points = G raph Const ants . getPoints ( attributes ) ;
if ( points == null ) {
List defaultPoints = new ArrayList () ;
defaultPoints . add ( DUMMY_POINT ) ;
60
/**
*
*/
public TransitionCell () {
super () ;
}
}
}
super . checkDefaults () ;
/**
*
* @return .
*/
public final boolean h as O n ly D um m y Po i nt s () {
List points = GraphConstants . getPoints ( attributes ) ;
return points != null
&& points . size () == 2
&& DUMMY_POINT . equals ( points . get (0) )
&& DUMMY_POINT . equals ( points . get (1) ) ;
}
}
defaultPoints . add ( DUMMY_POINT ) ;
GraphConstants . setPoints ( attributes , defaultPoints ) ;
/**
* Comment for < code > DUMMY_POINT </ code >.
*/
public static final Point2D DUMMY_POINT =
new AttributeMap . S e r i a l i z a b l e P o i n t 2 D (
Double . NEGATIVE_INFINITY , Double . N EG ATI VE _IN FI NIT Y ) ;
/**
* Describes a Transition in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.19 $ last modified $Date : 2005/07/25 11:44:37 $
*/
50
public class Tra nsit ionCe ll extends EdgeCell {
import org . jgraph . graph . AttributeMap ;
import org . jgraph . graph . G raphC onst ants ;
import java . awt . geom . Point2D ;
import java . util . ArrayList ;
import java . util . List ;
package kiel . editor . graph ;
kiel.editor.graph.TransitionCell
A. Java-Programm-Quelltext
50
40
30
20
10
kiel . editor . MyJGraph ;
kiel . editor . resources . Preferences ;
kiel . g r a p h i c a l I n f o r m a t i o n s . Properties ;
kiel . util . LogFile ;
java . awt . Dimension ;
java . awt . Graphics ;
java . awt . Graphics2D ;
java . awt . Shape ;
java . awt . geom . Point2D ;
java . awt . geom . Rectangle2D ;
60
80
90
/**
* Workaround ( JGraph throws a N u l l P o i n t e r E x c e p t i o n ) .
* @see org . jgraph . graph . EdgeRenderer # g et Ext ra Lab el Siz e (
* org . jgraph . graph . EdgeView , int )
*/
public Dimension g e t E x t r a L a b e l S i z e ( final EdgeView aView , final int index
) {
if ( graph == null ) {
return null ;
} else {
100
return super . g e t E x t r a L a b e l S i z e ( aView , index ) ;
/**
* Workaround ( JGraph throws a N u l l P o i n t e r E x c e p t i o n ) .
* @see org . jgraph . graph . EdgeRenderer # g e t E x t r a L a b e l B o u n d s (
* org . jgraph . graph . EdgeView , int )
*/
public Rectangle2D g e t E x t r a L a b e l B o u n d s (
final EdgeView aView , final int index ) {
if ( graph == null ) {
return null ;
} else {
return super . g e t E x t r a L a b e l B o u n d s ( aView , index ) ;
}
}
/**
* Describes a Transition in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p70
>
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.25 $ last modified $Date : 2005/07/27 09:42:14 $
*/
class T r a n s i t i o n R e n d e r e r extends EdgeRenderer {
import org . jgraph . graph . EdgeRenderer ;
import org . jgraph . graph . EdgeView ;
import
import
import
import
import
import
import
import
import
import
package kiel . editor . graph ;
kiel.editor.graph.TransitionRenderer
}
/**
* @see java . awt . Component # paint ( java . awt . Graphics )
*/
public void paint ( final Graphics g ) {
setForeground ( getGraph () . getViewsBlack ( view ) ) ;
setFont ( Properties . getLabelFont () ) ;
super . paint ( g ) ;
if ( getView () . endShape != null ) {
/**
* Workaround for setting the label color .
* @see org . jgraph . graph . EdgeRenderer # paintLabel (
* java . awt . Graphics , java . lang . String , java . awt . geom . Point2D , boolean )
*/
protected void paintLabel ( final Graphics g , final String label ,
final Point2D p , final boolean mainLabel ) {
fontColor = getGraph () . getViewsBlack ( view ) ;
super . paintLabel (g , label , p , mainLabel ) ;
}
/**
* .
* @return .
*/
protected EdgeView getView () {
return view ;
}
/**
* .
* @return .
*/
protected MyJGraph getGraph () {
return ( MyJGraph ) graph ;
}
/**
*
* @return .
*/
protected LogFile getLogFile () {
return logFile ;
}
/**
* The logging handle . Prints logs to standard out .
*/
private LogFile logFile = new LogFile (" Editor " , 2) ;
}
A.4. Der Quelltext
393
394
120
110
}
(( Graphics2D ) g ) . fill ( getView () . endShape ) ;
130
/**
* TODO why ? This method is needed even if TransitionRenderers ’
* subclasses do not have any code and even if Tr a ns i ti o n Re n de r e r itself
* doen ’ t have any code as well .
140
* @see org . jgraph . graph . EdgeRenderer # createShape ()
*/
/**
* @see org . jgraph . graph . EdgeRenderer # g etLabel Position (
* org . jgraph . graph . EdgeView )
*/
public Point2D g e t L a b e l P o s i t i o n ( final EdgeView aView ) {
Point2D p = super . g e t L a b e l P o s i t i o n ( aView ) ;
p . setLocation ( p . getX () + Preferences . getLabelOffset () .x ,
p . getY () + Preferences . get Label Offset () . y ) ;
return p ;
}
}
}
protected Shape createShape () {
final int times = 10;
for ( int i = 1; i <= times ; i ++) {
try {
Shape result = super . createShape () ;
if ( result != null ) {
return result ;
} else {
logFile . log (1 , " org . jgraph . graph . EdgeRenderer .
createShape () "
+ " returned null .") ;
}
} catch ( N u l l P o i n t e r E x c e p t i o n e ) {
logFile . log (1 , " EdgeRenderer . createShape () threw "
+ " N u l l p o i n t e r E x c e p t i o n .") ;
}
}
return null ;
}
A. Java-Programm-Quelltext
/**
* @param cell .
*/
public TransitionView ( final Object cell ) {
super ( cell ) ;
}
/**
* Describes a Transition in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.25 $ last modified $Date : 2005/03/15 11:52:54 $
*/
}
public class TransitionView extends EdgeView {
package kiel . editor . graph ;
10
kiel.editor.graph.TransitionView
A.4. Der Quelltext
395
396
10
/**
*
/**
* Describes a WeakAbortion in the JGraph model .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 20
* @version $Revision : 1.13 $ last modified $Date : 2005/03/15 11:52:53 $
*/
public class W e a k A b o r t i o n C e l l extends Trans itionCell {
package kiel . editor . graph ;
kiel.editor.graph.WeakAbortionCell
}
/**
* @param userObject .
*/
public WeakAbor tionCell ( final Object userObject ) {
super ( userObject ) ;
}
*/
public WeakAbor tionCell () {
super () ;
}
A. Java-Programm-Quelltext
10
/**
* Describes a WeakAbortion in the JGraph view .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.15 $ last modified $Date : 2005/03/15 11:52:54 $
*/
package kiel . editor . graph ;
kiel.editor.graph.WeakAbortionView
}
/**
* @param cell .
*/
public WeakAbor tionView ( final Object cell ) {
super ( cell ) ;
}
public class WeakAbortion View extends TransitionView {
A.4. Der Quelltext
397
398
40
30
20
10
java . awt . Color ;
java . awt . Dimension ;
java . awt . Point ;
java . awt . Rectangle ;
java . io . File ;
java . io . F il e In p ut S tr e am ;
java . io . F i l e O u t p u t S t r e a m ;
java . io . IOException ;
java . util . ArrayList ;
java . util . HashMap ;
java . util . Properties ;
java . util . Set ;
java . util . St r in g To k en i ze r ;
60
50
/**
}
/**
* Is called whenever the preferences values have changed .
*/
void p r e f e r e n c e s C h a n g e d () ;
90
80
/**
* components can register to be notified whenever the preferences have
* changed , that is , when the user edited the preferences table in the
* preferences dialog .
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </
a>
*/
public interface Listener {
}
/**
* .
*
*/
private Preferences () {
/**
* Handles the user preferences , that can be edited through the
* File - - > Preferences menu item .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.36 $ last modified $Date : 2005/08/01 17:46:35 $
70
*/
public final class Preferences {
import
import
import
import
import
import
import
import
import
import
import
import
import
package kiel . editor . resources ;
kiel.editor.resources.Preferences
/**
*
/**
* loads all the preferences .
*/
static {
initialize () ;
}
/**
* The preferences file name without directory .
*/
private static final String FILENAME = " MyPreferences . properties ";
/**
* the directory where the preferences are stored .
*/
private static final String WORKING_DIR =
System . getProperty (" user . home ")
+ File . separator
+ ". kiel "
+ File . separator ;
/**
* The listeners to be notified whenever the preferences changed .
*/
private static ArrayList listeners = new ArrayList () ;
/**
* Some preferences are not just Strings or ints , but are quite complex
* objects , like fonts or rectangles , so once they are requested , they
are
* build and stored . They will be replaced from this cache , whenever
they
* change ( through setProperty () .
*/
private static HashMap cache = new HashMap () ;
/**
* The default and non editable preferences , that are stored in this
* package . These values are needed whenever the user types in permitted
* values for some preferences .
*/
private static final Properties D E F A U L T _ P R E F E R E N C E S = new Properties () ;
* The user editable preferences that are loaded and stored in the user
home
* directory .
*/
private static final Properties PREFERENCES = new Properties () ;
A. Java-Programm-Quelltext
150
140
130
120
110
100
/**
* Returns all the preferences keys .
* @return .
/**
* Stores the current PREFERENCES hashmap .
*/
public static void store () {
try {
PREFERENCES . store ( new F i l e O u t p u tStream (
WORKING_DIR + FILENAME ) , null ) ;
} catch ( IOException e ) {
e . p ri n tS t ac k Tr a ce () ;
}
}
/**
* Add a listener to the listeners ’ list .
* @param listener .
*/
public static void addListener ( final Listener listener ) {
listeners . add ( listener ) ;
}
/**
*
*
*/
public static void s e t D e f a u l t V a l u e s () {
File f = new File ( WORKING_DIR + FILENAME ) ;
if ( f . exists () ) {
f . delete () ;
}
initialize () ;
n ot i fy L is t en e rs () ;
}
200
190
180
170
*
*/
private static void initialize () {
try {
D E F A U L T _ P R E F E R E N C E S . load (
Preferences . class . g e t R e s o u r c e A s S t r e a m ( FILENAME ) ) ;
if ( new File ( WORKING_DIR + FILENAME ) . exists () ) {
PREFERENCES . load ( new Fi l eI n putStream ( WORKING_DIR + FILENAME )
);
160
} else {
PREFERENCES . load (
Preferences . class . g e t R e s o u r c e A s S t r e a m ( FILENAME ) ) ;
}
} catch ( IOException e ) {
e . p ri n tS t ac k Tr a ce () ;
}
}
/**
* Returns the preference value of the given key as int .
* If that fails ( because of an invalid value in the preferences file ) ,
the
* appropriate value of the default preferences is returned .
* @param key .
* @return .
*/
private static int getInt ( final String key ) {
Integer result = ( Integer ) cache . get ( key ) ;
if ( result == null ) {
try {
result = new Integer ( PREFERENCES . getProperty ( key ) ) ;
} catch ( N u m b e r F o r m a t E x c e p t i o n e ) {
setProperty ( key , D E F A U L T _ P R E F E R E N C E S . getProperty ( key ) ) ;
return getInt ( key ) ;
}
cache . put ( key , result ) ;
}
/**
*
*
*/
private static void notifyListeners () {
for ( int i = 0; i < listeners . size () ; i ++) {
(( Listener ) listeners . get ( i ) ) . p re f er e n ce s Ch a n ge d () ;
}
}
/**
* Sets the value for a particular preference .
* @param key .
* @param value .
*/
public static void setProperty ( final String key , final String value ) {
cache . remove ( key ) ;
PREFERENCES . setProperty ( key , value ) ;
notifyListeners () ;
}
/**
* Returns a particular preference value .
* @param key .
* @return .
*/
public static String getProperty ( final String key ) {
return PREFERENCES . getProperty ( key ) ;
}
*/
public static Set keySet () {
return PREFERENCES . keySet () ;
}
A.4. Der Quelltext
399
400
250
240
230
220
210
return result . intValue () ;
/**
* Returns the preference value of the given key as boolean .
280
* If that fails ( because of an invalid value in the preferences file ) ,
the
* appropriate value of the default preferences is returned .
* @param key .
* @return .
*/
private static boolean getBoolean ( final String key ) {
Boolean result = ( Boolean ) cache . get ( key ) ;
if ( result == null ) {
290
try {
result = new Boolean ( PREFERENCES . getProperty ( key ) ) ;
} catch ( N u m b e r F o r m a t E x c e p t i o n e ) {
setProperty ( key , D E F A U L T _ P R E F E R E N C E S . getProperty ( key ) ) ;
return getBoolean ( key ) ;
}
cache . put ( key , result ) ;
}
return result . booleanValue () ;
}
300
/**
* Returns the preference value of the given key as point .
* If that fails ( because of an invalid value in the preferences file ) ,
the
* appropriate value of the default preferences is returned .
* @param key .
* @return .
/**
* Returns the preference value of the given key as double .
* If that fails ( because of an invalid value in the preferences file )260
,
the
* appropriate value of the default preferences is returned .
* @param key .
* @return .
*/
private static double getDouble ( final String key ) {
Double result = ( Double ) cache . get ( key ) ;
if ( result == null ) {
try {
270
result = new Double ( PREFERENCES . getProperty ( key ) ) ;
} catch ( N u m b e r F o r m a t E x c e p t i o n e ) {
setProperty ( key , D E F A U L T _ P R E F E R E N C E S . getProperty ( key ) ) ;
return getDouble ( key ) ;
}
cache . put ( key , result ) ;
}
return result . doubleValue () ;
}
}
/**
* Returns the preference value of the given key as rectangle .
* If that fails ( because of an invalid value in the preferences file ) ,
the
* appropriate value of the default preferences is returned .
* @param key .
* @return .
*/
private static Rectangle getRectangle ( final String key ) {
/**
* Returns the preference value of the given key as dimension .
* If that fails ( because of an invalid value in the preferences file ) ,
the
* appropriate value of the default preferences is returned .
* @param key .
* @return .
*/
private static Dimension getDimension ( final String key ) {
Dimension result = ( Dimension ) cache . get ( key ) ;
if ( result == null ) {
try {
StringTokenizer st =
new StringTokenizer ( PREFERENCES . getProperty ( key ) , " ,") ;
result = new Dimension (
Integer . parseInt ( st . nextToken () ) ,
Integer . parseInt ( st . nextToken () ) ) ;
} catch ( N u m b e r F o r m a t E x c e p t i o n e ) {
setProperty ( key , D E F A U L T _ P R E F E R E N C E S . getProperty ( key ) ) ;
return getDimension ( key ) ;
}
cache . put ( key , result ) ;
}
return result ;
}
*/
private static Point getPoint ( final String key ) {
Point result = ( Point ) cache . get ( key ) ;
if ( result == null ) {
try {
StringTokenizer st =
new StringTokenizer ( PREFERENCES . getProperty ( key ) , " ,") ;
result = new Point (
Integer . parseInt ( st . nextToken () ) ,
Integer . parseInt ( st . nextToken () ) ) ;
} catch ( N u m b e r F o r m a t E x c e p t i o n e ) {
setProperty ( key , D E F A U L T _ P R E F E R E N C E S . getProperty ( key ) ) ;
return getPoint ( key ) ;
}
cache . put ( key , result ) ;
}
return result ;
}
A. Java-Programm-Quelltext
350
340
330
320
310
/**
* Returns the GuiColorLight .
* @return .
*/
public static Color g e t G u i C o l o r L i g h t () {
return getColor (" guiColorLight ") ;
}
410
/**
* Returns the preference value of the given key as color .
380
* If that fails ( because of an invalid value in the preferences file ) ,
the
* appropriate value of the default preferences is returned .
* @param key .
* @return .
*/
private static Color getColor ( final String key ) {
Color result = ( Color ) cache . get ( key ) ;
if ( result == null ) {
390
try {
S tr i ng T ok e ni z er st =
new S tr i ng T ok e ni z er ( PREFERENCES . getProperty ( key ) , " ,") ;
result = new Color (
Integer . parseInt ( st . nextToken () ) ,
Integer . parseInt ( st . nextToken () ) ,
Integer . parseInt ( st . nextToken () ) ) ;
} catch ( N u m b e r F o r m a t E x c e p t i o n e ) {
setProperty ( key , D E F A U L T _ P R E F E R E N C E S . getProperty ( key ) ) ;
return getColor ( key ) ;
}
400
cache . put ( key , result ) ;
}
return result ;
}
}
Rectangle result = ( Rectangle ) cache . get ( key ) ;
360
if ( result == null ) {
try {
S tr i ng T ok e ni z er st =
new S tr i ng T ok e ni z er ( PREFERENCES . getProperty ( key ) , " ,") ;
result = new Rectangle (
Integer . parseInt ( st . nextToken () ) ,
Integer . parseInt ( st . nextToken () ) ,
Integer . parseInt ( st . nextToken () ) ,
Integer . parseInt ( st . nextToken () ) ) ;
370
} catch ( N u m b e r F o r m a t E x c e p t i o n e ) {
setProperty ( key , D E F A U L T _ P R E F E R E N C E S . getProperty ( key ) ) ;
return getRectangle ( key ) ;
}
cache . put ( key , result ) ;
}
return result ;
/**
* Returns the c o m p o s i t e S t a t e I m a g e O f f s e t .
* @return .
*/
public static int g e t C o m p o s i t e S t a t e I m a g e O f f s e t () {
return getInt (" c o m p o s i t e S t a t e I m a g e O f f s e t ") ;
/**
* Returns the arcWidthHeight .
* @return .
*/
public static int ge tAr cW idt hH eig ht () {
return getInt (" arcWidthHeight ") ;
}
/**
* Returns the i n t e r s e c t i o n S e n s i t i v i t y .
* @return .
*/
public static int g e t I n t e r s e c t i o n S e n s i t i v i t y () {
return getInt (" i n t e r s e c t i o n S e n s i t i v i t y ") ;
}
/**
* Returns the g u i B u t t o n C o l o r S e l e c t e d D a r k .
* @return .
*/
public static Color g e t G u i B u t t o n C o l o r S e l e c t e d D a r k () {
return getColor (" g u i B u t t o n C o l o r S e l e c t e d D a r k ") ;
}
/**
* Returns the g u i B u t t o n C o l o r S e l e c t e d L i g h t .
* @return .
*/
public static Color g e t G u i B u t t o n C o l o r S e l e c t e d L i g h t () {
return getColor (" g u i B u t t o n C o l o r S e l e c t e d L i g h t ") ;
}
/**
* Returns the portColor .
* @return .
*/
public static Color getPortColor () {
return getColor (" portColor ") ;
}
/**
* Returns the guiColorDark .
* @return .
*/
public static Color getGuiColorDark () {
return getColor (" guiColorDark ") ;
}
A.4. Der Quelltext
401
402
460
450
440
430
420
/**
* Returns the r eplay StepT ime .
* @return .
*/
/**
* Returns the zoomOutFactor .
* @return .
*/
public static double g e t Z o o m O u t F a c t o r () {
return getDouble (" zoomOutFactor ") ;
}
/**
* Returns the zoomInFactor .
* @return .
*/
public static double g et Z oo m In F ac t or () {
return getDouble (" zoomInFactor ") ;
}
/**
* Returns the p s e u d o S t a t e N a m e O f f s e t .
* @return .
*/
public static Point g e t P s e u d o S t a t e N a m e O f f s e t () {
return getPoint (" p s e u d o S t a t e N a m e O f f s e t ") ;
}
/**
* Returns the li n eE n dD i am e te r .
* @return .
*/
public static int g e t L i n e E n d D i a m e t e r () {
return getInt (" l in e En d Di a me t er ") ;
}
/**
* Returns the labelOffset .
* @return .
*/
public static Point ge tLabe lOff set () {
return getPoint (" labelOffset ") ;
}
/**
* Returns the f i n a l S t a t e B o r d e r .
* @return .
*/
public static int g e t F i n a l S t a t e B o r d e r () {
return getInt (" f i n a l S t a t e B o r d e r ") ;
}
}
520
510
500
490
480
470
public static int ge tRe pl ayS te pTi me () {
return getInt (" replayStepTime ") ;
/**
* Returns the overviewColor .
/**
* Returns the gridVisible .
* @return .
*/
public static boolean getGridVisible () {
return getBoolean (" gridVisible ") ;
}
/**
* Returns the gridEnabled .
* @return .
*/
public static boolean getGridEnabled () {
return getBoolean (" gridEnabled ") ;
}
/**
* Returns the c e l l S e l e c t i o n T o l e r a n c e .
* @return .
*/
public static int g e t C e l l S e l e c t i o n T o l e r a n c e () {
return getInt (" c e l l S e l e c t i o n T o l e r a n c e ") ;
}
/**
* Returns the gridSize .
* @return .
*/
public static int getGridSize () {
return getInt (" gridSize ") ;
}
/**
* Returns the flipArea .
* @return .
*/
public static Rectangle getFlipArea () {
return getRectangle (" flipArea ") ;
}
/**
* Returns the r ep l ay S t ep T im e F as t .
* @return .
*/
public static int g e t R e p l a y S t e p T i m e F a s t () {
return getInt (" r ep l a yS t ep T i me F as t ") ;
}
}
A. Java-Programm-Quelltext
570
560
550
540
530
/**
* Returns the gridVisible .
* @return .
*/
public static boolean getShowGrid () {
return getBoolean (" gridVisible ") ;
}
/**
* Returns the s h o w O v e r v i e w L a y e r .
* @return .
*/
public static boolean g e t S h o w O v e r v i e w L a y e r () {
return getBoolean (" s h o w O v e r v i e w L a y e r ") ;
}
/**
* Returns the s h o w S p l a s h S c r e e n .
* @return .
*/
public static boolean g e t S h o w S p l a s h S c r e e n () {
return getBoolean (" s h o w S p l a s h S c r e e n ") ;
}
/**
* Returns the l ayout OnIns ert .
* @return .
*/
public static boolean g e t L a y o u t O n I n s e r t () {
return getBoolean (" lay outOn Inse rt ") ;
}
/**
* Returns the language .
* @return .
*/
public static String getLanguage () {
return PREFERENCES . getProperty (" language ") ;
}
/**
* Returns the l astFi lesCo unt .
* @return .
*/
public static int g e t L a s t F i l e s C o u n t () {
return getInt (" last Files Coun t ") ;
}
* @return .
*/
public static Color g e t O v e r v i e w C o l o r () {
return getColor (" overviewColor ") ;
}
620
610
600
590
580
/**
* .
*
*/
/**
* Returns the showSt ateActions .
* @return .
*/
public static boolean g e t S h o w C o l l a p s e B u t t o n s () {
return getBoolean (" s h o w C o l la p s e B u t t o n s ") ;
}
/**
* Returns the showSt ateActions .
* @return .
*/
public static boolean g e t S h o w S t a t e Ac t i o n s () {
return getBoolean (" showStateActions ") ;
}
/**
* Returns the s h o w A l i g n m e n t T o o l B a r O n L o a d .
* @return .
*/
public static boolean g e t S h o w A l i g n m e n t T o o l B a r O n L o a d () {
return getBoolean (" s h o w A l i g n m e n t T o o l B a r O n L o a d ") ;
}
/**
* Returns the s h o w R e p l a y T o o l B a r O n L o a d .
* @return .
*/
public static boolean g e t S h o w R e p l a y T o o l B a r O n L o a d () {
return getBoolean (" s h o w R e p l a y T o o l B a r O n L o a d ") ;
}
/**
*
*
*/
public static void toggleShowGrid () {
setProperty (" gridVisible " ,
(! getBoolean (" gridVisible ") ) + "") ;
}
/**
*
*
*/
public static void t o g g l e S h o w O v e r v i e w L a y e r () {
setProperty (" sh ow Ove rv iew La yer " ,
(! getBoolean (" sh owO ve rvi ew Lay er ") ) + "") ;
}
A.4. Der Quelltext
403
404
680
670
660
650
640
630
public static void t o g g l e S h o w S t a t e A c t i o n s () {
setProperty (" s h o w S t a t e A c t i o n s " , (! g e t S h o w S t a t e A c t i o n s () ) + "") ;
/**
* Returns the m o r p h i n g L a y o u t e r B o r d e r D i s t a n c e .
* @return .
*/
public static int g e t M o r p h i n g L a y o u t e r B o r d e r D i s t a n c e () {
return getInt (" m o r p h i n g L a y o u t e r B o r d e r D i s t a n c e ") ;
}
/**
* Returns the m o r p h i n g L a y o u t e r S p e e d .
* @return .
*/
public static int g e t M o r p h i n g L a y o u t e r S p e e d () {
return getInt (" m o r p h i n g L a y o u t e r S p e e d ") ;
}
/**
* .
*
*/
public static void t o g g l e S h o w C o m p o s i t e S t a t e E v e n t s () {
setProperty (" s h o w C o m p o s i t e S t a t e E v e n t s " ,
(! g e t S h o w C o m p o s i t e S t a t e E v e n t s () ) + "") ;
}
/**
* Returns the s h o w S t a t e A c t i o n s .
* @return .
*/
public static boolean g e t S h o w C o m p o s i t e S t a t e E v e n t s () {
return getBoolean (" s h o w C o m p o s i t e S t a t e E v e n t s ") ;
}
/**
* .
*
*/
public static void t o g g l e S h o w C o m p o s i t e S t a t e V a r i a b l e s () {
setProperty (" s h o w C o m p o s i t e S t a t e V a r i a b l e s " ,
(! g e t S h o w C o m p o s i t e S t a t e V a r i a b l e s () ) + "") ;
}
/**
* Returns the s h o w S t a t e A c t i o n s .
* @return .
*/
public static boolean g e t S h o w C o m p o s i t e S t a t e V a r i a b l e s () {
return getBoolean (" s h o w C o m p o s i t e S t a t e V a r i a b l e s ") ;
}
}
730
720
710
700
690
/**
* Returns the validAreaBorder .
* @return .
*/
public static int g e tV a li d A re a Bo r de r () {
return getInt (" validAreaBorder ") ;
/**
* Returns the i ni t ia l G ra p hO f f se t .
* @return .
*/
public static int g e t I n i t i a l G r a p h O f f s e t () {
return getInt (" i ni t i al G ra p h Of f se t ") ;
}
/**
* Returns the p la c eO f D ee p Hi s t or y .
* @return .
*/
public static Point g e t P l a c e O f D e e p H i s t o r y () {
return getPoint (" pl a c eO f De e pH i s to r y ") ;
}
/**
* Returns the defaul tRootState .
* @return .
*/
public static Dimension g e t D e f a u l t R o o t S t a t e () {
return getDimension (" defaul tRootState ") ;
}
/**
* Returns the defaultNode .
* @return .
*/
public static Dimension getDefaultNode () {
return getDimension (" defaultNode ") ;
}
/**
* Returns the defaultState .
* @return .
*/
public static Dimension getDefaultState () {
return getDimension (" defaultState ") ;
}
/**
* Returns the m o r p h i n g L a y o u t e r C h e c k I n t e r v a l .
* @return .
*/
public static int g e t M o r p h i n g L a y o u t e r C h e c k I n t e r v a l () {
return getInt (" m o r p h i n g L a y o u t e r C h e c k I n t e r v a l ") ;
}
A. Java-Programm-Quelltext
760
750
740
/**
* Returns the s i z e H a n d l e S e n s i t i v i t y .
* @return .
*/
public static int g e t S i z e H a n d l e S e n s i t i v i t y () {
return getInt (" s i z e H a n d l e S e n s i t i v i t y ") ;
}
/**
* Returns the s izeHa ndleS ize .
* @return .
*/
public static int g e t S i z e H a n d l e S i z e () {
return getInt (" size Handl eSiz e ") ;
}
/**
* Returns the t r a c e L o g S e p a r a t o r .
* @return .
*/
public static String g e t T r a c e L o g S e p a r a t o r () {
return PREFERENCES . getProperty (" t r a c eLo gS epa ra tor ") ;
}
}
780
770
}
/**
* Returns the s i z e H a n d l e S e n s i t i v i t y .
* @return .
*/
public static int g e t M o r p h i n g L a y o u t e r S t e p I n t e r v a l () {
return getInt (" m o r p h i n g L a y o u t e r S t e p I n t e r v a l ") ;
}
/**
* Returns the gridVisible .
* @return .
*/
public static boolean g e t S i z e H a n d l e V i s i b l e () {
return getBoolean (" si ze Han dl eVi si ble ") ;
}
/**
* Returns the sizeHandleColor .
* @return .
*/
public static Color ge t S iz e Ha n d le C ol o r () {
return getColor (" sizeHandleColor ") ;
}
A.4. Der Quelltext
405
406
30
20
10
40
60
/**
* Returns the value of the current resource bundle for the given key .
* @param key .
* @return .
*/
public static String getString ( final String key ) {
70
if ( instance . myResources != null ) {
try {
String value = instance . myResources . getString ( key ) ;
if ( value != null ) {
/**
* The logging handle . Prints logs to standard out .
*/
private static LogFile logFile = new LogFile (" Editor " , 2) ;
/**
* The singleton instance .
*/
private static Reso urce Bundl e instance = new ResourceBundle () ;
/**
* Provides access to the user language dependent displayed strings , like
label
* texts , menu texts , ...
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a > 50
* @version $Revision : 1.25 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class Reso urce Bundl e implements Preferences . Listener {
import kiel . util . LogFile ;
import java . util . Locale ;
import java . util . M i s s i n g R e s o u r c e E x c e p t i o n ;
package kiel . editor . resources ;
kiel.editor.resources.ResourceBundle
}
/**
* Creates the ResourceBundle object and adds itself to the Preferences
* listener list .
*/
private ResourceBundle () {
Preferences . addListener ( this ) ;
p re f e re n ce s C ha n ge d () ;
}
/**
* Is called when the user preferences have changed . If the user
preferenced
* language has changed , then another resource bundle has to be loaded .
* @see kiel . editor . resources . Preferences . Listener # pr e f e r e n c e s C h a n g e d ()
*/
public void p r ef e r en c es C h an g ed () {
System . setProperty (" user . language " , Preferences . getLanguage () ) ;
myResources = java . util . ResourceBundle . getBundle (
" kiel . editor . resources . MyResources " ,
new Locale ( Preferences . getLanguage () ) ) ;
}
/**
* Reference to the language dependent current resource bundle file .
*/
private java . util . ResourceBundle myResources ;
}
return key ;
}
}
return key ;
.") ;
return value ;
}
} catch ( M i s s i n g R e s o u r c e E x c e p t i o n e ) {
logFile . log (2 , " Key " + key + " not found in Reso urce Bundl e
A. Java-Programm-Quelltext
20
10
/**
* Returns the image .
* @param filename .
/**
* Caches the already loaded images .
*/
private static Hashtable images = new Hashtable () ;
40
30
/**
* Loads resources .
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.19 $ last modified $Date : 2005/07/25 11:44:36 $
*/
public final class Reso urce Loade r {
import javax . swing . ImageIcon ;
import java . util . Hashtable ;
package kiel . editor . resources ;
kiel.editor.resources.ResourceLoader
}
/**
* .
*
*/
private ResourceLoader () {
}
* @return .
*/
public static ImageIcon get ( final String filename ) {
if ( filename == null ) {
return null ;
}
Object result = images . get ( filename ) ;
if ( result == null ) {
result = new ImageIcon ( ResourceLoader . class . getResource ( filename
));
images . put ( filename , result ) ;
}
return ( ImageIcon ) result ;
}
A.4. Der Quelltext
407
408
50
40
30
20
10
60
90
80
70
/**
* @param disp layM essag e .
* @param isError .
* @param e .
*/
100
void h an d le E xc e pt i on ( final String displayMessage , final boolean isError
,
/**
* @param file .
*/
void open ( File file ) ;
/**
* @return .
*/
File getC urren tFil e () ;
/**
* For use as parent for dialogs
* @return .
*/
JFrame getJFrame () ;
/**
* @param file .
*/
void setC urren tFil e ( File file ) ;
/**
* @return .
*/
Object g e t F i l e I n t e r f a c e M o d e l () ;
/**
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.13 $ last modified $Date : 2005/07/14 15:31:09 $
*/
public interface IKielFrame {
import kiel . dataStructure . StateChart ;
import kiel . g r a p h i c a l I n f o r m a t i o n s . View ;
import javax . swing . JFrame ;
import javax . swing . JMenu ;
import java . io . File ;
import java . util . Collection ;
package kiel . util . main ;
kiel.util.main.IKielFrame
/**
/**
* Calls F il e In t e rf a ce M o de l . setStateChart ( StateChart ) ;
* Calls F il e In t e rf a ce M o de l . setActualView ( View ) ;
* Calls F il e In t e rf a ce M o de l . w r i t e S t a t e C h a r t F i l e (
getCurrentFile () , F il e I nt e rf a c eM o de l . g et Las tF ile F i l t e r () ) ;
* @param stateChart .
* @param view .
* @throws Exception .
*/
void wr i t e S t a t e C h a r t F i l e ( StateChart stateChart , View view )
throws Exception ;
/**
* .
* @return .
*/
File g e t F i l e I n t e r f a c e S a v e D i r () ;
/**
* Calls kiel . fileInterface . esterelstudio . NodeParser . pars eVari able s (
String )
* @param text .
* @return .
* @throws Exception an E s t u d i o P a r s e E x c e p t i o n
*/
Collection parseVariables ( String text ) throws Exception ;
/**
* Calls kiel . fileInterface . esterelstudio . GraphParser . parseSignals (
String )
* @param text .
* @return .
* @throws Exception an E s t u d i o P a r s e E x c e p t i o n
*/
Collection parseSignals ( String text ) throws Exception ;
/**
*
* @param layouterName .
* @return .
*/
KielLayouter g e t K i e l L a y o u t e r B y N a m e ( String layouterName ) ;
/**
*
*/
void r e si z eT o o lb a rP a n el () ;
final Exception e ) ;
A. Java-Programm-Quelltext
110
/**
* Dynamically creates the Layouter menu depending on what
* Handler . getHandeler () . g e t L a y o u t e r N a m es () will return . Hopefully
/**
* Calls F i l e I n t e r f a c e M o d e l . g e t S t a t e c h a rt Fil e () ;
* @return .
*/
File g e t S t a t e c h a r t F i l e () ;
130
* Calls F i l e I n t e r f a c e M o d e l . setStateChart ( StateChart ) ;
120
* Calls F i l e I n t e r f a c e M o d e l . setActualView ( View ) ;
* Calls F i l e I n t e r f a c e M o d e l . s h o w S a v e F i l eD i al o g () ;
* @param stateChart .
* @param view .
* @throws Exception .
*/
void w r i t e S t a t e C h a r t F i l e W i t h S a v e D i a l o g ( StateChart stateChart , View view )
throws Exception ;
}
/**
* .
* @param question .
* @return .
*/
boolean ask ( String question ) ;
* more then none : -)
* @param isRootMenu is this menu shown in the menu bar ?
* @param actionClass the Action class which contains code to be
executed
* when a layout request is handled . Browser and Editor have to provide
* their own action class with a constructor taking the name of the
* layouter .
* @return a new layouter menu object .
*/
JMenu c re a t eL a yo u t er M en u ( boolean isRootMenu , Class actionClass ) ;
A.4. Der Quelltext
409
410
50
40
30
20
10
60
/**
* @param aJToolBar .
* @param aMenuName .
* @param anIsVisible .
*/
public ToolBar ( final JToolBar aJToolBar , final String aMenuName ,
final boolean anIsVisible ) {
jToolBar = aJToolBar ;
menuName = aMenuName ;
isVisible = anIsVisible ;
/**
*
*/
private boolean isVisible ;
/**
*
*/
private String menuName ;
/**
*
*/
private JToolBar jToolBar ;
100
90
80
/**
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.8 $ last modified $Date : 2005/03/12 02:09:59 $
*/
public interface KielComponent {
70
/**
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </
a>
*/
public final class ToolBar {
import kiel . dataStructure . StateChart ;
import kiel . g r a p h i c a l I n f o r m a t i o n s . View ;
}
/**
/**
* @return all leading menu items in the file menu . they are followed by
* the file open menu item .
*/
JMenuItem [] g et Fil eM enu It ems 1 () ;
/**
* @return all menus that this component has , except for the file menu
* and the help menu .
*/
JMenu [] getRootMenus () ;
/**
* @param anIsVisible .
*/
public void setVisible ( final boolean anIsVisible ) {
isVisible = anIsVisible ;
}
/**
* @return .
*/
public boolean isVisible () {
return isVisible ;
}
/**
* @return .
*/
public String getMenuName () {
return menuName ;
}
/**
* @param toolBar .
*/
public void setJToolBar ( final JToolBar toolBar ) {
this . jToolBar = toolBar ;
}
/**
* @return .
*/
public JToolBar getJToolBar () {
return jToolBar ;
}
import
import
import
import
import
import
javax . swing . ImageIcon ;
javax . swing . JComponent ;
javax . swing . JMenu ;
javax . swing . JMenuItem ;
javax . swing . JTabbedPane ;
javax . swing . JToolBar ;
}
package kiel . util . main ;
kiel.util.main.KielComponent
A. Java-Programm-Quelltext
130
120
110
140
/**
* the main application frame components should be able to exchange
their
170
/**
* Sets the parent frame of the component . this frame should be used as
* parent for dialogs .
* @param parentFrame the main application frame .
*/
void setKielFrame ( IKielFrame parentFrame ) ;
/**
* @return sub panels . e . g . , console output , simulation output . can be
null .
*/
160
JTabbedPane getSubPanels () ;
/**
* @return the tree view . can be null .
*/
JComponent getTreePanel () ;
/**
* @return the components ’ main panel , e . g . the browser display panel or
* the editor graph panel .
*/
150
JComponent g e t M a i n C o m p o n e n t () ;
/**
* @return .
*/
ToolBar [] getToolBars () ;
* @return all menu items in the file menu between the print and the
exit
* menu item
*/
JMenuItem [] g e t F i l e M e n u I t e m s 2 () ;
}
/**
* @return .
*/
String g et Kie lF ram eT itl e () ;
/**
* @return the component in the right corner of the status line .
*/
JComponent g e t S t a t u s L i n e C o m p o n e n t () ;
/**
* @return an image icon for the switch button
*/
ImageIcon getImageIcon () ;
/**
* the main application frame components should be able to exchange
their
* current displayed / used statechart .
* @return view the current view
*/
View getCurrentView () ;
/**
* the main application frame components should be able to exchange
their
* current displayed / used statechart .
* @return statechart the current statechart
*/
StateChart g e t C u r r e n t S t a t e C h a r t () ;
* current displayed / used statechart .
* @param statechart the current statechart
* @param view the current view
*/
void s e t C u r r e n t S t a t e C h a r t ( StateChart statechart , View view ) ;
A.4. Der Quelltext
411
412
20
10
/**
*
/**
*
* @param statechart .
* @throws Exception .
*/
void setStatechart ( StateChart statechart ) throws Exception ;
40
30
/**
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.3 $ last modified $Date : 2005/07/18 15:04:19 $
*/
public interface KielLayouter {
import kiel . dataStructure . StateChart ;
import kiel . g r a p h i c a l I n f o r m a t i o n s . View ;
import kiel . configMngr . Configuration ;
package kiel . util . main ;
kiel.util.main.KielLayouter
}
/**
* Set the static view for the pseudolayouter .
* @param v View
*/
void setStaticView ( View v ) ;
/**
* @param config Configuration
* @return View
*/
View g e t C o n f i g u r a t i o n V i e w ( Configuration config ) ;
/**
*
* @param view .
*/
void layoutView ( View view ) ;
* @return .
*/
View getStaticView () ;
A. Java-Programm-Quelltext
50
40
30
20
10
java . awt . BorderLayout ;
java . awt . Color ;
java . awt . Component ;
java . awt . Dimension ;
java . awt . FlowLayout ;
java . awt . Toolkit ;
java . awt . event . ActionEvent ;
java . awt . event . KeyEvent ;
java . awt . event . MouseAdapter ;
java . awt . event . MouseEvent ;
java . awt . event . WindowAdapter ;
java . awt . event . WindowEvent ;
java . io . File ;
java . io . F il e In p ut S tr e am ;
java . io . F i l e N o t F o u n d E x c e p t i o n ;
java . io . F i l e O u t p u t S t r e a m ;
java . io . IOException ;
java . net . URL ;
java . util . Collection ;
java . util . Properties ;
javax . jnlp . BasicService ;
javax . jnlp . Servi ceMa nager ;
javax . swing . Abst ract Actio n ;
javax . swing . Abst ract Butto n ;
javax . swing . Action ;
javax . swing . ImageIcon ;
javax . swing . JCheckBox ;
javax . swing . J C h e c k B o x M e n u I t e m ;
javax . swing . JComponent ;
javax . swing . JFrame ;
javax . swing . JLabel ;
javax . swing . JMenu ;
javax . swing . JMenuBar ;
javax . swing . JMenuItem ;
javax . swing . JOptionPane ;
javax . swing . JPanel ;
javax . swing . JPopupMenu ;
javax . swing . JSplitPane ;
javax . swing . JTabbedPane ;
javax . swing . JToolBar ;
javax . swing . JWindow ;
javax . swing . KeyStroke ;
javax . swing . Swin gUti litie s ;
javax . swing . UIManager ;
javax . swing . border . LineBorder ;
javax . swing . plaf . Co l or U IR e so u rc e ;
javax . swing . plaf . metal . D e f a u l t M e t a l T hem e ;
javax . swing . plaf . metal . M e t a l L o o k A n d F eel ;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
package kiel ;
kiel.KielFrame
100
90
80
70
60
kiel . browser . Browser ;
kiel . dataStructure . StateChart ;
kiel . editor . Editor ;
kiel . editor . FileHistory ;
kiel . editor . Utils ;
kiel . editor . resources . Preferences ;
kiel . editor . resources . ResourceBundle ;
kiel . editor . resources . ResourceLoader ;
kiel . fileInterface . F i l e I n t e r f a c e E x c e p t i o n ;
kiel . fileInterface . Fi l eI n te r f ac e Mo d e l ;
kiel . fileInterface . F i l e I n t e r f a c e P r o p e r t i e s ;
kiel . fileInterface . esterelstudio . GraphParser ;
kiel . fileInterface . esterelstudio . NodeParser ;
kiel . g r a p h i c a l I n f o r m a t i o n s . View ;
kiel . layouter . Handler ;
kiel . layouter . LayoutException ;
kiel . layouter . Layouter ;
kiel . layouter . PseudoLayouter ;
kiel . optimizer . OptimizerChooser ;
kiel . util . M at lab Pr oce ss Inf o ;
kiel . util . main . IKielFrame ;
kiel . util . main . KielComponent ;
kiel . util . main . KielLayouter ;
kiel . configMngr . Configuration ;
if ( jwsHome != null ) { // Windows environment
jwsHome += "/ javaws / cache ";
} else { // Unix environment
jwsHome = System . getProperty (" deployment . javaws . splash . index ") ;
if ( jwsHome != null && jwsHome . indexOf ("/ cache / javaws ") != -1) {
jwsHome = jwsHome . substring (
0 , jwsHome . indexOf ("/ cache / javaws ") ) ;
jwsHome += "/ cache / javaws ";
String jwsHome = System . getProperty (" jnlpx . deployment . user . home ") ;
/**
* @param args .
* @throws Exception .
*/
public static void main ( final String [] args ) throws Exception {
/**
* <p > Copyright : ( c ) 2004 <a href =" http :// luepke . com " > Florian Luepke </ a > </p >
* <p > Company : Uni Kiel </ p >.
* @author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </a >
* @version $Revision : 1.84 $ last modified $Date : 2005/08/01 17:55:23 $
*/
public final class KielFrame extends JFrame implements IKielFrame ,
Preferences . Listener {
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
A.4. Der Quelltext
413
414
150
140
130
120
110
180
170
160
/**
* @see javax . swing . plaf . metal . MetalTheme # getControlInfo ()
210
/**
* @see javax . swing . plaf . metal . MetalTheme # getSecondary3 ()
*/
protected C ol o rU I Re s ou r ce getSecondary3 () {
return new C ol o rU I Re s ou r ce ( Preferences . getGuiColorDark () ) ;
}
/**
* @see javax . swing . plaf . metal . MetalTheme # getSecondary2 ()
*/
protected C ol o rU I Re s ou r ce getSecondary2 () {
return new C ol o rU I Re s ou r ce ( Preferences . getGuiColorDark () ) ;
200
}
/**
* @see javax . swing . plaf . metal . MetalTheme # getSecondary1 ()
*/
190
protected C ol o rU I Re s ou r ce getSecondary1 () {
return new C ol o rU I Re s ou r ce ( Preferences . getGuiColorDark () ) ;
}
M e t a l L o o k A n d F e e l . se t Cu r re n tT h em e ( new Def au ltM et alT he me () {
}
}
if ( jwsHome != null && jwsHome . trim () . length () > 0) {
System . setProperty (" java . library . path " ,
jwsHome + System . getProperty (" layouter . path ") ) ;
System . setProperty (" layouter . path . windows " ,
System . getProperty (" java . library . path ") ) ;
System . setProperty (" layouter . path . other " ,
System . getProperty (" java . library . path ") ) ;
F i l e I n t e r f a c e P r o p e r t i e s . getInstance () . setProperty (
F i l e I n t e r f a c e P r o p e r t i e s . PLUGINDIR ,
jwsHome + System . getProperty (" fileInterface . path ") ) ;
}
s e t P r e f e r e n c e s D e p e n d e n t U I D e f a u l t s () ;
UIManager . getDefaults () . put (" Menu . background " ,
new C o lo r UI R es ou r ce ( Color . WHITE ) ) ;
UIManager . getDefaults () . put (" MenuItem . background " ,
new C o lo r UI R es ou r ce ( Color . WHITE ) ) ;
UIManager . getDefaults () . put (" C h e c k B oxMenuItem . background " ,
new C o lo r UI R es ou r ce ( Color . WHITE ) ) ;
UIManager . getDefaults () . put (" Separator . background " ,
new C o lo r UI Re s ou r ce ( Color . WHITE ) ) ;
UIManager . getDefaults () . put (" Separator . shadow " ,
new C o lo r UI Re s ou r ce ( Color . WHITE ) ) ;
UIManager . getDefaults () . put (" Separator . highlight " ,
new C o lo r UI Re s ou r ce ( Color . WHITE ) ) ;
UIManager . getDefaults () . put (" Separator . foreground " ,
new C o lo rU I Re s ou r ce ( Color . WHITE ) ) ;
/**
*
*/
private static void s e t P r e f e r e n c e s D e p e n d e n t U I D e f a u l t s () {
UIManager . getDefaults () . put (" SplitPan eDivider . border " ,
new ColorUIResource ( Preferences . getGuiColorDark () ) ) ;
UIManager . getDefaults () . put (" SplitPane . background " ,
new ColorUIResource ( Preferences . getGuiColorDark () ) ) ;
UIManager . getDefaults () . put (" TabbedPane . selected " ,
new ColorUIResource ( Preferences . getGuiColorDark () ) ) ;
UIManager . getDefaults () . put (" TabbedPane . ta bAr ea Bac kg r o u n d " ,
}
JWindow w = new JWindow () ;
Dimension d = Toolkit . g et Def au ltT oo lki t () . getScreenSize () ;
final int screenWidth = 341;
final int screenHeight = 360;
w . setBounds (( d . width - screenWidth ) / 2 ,
( d . height - screenHeight ) / 2 , screenWidth , screenHeight ) ;
w . getContentPane () . setLayout ( new BorderLayout () ) ;
w . getContentPane () . add (
new JLabel ( ResourceLoader . get (" splashscreen3 . gif ") ) ) ;
if ( Preferences . g e t S h o w S p l a s h S c r e e n () ) {
w . setVisible ( true ) ;
}
KielFrame kielFrame = new KielFrame () ;
kielFrame . set Ki el Com po nen ts ( new KielComponent []{
new Editor ( kielFrame ) ,
new Browser ( kielFrame ) }) ;
kielFrame . setVisible ( true ) ;
if ( Preferences . g e t S h o w S p l a s h S c r e e n () ) {
w . dispose () ;
}
statusLeft . setIcon ( ResourceLoader . get (" logo_cau . gif ") ) ;
}) ;
/**
* @see javax . swing . plaf . metal . MetalTheme # get Me n u B a c k g r o u n d ()
*/
public ColorUIResource g etM en uBa ck gro un d () {
return new ColorUIResource ( Preferences . getGu i C o l o r L i g h t () ) ;
}
/**
* @see javax . swing . plaf . metal . MetalTheme # getControl ()
*/
public ColorUIResource getControl () {
return new ColorUIResource ( Preferences . getGu i C o l o r L i g h t () ) ;
}
*/
public ColorUIResource getControlInfo () {
return new ColorUIResource ( Preferences . getGu iC o lo r Da r k () ) ;
}
A. Java-Programm-Quelltext
260
250
240
230
220
()
300
290
280
270
for ( int i = 0; i < layouters . length ; i ++) {
try {
Action action = ( Action ) actionClass . getConstructor (
new Class []{ String . class }) . newInstance (
. toArray ( new String [0]) ;
String [] layouters = ( String []) Handler . instance () . ge tLayouterNames
310
JMenu layout ;
if ( isRootMenu ) {
layout = Utils . createJMenu (" ActionLayout " , " layoutMnemonic ") ;
} else {
layout = Utils . createJMenu (" ActionLayout " , " layoutMnemonic " ,
" layout . gif ") ;
}
/**
* @see kiel . util . main . IKielFrame # c r e a t e La y o ut e rM e n u (
* boolean , java . lang . Class )
*/
public JMenu c r e a t e L a y o u t e r M e n u ( final boolean isRootMenu ,
final Class actionClass ) {
}
new C o lo r UI R es o ur c e ( Preferences . getGuiCo lorLight () ) ) ;
UIManager . getDefaults () . put (" TabbedPane . background " ,
new C o lo r UI R es o ur ce ( Preferences . getGuiCo lorLight () ) ) ;
UIManager . getDefaults () . put (" ScrollBar . foreground " ,
new C o lo r UI R es o ur ce ( Preferences . getGuiCo lorLight () ) ) ;
UIManager . getDefaults () . put (" ScrollBar . background " ,
new C o lo r UI R es o ur ce ( Preferences . getGuiCo lorLight () ) ) ;
UIManager . getDefaults () . put (" ScrollBar . thumbHighlight " ,
new C o lo r UI R es ou r ce ( Preferences . getGuiColorDark () ) ) ;
UIManager . getDefaults () . put (" ScrollBar . thumbShadow " ,
new C o lo r UI R es ou r ce ( Preferences . getGuiColorDark () ) ) ;
UIManager . getDefaults () . put (" ScrollBar . thumb " ,
new C o lo r UI R es ou r ce ( Preferences . getGuiCol orLight () ) ) ;
UIManager . getDefaults () . put (" ScrollBar . darkShadow " ,
new C o lo r UI R es ou r ce ( Preferences . getGuiColorDark () ) ) ;
UIManager . getDefaults () . put (" ScrollBar . highlight " ,
new C o lo r UI Re s ou r ce ( Preferences . getGuiCol orLight () ) ) ;
UIManager . getDefaults () . put (" ScrollBar . shadow " ,
new C o lo r UI Re s ou r ce ( Preferences . getGuiCol orLight () ) ) ;
UIManager . getDefaults () . put (" Slider . highlight " ,
new C o lo r UI Re s ou r ce ( Preferences . getGuiCol orLight () ) ) ;
UIManager . getDefaults () . put (" Slider . darkShadow " ,
new C o lo rU I Re s ou r ce ( Preferences . getGuiColorDark () ) ) ;
UIManager . getDefaults () . put (" Slider . thumb " ,
new C o lo rU I Re s ou r ce ( Preferences . getGuiCol orLight () ) ) ;
UIManager . getDefaults () . put (" Menu . s e l e c t i o n B a c k g r o u n d " ,
new C o lo rU I Re s ou r ce ( Preferences . getGuiColorDark () ) ) ;
UIManager . getDefaults () . put (" MenuItem . s e l e c t i o n B a c k g r o u n d " ,
new C ol o rU I Re s ou r ce ( Preferences . getGuiColorDark () ) ) ;
/**
* @see kiel . util . main . IKielFrame # w r i t e S t a t e C h a r t F i l e W i t h S a v e D i a l o g (
* kiel . dataStructure . StateChart , kiel . g r a p h i c a l I n f o r m a t i o n s . View )
*/
}
F il e I nt e rf a ce M o de l fi l e In t er f a ce M od e l =
( F il e In t er f a ce M od e l ) g e t F i l e I n t e r f a c e M o d e l () ;
f il e I nt e rf a ce M o de l . setStateChart ( stateChart ) ;
f il e I nt e rf a ce M o de l . setActualView ( view ) ;
f il e I nt e rf a c eM o de l . w r i t e S t a t e C h a r t F i l e (
getCurrentFile () , f il e I nt e rf a ce M o de l . g et Las tF ile Fi lt e r () ) ;
/**
* @see kiel . util . main . IKielFrame # w r i t e S t a t e C h a r t F i l e (
* kiel . dataStructure . StateChart , kiel . g r a p h i c a l I n f o r m a t i o n s . View )
*/
public void w r i te S t a t e C h a r t F i l e ( final StateChart stateChart ,
final View view ) throws Exception {
/**
* .
* @return .
*/
public File g e t F i l e I n t e r f a c e S a v e D i r () {
return (( F i l eI n te r f ac e Mo d el ) g e t F i l e I n t e r f a c e M o d e l () ) . getSaveDir () ;
}
/**
* @see kiel . util . main . IKielFrame # parseVariables ( java . lang . String )
*/
public Collection parseVariables ( final String text ) throws Exception {
return NodeParser . parseVariables ( text ) ;
}
/**
* @see kiel . util . main . IKielFrame # parseSignals ( java . lang . String )
*/
public Collection parseSignals ( final String text ) throws Exception {
return GraphParser . parseSignals ( text ) ;
}
}
}
return layout ;
new Object []{ layouters [ i ]}) ;
JMenuItem mi = new JMenuItem ( action ) ;
final int ctrlAndShift = 3;
mi . setAccelerator ( KeyStroke . getKeyStroke ( KeyEvent . VK_F1 + i ,
ctrlAndShift ) ) ;
layout . add ( mi ) ;
} catch ( Exception e ) {
handleException ( e . getMessage () , true , e ) ;
}
A.4. Der Quelltext
415
416
360
350
340
330
320
380
370
/**
420
* @see kiel . editor . resources . Preferences . Listener # pr e f er e nc e s Ch a ng e d ()
*/
public void p r e f e r e n c e s C h a n g e d () {
s e t P r e f e r e n c e s D e p e n d e n t U I D e f a u l t s () ;
/**
390
* @see kiel . util . main . IKielFrame # g e t K i e l L a y o u t e r B y N a m e ( java . lang . String
)
*/
public KielLayouter g e t K i e l L a y o u t e r B y N a m e ( final String layouterName ) {
return new KielLayouter () {
private Layouter layouter = Handler . instance ()
. g e t L a y o u t e r N a m e d ( layouterName ) ;
public View getStaticView () {
return layouter . getStaticView () ;
400
}
public void layoutView ( final View view ) {
layouter . layoutView ( view ) ;
}
public View g e t C o n f i g u r a t i o n V i e w ( final Configuration config ) {
return layouter . g e t C o n f i g u r a t i o n V i e w ( config ) ;
}
public void setStatechart ( final StateChart statechart )
throws Exception {
layouter . setStatechart ( statechart ) ;
}
410
public void setStaticView ( final View v ) {
if ( layouter . getClass () == PseudoLayouter . class ) {
(( Pse udoLa yout er ) layouter ) . setView ( v ) ;
}
}
};
}
/**
* @see kiel . util . main . IKielFrame # g e t S t a tec ha rtF il e ()
*/
public File g e t S t a t e c h a r t F i l e () {
FileInterfaceModel fileInterfaceModel =
( F i l e I n t e r f a c e M o d e l ) g e t F i l e I n t e r f a c e M o d e l () ;
return f i l e I n t e r f a c e M o d e l . g e t S t a t e c ha rtF il e () ;
}
}
FileInterfaceModel fileInterfaceModel =
( F i l e I n t e r f a c e M o d e l ) g e t F i l e I n t e r f a c e M o d e l () ;
f i l e I n t e r f a c e M o d e l . setStateChart ( stateChart ) ;
f i l e I n t e r f a c e M o d e l . setActualView ( view ) ;
f i l e I n t e r f a c e M o d e l . s h o w S a v e F i l e D i a l o g () ;
public void w r i t e S t a t e C h a r t F i l e W i t h S a v e D i a l o g ( final StateChart
stateChart ,
final View view ) throws Exception {
/**
* @see kiel . util . main . IKielFrame # ask ( java . lang . String )
*/
public boolean ask ( final String question ) {
if ( s up p r es s ed M e ss a ge s . containsKey ( question + " YES ") ) {
return true ;
} else if ( s up p re s s ed M es s a ge s . containsKey ( question + " NO ") ) {
return false ;
} else {
MessagePanel messagePanel = new MessagePanel (
question , ResourceBundle . getString (" rememberAnsw er ") ) ;
int answer = JOptionPane . showOptionDi alog (
this ,
messagePanel ,
ResourceBundle . getString (" note ") ,
JOptionPane . OK_CANCEL_OPTION ,
JOptionPane . QUESTION_MESSAGE ,
null , new Object [] {
ResourceBundle . getString (" yes ") ,
ResourceBundle . getString (" no ") } ,
ResourceBundle . getString (" yes ") ) ;
/**
* Lists all messages that the user does not want to see anymore .
*/
private Properties s u p pr e ss e d Me s sa g e s = new Properties () ;
/**
*
*/
private File currentFile ;
/**
*
*/
private F il e I nt e rf a c eM o de l fileModel = new Fi l e In t er f a ce M o d e l () ;
/**
*
*/
private int current ;
/**
*
*/
private E x t e n d e d K i e l C o m p o n e n t [] kielComponents ;
}
for ( int i = 0; kielComponents != null && i < kielCo mpon ents . length ;
i ++) {
kielComponents [ i ]. p re f e re n ce s C ha n ge d () ;
}
updateContent ( current , current ) ;
repaint () ;
A. Java-Programm-Quelltext
470
460
450
440
430
}
/**
* .
* @param disp layM essag e .
*/
private void h a n d l e S u p p r e s s M e s s a g e ( final String displayMessage ) {
s u p p r e s s e d M e s s a g e s . put ( displayMessage , "") ;
try {
s u p p r e s s e d M e s s a g e s . store ( new F i leOutp utStream (
}
MessagePanel messagePanel = new MessagePanel (
displayMessage , Res ourc eBund le . getString (" doNotShowAgain ") ) ;
if ( i s A p p l i c a t i o n E r r o r ) {
JOptionPane . s h o w M e s s a g e D i a l o g ( this ,
messagePanel ,
Res ourc eBund le . getString (" error ") ,
JOptionPane . ERROR_MESSAGE ) ;
} else {
JOptionPane . s h o w M e s s a g e D i a l o g ( this ,
messagePanel ,
Res ourc eBund le . getString (" note ") ,
JOptionPane . I N F O R M A T I O N _ M E S S A G E ) ;
}
if ( messagePanel . i s C h e c k B o x S e l e c t e d () ) {
h a n d l e S u p p r e s s M e s s a g e ( d ispl ayMessage ) ;
}
if ( displ ayMe ssage == null
|| s u p p r e s s e d M e s s a g e s . containsKey ( displayMessage ) ) {
return ;
}
}
if ( i s A p p l i c a t i o n E r r o r && e != null ) {
e . p ri n tS t ac k Tr a ce () ;
/**
* @param disp layM essag e .
* @param i s A p p l i c a t i o n E r r o r .
* @param e .
*/
public void h a nd l eE xc e pt i on ( final String displayMessage ,
final boolean isApplicationError , final Exception e ) {
}
if ( messagePanel . i s C h e c k B o x S e l e c te d () ) {
if ( answer == 0) {
h a n d l e S u p p r e s s M e s s a g e ( question + " YES ") ;
} else {
h a n d l e S u p p r e s s M e s s a g e ( question + " NO ") ;
}
}
return answer == 0;
530
520
510
500
490
480
/**
* @see kiel . util . main . IKielFrame # getJFrame ()
*/
public JFrame getJFrame () {
return this ;
}
}
/**
* .
* @return .
*/
boolean i s Ch e ck B o xS e le c t ed () {
return checkBox . isSelected () ;
}
}
checkBox = new JCheckBox ( checkBoxMessage ) ;
setLayout ( new BorderLayout () ) ;
JLabel label = new JLabel ( displayMessage ) ;
add ( label , " Center ") ;
add ( checkBox , " South ") ;
final int height = 80;
int width = Math . max (
label . getP referredSize () . width ,
checkBox . get PreferredSize () . width ) ;
setPrefer redSize ( new Dimension ( width , height ) ) ;
/**
* @param displayMessage .
* @param checkBoxMessage .
*/
MessagePanel ( final String displayMessage ,
final String checkBoxMessage ) {
/**
* .
*/
private JCheckBox checkBox ;
/**
* @author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </
a>
*/
private class MessagePanel extends JPanel {
}
new File ( S U P P R E S S E D _ M E S S A G E S _ F I L E _ N A M E ) ) , null ) ;
} catch ( IOException ex ) {
if (!( ex instanceof F i l e N o t F o u n d E x c e p t i o n ) ) {
handleException ( ex . getMessage () , true , ex ) ;
}
}
A.4. Der Quelltext
417
418
580
570
560
550
540
610
600
590
/**
*
*/
private static final String S U P P R E S S E D _ M E S S A G E S _ F I L E _ N A M E =
System . getProperty (" user . home ")
+ File . separator
+ ". kiel "
/**
* @see kiel . util . main . IKielFrame # get CurrentFile ()
*/
public File getC urren tFil e () {
return currentFile ;
}
630
/**
* Is called with null when a new Chart is being created or with the new
* file name when the chart is saved .
* @see kiel . util . main . IKielFrame # set CurrentFile ( java . io . File )
*/
public void setC urren tFil e ( final File newFile ) {
currentFile = newFile ;
620
changeTitle () ;
FileHistory . getInstance ( this ) . add ( newFile ) ;
}
/**
*
*/
private void changeTitle () {
String modelSource = "";
if ( kielC ompo nents [ current ]. g e t C u r r e n t S t a t e C h a r t () != null ) {
modelSource = kie lCom ponen ts [ current ]. g e t C u r r e n t S t a t e C h a r t ()
. g etMod elSo urce () ;
}
if ( modelSource == null ) {
modelSource = "";
}
if ( currentFile != null ) {
setTitle ( currentFile . getName () + " - "
+ kielC ompo nents [ current ]. g e tK iel Fr ame Ti tle () + " "
+ modelSource ) ;
} else {
setTitle ( k ielCo mpon ents [ current ]. ge tKi el Fra me Tit le () + " "
+ modelSource ) ;
}
}
/**
* @see kiel . util . main . IKielFrame # g e t F i l e I n t e r f a c e M o d e l ()
*/
public Object g e t F i l e I n t e r f a c e M o d e l () {
return fileModel ;
}
Preferences . addListener ( this ) ;
final ImageIcon [] flipButtonIcons =
new ImageIcon [ aKielComponents . length ];
for ( int i = 0; aKielComponents != null && i < aKielC o mp o ne n ts .
length ;
i ++) {
kielComponents [ i ] = c r e a t e E x t e n d e d K i e l C o m p o n e n t ( a Ki e lC o mp o ne n ts [
i ]) ;
/**
* @param aKielComponents .
*/
public void se tK iel Co mpo ne nts ( final KielComponent [] aKie l Co m po n en t s ) {
if ( aKielComponents == null ) {
kielComponents = new E x t e n d e d K i e l C o m p o n e n t [0];
} else {
kielComponents = new E x t e n d e d K i e l C o m p o n e n t [ aKiel C om po n en t s .
length ];
}
}
try {
s up p r es s ed M e ss a ge s . load ( new FileInputStream (
SUPPRESSED_MESSAGES_FILE_NAME ));
} catch ( IOException e ) {
if (!( e instanceof F i l e N o t F o u n d E x c e p t i o n ) ) {
handleException ( e . getMessage () , true , e ) ;
}
}
ad dW ind ow Lis te ner ( new WindowAdapter () {
public void windowClosing ( final WindowEvent e ) {
new ActionFileExit () . actionPerformed ( null ) ;
}
}) ;
/**
*
*/
public KielFrame () {
super ( ResourceBundle . getString (" K I E L _ S t a t e c h a r t _ T o o l ") ) ;
s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . D O _ N O T H I N G _ O N _ C L O S E ) ;
Dimension d = Toolkit . g et Def au ltT oo lki t () . getScreenSize () ;
final int frameWidth = 850;
final int frameHeight = 500;
setBounds (( d . width - frameWidth ) / 2 , ( d . height - frameHeight ) / 2 ,
frameWidth , frameHeight ) ;
setIconImage ( ResourceLoader . get (" s mi ley Tr ans pa ren t . gif ") . getImage () )
;
+ File . separator
+ " KielFrame . properties ";
A. Java-Programm-Quelltext
680
670
660
650
640
700
690
statusPanel . add ( statusLeft , BorderLayout . CENTER ) ;
final int statusHeight = 23;
740
final A bstr actBu tton flipButton =
Utils . createJButton ( null , " t o o l t i p T o g g l e E d i t o r B r o w s e r ") ;
flipButton . setAction ( new Ab stra ctAction ("" ,
Res ourc eLoad er . get (" s m i l e y T r a n s par en t . gif ") ) {
710
public void a c ti o nP e rf o rm e d ( final ActionEvent e ) {
if ( k ielC ompon ents . length != 0) {
int newCurrent = ( current + 1) % kielComponents . length ;
updateContent ( current , newCurrent ) ;
flipButton . setIcon (
f li p Bu t to n Ic o ns [( current + 2) % kielComponents .
length ]) ;
kie lCom ponen ts [ newCurrent ]. s e t C u r r e n t S t a t e C h a r t (
kie lCom ponen ts [ current ]. g e t C u r r e n t S t a t e C h a r t () ,
kie lCom ponen ts [ current ]. getCurrentView () ) ;
current = newCurrent ;
720
changeTitle () ;
repaint () ;
}
}
}) ;
JToolBar flipToolbar = Utils . creat eJToolBar () ;
flipToolbar . setFloatable ( true ) ;
flipToolbar . add ( flipButton ) ;
toolbarPanel . add ( flipToolbar ) ;
730
final int toolbarSize = 32;
toolbarPanel . s e t P r e f e r r e d S i z e ( new Dimension ( toolbarSize , toolbarSize
));
get Conte ntPa ne () . add ( toolbarPanel , " North ") ;
get Conte ntPa ne () . add ( centerPanel , " Center ") ;
final int dividerSize = 3;
centerPanel . s etDi vider Size ( dividerSize ) ;
centerPanel . s etOr ienta tion ( JSplitPane . VERTICAL_SPLIT ) ;
toolbarPanel . a d d M o u s e L i s t e n e r ( new MouseAdapter () {
public void mousePressed ( final MouseEvent e ) {
if ( Swing Utili ties . i s R i g h t M o u se B u tt o n ( e ) ) {
kie lCom ponen ts [ current ]. getPopupMenu ()
. show ( toolbarPanel , e . getX () , e . getY () ) ;
}
}
}) ;
}
// This is needed to avoid multiple calls on getToolBar ()
// returning new Objects each time
kie lCom ponen ts [ i ]. g e t M a i n C o m p o n ent () . setBorder ( null ) ;
f li p Bu t to n Ic o ns [ i ] = kie lCom ponents [ i ]. getImageIcon () ;
if ( f li p Bu t to n Ic o ns [ i ] == null ) {
f li p Bu t to n Ic o ns [ i ] =
Res ourc eLoad er . get (" s m i l ey Tra ns pa ren t . gif ") ;
}
//
/**
* @param currentIndex .
* @param newIndex .
/**
*
*/
private JSplitPane centerPanel = new JSplitPane () ;
/**
*
*/
private JPanel toolbarPanel =
Utils . createJPanel ( new FlowLayout ( FlowLayout . LEFT , 0 , 0) ) ;
/**
* @param text .
*/
public static void setStatus ( final String text ) {
statusLeft . setText ( text ) ;
}
/**
*
*/
private static JLabel statusLeft = Utils . createJLabel () ;
/**
*
*/
private JPanel statusPanel = new JPanel ( new BorderLayout () ) ;
/**
* @see kiel . util . main . IKielFrame # re s iz e T oo l ba r P an e l ()
*/
public void r e si z e To o lb a r Pa n el () {
toolbarPanel . invalidate () ;
int width = 0;
for ( int i = 0; i < toolbarPanel . get Co mpo ne ntC ou nt () ; i ++) {
width += toolbarPanel . getComponent ( i ) . getPreferre dS i z e () . width ;
}
final int toolbarSize = 32;
toolbarPanel . setPreferredSi ze (
new Dimension ( toolbarSize ,
( int ) ( Math . ceil (( double ) width
/ ( double ) getSize () . width ) * toolbarSize ) ) ) ;
setVisible ( true ) ;
}
}
statusPanel . setP referredSize ( new Dimension (0 , statusHeight ) ) ;
getContentPane () . add ( statusPanel , BorderLayout . SOUTH ) ;
setStatus ("
Christian Albrecht University Kiel ") ;
updateContent ( current , current ) ;
A.4. Der Quelltext
419
420
780
770
760
750
}
for ( int i = 0; i < n e w K i e l C o m p o n e n t . getToolBars () . length ; i ++) {
if ( n e w K i e l C o m p o n e n t . getToolBars () [ i ]. isVisible () ) {
toolbarPanel . add (
n e w K i e l C o m p o n e n t . getToolBars () [ i ]. getJToolBar () ) ;
}
}
810
ge tCont entP ane () . remove ( c u r r e n t K i e l C o m p o n e n t . g e t C o m p l e t e C o m p o n e n t ()
)
if ( c u r r e n t K i e l C o m p o n e n t . getToolBars () [ i ]. isVisible () ) {
toolbarPanel . remove (
800
c u r r e n t K i e l C o m p o n e n t . getToolBars () [ i ]. getJToolBar () ) ;
}
for ( int i = 0; i < c u r r e n t K i e l C o m p o n e n t . getToolBars () . length ; i ++)
JMenuItem [] fi leMe nuIte ms1 = null ;
if ( kielC ompo nents . length != 0) {
fil eMenu Item s1 = ( JMenuItem []) newKiel Component .
g e t F i l e M e n u I t e m s 1 () ;
}
if ( fileM enuI tems1 != null ) {
for ( int i = 0; i < fileM enuI tems1 . length ; i ++) {
menu . add ( fil eMenu Item s1 [ i ]) ;
}
JMenu menu = Utils . createJMenu (" file " , " fileMnemonic ") ;
menubar . add ( menu ) ;
JMenuBar menubar = Utils . c reate JMen uBar () ;
setJMenuBar ( menubar ) ;
840
830
if ( c u r r e n t K i e l C o m p o n e n t . g e t S t a t u s L i n e C o m p o n e n t () != null ) {
statusPanel . remove ( c u r r e n t K i e l C o m p o n e n t . g e t S t a t u s L i n e C o m p o n e n t ()
820
);
}
if ( n e w K i e l C o m p o n e n t . g e t S t a t u s L i n e C o m p o n e n t () != null ) {
statusPanel . add ( n e w K i e l C o m p o n e n t . g e t S t a t u s L i n e C o m p o n e n t () , " East
") ;
}
r e s i z e T o o l b a r P a n e l () ;
s e t S t a t u s P a n e l V i s i b l e ( n e w K i e l C o m p o n ent . i s S t a t u s P a n e l V i s i b l e () ) ;
ge tCont entP ane () . add ( n e w K i e l C o m p o n e nt . g e t C o m p l e t e C o m p o n e n t () , "
Center ") ;
;
{
kie lComp onen ts [ newIndex ]. setKielFrame ( this ) ;
ExtendedKielComponent currentKielComponent =
kie lCom ponen ts [ currentIndex ];
E x t e n d e d K i e l C o m p o n e n t n e w K i e l C o m p o n ent = kielComponents [ newIndex ];
*/
private void updateContent ( final int currentIndex , final int newIndex )790
{
//
/**
* @author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </
a>
}
menu = Utils . createJMenu (" help " , " helpMnemonic ") ;
menubar . add ( menu ) ;
menu . add ( new ActionHelpAbout () ) ;
menu . add ( new ActionHelp Editor () ) ;
setVisible ( true ) ;
menu = Utils . createJMenu (" optimize " , " optimizeMnemon i c ") ;
menubar . add ( menu ) ;
menu . add ( new A ct ion Op tim iz eAl l () ) ;
menu . add ( new A c t i o n O p t i m i z e L e v e l () ) ;
JMenu [] rootMenus = null ;
if ( kielComponents . length != 0) {
rootMenus = ( JMenu []) newKielCo mponent . getRootMenus () ;
}
if ( rootMenus != null ) {
for ( int i = 0; i < rootMenus . length ; i ++) {
menubar . add ( rootMenus [ i ]) ;
}
}
menu . add ( FileHistory . getInstance ( this ) . getMenu () ) ;
menu . addSeparator () ;
mi = new JMenuItem ( new A c t i o n R e s e t M e s s a g e s () ) ;
mi . setAccelerator ( KeyStroke . getKeyStroke ( ’Q ’ , 2) ) ;
menu . add ( mi ) ;
menu . addSeparator () ;
mi = new JMenuItem ( new ActionFileExit () ) ;
mi . setAccelerator ( KeyStroke . getKeyStroke ( ’Q ’ , 2) ) ;
menu . add ( mi ) ;
JMenuItem [] fileMenuItems2 = null ;
if ( kielComponents . length != 0) {
fileMenuItems2 = ( JMenuItem []) newKi elComponent .
ge tF ile Me nuI te ms2 () ;
}
if ( fileMenuItems2 != null ) {
for ( int i = 0; i < fileMenuItems2 . length ; i ++) {
menu . add ( fileMenuItems2 [ i ]) ;
}
menu . addSeparator () ;
}
menu . addSeparator () ;
}
JMenuItem mi = new JMenuItem ( new ActionFileOpen () ) ;
mi . setAccelerator ( KeyStroke . getKeyStroke ( ’O ’ , 2) ) ;
menu . add ( mi ) ;
menu . addSeparator () ;
A. Java-Programm-Quelltext
880
870
860
850
910
900
890
930
/**
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </
a>
940
*/
class A c t i o n H e l p E d i t o r extends K i el F ra m eAction {
}
/**
* @see java . awt . event . Acti onLis tener #
* a ct i on P er f or m ed ( java . awt . event . ActionEvent )
*/
public void a c ti o nP er f or m ed ( final ActionEvent e ) {
}
/**
*
*/
A ct i on H el p Ab o ut () {
super (" Help16 . gif ") ;
setEnabled ( false ) ;
}
}
/**
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </
a>
*/
920
class A ct i on H el pA b ou t extends K ie l Fr a me Action {
/**
* Changes the Action . NAME according to the changes in the
Preferences
* class .
* @see kiel . editor . resources . Preferences . Listener #
p r e f e r e n c e s C h a n g e d ()
*/
public final void p r e f e r e n c e s C h a n g e d () {
putValue ( Action . NAME , R esour ceBundle . getString ( getClass () .
getName ()
. substring ( getClass () . getName () . lastIndexOf ( ’$ ’) + 1) ) ) ;
}
/**
* Adds the created object to the preferences listener list .
* @param iconName .
*/
protected K ie l Fr a me A ct i on ( final String iconName ) {
super ( null , R esour ceLo ader . get ( iconName ) ) ;
Preferences . addListener ( this ) ;
p r e f e r e n c e s C h a n g e d () ;
}
*/
abstract class Ki e lF r am e Ac t io n extends AbstractAction
implements Preferences . Listener {
/**
*
/**
* @author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </
a>
*/
class A c t i o n O p t i m i z e L e v e l extends KielFrameAction {
}
/**
* @see java . awt . event . ActionListener #
* actionPerformed ( java . awt . event . ActionEvent )
*/
public void actionPerformed ( final ActionEvent e ) {
optimize ( true ) ;
}
/**
*
*/
Ac ti onO pt imi ze All () {
super (" empty . gif ") ;
}
/**
* @author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </
a>
*/
class Act io nOp ti miz eA ll extends KielFrameAction {
}
/**
* @see java . awt . event . ActionListener #
* actionPerformed ( java . awt . event . ActionEvent )
*/
public void actionPerformed ( final ActionEvent e ) {
try {
(( BasicService ) ServiceManager
. lookup (" javax . jnlp . BasicService ") ) . showDocument (
new URL ( System . getProperty (" editor . manual . path ") ) ) ;
} catch ( Exception ex ) {
handleException ( ResourceBundle . getString (" jnlpU n av a il a bl e ") ,
false , ex ) ;
}
}
/**
*
*/
ActionHelp Editor () {
super (" Edit16 . gif ") ;
}
A.4. Der Quelltext
421
422
990
980
970
960
950
1020
1010
1000
/**
* @see java . awt . event . Acti onLis tener #
* a ct i on P er f or m ed ( java . awt . event . ActionEvent )
*/
public void a c ti on P er f or m ed ( final ActionEvent e ) {
s u p p r e s s e d M e s s a g e s . clear () ;
/**
*
*/
A c t i o n R e s e t M e s s a g e s () {
super (" About16 . gif ") ;
}
1040
/**
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke1030
</
a>
*/
class A c t i o n R e s e t M e s s a g e s extends K i el F rameAction {
/**
* .
* @param flag .
*/
private void optimize ( final boolean flag ) {
StateChart st = k ielC ompon ents [ current ]. g e t C u r r e n t S t a t e C h a r t () ;
if ( st == null ) {
return ;
}
O p t i m i z e r C h o o s e r . startOptimize ( st , flag ) ;
Layouter layouter = Handler . instance () . g e tD e fa u lt L a yo u te r () ;
try {
layouter . setStatechart ( st ) ;
layouter . layoutView ( layouter . getStaticView () ) ;
} catch ( L a yo u tE x ce p ti o n ex ) {
h an d le E xc e pt i on ( ex . getMessage () , false , ex ) ;
}
kie lCom ponen ts [ current ]. s e t C u r r e n t S t a t e C h a r t (
st , layouter . getStaticView () ) ;
}
}
/**
* @see java . awt . event . Acti onLis tener #
* a ct i on P er f or m ed ( java . awt . event . ActionEvent )
*/
public void a c ti o nP er f or m ed ( final ActionEvent e ) {
optimize ( false ) ;
}
*/
A c t i o n O p t i m i z e L e v e l () {
super (" empty . gif ") ;
}
}
/**
* @see java . awt . event . ActionListener #
* actionPerformed ( java . awt . event . ActionEvent )
*/
/**
*
*/
ActionFileOpen () {
super (" Open16 . gif ") ;
}
/**
* @author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </
a>
*/
class ActionFileOpen extends KielFrameAction {
}
/**
* @see java . awt . event . ActionListener #
* actionPerformed ( java . awt . event . ActionEvent )
*/
public void actionPerformed ( final ActionEvent e ) {
boolean yes = ask ( ResourceBundle . getString (" exit Ap p li c at i on ") ) ;
if ( yes ) {
Ma tl abP ro ces sI nf o . shutdownMatlab () ;
System . exit (0) ;
}
}
/**
*
*/
ActionFileExit () {
super (" Stop16 . gif ") ;
}
/**
* @author <a href =" mailto : [email protected] . uni - kiel . de " > Florian Luepke </
a>
*/
class ActionFileExit extends KielFrameAction {
}
try {
s up p r es s ed M e ss a ge s . store ( new FileOu tputStrea m (
new File ( S U P P R E S S E D _ M E S S A G E S _ F I L E _ N A M E ) ) , null ) ;
} catch ( IOException ex ) {
if (!( ex instanceof F i l e N o t F o u n d E x c e p t i o n ) ) {
handleException ( ex . getMessage () , true , ex ) ;
}
}
A. Java-Programm-Quelltext
1090
1080
1070
1060
1050
1110
1100
/**
* @author <a href =" mailto : flu @info rmat ik . uni - kiel . de " > Florian Luepke </
1150
a>
*/
private abstract static class E x t e n d e d K i e l C o m p o n e n t
implements KielComponent , Preferences . Listener {
/**
*
*/
1120
private void s e t L o a d e d S t a t e c h a r t () {
try {
if ( fileModel . getStateChart () != null ) {
if ( fileModel . getActualView () == null ) {
Layouter layouter = Handler . instance () . g e tD e fa u lt L a yo u te r () ;
try {
layouter . setStatechart ( fileModel . getStateChart () ) ;
layouter . layoutView ( layouter . getStaticView () ) ;
} catch ( L a yo u tE x ce p ti o n e ) {
1130
h an d le E xc e pt i on ( e . getMessage () , false , e ) ;
}
fileModel . setActualView ( layouter . getStaticView () ) ;
}
kie lCom ponen ts [ current ]. s e t C u r r e n t S t a t e C h a r t (
fileModel . getStateChart () ,
fileModel . getActualView () ) ;
set Curr entFi le ( fileModel . g e t S t a t ech ar tFi le () ) ;
} else {
h an d le E xc e pt i on ( R esou rceBu ndle . getString (" fileNotFound ") ,
true , null ) ;
1140
}
} catch ( F i l e I n t e r f a c e E x c e p t i o n ex ) {
h an d le E xc e pt i on ( ex . toString () ,
false , ex ) ;
}
}
/**
* @see kiel . util . main . IKielFrame # open ( java . io . File )
*/
public void open ( final File file ) {
try {
fileModel . r e a d S t a t e C h a r t F i l e ( file ) ;
s e t L o a d e d S t a t e c h a r t () ;
} catch ( F i l e I n t e r f a c e E x c e p t i o n e ) {
h an d le E xc e pt i on ( e . getMessage () , false , e ) ;
}
}
}
public void a c ti o nP e rf o rm e d ( final ActionEvent e ) {
fileModel . s h o w O p e n F i l e D i a l o g () ;
s e t L o a d e d S t a t e c h a r t () ;
}
/**
* @return .
*/
protected JPanel getFiller2 () {
/**
*
*/
private JPanel filler2 = new JPanel () ;
/**
* @return .
*/
protected JPanel getFiller1 () {
return filler1 ;
}
/**
*
*/
private JPanel filler1 = new JPanel () ;
/**
* @return .
*/
protected JPanel getNorthPanel () {
return northPanel ;
}
/**
*
*/
private JPanel northPanel = new JPanel ( new BorderLayout () ) ;
/**
*
*/
public abstract void p re f er e n ce s Ch a n ge d () ;
/**
* @return .
*/
abstract JPopupMenu getPopupMenu () ;
/**
* @return .
*/
abstract JComponent g e t C o m p l e t e C o m p o n e n t () ;
/**
* @return .
*/
abstract boolean i s S t a t u s P a n e l V i s i b l e () ;
A.4. Der Quelltext
423
424
1200
1190
1180
1170
1160
/**
* @return .
*/
protected JPanel getFiller3 () {
return filler3 ;
}
1240
1230
1220
1210
{
private ToolBar [] toolBars = kielComponent . getToolBars () ;
private JPopupMenu popupMenu = new JPopupMenu () ;
private JComponent mainComponent = kielComponent .
g e t M a i n C o m p o n e n t () ;
private JComponent treePanel = kielComponent . getTreePanel () ;
private JTabbedPane subPanels = kielComponent . getSubPanels () ;
private JComponent s t a t u s L i n e C o m p o n e n t =
kielComponent . g e t S t a t u s L i n e C o m p o n e n t () ;
private KielComponent o r i g i n a l K i e l C o m p o n e n t = kielComponent ;
private boolean i s S t a t u s P a n e l V i s i b l e = true ;
1250
public boolean i s S t a t u s P a n e l V i s i b l e () {
return i s S t a t u s P a n e l V i s i b l e ;
}
private JComponent c o m p l e t e C o m p on en t ;
return new E x t e n d e d K i e l C o m p o n e n t () {
/**
* @param kielComponent .
* @return .
*/
private E x t e n d e d K i e l C o m p o n e n t c r e a t e E x t e n d e d K i e l C o m p o n e n t (
final KielComponent kielComponent ) {
/**
* @param isVisible .
*/
private void s e t S t a t u s P a n e l V i s i b l e ( final boolean isVisible ) {
if (! isVisible ) {
get Conte ntPa ne () . remove ( statusPanel ) ;
} else {
get Conte ntPa ne () . add ( statusPanel , " South ") ;
}
ge tCont entP ane () . invalidate () ;
setVisible ( true ) ;
}
}
return filler2 ;
/**
*
*/
private JPanel filler3 = new JPanel () ;
}
setVisible
...
;
...
Preferences . addListener ( this ) ;
// of the toolbar
final JCh ec kBo xM enu It em item =
new JC hec kB oxM en uIt em (
toolBars [ toolBarIndex ]. getMenuName () ,
toolBars [ toolBarIndex ]. isVisible () ) ;
item . setAction (
new AbstractAction (
toolBars [ toolBarIndex ]. getMenuName () ) {
public void actionPerformed ( final ActionEvent e ) {
if ( item . isSelected () ) {
toolbarPanel . add (
toolBars [ toolBarIndexx ]. getJToolBar () ) ;
} else {
toolbarPanel . remove (
if ( toolBars [ toolBarIndex ]. getJToolBar () . getClass ()
== JToolBar . class ) {
JToolBar newToolBar = Utils . createJTool Bar () ;
for ( int j = 0; j < components . length ; j ++) {
newToolBar . add ( components [ j ]) ;
}
toolBars [ toolBarIndex ]. setJToolBar ( newToolBar ) ;
}
// Add item to the toolbarPanel popup - Menu for
// Check if the toolbars are Utils . createJ ToolB ar () - like
for ( int j = 0; j < components . length ; j ++) {
(( JComponent ) components [ j ]) . setPref e r r e d S i z e (
new Dimension (
components [ j ]. getPreferr e d S i z e () . width ,
buttonHeight ) ) ;
(( JComponent ) components [ j ]) . setOpaque ( false ) ;
}
Component [] components =
toolBars [ toolBarIndex ]. getJToolBar () . getComponents ()
for ( int toolBarIndex = 0; toolBarIndex < toolBars . length ;
toolBarIndex ++) {
final int toolBarIndexx = toolBarIndex ;
// set the toolbar components height and opaque property
// set the toolbars ...
final int buttonHeight = 28;
JMenu [] rootMenus = kielComponent . getRootMenus () ;
// the root Menus ...
for ( int i = 0; rootMenus != null && i < rootMenus . length ;
i ++) {
rootMenus [ i ]. setOpaque ( false ) ;
}
A. Java-Programm-Quelltext
1300
1290
1280
1270
1260
*/
/*
);
{
1330
JPanel p = new JPanel ( new BorderLayout () ) ;
p . add ( label , " North ") ;
p . add ( subPanels . get ComponentAt (0) , " Center ") ;
subPanel =
Utils . c r e a t e F l o a t a b l e C o m p o n e n t F o r S p l i t P a n e ( p ) ;
final int labelHeight = 18;
if ( subPanels != null ) {
if ( subPanels . getTabCount () == 1) {
1350
JLabel label = Utils . c r e a t e J L a b e l H o r i z o n t a l () ;
label . setText (" " + subPanels . getTitleAt (0) ) ;
label . s e t P r e f e r r e d S ize ( new Dimension (0 , labelHeight )
// set the rest ...
JComponent subPanel = subPanels ;
}
if ( getSubPanels () != null ) {
final J C h e c k B o x M e n u I t e m i n f o r m a t i o n P a n e l I t e m =
new J C h e c k B o x M e n u I t em (" Information Panels " , true ) ;
i n f o r m a t i o n P a n e l I t e m . setAction (
new Abst ractA ctio n (" Information Panels ") {
public void a c ti o nP erformed ( ActionEvent e ) {
}
1340
}) ;
popupMenu . add ( i n f o r m a t i o n P a n e l I t e m ) ;
}
public void a c ti o nP erformed ( ActionEvent e ) {
}
}) ;
popupMenu . add ( treePanelItem ) ;
}
final J C h e c k B o x M e n u I t e m s t atusPanelItem =
new J C h e c k B o x M e n u I t e m (" Status Bar " , true ) ;
s ta t us P an e lI t em . setAction ( new AbstractAction (" Status Bar ") {
public void a ct i on P er f ormed ( final ActionEvent e ) {
i s S t a t u s P a n e l V i s i b l e = statusPanelItem . isSelected1320
() ;
setStatusPanelVisible ( isStatusPanelVisible );
}
}) ;
popupMenu . add ( s t at u sP a ne l It em ) ;
if ( getTreePanel () != null ) {
final J C h e c k B o x M e n u I t e m treePanelItem =
new J C h e c k B o x M e n u I t em (" Tree View " , true ) ;
treePanelItem . setAction ( new AbstractAction (" Tree View ")
}
}) ;
popupMenu . add ( item ) ;
toolBars [ toolBarIndexx ]. getJToolBar () ) ;
1310
}
r e s i z e T o o l b a r P a ne l () ;
toolBars [ toolBarIndexx ]. setVisible (
item . isSelected () ) ;
co mp let eC omp on ent = new JSplitPane (
null , i ) ;
}
subPanel = Utils .
createFloatableComponentForSplitPane (
subPanels ) ;
}
}
final int dividerSize = 3;
final int dividerLocation = 150;
final double d i v i d e r L o c a t i o n F l o a t = 0.8;
final int i n i t i a l D i v i d e r L o c a t i o n = 1000;
if ( getTreePanel () == null && getSubPanels () == null ) {
co mp let eC omp on ent = getMainComponen t () ;
} else if ( getTreePanel () != null && getSubPanels () == null )
{
co mp let eC omp on ent = new JSplitPane (
JSplitPane . HORIZONTAL_SPLIT , createTreeP a ne l () ,
getMainCom ponent () ) ;
(( JSplitPane ) com pl ete Co mpo ne nt ) . setDividerS ize (
dividerSize ) ;
(( JSplitPane ) com pl ete Co mpo ne nt ) . se t D iv i de r L o c a t i o n (
dividerLocation ) ;
(( JSplitPane ) com pl ete Co mpo ne nt ) . setBorder ( null ) ;
} else if ( getTreePanel () == null && getSubPanels () != null )
{
co mp let eC omp on ent = new JSplitPane (
JSplitPane . VERTICAL_SPLIT ,
getMainCom ponent () , subPanel ) ;
(( JSplitPane ) com pl ete Co mpo ne nt ) . setDividerS ize (
dividerSize ) ;
(( JSplitPane ) com pl ete Co mp one nt ) . se t D iv i de r L o c a t i o n (
dividerLocationFloat );
(( JSplitPane ) com pl ete Co mp one nt ) . setBorder ( null ) ;
} else {
JSplitPane top = new JSplitPane (
JSplitPane . HORIZONTAL_SPLIT ,
createTreePanel () , getMainC omponent () ) ;
top . setSize ( initialDividerLocation ,
initialDividerLocation );
// For initial divider location
(( JSplitPane ) top ) . setDividerSize ( dividerSize ) ;
(( JSplitPane ) top ) . se t Di v id e r Lo c at i o n ( divid er L oc a ti o n ) ;
(( JSplitPane ) top ) . setBorder ( null ) ;
c),
} else if ( subPanels . getTabCount () > 1) {
for ( int i = 0; i < subPanels . getTabCount () ; i ++) {
String title = subPanels . getTitleAt ( i ) ;
JComponent c =
( JComponent ) subPanels . getComponen tAt ( i ) ;
subPanels . removeTabAt ( i ) ;
subPanels . insertTab ( title , null ,
Utils . c r e a t e F l o a t a b l e C o m p o n e n t F o r T a b b e d P a n e (
A.4. Der Quelltext
425
426
1410
1400
1390
1380
1370
1360
);
);
}
panel . add ( getNorthPanel () , " North ") ;
getFiller1 () . s e t P r e f e r r e d S i ze ( new Dimension (
spaceNorth , spaceNorth ) ) ;
panel . add ( getFiller1 () , " West ") ;
getFiller2 () . s e t P r e f e r r e d S i ze ( new Dimension (
spaceWest , spaceWest ) ) ;
panel . add ( getFiller2 () , " East ") ;
getFiller3 () . s e t P r e f e r r e d S i ze ( new Dimension (
spaceEast , spaceEast ) ) ;
panel . add ( getFiller3 () , " South ") ;
panel . add ( getTreePanel () , " Center ") ;
p r e f e r e n c e s C h a n g e d () ;
label = new JLabel () ;
label . s e t P r e f e r r e d S i z e ( new Dimension (0 , labelHeight ) ) ;
label . setOpaque ( false ) ;
getNorthPanel () . add ( label , " Center ") ;
1460
1450
JLabel label = Utils . c r e a t e J L a b e l H o r i z o n t a l () ;
label . setText (" " + Resou rceBundle . getString (" treeView ") ) ;
label . s e t P r e f e r r e d S i z e ( new Dimension (0 , labelHeight ) ) ;
getNorthPanel () . add ( label , " North ") ;
private JComponent c r ea t eT r ee P anel () {
final int space = 46;
final int labelHeight = 18;
final int spaceNorth = 6;
final int spaceWest = 6;
final int spaceEast = 22;
JPanel panel = new JPanel ( new BorderLayout () ) ;
1440
getNorthPanel () . s e t P r e f e r r e dSize ( new Dimension ( space , space
)
}
getFiller1 () . setBackground ( Preferences . getGuiC olorLight () ) ;
getFiller2 () . setBackground ( Preferences . getGuiC olorLight () ) ;
getFiller3 () . setBackground ( Preferences . getGuiC olorLight () ) ;
if ( getTreePanel () != null ) {
getTreePanel () . setBorder (
new LineBorder ( Preferences . getGuiColorDark () ) ) ;
}
1430
1420
public void p r e f e r e n c e s C h a n g e d () {
getNorthPanel () . setBackground ( Preferences . getGuiCol orLight ()
}
JSplitPane . VERTICAL_SPLIT , top , subPanel ) ;
(( JSplitPane ) c o m p l e t e C o mp one nt ) . setDividerSize (
dividerSize ) ;
(( JSplitPane ) c o m p l e t e C o mp one nt ) . s et D iv i d er L oc a t io n (
dividerLocationFloat );
(( JSplitPane ) c o m p l e t e C o mp one nt ) . setResizeWeight (1.0) ;
(( JSplitPane ) c o m p l e t e C o mp one nt ) . setBorder ( null ) ;
;
}
public String g et Kie lF ram eT it le () {
return o r i g i n a l K i e l C o m p o n e n t . ge tK iel Fr am eTi t l e () ;
}
public JPopupMenu getPopupMenu () {
return popupMenu ;
}
public JComponent get MainComponent () {
return mainComponent ;
}
public JComponent getTreePanel () {
return treePanel ;
}
public JTabbedPane getSubPanels () {
return subPanels ;
}
public JMenuItem [] ge tF ile Me nuI te ms1 () {
return kielComponent . get Fi leM en uIt em s1 () ;
}
public JMenuItem [] ge tF ile Me nuI te ms2 () {
return kielComponent . get Fi leM en uIt em s2 () ;
}
public JMenu [] getRootMenus () {
return kielComponent . getRootMenus () ;
}
public JComponent g e t S t a t u s L i n e C o m p o n e n t () {
return s t a t u s L i n e C o m p o n e n t ;
}
public View getCurrentView () {
return o r i g i n a l K i e l C o m p o n e n t . getCurrentView () ;
}
public StateChart g e t C u r r e n t S t a t e C h a r t () {
return o r i g i n a l K i e l C o m p o n e n t . g e t C u r r e n t S t a t e C h a r t () ;
}
public void setKielFrame ( final IKielFrame kielFrame ) {
o r i g i n a l K i e l C o m p o n e n t . setKielFrame ( kielFrame ) ;
}
public ImageIcon getImageIcon () {
return o r i g i n a l K i e l C o m p o n e n t . getImageIcon () ;
}
public void s e t C u r r e n t S t a t e C h a r t ( final StateChart stateChart ,
final View view ) {
o r i g i n a l K i e l C o m p o n e n t . s e t C u r r e n t S t a t e C h a r t ( stateChart , view )
return Utils . c r e a t e F l o a t a b l e C o m p o n e n t F o r S p l i t P a n e ( panel ) ;
}
public JComponent g e t C o m p l e t e C o m p o n e n t () {
return c om ple te Com po nen t ;
}
public ToolBar [] getToolBars () {
return toolBars ;
}
A. Java-Programm-Quelltext
}
};
}
A.4. Der Quelltext
427
Was this manual useful for you? yes no
Thank you for your participation!

* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project

Download PDF

advertisement