ProFLOW Tutorial Dieses Dokument soll dazu dienen, die Installation, Benutzung und Erweiterungsmöglichkeiten des ProFLOW Frameworks zu erklären. 1. Installation ............................................................................................... 2 2. Benutzung ................................................................................................ 4 Anlegen eines neuen Projekts ...................................................................................... 4 Erzeugen eines neuen Diagramms ............................................................................... 4 Editieren eines Diagramms .......................................................................................... 5 Weitere Features .......................................................................................................... 6 3. Erweiterung ............................................................................................. 7 Learning from Examples.............................................................................................. 7 Anlegen einen neuen Plug-In Projects ......................................................................... 8 Erzeugen eines neuen Prozesses .................................................................................. 9 Starten einer Runtime Workbench ............................................................................. 11 Erzeugen eines neuen Prozesselements ..................................................................... 12 Erzeugen einer neuen Transition................................................................................ 16 Erzeugen einer neuen Annotation .............................................................................. 17 Definieren der Editorpalette....................................................................................... 20 Registrieren von zusätzlichen Attributen ................................................................... 22 Registrieren von Process Actions............................................................................... 25 Registrieren von Model Object Actions..................................................................... 27 Verwendung von Commands..................................................................................... 29 Deployen des Plug-Ins ............................................................................................... 31 1. Installation ProFLOW wurde mit und für Eclipse 3.2 entwickelt. Das Eclipse 3.2 Release steht unter folgendem Link zur Verfügung: http://download.eclipse.org/eclipse/downloads/ Zur Installation von Eclipse muss lediglich die heruntergeladene .zip-Datei in einen gewünschten Zielordner entpackt werden. Außerdem benötigt man noch das Graphical Editing Framework (GEF) in der entsprechenden Version 3.2. Dieses ist unter dem folgenden Link verfügbar: http://download.eclipse.org/tools/gef/downloads/index.php Die hierzu gehörende .zip-Datei muss ebenfalls lediglich in den Eclipse-Ordner entpackt werden. Dabei werden die Unterordner /features und /plugins um einige Dateien und Ordner erweitert. Abschließend muss nun noch das ProFLOW Framework installiert werden. Hierzu muss ebenfalls lediglich die gegebene .zip-Datei in den Eclipse-Ordner entpackt werden, sodass die Unterordner /features und /plugins mit den notwendigen Dateien erweitert werden. Abschließend müssen sie nun nur noch die beiden Frameworks GEF und ProFLOW in Eclipse aktivieren. Führen sie hierfür folgende Schritte aus: 1. Starten sie Eclipse (Ausführen der eclipse.exe im Eclipse-Ordner) 2. Aktivieren sie die beiden Frameworks unter Help Æ Software Updates Æ Manage Configuration 3. Aktivieren sie den dritten Schalter in der Toolbar-Leiste "Show Disabled Features" und aktivieren sie die deaktivierten Frameworks GEF und ProFLOW (auswählen und "enablen" … siehe Abbildung 1-1) 4. Schließen und Starten sie Eclipse neu Die Installation ist somit abgeschlossen und sie können ihre ersten ProFLOW Diagramme erstellen. Außerdem ist es nun auch möglich, neue Eclipse Plug-ins zu entwickeln, welche auf ProFLOW aufbauen und das Framework um weitere Diagrammtypen erweitern. Hierauf soll nun in den folgenden Kapiteln eingegangen werden. Abbildung 1-1 2. Benutzung In diesem Kapitel soll nun kurz darauf eingegangen werden, wie sie mittels ProFLOW Diagramme erstellen können. Anlegen eines neuen Projekts ProFLOW Diagramme müssen einem Projekt zugeordnet sein. Somit benötigen sie, bevor sie ein ProFLOW Diagramm erstellen möchten, zunächst ein Projekt. Es genügt, wenn sie ein einfaches Projekt anlegen. Starten sie hierfür den Menupunkt: File Æ New Æ Project.. Es erscheint somit der Project Creation Wizard. Hier wählen sie den Eintrag Project im Ordner General aus. Natürlich können sie hier auch jeden anderen Projekttyp auswählen. Erzeugen eines neuen Diagramms Haben sie ein neues Projekt erstellt, können sie in diesem ein neues ProFLOW Diagramm erzeugen. Rechtsklicken sie auf ihr neu angelegtes Projekt und starten sie den folgenden Kontextmenueintrag: New Æ Other.. In dem erscheinenden Creation Wizard wählen sie nun den Eintrag ProFLOW Diagram im Other Ordner aus und drücken sie Next. In der folgenden Wizard Page können sie den Diagrammtyp auswählen. Hier können sie zwischen allen registrierten Diagrammtypen wählen. Das Description-Feld liefert die Beschreibung zu dem ausgewählten Diagrammtyp. Haben sie sich für einen Diagrammtyp entschieden, müssen sie in der folgenden Wizard Page nun nur noch den Namen und den Dateinamen des zu erstellenden Diagramms definieren. ProFLOW Diagramm Dateien müssen mit der Extension .proFLOW enden. Schließt man den Creation Wizard mit Finish wird die erzeugte .proFlowDatei mit dem grafischen ProFLOW Editor geöffnet. Editieren eines Diagramms In dem geöffneten ProFLOW Editor können sie nun ihr Diagramm erzeugen. Hierfür müssen sie lediglich ein gewünschtes Element in der Palette auswählen und in der Zeichenfläche platzieren. Das Cursor-Feedback zeigt dabei an, ob das Hinzufügen eines Elementes bzw. das Verbinden zweier Elemente miteinander über eine Transition zulässig ist. Die Palette des jeweiligen Editors beinhaltet immer die Elemente des jeweiligen Diagrammtyps sowie alle FLOW Elemente. Außerdem stehen immer die Paletteneinträge Select und Marquee zum Auswählen von Elementen zur Verfügung sowie der Eintrag Text zum Hinzufügen einfacher Text-Labels. Die erzeugten Elemente lassen sich frei auf der Zeichenfläche positionieren. Sie können zudem (soweit zulässig) auch in einem fest vorgeschriebenen Bereich vergrößert bzw. verkleinert werden. Das Routing einer Transition kann zudem mittels Bendpoints verändert werden. Der Name eines Elements kann mittels Doppelklick mit einem TextCellEditor verändert werden. Der Name sowie weitere registrierte Attribute eines selektierten Elements können auch über die Properties View geändert werden. Sollte die Properties View nicht sichtbar sein, öffnen sie diese mittels Window Æ Show View Æ Other.. Æ General Æ Properties. Der ProFLOW Editor verfügt über eine Undo/Redo Funktionalität, sodass alle Veränderungen auch wieder rückgängig gemacht werden können. Weitere Features • Zoom: Über die Kontextmenueinträge Zoom In und Zoom Out des ProFLOW Editors sowie über den entsprechenden Toolbar Eintrag ist es möglich, die Editor Zeichenfläche zu zoomen. • Drucken: Über den Menueintrag File Æ Print.. ist es möglich, den Inhalt des aktuellen ProFLOW Editors auszudrucken. • Process Actions: Im Kontextmenü, in der Symbolleiste oder in dem Hauptmenü des ProFLOW Editors können zudem (falls vorhanden) registrierte Diagramm-spezifische Actions gestartet werden. o Eine Process Action, welche für alle Diagramm-Typen zur Verfügung steht, ist beispielsweise die Action Export as Plain XML… Diese Action ermöglicht einen XML-Export, wobei anders als beim normalen Speichern in der .proFlow-Datei keine Layout-Informationen mit abgespeichert werden. o Eine weitere Process Action, welche für alle Diagramm-Typen zur Verfügung steht, ist die Action Export as Image File… Hiermit kann man das aktuelle Diagramm als Bilddatei (.jpg oder .bmp) abspeichern. • ModelObject Actions: Abhängig von der Definition der registrierten Actions, können im Kontextmenu, in der Symbolleiste oder in dem Hauptmenü des ProFLOW Editors auch Actions auf Diagrammelementen ausgeführt werden. • Alignment und Match Actions: In der zugehörigen Toolbarleiste des ProFLOW Editors werden noch einige Actions zur Verfügung gestellt, womit selektierte Diagrammelemente ausgerichtet werden können oder deren Größe angeglichen werden können. 3. Erweiterung Es ist möglich, das bestehende ProFLOW Framework um neue Diagrammtypen zu erweitern. Hierfür ist es notwendig, ein neues Eclipse Plug-in zu entwickeln, welches auf den ProFLOW Plug-ins ProFLOW.core und ProFLOW.ui aufbaut. Learning from Examples Bevor im Folgenden Schritt für Schritt erklärt werden soll, wie sie ein eigenes Plug-in mit einem eigenen neuen Diagrammtyp entwickeln können, wollen wir einen kurzen Blick in bereits bestehende Diagramm-Implementationen werfen. Wie sie sicherlich schon im vorigen Kapitel bemerkt haben, existieren bereits zwei Diagrammtypen mit der erweiterten ereignisgesteuerten Prozesskette (eEPK) und dem Aktivitätsdiagramm. Diese beiden Diagrammtypen sind ebenfalls als eigenständige Plug-ins, welche auf den angesprochenen ProFLOW Plug-ins aufbauen, realisiert. Es lohnt sich also sicherlich, dort erst einmal ein wenig „rumzustöbern“, um sich einen Überblick zu verschaffen, wie schwer unser Unterfangen wohl werden wird. Die Frage die sich nun natürlich gleich stellt ist, wie komme ich an den Source-Code der angesprochenen Plug-ins? Ganz einfach. Alle Plug-ins, welche in ihrer Eclipse Umgebung installiert/registriert sind, können sich in Eclipse auch angezeigt werden. Sofern diese registrierten Plug-ins auch den Source-Code mitliefern (was bei den angesprochenen ProFLOW Plug-ins der Fall ist), können sie auf einfache Weise diese als Source Projects in den Workspace von Eclipse laden. Gehen sie hierfür nun wie folgt vor: • • • • Öffnen sie die Plug-in Development Perspective Öffnen sie die Plug-ins View Markieren sie die ProFLOW Plug-ins Führen sie den Kontextmenueintrag Import as Æ Source Project aus Wenn sie nun einen Blick in den Package Explorer werfen, sehen sie, dass die ausgewählten Plug-ins sich nun in ihrem Workspace befinden. Wenn sie sich die einzelnen DiagrammImplementierungen in den Plug-ins ProFLOW.eepk und ProFLOW.activity anschauen, werden sie bemerken, dass die Realisierung eines neuen Diagramms pro Element, Transition oder Annotation lediglich eine Model-Klasse und eine UI-Klasse benötigt. Also alles doch gar nicht so schwer. Fangen wir doch am besten gleich mit einem einfachen eigenen Diagramm an, um mit dem Framework besser vertraut zu werden. Anlegen einen neuen Plug-In Projects Bevor wir uns in die konkrete Implementierung unseres neuen Diagramms stürzen können, müssen wir jedoch zunächst noch ein neues Plug-in Project erzeugen. Führen sie dafür folgenden Menueintrag aus: File Æ New Æ Project.. Im erscheinenden Project Creation Wizard wählen sie den Eintrag Plug-in Project und drücken sie Next. In der folgenden Wizard Page müssen sie nun lediglich den Namen des neuen Projekts festlegen, in unserem Fall ProFLOW.example. In der darauf folgenden Wizard Page können sie nun noch den Plug-In Namen verändern bzw. weitere Informationen zu Provider, Version, etc. angeben. In unserem Beispiel haben wir lediglich den Namen des Plug-Ins und der Activator-Klasse verändert. Der Rest bleibt unverändert. Nach dem Drücken des Finish Buttons wird das neue Plug-In Project in ihrem Workspace angelegt. Das neue Plug-In Project enthält an für uns interessanten Dateien zunächst nur die Manifest.MF-Datei in dem META-INF-Ordner. Diese Datei ist auch von Beginn an im PlugIn Editor geöffnet. Die Dateien Manifest.MF, build.properties und die später erzeugte plugin.xml bilden den Kern eines jeden Plug-In Projects. Hier werden sämtliche Plug-Inspezifischen Einstellungen getroffen. Diese drei Dateien werden im Plug-In Editor verwaltet. Zu Beginn werden wir die Abhängigkeiten (Dependencies) unseres neu erstellten Plug-In Projects setzen. Wechseln sie hierfür zur Dependencies Page des Plug-In Editors. Hier sind schon zwei Abhängigkeiten gesetzt: org.eclipse.ui und org.eclipse.core.runtime. Um in unserem Projekt auf die beiden ProFLOW Plug-Ins ProFLOW.core und ProFLOW.ui zugreifen zu können, müssen wir diese beiden Plug-Ins nun ebenfalls zu den Abhängigkeiten aufnehmen. Außerdem benötigen wir noch eine Abhängigkeit zu dem Plug-In org.eclipse.gef, welches im Plug-In ProFLOW.ui verwandt wird (s. Abbildung 3-1). Bevor wir nun mit der konkreten Implementierung beginnen, führen sie am besten gleich noch eine saubere Packagestruktur ein. Analog zu den beiden Beispiel-Plug-Ins ProFLOW.eepk und ProFLOW.activity erstellen wir somit die Packages proFlow.example.model und proFlow.example.ui.editParts. Abbildung 3-1 Erzeugen eines neuen Prozesses Nachdem wir nun ein neues Plug-In Project angelegt haben und auch die benötigten Abhängigkeiten gesetzt sind, können wir nun mit der Implementierung unseres neuen Diagramm- bzw. Prozesstyps beginnen. Um einen neuen Prozesstyp zu erstellen, müssen wir zunächst eine neue Klasse erzeugen, welche die Klasse ProFLOW.core.model.Process erweitert. Erstellen wir nun also die Klasse ExampleProcess im Package proFlow.example.model. In dieser müssen wir nun lediglich die Methode getTypeID():String implementieren. Die TypeId stellt den eindeutigen Identifier für diesen Prozesstyp dar, welcher zur eindeutigen Identifizierung ihres Prozesstypen im ProFLOW Framework benötigt wird. In unserem Beispiel wählen wir als TypeId den String „ProFLOW.example.Process“. Der Code für unsere Prozess-Model-Klasse sieht also wie folgt aus: public class ExampleProcess extends Process { public String getTypeID() { return "ProFLOW.example.Process"; } } Im Anschluss müssen wir nun noch den neu erstellten Prozess dem ProFLOW Framework bekannt machen. Dies wird mittels Extension Points (dem Erweiterungsmechanismus von Eclipse) realisiert. Hierbei unterscheiden wir gezielt in Core- und UI-Extension Points unseres Frameworks. Die Core-Extension Points sind dabei verantwortlich für das Class Loading und die Persistenz wohingegen die UI-Extension Points die grafische Repräsentation definieren. Für einen neu erstellten Prozesstyp müssen Extensions für die Extension Points ProFLOW.core.processes und ProFLOW.ui.processes definiert werden. Gehen sie hierbei wie folgt vor: • • • Öffnen sie den Plug-In Editor (Öffnen der Datei Manifest.MF) Wechseln sie zur Extensions Page des Plug-In Editors Fügen sie mittels Add eine Extension des Typs ProFLOW.core.processes hinzu • • • Rechtsklicken sie auf die neu erstellte Extension und führen sie den Kontextmenueintrag New Æ process aus Spezifizieren sie nun das neu erstellte Extension Element process auf der rechten Seite des Editors wie folgt: o id: Hier muss der eindeutige Identifier für den zu registrierenden Prozess angegeben werden. Der Identifier entspricht dem bereits in der Process-Klasse verwandten Identifier, in unserem Beispiel also ProFLOW.example.Process. o class: Hier muss die Klasse angegeben werden, welche die Framework-Klasse ProFLOW.core.model.Process erweitert, also in unserem Beispiel die gerade implementierte Klasse ProFLOW.example.model.ExampleProcess. Fügen sie nun noch analog eine Extension des Typs ProFLOW.ui.processes hinzu, erstellen sie ebenfalls ein process Extension Element und spezifizieren sie dieses wie folgt: o id: Hier muss derselbe Identifier angegeben werden, wie schon in der CoreExtension und der implementierenden Process-Klasse, in unserem Beispiel also wieder ProFLOW.example.Process. o name: Hier muss der Name angegeben werden, mit welchem dieser Prozess in dem ProFLOW Diagram Creation Wizard aufgeführt werden soll. o description: Hier kann eine Beschreibung zu dem Prozess mit angegeben werden, welche ebenfalls in dem Creation Wizard erscheint. o defaultName: Der optionale Default-Name wird im Creation Wizard als Default Datei- und Diagrammname verwandt. o icon: Hier kann noch ein Icon angeben werden, welches im Creation Wizard neben dem Namen dargestellt werden soll. Wie sie evtl. schon bemerkt haben, ist mit dem Definieren der Extensions ein weitere Datei in ihrem Plug-In Project erstellt worden – die plugin.xml. Sie haben über die beschriebene grafische Schnittstelle der Extensions Page lediglich diese Datei editiert. Sie können sich den erstellten XML-Code auch in dem Plug-In Editor ansehen indem sie zu dem plugin.xml Reiter wechseln. Natürlich ist es auch möglich die plugin.xml auf herkömmlichen Wege, anstatt über die grafischen Schnittstelle, zu verändern. Die plugin.xml-Datei sollte nun folgendermaßen aussehen: <?xml version="1.0" encoding="UTF-8"?> <?eclipse version="3.2"?> <plugin> <extension point="ProFLOW.core.processes"> <process id="ProFLOW.example.Process" class="proFlow.example.model.ExampleProcess"/> </extension> <extension point="ProFLOW.ui.processes"> <process id="ProFLOW.example.Process" name="Example Process" description="A simple example process to demonstrate the extension mechanism." defaultName="example_process" icon="icons/sample.gif"/> </extension> </plugin> Starten einer Runtime Workbench Bevor wir nun weitere Elemente für unseren neu erstellten Prozesstyp implementieren wollen, lassen sie uns erst einmal ansehen, was wir mit unserer derzeitigen Arbeit schon erreicht haben. Um ein Plug-In Project ausprobieren zu können, ist es in Eclipse möglich ein weitere „innere“ Eclipse-Instanz aus Eclipse heraus zu starten – eine sog. Runtime Workbench. Gehen sie hierbei wie folgt vor: • • • • • Starten sie den Menueintrag: Run Æ Run.. (bzw. Run Æ Debug.. wenn sie ihr Projekt Debuggen wollen) Erzeugen sie eine neue Eclipse Application (Eclipse Application auswählen und New Button drücken) Geben sie ihrer neu erstellten Configuration einen passenden Namen (z.B. ProFLOW Example) und ändern sie ggf. die Runtime Workspace Location Vergewissern sie sich nochmals, dass im Plug-ins Reiter ihr Plug-In ProFLOW.example mit ausgewählt ist Starten sie die Runtime Workbench mit Run Es wird daraufhin eine neue Eclipse-Instanz gestartet in der ihr Plug-In schon integriert ist. Wenn sie nun wie oben beschrieben ein neues ProFLOW Diagramm in ihrer Runtime Workbench erstellen möchten, werden sie sehen, dass unser gerade erstellter Prozess in dem entsprechenden Wizard mit aufgeführt ist. Der in der Extension definierte Name, die Beschreibung sowie das angegebene Icon werden hier ebenso verwandt, wie auf der folgenden Wizard Page zur Dateierzeugung der angegebene Default-Name. Drücken sie auf Finish, werden sie jedoch bemerken, dass außer den Paletteneinträgen Select und Marquee zur Markierung und dem einfachen Textlabel noch keine weiteren Elemente in dem geöffneten ProFLOW Editor zur Verfügung stehen. Wie neue Elemente, Transitionen und Annotationen unserem Prozess hinzugefügt werden können, soll nun im Weiteren genauer erläutert werden. Erzeugen eines neuen Prozesselements Um ein neues Prozesselement zu erstellen, müssen wir eine Klasse implementieren, welche die Framework-Klasse proFlow.core.model.SimpleElement erweitert. In unserem Beispiel erzeugen wir somit eine solche Klasse namens ExampleElement im entsprechenden ModelPackage proFlow.example.model. Hier muss, wie auch schon bei unserer Process-Klasse, die Methode getTypeID():String implementiert werden. Als eindeutigen Identifier für unseren Prozesselementtyp wählen wir dieses Mal den String „ProFLOW.example.Element“. Es ist zudem sinnvoll im Default-Konstruktor einige Werte unseres Prozesselements zu initialisieren. So initialisieren wir im super-Konstruktoraufruf den Default-Namen des Elements. Außerdem können hier auch gleich die aktuelle, maximale und minimale Dimension gesetzt werden. Abhängig von diesen Werten ist dann das Vergrößern und Verkleinern eines gezeichneten Elements möglich. Achtung: Es ist wichtig, dass jedes Model-Object (also jeder Process, SimpleElement, ContainerElement, Annotation oder Transition) einen Default-Konstruktor enthält, da es sonst zu Problemen mit dem Class Loading kommt. Der Code für unsere ExampleElement-Klasse sieht somit wie folgt aus: public class ExampleElement extends SimpleElement { public ExampleElement() { super("Element"); setMaxDimension(new Dimension(200, 100)); setMinDimension(new Dimension(50, 30)); setDimension(new Dimension(100, 50)); } public String getTypeID() { return "ProFLOW.example.Element"; } } Damit unser neu erstelltes Element auch in unseren Prozess hinzugefügt werden darf, muss noch die zuvor implementierte Klasse ExampleProcess ein wenig ergänzt werden. In dieser Klasse müssen sie noch die Methode isValidChildElement(Element):boolean überschreiben. In unserem Fall wird ein positiver instanceof-Check mit unserem neuen Prozesselement hinzugefügt. Die Klasse ExampleProcess sieht danach wie folgt aus: public class ExampleProcess extends Process { public boolean isValidChildElement(Element element) { return super.isValidChildElement(element) || element instanceof ExampleElement; } … } Nachdem wir nun die nötige Implementation auf Model-Ebene vollzogen haben, müssen wir uns nun noch um die grafische Repräsentation unseres neuen Prozesselements kümmern. Hierfür müssen wir eine weitere Klasse implementieren, welche die Framework-Klasse proFlow.ui.editParts.ElementEditPart erweitert. Info: Das ProFLOW Framework verfolgt, da es auf dem Graphical Editing Framework (GEF) aufbaut, das MVC-Paradigma (Model-View-Controller). Die EditPart-Klassen stellen dabei die Controller des Frameworks dar. Sie sind dafür zuständig, wie ein Model-Object grafisch dargestellt wird und wie sich Modelländerungen grafisch auswirken. In einem GEF-basierten Projekt stellen die View-Elemente die sog. Figures dar. Diese gilt es im Controller zu erzeugen und zu verwalten. Erzeugen sie nun also eine Klasse ExampleElementEditPart im Package proFlow.example.ui.editParts, welche die Klasse ElementEditPart erweitert. Wie sie sehen, müssen sie hier lediglich die Methode createFigure():IFigure implementieren. Ein Figure kann dabei beliebig komplex gestaltet sein. Das ProFLOW Framework stellt jedoch schon einige nützliche Figure-Implementationen bereit, welche für den Großteil der Anwendungsfälle ausreichen sollte. Die folgenden Figure-Implementation im ProFLOW.ui Plug-In sind dabei verfügbar: • LabeledRoundedRectangle: Mit dieser Figure-Klasse können sie rechteckige Formen erzeugen, welche mit einem editierbaren Label versehen sind. Abhängig von der gesetzten Corner-Dimension, können die Ecken des Rechtecks abgerundet werden, aber auch elliptische bis hinzu kreisförmige Formen erstellt werden. Nahezu alle Figures der Plug-Ins ProFLOW.activity und ProFLOW.eepk sind mit dieser Figure-Klasse implementiert. • LabeledPolygon: Mit dieser Figure-Klasse können sie beliebig aufgebaute Polygone erzeugen, welche ebenfalls mit einem editierbaren Label versehen sind. Abhängig von der beliebig komplex gesetzten Punktliste, können hierbei beliebig geformte Polygone erzeugt werden. Das Event-Figure des ProFLOW.eepk Plug-Ins sowie das Decision/Merge-Figure des ProFLOW.activity Plug-Ins sind mit dem LabeledPolygonFigure realisiert. • LabeledImage: Mit dieser Figure-Klasse lassen sich beliebige Images darstellen. Zudem ist es möglich, das Image unterhalb mit einem editierbaren Label zu versehen. Sämtliche FLOW-Figures sind mit dieser Figure-Klasse implementiert. Unser Prozesselement soll in unserem Beispiel lediglich ein einfaches weißes Rechteck darstellen, welches mit einem editierbaren Label versehen ist. Die ExampleElementEditPartKlasse sieht demnach wie folgt aus: public class ExampleElementEditPart extends ElementEditPart { protected IFigure createFigure() { LabeledRoundedRectangle elementFigure = new LabeledRoundedRectangle(); elementFigure.setCornerDimensions(new Dimension(0, 0)); elementFigure.setSize( getCastedModel().getDimension().getWidth(), getCastedModel().getDimension().getHeight()); elementFigure.setLocation(new Point( getCastedModel().getLocation().getX(), getCastedModel().getLocation().getY())); elementFigure.setText(getCastedModel().getName()); return elementFigure; } public ILabelContainer getLabelContainer() { return ((LabeledRoundedRectangle) getFigure()) .getLabelContainer(); } } Das Implementieren der Methode getLabelContainer():ILabelContainer, in der lediglich der LabelContainer der Figure-Klasse weitergeleitet wird, ist notwendig, damit der Name des erzeugten Elements im ProFLOW Editor über einen TextCellEditor editierbar ist. Überschreibt man diese Methode nicht, wie dies beispielsweise bei der Implementation der Connector-Elemente der Fall ist, so wird der Name des Elements zwar dargestellt, er ist jedoch nicht editierbar. Nachdem wir nun sowohl die Model-Klasse als auch die EditPart-Klasse für unser neues Prozesselement implementiert haben, müssen wir unser Element, wie dies schon bei unserem neuen Prozesstyp der Fall war, nun nur noch unserem Plug-In bekannt machen. Für einen neu erstellten Prozesselementtyp müssen Extensions für die Extension Points ProFLOW.core.simpleElements und ProFLOW.ui.simpleElements im Plug-In Editor definiert werden. Gehen sie dabei wie folgt vor: • • Fügen sie eine Extension des Typs ProFLOW.core.simpleElements ein Spezifizieren sie das neu erstellte Extension Element simpleElement wie folgt: o id: Hier muss der eindeutige Identifier für das zu registrierende Prozesselement angegeben werden. Der Identifier entspricht dem bereits in der ModelKlasse verwandten Identifier, also ProFLOW.example.Element. o class: Hier muss die Klasse angegeben werden, welche die Framework-Klasse ProFLOW.core.model.SimpleElement erweitert, also in unserem Beispiel die Klasse ProFLOW.example.model.ExampleElement. • • Fügen sie nun noch eine Extension des Typs ProFLOW.ui.simpleElements hinzu Erstellen sie ebenfalls ein simpleElements Extension Element und spezifizieren sie dieses wie folgt: o id: Hier muss derselbe Identifier angegeben werden, wie schon in der CoreExtension und der Model-Klasse, also ebenfalls ProFLOW.example.Element. o name: Hier muss der Name angegeben werden, mit welchem dieses Prozesselement in der Editorpalette aufgeführt werden soll. o editPart: Hier muss die Klasse angegeben werden, welche die FrameworkKlasse ProFLOW.ui.editParts.ElementEditPart erweitert, also in unserem Beispiel die Klasse ProFLOW.example.ui.editParts.ExampleElementEditPart. o description: Hier kann eine Beschreibung zu dem Prozesselement mit angegeben werden, welche als Tooltip bei dem Editorpaletteneintrag erscheint. o icon: Hier kann noch ein Icon angeben werden, welches beim Editorpaletteneintrag neben dem Namen dargestellt werden soll. Die plugin.xml-Datei wurde somit um folgenden Code ergänzt: <extension point="ProFLOW.core.simpleElements"> <simpleElement id="ProFLOW.example.Element" class="proFlow.example.model.ExampleElement"/> </extension> <extension point="ProFLOW.ui.simpleElements"> <simpleElement id="ProFLOW.example.Element" name="Element" editPart="proFlow.example.ui.editParts.ExampleElementEditPart" description="Create an Example Element" icon="icons/element.gif"/> </extension> Erzeugen einer neuen Transition Im Folgenden soll nun erläutert werden, wie sie eine neue Transition erzeugen können. Hierfür müssen sie, wie schon beim Erzeugen eines neuen Prozesselements, eine ModelKlasse sowie eine EditPart-Klasse implementieren. Die Model-Klasse unserer neuen Transition muss in diesem Fall die Framework-Klasse ProFLOW.core.model.Transition erweitern. Erzeugen sie eine Klasse ExampleTransition im Package proFlow.example.model. In dieser Klasse müssen sie lediglich neben der bereits bekannten Methode getTypeID():String die Methoden isValidSourceElement(Element): boolean und isValidTargetElement(Element):boolean implementieren. Mit den beiden letzteren Methoden können sie definieren, welche Elemente gültige Start- und Endpunkte dieser Transition darstellen dürfen. In unserem einfachen Beispiel gibt es mit unserem zuvor erstellten ExampleElement lediglich ein gültiges Element für beide Methoden. Unsere Transitions-Klasse sieht demnach wie folgt aus: public class ExampleTransition extends Transition { public boolean isValidSourceElement(Element source) { return (source instanceof ExampleElement); } public boolean isValidTargetElement(Element target) { return (target instanceof ExampleElement); } public String getTypeID() { return "ProFLOW.example.Transition"; } } Um kompliziertere Transitionsregeln zu definieren, können sie neben den angesprochenen Methoden noch die Methoden isValidTransition(Element, Element):boolean, canChangeSourceElement(Element):boolean und canChangeTargetElement(Element):boolean überschreiben. Ein gutes Beispiel für eine komplexer gestaltete Transition ist die Transition proFlow.eepk.model.EEPKTransition des ProFLOW.eepk Plug-Ins. Nun müssen wir noch die EditPart-Klasse unserer Transition implementieren. Diese muss eine Subklasse der Framework-Klasse proFlow.ui.editParts.TransitionEditPart sein. Die Figure-Klasse einer Transition stellt eine einfache PolylineConnection dar. Diese können sie noch modifizieren, indem sie die Methode createFigure():IFigure überschreiben. In unserem Beispiel fügen wir dabei eine einfache Decoration hinzu: public class ExampleTransitionEditPart extends TransitionEditPart { protected IFigure createFigure() { PolylineConnection connection = (PolylineConnection) super.createFigure(); connection.setTargetDecoration(new PolygonDecoration()); connection.setLineStyle(SWT.LINE_SOLID); return connection; } } Abschließend müssen wir nun nur noch die implementierte Transition unserem Plug-In bekannt machen. Analog zur Erstellung eines neuen Prozesselementtyps müssen sie für eine Transitions lediglich Extensions für die Extension Points ProFLOW.core.transitions und ProFLOW.ui.transitions im Plug-In Editor definiert werden. Die Spezifikation der Attribute der entsprechenden Extensions ist dabei genauso definiert, wie schon zuvor bei den Extensions eines neuen Prozesselements beschrieben. Die plugin.xml wird somit um folgenden Einträge erweitert: <extension point="ProFLOW.core.transitions"> <transition id="ProFLOW.example.Transition" class="proFlow.example.model.ExampleTransition"/> </extension> <extension point="ProFLOW.ui.transitions"> <transition id="ProFLOW.example.Transition" name="Transition" editPart="proFlow.example.ui.editParts .ExampleTransitionEditPart" description="Create a new Transition" icon="icons/transition.gif"/> </extension> Erzeugen einer neuen Annotation Nachdem wir nun für unseren neuen Prozesstyp ein Prozesselement und eine Transition implementiert haben, wollen wir nun noch ein letztes Element unserer Prozessdefinition hinzufügen – eine Annotation. Annotationen können sowohl Prozesselementen als auch Transitionen hinzugefügt werden. Achtung: In der derzeitigen Version des ProFLOW Frameworks wird nur das Annotieren von Prozesselementen unterstützt. Das Annotieren von Transitionen soll aber in späteren Versionen ebenfalls mit zur Verfügung stehen. Zum Erzeugen einer neuen Annotation müssen sie wieder eine Model-Klasse und dieses mal sogar zwei EditPart-Klassen implementieren. Die Model-Klasse muss dabei die Framework- Klasse proFlow.core.model.Annotation erweitern. Erstellen sie somit eine neue Klasse ExampleAnnotation im Package proFlow.example.model. Diese Klasse muss neben der bereits bekannten Methode getTypeID():String ebenfalls noch die Methode isValidAnnotatableObject(AnnotatableObject):boolean implementieren. In der letzteren Methode wird definiert, welchen Prozesselementen bzw. welchen Transitionen diese Annotation hinzugefügt werden darf. In unserem Beispiel soll die neu erstellte Annotation lediglich unserem ExampleElement hinzugefügt werden dürfen. Wie schon bei der ExampleElement-Klasse bietet es sich bei einer Annotation-ModelImplementation an, im Default-Konstruktor den Default-Namen sowie die Dimensionswerte zu initialisieren. Außerdem kann man hier auch noch die Orientierung der Annotation initialisieren. Die Orientierung definiert, wo der Layout-Algorithmus beim Hinzufügen von neuen Annotationen diese relativ zum annotierten Elemente platzieren soll. Unsere ExampleAnnotation-Klasse sieht demnach wie folgt aus: public class ExampleAnnotation extends Annotation { public ExampleAnnotation() { super("Annotation"); setMaxDimension(new Dimension(200, 100)); setMinDimension(new Dimension(50, 30)); setDimension(new Dimension(80, 40)); setOrientation(ALL_SIMPLE_ORIENTATIONS); } public boolean isValidAnnotatableObject( AnnotatableObject annotatableObject) { return (annotatableObject instanceof ExampleElement); } public String getTypeID() { return "ProFLOW.example.Annotation"; } } Da sich eine Annotation grafisch aus zwei Elementen zusammensetzt, dem eigentlichen Annotationselement und einer Kante zwischen dem Annotationselement und dem annotierten Element, müssen sie auch zwei EditPart-Klassen erweitern. Die EditPart-Klasse, welche die Darstellung des Annotationselements regelt, muss die Framework-Klasse proFlow.ui.editParts.AnnotationEditPart erweitert. Erzeugen sie also eine Klasse ExampleAnnotationEditPart im Package proFlow.example.ui.editParts. Die Implementation dieser Klasse ähnelt stark unserer ExampleElementEditPart-Klasse. Die Annotation stellt wieder ein editierbares weißes Rechteck dar, dieses mal jedoch mit abgerundeten Ecken. Die Klasse sieht demnach wie folgt aus: public class ExampleAnnotationEditPart extends AnnotationEditPart { protected IFigure createFigure() { LabeledRoundedRectangle annotationFigure = new LabeledRoundedRectangle(); annotationFigure.setCornerDimensions(new Dimension(10, 10)); annotationFigure.setSize( getCastedModel().getDimension().getWidth(), getCastedModel().getDimension().getHeight()); annotationFigure.setLocation(new Point( getCastedModel().getLocation().getX(), getCastedModel().getLocation().getY())); annotationFigure.setText(getCastedModel().getName()); return annotationFigure; } public ILabelContainer getLabelContainer() { return ((LabeledRoundedRectangle) getFigure()) .getLabelContainer(); } } Im Weiteren muss nun noch eine EditPart-Klasse implementiert werden, welche die Klasse proFlow.ui.editParts.AnnotationConnectionEditPart erweitert. Diese ähnelt in der Realisierung stark der Implementation einer TransitionsEditPart-Klasse. In unserem Beispiel soll die Kante eine gepunktete schwarze Linie darstellen. Die Implementation der Klasse ExampleAnnotationConnectionEditPart sieht demnach wie folgt aus: public class ExampleAnnotationConnectionEditPart extends AnnotationConnectionEditPart { protected IFigure createFigure() { PolylineConnection connection = (PolylineConnection) super.createFigure(); connection.setLineStyle(SWT.LINE_DOT); return connection; } } Abschließend muss nun nur noch die neu erstellte Annotation dem Plug-In bekannt gemacht werden. Erstellen sie hierfür, wie bereits bekannt, Extensions der Extension Points ProFLOW.core.annotations und ProFLOW.zu.annotations. Die plugin.xml-Datei wird somit um die folgenden Einträge erweitert: <extension point="ProFLOW.core.annotations"> <annotation id="ProFLOW.example.Annotation" class="proFlow.example.model.ExampleAnnotation"/> </extension> <extension point="ProFLOW.ui.annotations"> <annotation id="ProFLOW.example.Annotation" name="Annotation" editPart="proFlow.example.ui.editParts .ExampleAnnotationEditPart" connectionEditPart="proFlow.example.ui.editParts .ExampleAnnotationConnectionEditPart" description="Create a new Annotation" icon="icons/annotation.gif"/> </extension> Definieren der Editorpalette Wie sie vielleicht schon beim Starten der Runtime Workbench zum Ausprobieren ihres neuen Diagrammtyps bemerkt haben, sind die neu erstellten Elemente noch nicht in der Editorpalette des ProFLOW Editors mit aufgeführt. Keine Angst, sie haben nichts falsch gemacht. Damit die neu erstellten Elemente in der Editorpalette erscheinen, müssen sie nur noch die Editorpaletten-Einträge mit Hilfe des Extension Points ProFLOW.ui.processPaletteEntries für ihren neuen Prozesstyp registrieren. Info: Die Realisierung der Editorpaletten-Einträge mittels eines Extension Points wurde aus dem Grunde gewählt, da sie so auch auf bereits in anderen Plug-Ins implementierte Elemente zurückgreifen können, solange sie deren eindeutigen Identifier wissen. Erstellen sie nun zunächst eine Extension des angesprochenen Extension Points im PluginEditor. Abhängig von der Art des Elements, welches sie in der Editorpalette registrieren wollen, müssen sie ein Extension Element vom Typ paletteElement (für SimpleElements), paletteContainer (für ContainerElements, Achtung: wird zurzeit noch nicht unterstützt), paletteTransition (für Transitionen) oder paletteAnnotation (für Annotationen) erstellen. Bei jedem dieser Elemente müssen sie nun lediglich den Identifier des Prozesstyps, den Identifier des zu registrierenden Elements sowie den Identifier der Palettengruppe, in welche das Element eingefügt werden soll, angeben. In unserem Fall benötigen wir also Extension Elements für ein Prozesselement (SimpleElement), eine Transition und eine Annotation. Da wir außerdem noch die FLOW-Elemente in unserem Diagramm nutzen möchten, müssen wir auch diese hier noch mit einem entsprechenden Extension Elements anbinden. Die plugin-xml-Datei wird somit um den folgenden Eintrag erweitert. <extension point="ProFLOW.ui.processPaletteEntries"> <paletteTransition transitionId="ProFLOW.example.Transition"/> processId="ProFLOW.example.Process" groupId="ProFLOW.ui.transitionPaletteGroup" <paletteElement elementId="ProFLOW.example.Element" processId="ProFLOW.example.Process"/> groupId="ProFLOW.ui.elementPaletteGroup" <paletteAnnotation annotationId="ProFLOW.example.Annotation" processId="ProFLOW.example.Process"/> groupId="ProFLOW.ui.annotationPaletteGroup" <paletteElement elementId="ProFLOW.flow.Document" processId="ProFLOW.example.Process"/> groupId="ProFLOW.ui.flowPaletteGroup" <paletteElement elementId="ProFLOW.flow.Documents" processId="ProFLOW.example.Process"/> groupId="ProFLOW.ui.flowPaletteGroup" <paletteElement elementId="ProFLOW.flow.Person" processId="ProFLOW.example.Process"/> groupId="ProFLOW.ui.flowPaletteGroup" <paletteElement elementId="ProFLOW.flow.Group" processId="ProFLOW.example.Process"/> groupId="ProFLOW.ui.flowPaletteGroup" <paletteTransition transitionId="ProFLOW.flow.Knowledge"/> processId="ProFLOW.example.Process" groupId="ProFLOW.ui.flowPaletteGroup" <paletteTransition transitionId="ProFLOW.flow.Experience"/> processId="ProFLOW.example.Process" groupId="ProFLOW.ui.flowPaletteGroup" </extension> In unserem Beispiel haben wir bei den Palettengruppen auf bereits im ProFLOW.ui Plug-in definierte Gruppen zurückgegriffen. Es ist jedoch auch möglich, mit dem Extension Element paletteGroup eigene Gruppen anzulegen. Bei einem solchen Extension Element musst du dann lediglich den eindeutigen Identifier sowie den Namen der Gruppe definieren. Bzgl. der Palettenstruktur hast du somit kompletten Handlungsfreiraum. Du kannst genau festlegen, welche Elemente in die Palette aufgenommen werden sollen und wie diese strukturiert ist. Wenn sie nun nochmals die Runtime Workbench starten, um unseren neu erstellten Prozesstyp auszuprobieren, werden sie sehen, dass die neu erstellten Elemente nun auch in der Editorpalette erscheinen. Sie können nun neue Diagramme ihres neuen Prozesstyps erstellen. Registrieren von zusätzlichen Attributen In den vorigen Kapiteln haben sie gelernt, wie sie mit Hilfe des ProFLOW Frameworks neue Prozesstypen erstellen können. Sie haben dabei einen neuen Prozesstyp erstellt, welcher ein Prozesselement, eine Transition und eine Annotation enthält. In diesem Kapitel soll nun erläutert werden, wie sie ihr Modell und speziell die einzelnen Elemente ihres Prozesstyps noch mit weiteren Attributen verfeinern können. Es ist möglich, für sämtliche ModelObjects neue Attribute zu registrieren. Diese Attribute sind dann über die Properties View, wie schon in Kapitel 2 zur Benutzung des Frameworks beschrieben, anzeigbar und editierbar. Die Registrierung eines Attributes erfolgt dabei ganz einfach auf Code-Ebene, sie müssen hierfür keine Extensions registrieren. Um ein neues Attribut zu registrieren, müssen sie lediglich die Methode registerAttribute(String attributeId, String name, String category, Object defaultValue, Object restriction) ausführen. Bevor im Folgenden einige Beispielattribute registriert werden sollen, hier noch eine kurze Beschreibung der Parameter dieser Methode: • • • • attributeId: Das Attribut muss mit einem eindeutigen Identifier registriert werden. Dieser Identifier wird auch als PropertyKey in Benachrichtigungen über ModelChanges verwandt. name: Geben sie hier den Namen für das Attribut an, welcher in der Properties View verwandt werden soll. category: Sie können neben dem Namen auch noch die Kategorie angeben, unter welcher das neue Attribut in der Properties View angezeigt werden soll. Beim Übergeben keines Kategorienamens erscheint das neue Attribut per Default unter der General-Kategorie. defaultValue: Hier müssen sie den Default-Wert ihres neuen Attributs angeben. Das ProFLOW Framework unterstützt das Registrieren von Attributen der folgenden Ty- • pen: java.lang.String, java.lang.Integer, java.lang.Double, java.lang.Boolean, java.io.File, org.eclipse.swt.graphics.FontData und org.eclipse.swt.graphics.RGB. restriction: Hier können sie noch optional Einschränkungen für ein definiertes Attribut festlegen. Eingeschränkt werden können hierbei Integer-Attribute mit einer Instanz der Klasse proFlow.core.properties.IntegerRange sowie Double-Attribute mit einer Instanz der Klasse proFlow.core.properties.DoubleRange. Ein String-Attribut kann ebenfalls auf eine bestimmte Menge von gültigen Strings beschränkt werden. Hierfür müssen sie lediglich ein String-Array mit den gültigen String-Werten übergeben. Außerdem ist es noch möglich ein File-Attribut durch eine Instanz der Klasse proFlow.core.properties.FileFilter einzuschränken bzw. das Verhalten des File Dialog CellEditors zu beeinflussen. Lassen sie uns nun ein paar einfache Attribute registrieren. Unserem Prozesstyp könnten wir beispielsweise ein einfaches Description-Attribut hinzufügen. Erweitern sie somit also die Klasse ExampleProcess um einen Default-Konstruktor-Implementation in der dieses Attribut registriert wird: public class ExampleProcess extends Process { public static final String DESCRIPTION_ATTRIBUTE_ID = "ProFLOW.example.Process.description"; public ExampleProcess() { registerAttribute(DESCRIPTION_ATTRIBUTE_ID, "Description", null, "", null); } … } In der Properties View erscheint somit das neue Attribut unter der General-Kategorie, wenn sie ihren Prozess selektiert haben. Sie können dieses Attribut dabei einfach über einen TextCellEditor editieren. Lassen sie uns nun noch ein weiteres Attribut registrieren, dessen Wert sich, anders als beim vorigen Attribut, auch grafisch widerspiegeln soll. Unserer Transition könnte beispielsweise noch ein Farb-Attribut hinzugefügt werden. Abhängig von dem dort ausgewählten Wert soll die Transition dann auch im Editor dargestellt werden. Erweitern sie hierfür nun zunächst die Klasse ExampleTransition um eine entsprechende Attributregistrierung: public class ExampleTransition extends Transition { public static final String COLOR_ATTRIBUTE_ID = "ProFLOW.example.Transition.color"; public ExampleTransition() { registerAttribute(COLOR_ATTRIBUTE_ID, "Color", "Layout", new RGB(0, 0, 0), null); } … } Das neue Attribut erscheint daraufhin nun auch in der Properties View, wenn sie eine Transition ihres Diagrammtyps im Editor selektieren. Damit der im ColorDialog ausgewählte Farbwert auch grafisch im Editor reflektiert wird, müssen sie nun noch die EditPart-Klasse ihrer Transition folgendermaßen erweitern: public class ExampleTransitionEditPart extends TransitionEditPart { protected IFigure createFigure() { PolylineConnection connection = (PolylineConnection) super.createFigure(); connection.setTargetDecoration(new PolygonDecoration()); connection.setLineStyle(SWT.LINE_SOLID); RGB rgb = (RGB) getCastedModel().getAttributeValue( ExampleTransition.COLOR_ATTRIBUTE_ID); if (rgb != null) connection.setForegroundColor(new Color(null, rgb)); return connection; } public void notifyChange(Object object, Object property) { super.notifyChange(object, property); if (property.equals(ExampleTransition.COLOR_ATTRIBUTE_ID) && object instanceof RGB) getFigure().setForegroundColor( new Color(null, (RGB) object)); } } Abschließend wollen wir noch ein letztes Attribut registrieren, welches im nächsten Kapitel noch eine Bedeutung spielen wird. Erweitern sie dafür die Klasse ExampleElement um ein Integer-Attribut namens Counter: public class ExampleElement extends SimpleElement { public static final String COUNTER_ATTRIBUTE_ID = "ProFLOW.example.Process.counter"; public ExampleElement() { … registerAttribute(COUNTER_ATTRIBUTE_ID, "Counter", null, new Integer(0), null); } … } Registrieren von Process Actions Wir haben an zwei einfachen Beispielen gesehen, wie sie ihr Modell mit der Registrierung von neuen Attributen verfeinern können. Im Folgenden soll nun noch erläutert werden, wie sie dem Kontextmenü, der Symbolleiste und dem Hauptmenü ihres ProFLOW Editors noch weitere Actions, welche auf dem gesamten Prozess arbeiten, hinzufügen können. Um solch eine neue Action zu definieren, müssen sie eine Subklasse der Klasse proFlow.ui.actions.ProcessActionRunner implementieren. In unserem Beispiel wollen wir eine einfache Action erstellen, welche die Anzahl der Prozesselemente (ausgenommen die Text Labels) unseres Prozesses zählt und das Ergebnis in einem Dialog anzeigt. Erstellen sie hierfür zunächst das Package proFlow.example.ui.actions und eine darin enthaltene neue Klasse ElementCountAction, welche die angesprochene Framework-Klasse erweitert. In dieser Klasse müssen sie nun lediglich die Methode run(Process, IWorkbenchPartSite) implementieren. Unsere Action-Klasse sieht demnach wie folgt aus: public class ElementCountAction extends ProcessActionRunner { protected void run(Process process, IWorkbenchPartSite site) { int elementCount = 0; for (Element currentElement : process.getAllElements()) { if (!(currentElement instanceof TextNoteElement)) elementCount++; } MessageDialog.openInformation(site.getShell(), "Element Count", "Process: " + process.getName() + "\n\nContains " + elementCount + " Elements. "); } } Abschließend müssen sie die neue Process Action noch mittels des Extension Points ProFLOW.ui.processActions registrieren. Erzeugen sie nun zunächst eine neue Extension dieses Extension Points im Plug-In Editor und erzeugen sie ein neues Extension Element processAction. Dieses müssen sie nun noch wie folgt spezifizieren: • id: Hier muss ein eindeutiger Identifier für die neue Process Action angegeben werden, in unserem Fall wählen wir ProFLOW.example.actions.ElementCount. • • • • • • • name: Hier muss der Name angegeben werden, mit welchem diese Action im Kontextmenu des ProFLOW Editors erscheinen soll, wir wählen Element Count. class: Hier muss die Klasse angegeben werden, welche die Framework-Klasse proFlow.ui.actions.ProcessAction erweitert, also in unserem Beispiel die gerade implementierte Klasse proFlow.example.ui.actions.ElementCountAction. icon: Hier kann optional noch ein Icon angegeben werden, welches neben dem Namen im Kontextmenu erscheinen soll. contextMenuGroup: Hier kann die Gruppe angegeben werden, unter welcher die neue Action im Kontextmenu aufgeführt werden soll. Gültige Werte sind hier die folgenden Group-Identifier: org.eclipse.gef.group.copy, .edit, .find, .print, .rest, .save, .undo und .view. Wir wählen in unserem Fall die Gruppe org.eclipse.gef.group.rest. toolbarMenuGroup: Hier kann die Gruppe angegeben werden, unter welcher die neue Action in der Symbolleiste (Toolbar) aufgeführt werden soll. Gültige Werte sind hier die folgenden Group-Identifier: left_group, middle_group und right_group. Hier wählen wir die Gruppe right_group. menuGroup: Hier kann die Gruppe angegeben werden, unter welcher die neue Action in dem Hauptmenü aufgeführt werden soll. Gültige Werte sind hier die folgenden Group-Identifier: top_group, middle_group und bottom_group. Hier wählen wir die Gruppe top_group. processTypeId: Als letztes Attribut muss noch spezifiziert werden, für welchen Prozesstyp diese Action ausgeführt werden darf. Hier muss entweder eine konkreter Processtyp-Identifier angegeben werden oder der Default-Wert all. Da unsere Action auf allen Prozesstypen ausgeführt werden kann, wählen wir in unserem Beispiel den Default-Wert all. Die plugin.xml-Datei wird somit um den folgenden Eintrag ergänzt: <extension point="ProFLOW.ui.processActions"> <processAction id="ProFLOW.example.actions.ElementCount" name="Element Count" class="proFlow.example.ui.actions.ElementCountAction" icon="icons/info.gif" contextMenuGroup="org.eclipse.gef.group.rest" toolbarGroup="right_group" menuGroup="top_group" processTypeId="all"/> </extension> Es steht ihnen frei, ob sie die Action im Kontextmenü, in der Symbolleiste und/oder in dem Hauptmenü platzieren wollen. Achtung: Wenn sie eine Action in der Symbolleiste platzieren möchten, müssen sie auch ein Icon angeben, da die Action sonst nicht in der Symbolleiste angezeigt werden kann. Wir haben somit auf einfache Weise eine neue Action registriert. Wenn sie nun die Runtime Workbench starten, werden sie sehen, dass die neue erstellte Action im Kontextmenu des ProFLOW Editors erscheint und in beschriebener Weise arbeitet. Registrieren von Model Object Actions Neben den zuvor beschriebenen Process Actions kann noch eine weitere Art von Actions ProFLOW Editor hinzugefügt werden, die Model Object Actions. Diese Actions können auf jeder Art von Modelobjekten (also SimpleElements, ContainerElements, Annotationen oder Transitionen) definiert werden. Im folgenden Beispiel wollen wir eine einfache Action definieren, welche auf einer beliebigen Transition ausgeführt, das Source- und Target-Element in einem Dialog anzeigt. Die Definition dieser Action ist dabei ähnlich der Definition der zuvor erläuterten Process Action. Implementieren sie hierbei zunächst eine Subklasse der Klasse proFlow.ui.actions.ModelObjectActionRunner. Erzeugen sie also die Klasse TransitionInfoAction in dem bereits zuvor erzeugten Package proFlow.example.ui.actions. In dieser Klasse müssen sie nun wie zuvor lediglich die Methode run(List<ModelObject>, Process, IWorkbenchPartSite) vervollständigen. Unsere ActionRunner-Klasse sieht demnach wie folgt aus: public class TransitionInfoAction extends ModelObjectActionRunner { public void run(List<ModelObject> modelObjects, Process process, IWorkbenchPartSite site) { Transition t = (Transition) modelObjects.get(0); MessageDialog.openInformation(site.getShell(), "Transition Info", "Source Element: " + t.getSourceElement() + "\n" + "Target Element: " + t.getTargetElement()); } } Abschließend müssen sie die neue Model Object Action noch mittels des Extension Points ProFLOW.ui.modelObjectActions registrieren. Erzeugen sie hierfür eine Extension dieses Extension Points und erzeugen sie ein neues Extension Element modelObjectAction. Dieses müssen sie nun noch wie folgt spezifizieren: • • id: Hier muss ein eindeutiger Identifier für die neue Model Object Action angegeben werden, in unserem Fall ProFLOW.example.actions.TransitionInfo. name: Hier muss der Name angegeben werden, mit welchem diese Action im Kontextmenu des ProFLOW Editors erscheinen soll, wir wählen Transition Info. • • • • • • • class: Hier muss die Klasse angegeben werden, welche die Framework-Klasse proFlow.ui.actions.ModelObjectActionRunner erweitert, also in unserem Beispiel die gerade implementierte Klasse proFlow.example.ui.actions.TransitionInfoAction. icon: Hier kann optional noch ein Icon angegeben werden, welches neben dem Namen im Kontextmenu erscheinen soll. contextMenuGroup: Hier kann die Gruppe angegeben werden, unter welcher die neue Action im Kontextmenu aufgeführt werden soll. Gültige Werte sind hier die folgenden Group-Identifier: org.eclipse.gef.group.copy, .edit, .find, .print, .rest, .save, .undo und .view. Wir wählen in unserem Fall die Gruppe org.eclipse.gef.group.rest. toolbarMenuGroup: Hier kann die Gruppe angegeben werden, unter welcher die neue Action in der Symbolleiste (Toolbar) aufgeführt werden soll. Gültige Werte sind hier die folgenden Group-Identifier: left_group, middle_group und right_group. menuGroup: Hier kann die Gruppe angegeben werden, unter welcher die neue Action in dem Hauptmenü aufgeführt werden soll. Gültige Werte sind hier die folgenden Group-Identifier: top_group, middle_group und bottom_group. Hier wählen wir die Gruppe bottom_group. modelObjectTypeId: Außerdem muss noch spezifiziert werden, für welchen Modelobjekttyp diese Action ausgeführt werden darf. Hier muss entweder eine konkreter Modelobjekt-Identifier angegeben werden oder eines der reservierten Wörter all, simpleElements, containerElements, annotations oder transitions abhängig von der Art des gültigen Modelobjekts. Da unsere Action auf allen Transitionen ausgeführt werden soll, wählen wir in unserem Beispiel den Wert transitions. enablesFor: Abschließend muss noch angegeben werden, wieviele Modelobjekte ausgewählt werden müssen, um eine die Action ausführen zu können. Hier stehen drei Möglichkeiten der Definition zur Verfügung: o n – Eine konkrete Anzahl von Modelobjekten muss ausgewählt werden. o n+ – Mindestens die angebene Anzahl von Modelobjekten muss ausgewählt werden. o + – Eine beliebige Anzahl von Modelobjekten kann ausgewählt werden. In unserem Beispiel soll die Action lediglich auf einer selektierten Transition ausgeführt werden können. Wir wählen also den Wert „1“. Die plugin.xml-Datei wird somit um den folgenden Eintrag ergänzt: <extension point="ProFLOW.ui.modelObjectActions"> <modelObjectAction id="ProFLOW.example.actions.TransitionInfo" name="Transition Info" class="proFlow.example.ui.actions.TransitionInfoAction" contextMenuGroup="org.eclipse.gef.group.rest" menuGroup="bottom_group" modelObjectTypeId="transitions" enablesFor="1"/> </extension> Die neu erzeugte Model Object Action erscheint nun im Kontextmenu des ProFLOW Editors. Verwendung von Commands Die in den obigen Kapiteln vorgestellte Implementation der Actions kann so leider nicht immer verwendet werden. Sie ist nur zulässig, wenn man lediglich Berechnungen auf dem Modell ausführt. Will man in Actions das zugrundeliegende Modell verändern, müssen Commands verwendet werden. Info: Verändert man das Modell ohne die Verwendung von Commands, so kann man die grafische Darstellung des dargestellten Prozesses zwar mit Hilfe des Benachrichtigungsmechanismus aktualisieren. Das Problem hierbei ist jedoch, dass der ProFLOW-Editor selbst von diesen Veränderungen nichts erfährt und somit den „Dirty State“ nicht aktualisiert und der Editor dementsprechend nicht abspeicherbar ist. Im Folgenden soll nun erklärt werden, wie man mit Hilfe von Commands diesem Problem begegnen kann. Lassen sie uns eine Action implementieren, welche das Counter-Attribut der Klasse ExampleElement hochzählt. Hierfür müssen wir zunächst die EditPart-Klasse unseres ExampleElements um eine weitere EditPolicy erweitern. EditPolicies definieren, wie EditParts verändert werden dürfen. Wir fügen somit unserer Klasse ExampleElementEditPart eine Component-Role-EditPolicy hinzu: public class ExampleElementEditPart extends ElementEditPart { … protected void createEditPolicies(){ super.createEditPolicies(); installEditPolicy(EditPolicy.COMPONENT_ROLE, new ExampleElementEditPolicy()); } } Info: Es gibt eine Vielzahl verschiedener Arten von EditPolicies. Zum Verändern des Modells bietet sich in den meisten Fällen jedoch die Component-Role-EditPolicy an. In der EditPolicy müssen wir nun definieren, wie ein EditPart auf eine konkrete Anfrage (Request) reagieren soll. Wenn ein EditPart eine Anfrage bearbeiten kann, so gibt sie eine entsprechende Command zurück, welche die Anfrage bearbeitet. In unserem Fall gibt sie eine Instanz der Command-Klasse IncrementCounterCommand zurück. Achtung: Eine EditPart kann nur zu jeder Policy-Rolle eine EditPolicy zugewiesen bekommen. Da die Superklasse ElementEditPart der Klasse ExampleElementEditPart bereits eine Component-Role-EditPolicy besitzt, müssen wir diese in unserem Beispiel erweitern. public class ExampleElementEditPolicy extends ElementComponentEditPolicy { public Command getCommand(Request request) { Object model = getHost().getModel(); if (IncrementCounterAction.INCREMENT_COUNTER_REQUEST_TYPE .equals(request.getType()) && model instanceof ExampleElement) { ExampleElement element = (ExampleElement) model; return new IncrementCounterCommand(element); } return super.getCommand(request); } } In der Command-Klasse können wir nun das Hochzählen unseres Counters implementieren. Bei Commands ist es möglich, neben einer Methode execute() auch undo()- und redo()Methoden zu implementieren. Somit ist es im ProFLOW-Editor möglich, diese Veränderungen auch wieder rückgängig zu machen. Die Klasse IncrementCounterCommand sieht demnach wie folgt aus: public class IncrementCounterCommand extends Command { private ExampleElement element; private Integer oldCounter; public IncrementCounterCommand(ExampleElement element) { this.element = element; this.oldCounter = (Integer) element.getAttributeValue( ExampleElement.COUNTER_ATTRIBUTE_ID); } public void execute() { elment.setAttributeValue( ExampleElement.COUNTER_ATTRIBUTE_ID, oldCounter + 1); } public void undo() { element.setAttributeValue( ExampleElement.COUNTER_ATTRIBUTE_ID, oldCounter); } public void redo() { execute(); } } Abschließend müssen wir nun noch die Command ansteuern. Dafür implementieren wir eine neue ModelObjectAction, welche diese Command aufruft. In der Klasse ModelObjectActionRunner stehen hierfür die Hilfsmethoden executeCommand(ModelObject, Request) sowie executeCommand(List<ModelObject>, Request) zur Verfügung. Da wir in unserem Fall lediglich ein selektiertes Element verändern wollen, benutzen wir die erste Methode, um die dazugehörige Command aufzurufen. Hierfür müssen wir lediglich das Element, dessen Counter-Attribut hochgezählt werden soll, sowie einen Request mit dem entsprechenden Typ übergeben: public class IncrementCounterAction extends ModelObjectActionRunner { public static final Object INCREMENT_COUNTER_REQUEST_TYPE = new Object(); public void run(List<ModelObject> modelObjects, Process process, IWorkbenchPartSite site) { Element element = (Element) modelObjects.get(0); executeCommand(element, new Request(INCREMENT_ELEMENT_COUNTER_REQUEST_TYPE)); } } Info: Die Methode executeCommand(…) arbeitet dabei wie folgt. Es wird zunächst der zum ModelObject dazugehörige EditPart ermittelt. Ausgehend von diesem EditPart wird der Command erfragt, welcher den gegebenen Request bearbeiten kann. Dabei werden alle registrierten EditPolicies des EditParts befragt. Abschließend wird die Command auf dem CommandStack des ProFLOW-Editors abgesetzt und somit ausgeführt. Info: Es ist natürlich möglich, die Klasse Request zu erweitern (also Subklassen dieser Klasse zu bilden). Dies kann notwendig werden, wenn man Informationen in Form von Parametern über die EditPolicy zu der entsprechende Command-Klasse weiterleiten möchte. Abschließend müssen wir nun nur noch die obige Action registrieren. Hierfür müssen wir in bereites bekannter Weise die plugin.xml um den folgenden Eintrag erweitern: <extension point="ProFLOW.ui.modelObjectActions"> <modelObjectAction id="proFlow.example.ui.actions.IncrementElementCounterAction" name="Increment Counter" class="proFlow.example.ui.actions.IncrementCounterAction" icon="icons/increment.gif" contextMenuGroup="org.eclipse.gef.group.rest" toolbarGroup="middle_group" modelObjectTypeId="ProFLOW.example.Element" enablesFor="1"/> </extension> Deployen des Plug-Ins Die Definition unseres Example Plug-Ins wäre damit abgeschlossen. Abschließend soll nun noch erläutert werden, wie sie ihr neu erstelltes Plug-In ausliefern können. Ausliefern bedeutet in unserem Fall, dass sie eine .jar-Datei aus ihrem Plug-In Project erzeugen. Gehen sie hierbei wie folgt vor. Spezifieren sie zunächst die Build Configuration ihres Plug-Ins. Gehen sie hierfür auf die Build Page ihres Plug-In Editors. Hier können sie festlegen, welche Dateien der Binary und welche Dateien der Source Build enthalten sollen. Dem Binary Build müssen sie lediglich den META-INF-Ordner, den icons-Ordner sowie die plugin.xml-Datei hinzufügen. Beim Source Build, welchen wir im Folgenden erstellen wollen, wählen sie alle Dateien bis auf bin-Ordner. Info: Wenn sie nichts dagegen haben, dass Nutzer ihres Plug-Ins auch ihren Source-Code sehen dürfen, sollten sie immer einen Source Build erstellen – schließlich profitieren und lernen sie selbst an vielen Stellen meist aus bereitgestelltem Source-Code. Um die .jar-Datei ihres Plug-Ins zu erstellen, wechseln sie zu der Overview Page des Plug-In Editors. Hier können sie rechts unten in der Exporting Section den Export Wizard starten. In diesem müssen sie dann lediglich noch die Destination (also den Zielordner ihres Builds) und die weiteren Optionen spezifizieren. Selektieren sie die ‚Include source code’ Checkbox, um den Source Build auszuwählen. Nachdem sie auf den Finish-Button gedrückt haben, wird die .jar-Datei im angegebenen Zielordner erstellt. Sie können nun die neu erstellte .jar-Datei ihres Plug-Ins in den plugins-Ordner ihrer Eclipse Version kopieren. Beim erneuten Ausführen von Eclipse müssen sie, damit die neue .jar-Datei geladen wird, einmalig das Argument -clean mit übergeben. Anschließend können sie nun den neu erstellten Diagrammtyp auch in ihrer „normalen“ Eclipse Workbench einsetzen.