• Keine Ergebnisse gefunden

für die Plugin-Plattform Plux.NET

N/A
N/A
Protected

Academic year: 2022

Aktie "für die Plugin-Plattform Plux.NET"

Copied!
34
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Technisch-Naturwissenschaftliche Fakultät

Konfigurationswerkzeug „Plugin-Explorer“

für die Plugin-Plattform Plux.NET

B ACHELORARBEIT

(Projektpraktikum)

zur Erlangung des akademischen Grades

Bachelor of Science

im Bachelorstudium

I NFORMATIK

Eingereicht von:

Andreas Gruber, 0655500

Angefertigt am:

Institut für Systemsoftware

Beurteilung:

Mag. Reinhard Wolfinger

Linz, Jänner 2010

(2)

Vorwort

Diese Bachelorarbeit beschreibt die Funktionalit¨at und Implementierung des Konfigura- tionswerkzeugs Plugin-Explorer, kurz Explorer, f¨ur die Plugin-Plattform Plux.NET. Mit dem Explorer kann ein Benutzer ein Programm aus Plugins zusammenstecken, ohne dass er dabei programmieren muss. Der Explorer zeigt die Komponenten eines Programms als Graph an. Dynamische Kontextmen¨us enthalten die Funktionen zum Konfigurieren des Programms.

Die Kapitel 1 und 2 beschreiben die urspr¨ungliche Aufgabenstellung und den Funkti- onsumfang des Explorers. Danach folgt ein Kapitel ¨uber die Bedienung des Programms anhand eines konkreten Beispiels. In den Kapiteln 4 und 5 folgt der technische Teil. Dabei wird als erstes der grunds¨atzliche Aufbau des Explorers beschreiben und danach wird auf wichtige Details der Implementierung einzelner Komponenten eingegangen. Abgeschlossen wird die Arbeit mit einem pers¨onlichem Fazit und einem Ausblick, wie man das Programm weiterentwickeln k¨onnte.

Ich bedanke mich bei Herrn Mag. Reinhard Wolfinger und bei Herrn Dipl.- Ing. Markus Jahn f¨ur die Unterst¨utzung und das zu Stande kommen dieser Arbeit.

I

(3)

Inhaltsverzeichnis

1 Aufgabenstellung 1

2 Funktionsumfang 3

3 Bedienung 5

3.1 Benutzerschnittstelle . . . 5

3.2 Beispiel . . . 7

4 Aufbau 10 4.1 Klassen . . . 10

4.1.1 Explorer . . . 10

4.1.2 ExplorerRuntime, Graph, Info . . . 14

4.1.3 BaseNode, BasePlug, BaseSlot, ToggleButton . . . 15

4.1.4 Toolbar, ToolbarPlugin, ToolbarType . . . 16

4.2 Schnittstellen . . . 17

4.2.1 INode, ISlot, IPlug . . . 17

4.2.2 INotification . . . 18

4.2.3 ILayout . . . 19

5 Implementierung 20 5.1 Windows Forms . . . 20

5.2 Graph . . . 22

5.3 Knoten . . . 25

6 Fazit und Ausblick 28

Abbildungsverzeichnis 29

Quellcodeverzeichnis 30

Literaturverzeichnis 31

II

(4)

Kapitel 1

Aufgabenstellung

Plux.NET ist eine Plugin-Plattform f¨ur Microsoft.NET und erm¨oglicht erweiterbare Pro- gramme, bestehend aus einem ultrad¨unnen Kern und einer Sammlung von Erweiterungen.

Plugins k¨onnen zur Laufzeit in Steckpl¨atze des Kerns oder in Steckpl¨atze anderer Erwei- terungen eingesteckt werden. Weiterf¨uhrende Informationen zu Plux.NET finden Sie auf der Projektseite [2].

F¨ur Plux.NET gibt es das Visualierungswerkzeug HotViz, das die Architektur einer Plugin- Anwendung sowie deren ¨Anderungen zur Laufzeit als Graph anzeigt. HotViz zeigt gelade- ne Erweiterungen, offene Steckpl¨atze und in welche Steckpl¨atze Erweiterungen eingesteckt sind.

Abbildung 1.1: Entwurf der Benutzerschnittstelle des Plugin-Explorers

Das Visualisierungswerkzeug HotViz soll zu einem Konfigurationswerkzeug umgebaut wer- den, mit dem die Architektur nicht nur angezeigt, sondern auch konfiguriert werden kann.

Ziel dieser Arbeit ist Design und Implementierung des Konfigurationswerkzeugs “Plugin- Explorer” mit folgenden Leistungsmerkmalen:

• Multiple Views: Ansichten f¨ur geladene Plugins/Extensions (ein Plugin kann meh- rere Extensions enthalten) oder verf¨ugbare (entdeckte) Plugins/Extensions.

(5)

2

• Zoom und Autoscroll: Stufenloses Zoomen der Ansicht. Bei ¨Anderungen automati- sches Scrollen zum Punkt der ¨Anderung.

• Drag and Drop Plugging, Guides: Einstecken von neuen Plugins durch Drag and Drop aus einem Komponenten-Repository in die View. Hervorhebung der passenden Steckpl¨atze beim Ziehen (siehe Abbildung 1.2).

Abbildung 1.2: Entwurf f¨ur Drag and Drop Plugging

• Unplugging: Gezieltes Ausstecken aus einzelnen Steckpl¨atzen beziehungsweise voll- st¨andiges Entladen des Plugins (siehe Abbildung 1.1).

• Hot Updating: Aktualisieren von Plugins mit neuen Versionen durch Drag and Drop zur Laufzeit.

• Live Statistics: Anzeige von Architekturmetriken, Anzahl der aktuell entdeckten/- geladenen Plugins/Extensions, Anzahl der insgesamt seit Programmstart entdeck- ten/geladenen/entladenen Plugins/Extensions, Anzahl der Steckpl¨atze, usw.

Der Plugin-Explorer ist mit Visual Studio 2005 in C# mit Windows Forms 2.0 zu imple- mentieren. Informationen zu Windows Forms 2.0 und B¨ucher, die zur Unterst¨utzung bei der Programmierung verwendet wurden, sind im Literaturverzeichnis aufgelistet.

Diese Aufgabenstellung ist aus [1] ¨ubernommen worden. Sie wurde in der Phase des Pro- totypings adaptiert und auf die Einschr¨ankungen und Eigenheiten von Windows Forms angepasst. Der endg¨ultige Funktionsumfang des Explorers, und somit auch dieser Arbeit, ist Kapitel 2 beschrieben. Hot Updating wurde aus Gr¨unden der Komplexit¨at gestrichen, aus Live Statistics wurde ein eigenst¨andiges Projekt (Plux-Metrix).

(6)

Kapitel 2

Funktionsumfang

Der Plugin-Explorer ist ein grafisches Konfigurationsprogramm f¨ur Plux.NET. Es erm¨og- licht eine nahezu vollst¨andige Kontrolle ¨uber ein Plux.NET Programm und der Benutzer kann aktiv das Programm manipulieren. Der Explorer kann auch so konfiguriert werden, dass er sich passiv verh¨alt und das System nur visualisiert.

Plux.NET Integration

Der Explorer nutzt nahezu den gesamten Funktionsumfang des Plux.NET Frameworks f¨ur das Konfigurieren und Erstellen von plugin-basierten Anwendungen. Es k¨onnen s¨amtliche Properties der einzelnen Komponenten ver¨andert werden. Das heißt f¨ur jede Komponen- te, wie zum Beispiel f¨ur Slot oder Extension, stehen alle von Plux.NET zu Verf¨ugung gestellten Methoden und Eigenschaften auch im Explorer zu Verf¨ugung.

Dynamische Men¨us

Die gesamte Funktionalit¨at des Explorers befindet sich in Kontextmen¨us. Jedes einzelne Kontextmen¨u wird dynamisch aufgebaut und bietet somit immer die aktuellsten Auswahl- m¨oglichkeiten. Enthalten Men¨ueintr¨age keine Unterpunkte oder sie sind zum Zeitpunkt des Aufrufs nicht m¨oglich, so wird der entsprechende Eintrag deaktiviert. Sind bei einem Unterpunkt mehrere Aktionen gleichzeitig m¨oglich, gibt es auch immer eine M¨oglichkeit alle diese Aktionen gemeinsam auszuf¨uhren.

Anpassbare Ansichten

Grunds¨atzlich wird bei Plux.NET mit Typen (ExtensionTypeInfo), Instanzen (Extension- Info), Plugs (PlugTypeInfo und PlugInfo) und Slots (SlotTypeInfo und SlotInfo) gearbei- tet. Diese Komponenten werden im Explorer in Form eines Extension-Graphs dargestellt.

Da auch noch zus¨atzlich Parameter und Properties der einzelnen Komponenten existieren, kann der Graph sehr komplex und un¨ubersichtlich werden. Aus diesen Gr¨unden ist die Ansicht des Graphs, im speziellen die der Knoten, anpassbar. Jede dieser Einzelkompo- nenten kann angezeigt oder ausgeblendet werden, somit kann immer genau die Ansicht erzeugt werden, die f¨ur die ben¨otigte Aufgabe die Richtige ist. Zudem werden Typen und Instanzen unterschiedlich dargestellt, sodass eine Unterscheidung am ersten Blick m¨oglich ist.

(7)

4

Typenmanagement

Extension Types kommen im Explorer in zwei verschiedenen Auspr¨agungen vor. Entweder sind sie mit einem Slot verbunden oder sie sind frei und ungebunden im Graph. Es gibt verschiedene M¨oglichkeiten diese Typen zu suchen und finden. Typen k¨onnen gruppiert angezeigt, oder auch versteckt werden. Zus¨atzlich gibt es auch eine M¨oglichkeit ungebun- dene Typen vollst¨andig zu entfernen. Wenn von einem Typ eine Instanz erstellt wird, so wird diese direkt beim Typ angezeigt und es kann damit unmittelbar weitergearbeitet werden.

Dynamischer Graph

Der Graph ist durch den Benutzer vielf¨altig manipulierbar, das heißt es k¨onnen einzelne Knoten und Subgraphen verschoben werden. Markierte Knoten k¨onnen mit der Tastatur in kleinen Schritten verschoben werden und es kann in oder aus dem Graphen gezoomt werden. Einzelne Subgraphen k¨onnen unabh¨angig vom Gesamtgraph neu angeordnet wer- den. Weiters werden geschlossene Slots und selektierte Plugs graphisch dargestellt.

Unterschiedliche Bearbeitungsmodi

Der Explorer kann in einem automatischen oder manuellen Modus verwendet werden. Im automatischen Modus k¨onnen einfache Aufgaben ausgef¨uhrt werden und die Komplexit¨at des Programms bleibt verborgen. Im manuellen Modus k¨onnen alle Aktionen vom Benut- zer selbst ausgef¨uhrt werden, das heißt der Benutzer hat volle Kontrolle ¨uber Plux.NET und sieht auch gesamten Funktionsumfang des Explorers.

Plux.NET Framework

Damit sich der Explorer nahtlos in das Plux.NET Framework einf¨ugen kann, ist der Explo- rer selbst auch mit Plux.NET entwickelt. So wird das dauerhafte Speichern der gesamten Einstellungen von Plux.NET ¨ubernommen. ¨Uber einen von Plux.NET zu Verf¨ugung ge- stellten Eigenschaften-Dialog k¨onnen viele Einstellungen ge¨andert werden. Der Explorer kann mittels spezieller Plugs sowohl als eigenst¨andiges Fenster, als auch als Subfenster in der Workbench dargestellt werden.

Erweiterbarkeit

Der Explorer nutzt Plux.NET, um selbst erweiterbar zu sein. Es wird ein Slot angebo- ten, in den neue Algorithmen zum Anordnen der Knoten des Graphs angesteckt werden k¨onnen. Zus¨atzlich ist auch das Benachrichtigungssystem austauschbar, das heißt Benach- richtigungen k¨onnen nicht nur am Bildschirm ausgegeben werden, sondern zum Beispiel auch in eine Datei geschrieben werden.

Toolbar

Alle verf¨ugbaren Plugins werden in einer optionalen Toolbar gruppiert. Innerhalb eines Plugins werden wiederum alle Typen des Plugins angezeigt. Mittels der Toolbar k¨onnen gesamte Plugins oder einzelne Typen dem Graphen hinzugef¨ugt werden. Die Toolbar ver- f¨ugt ¨uber die selben M¨oglichkeiten zum Scrollen wie der Graph und passt ihre Darstellung an den verf¨ugbaren Platz an.

(8)

Kapitel 3 Bedienung

3.1 Benutzerschnittstelle

Um die Grundz¨uge des Explorers zu verstehen wird im ersten Teil dieses Kapitels auf die allgemeinen Teile des Programms eingegangen, danach werden einzelne Funktionen an- hand eines Beispiels n¨aher beschrieben. Zu Beginn wird Plux.NET zusammen mit der Ex- tension Cerberus, einigen wichtigen Contracts und dem Explorer gestartet. Der Explorer verwendet standardm¨aßig eine Extension f¨ur das Layout und f¨ur die Benachrichtigungen, damit er von Beginn an voll einsatzf¨ahig ist. Falls auch Einstellungen ge¨andert werden sollen, wird zus¨atzlich die PropertyDialog Extension ben¨otigt. Beim Start werden keine Einstellungen von Plux.NET ge¨andert, sodass der Explorer anf¨anglich transparent agiert.

Der erste Blick auf das Programm zeigt, dass es keine Men¨uleiste oder Buttons gibt, alle Funktionen sind in den Kontextmen¨us der jeweiligen Komponenten zu finden, zus¨atzlich stehen auch programmweite Tastaturbefehle zu Verf¨ugung.

Abbildung 3.1: Startbildschirm des gestarteten Explorers

(9)

3.1. BENUTZERSCHNITTSTELLE 6

Abbildung 3.1 zeigt den Explorer nach dem Start. Im oberen Bereich ist ein Graph mit den derzeitigen Extensions, sowie deren Slots und Plugs, zu sehen. Das Aussehen der Knoten ist von den gew¨ahlten Einstellungen abh¨angig. Im unteren Bereich sind alle verf¨ugbaren Plugins eingeblendet. Beide Bereiche k¨onnen entweder mit dem Mausrad oder den Cur- sortasten gescrollt werden. Zum Scrollen muss mit der Maus in den jeweiligen Bereich geklickt werden, um ihn zu aktivieren. Wird ein einzelner Knoten ausgew¨ahlt, so kann dieser mit den Cursortasten oder mittels der Maus bewegt werden. Wird zus¨atzlich die Umschalt-Taste gedr¨uckt, so kann mit der Maus ein ganzer Teilgraph verschoben werden.

Uber das Kontextmen¨¨ u des Graph-Bereiches kann ein beliebiger Zoom eingestellt werden.

Das Kontextmen¨u des Graphs beinhaltet auch s¨amtliche Funktionen zur Anpassung der Ansicht. Es k¨onnen Plugins, Extension Types, Slots, Parameter, Plugs und Properties ein- und ausgeblendet werden. Extensions k¨onnen als einzige Komponente nicht ausgeblendet werden. F¨ur die Pfeile zwischen den Knoten ist die Layout-Extension zust¨andig. Abbildung 3.2 zeigt den Explorer in einer angepassten Ansicht.

Abbildung 3.2: Ansicht mit aktivierten Extension Types, Properties und Parameter Die Extension Types sind im Graph immer gepunktet umrandet und zus¨atzlich in einem anderen Farbton gehalten, damit sie auf den ersten Blick zu normalen Extensions unter- schieden werden k¨onnen. Die Properties der einzelnen Komponenten sind immer direkt bei der Komponente ¨uber Buttons zu ¨andern. Gr¨un symbolisiert ein aktiviertes Property, rot eine deaktiviertes Property. Die Runtime, Slots und Extensions besitzen solche um- schaltbaren Properties. In der Abbildung 3.2 sind auch die Parameter eingeblendet. Bei den Slots werden die Parameterdefinitionen und deren Typ angezeigt, graphisch werden diese Parameter mit << dargestellt. Bei den Plugs wird der Parametername und der Parameterwert angezeigt, im Graph wird >> zur Visualisierung verwendet.

Das Kontextmen¨u des Graphs beinhaltet noch viele weitere Funktionen. Es k¨onnen damit die Extension Types aufgelistet und gesucht werden, der Graph kann noch weiter ange- passt werden und die Farboptionen k¨onnen aufgerufen werden. Zu jedem dieser Befehle gibt es einen Tastaturbefehl. Eine wichtige Funktionen dieses Men¨us ist das Umschalten des Modus. Die beiden Modi unterscheiden sich dadurch, dass im manuellen Modus in den Kontextmen¨us der einzelnen Komponenten die volle Funktionalit¨at zu Verf¨ugung steht.

Urspr¨unglich wurden auch die Properties der Runtime je nach Modus ge¨andert, doch diese Funktionalit¨at wurde entfernt, da sie zu Problemen f¨uhrte wenn der Explorer mit anderen Plugins betrieben wurde.

(10)

3.2. BEISPIEL 7

3.2 Beispiel

Zu Beginn werden die Properties im Explorer aktiviert und in der Runtime das Property AutoRegister deaktiviert, damit der Explorer die Kontrolle ¨uber Plux.NET ¨ubernehmen kann. Das Beispiel zeigt nun das Zusammenspiel zwischen dem Explorer, der Workbench und der HelloWorld-Extension. Dazu m¨ussen die beiden Extensions in das Arbeitsver- zeichnis des Explorers kopiert werden, diese erscheinen dann sofort in der Toolbar. Das Ergebnis dieser Schritte in Abbildung 3.3 zu sehen.

Abbildung 3.3: Explorer mit eingeblendeter Toolbar

F¨ur die n¨achsten Schritte muss der Explorer im manuellen Modus sein, da alle Funktionen der Kontextmen¨us ben¨otigt werden. Diese Einstellung ist im Kontextmen¨u des Graphs zu

¨ andern.

(a) Workbench (b) HelloWorld

Abbildung 3.4: Aufrufe zum Registrieren der Extensions Types

(11)

3.2. BEISPIEL 8

Nun wird die Workbench im Slot Startup der Runtime registriert. Dazu muss der Befehl Register im Kontextmen¨u (3.4a) des Startup-Slots aufgerufen werden. Dieses Kontextme- n¨u bietet zus¨atzlich eine Plug- und OpenSlot-Funktion, sowie deren gegenteilige Funktio- nen. Es kann ein Plug selektiert werden und f¨ur den Slot k¨onnen auch einzelne Properties ge¨andert werden. Die Workbench wird automatisch gepluggt, da das Property AutoPlug aktiviert ist. Im n¨achsten Schritt (3.4b) wird der HelloWorld Extension Type im Slot Plux.View der Workbench registriert. Da der Explorer die Typen nicht standardm¨aßig anzeigt, wird der Typ ¨uber das Kontextmen¨u des Graphs gesucht und angezeigt. Von die- sem Extension Type m¨ussen nun konkrete Extensions erzeugt werden, diese Funktion ist im Kontextmen¨u des HelloWorld Extension Types zu finden (3.5a). Das Kontextmen¨u der Extension Types bietet dar¨uber hinaus Funktionen zum Registrieren von Plugs, es k¨on- nen die Werte der Parameter ausgegeben werden und grafische Optionen sowie Properties ge¨andert werden.

(a) Erstellen (b) Pluggen

Abbildung 3.5: Pluggen von HelloWorld an die Workbench

F¨ur das Beispiel werden mittels CreateUnique-Extension Befehl zwei neue HelloWorld- Extensions erzeugt. Diese werden dann an den Plux.View-Slot der Workbench gepluggt.

Diese Funktion l¨asst sich am Plux.View-Slot der Workbench, dem Plux.View-Plug von HelloWorld sowie bei den jeweiligen Extensions aufrufen. In diesem Fall wird das Plug- Kontextmen¨u (3.5b) der einzelnen HelloWorld-Extensions dazu verwendet.

Durch das Pluggen der Extensions wird eine Struktur wie in Abbildung 3.6a erzeugt. Die breite Markierung beim Plug der unteren HelloWorld-Extension ist eine Selektion. ¨Uber das Kontextmen¨u des Plux.View-Slots k¨onnte die Selektion auch auf die obere Exten- sion gelegt werden. Eine Selektion ist auch ¨uber den entsprechenden Plug m¨oglich. In Abbildung 3.6b w¨urde eine ¨Anderung der Selektion bewirken, dass das zu HelloWorld geh¨orende Fenster im Vordergrund angezeigt wird. Wenn in der Benutzerschnittstelle der Workbench das zu HelloWorld geh¨orende Fenster ge¨andert wird, dann wird auch im Ex- plorer die Selektion ge¨andert.

(12)

3.2. BEISPIEL 9

(a) Struktur (b) Benutzerschnittstelle

Abbildung 3.6: Struktur und Benutzerschnittstelle der Workbench

Plux.NET ist so aufgebaut, dass es in unterschiedlichen Komponenten Funktionen gibt, die zum selben Ergebnis f¨uhren. So kann zum Beispiel das Pluggen einer Extension so- wohl vom Plug, als auch vom Slot aus aufgerufen werden. Aus diesem Grund g¨abe es noch weitere Wege, dieses Beispiel zu beschreiben. Zus¨atzlich k¨onnten noch mehr Properties deaktiviert werden, dies h¨atte zur Folge dass die Runtime weniger Aufgaben automatisch erledigt und der Bediener des Explorers mehr Schritte erledigen muss, um zum gew¨unsch- ten Endergebnis zu kommen.

(13)

Kapitel 4 Aufbau

In diesem Kapitel werden die Klassenstruktur und die Schnittstellen des Explorers be- schrieben. Der Explorer besteht aus 37 Klassen, deshalb ist das Klassendiagramm stufen- weise aufgebaut und wird Schritt f¨ur Schritt verfeinert. Prim¨ar wird das Zusammenspiel und die wichtigsten Methoden der Klassen beschrieben.

4.1 Klassen

4.1.1 Explorer

Der Einstiegspunkt in das Programm ist die Klasse Explorer (Klassendiagramm 4.1).

«Interface»

IStartup

«Interface»

IPropertyGroup

«Interface»

IView

«Interface»

ITool Explorer

Control: Control

[Category("Explorer")] ArrowColor: Color [Category("Node")] InstanceColor: Color [Category("Properties")] TrueColor: Color [Category("Switches")] ViewPlugins: bool Run(): void

OnViewPlugged(sender: object, args: PlugEventArgs): void OnToolPlugged(sender: object, args: PlugEventArgs): void OnCreated(sender: object, args: ExtensionEventArgs): void OnReleased(sender: object, args: ExtensionEventArgs): void OnPluginAdded(sender: object, args: PluginEventArgs): void OnPluginRemoved(sender: object, args: PluginEventArgs): void OnExtensionCreated(sender: object, args: ExtensionEventArgs): void OnExtensionReleased(sender: object, args: ExtensionEventArgs): void OnRegistered(sender: object, args: RegisterEventArgs): void

OnDeregistered(sender: object, args: RegisterEventArgs): void OnPlugged(sender: object, args: PlugEventArgs): void

OnUnplugged(sender: object, args: PlugEventArgs): void

OnSelectionChanged(sender: object, args: SelectionChangedEventArgs): void PreferencesPlugged(sender: object, args: PlugEventArgs): void

PreferencesUnplugged(sender: object, args: PlugEventArgs): void AddNotify(sender: object, args: PlugEventArgs): void

AddStructure(sender: object, args: PlugEventArgs): void RemoveNotify(sender: object, args: PlugEventArgs): void RemoveStructure(sender: object, args: PlugEventArgs): void

ExporerRuntime form

Abbildung 4.1: Klassendiagramm Explorer

(14)

4.1. KLASSEN 11

Attribut Extension

Zu den Aufgaben der KlasseExplorer geh¨ort das Verwalten von Plugs und Slots, sowie das Monitoring von Ereignissen der Runtime. Da der Explorer selbst ein Plux.NET Plugin ist, ist das AttributExtension (Quellcode 4.1) notwendig. Dieses Attribut deklariert die Klasse Explorer als Extension. Wenn die Extension erstellt wird, wird die Methode OnCreated aufgerufen. Beim Freigeben der Extension kommt die MethodeOnReleased zum Einsatz.

Dabei wird das Fenster versteckt, erst bei einem neuerlichen Erstellen der Extension wird das Fenster wieder angezeigt.

[ E x t e n s i o n (" E x p l o r e r ",

O n C r e a t e d = " O n C r e a t e d ", O n R e l e a s e d = " O n R e l e a s e d ") ] Quellcode 4.1: Attribut Extension

Monitor Attribute

Um auf ¨Anderungen im Plux.NET System reagieren zu k¨onnen, wird eine Vielzahl von Runtime-Ereignissen beobachtet. Damit ein Plux.NET-Ereignis beobachtet werden kann, muss das Monitor-Attribut verwendet werden. In Quellcode 4.2 sind alle verwendeten Monitoring-Funktionen aufgelistet. Es wird auf das Hinzuf¨ugen und Entfernen von Kom- ponenten, sowie auf das Registrieren und Pluggen reagiert. Jede dieser Funktionen findet sich auch im Klassendiagramm wieder und diese Funktionen rufen wiederum Funktionen von den Klassen Graph oder Toolbar auf. Die Toolbar wird von den beiden OnPlugin- Methoden verwendet, alle anderen Monitoring-Funktionen h¨angen mit der Klasse Graph zusammen.

[ M o n i t o r (

O n R e g i s t e r e d = " O n R e g i s t e r e d ", O n P l u g i n A d d e d = " O n P l u g i n A d d e d ", O n U n p l u g g e d = " O n U n p l u g g e d ", O n D e r e g i s t e r e d = " O n D e r e g i s t e r e d ", O n P l u g g e d = " O n P l u g g e d ", O n P l u g i n A d d e d = " O n P l u g i n A d d e d ",

O n P l u g i n R e m o v e d = " O n P l u g i n R e m o v e d ",

O n E x t e n s i o n C r e a t e d = " O n E x t e n s i o n C r e a t e d ", O n S e l e c t i o n C h a n g e d = " O n S e l e c t i o n C h a n g e d ", O n E x t e n s i o n R e l e a s e d = " O n E x t e n s i o n R e l e a s e d ") ]

Quellcode 4.2: Monitor Attribute Parameter

Plugs k¨onnen parametrisiert werden, die verwendeten Parameter sowie deren Paramter- werte sind in Quellcode 4.3 angegeben. Die ParameterExecuteInMainThread undUnplu- gOnExit werden f¨ur den Plug Startup verwendet, die Parameter OrderIndex, Name und Kind werden von den restlichen Plugs verwendet. Je gr¨oßer der Parameter OrderIndex ist, desto weiter unten wird die Extension in einer Liste angeordnet.

[ P a r a m V a l u e (" E x e c u t e I n M a i n T h r e a d ", tru e) ] [ P a r a m V a l u e (" U n p l u g O n E x i t ", f a l s e) ]

[ P a r a m V a l u e (" O r d e r I n d e x ", 0.9 f ) ] [ P a r a m V a l u e (" Na me ", " E x p l o r e r ") ] [ P a r a m V a l u e (" Ki nd ", V i e w K i n d . T ool ) ]

Quellcode 4.3: Plug Parameterwerte

(15)

4.1. KLASSEN 12

Plug Startup

Der Plug Startup erm¨oglicht es dem Explorer, an den SlotStartup der Runtime gepluggt zu werden. Dazu ist ein Attribut (Quellcode 4.4) notwendig und das Interface IStartup muss implementiert werden. Das Interface verlangt die Implementierung der Methode Run. Diese Methode wird aufgerufen, wenn die Runtime startet.

[ Pl ug (" S t a r t u p ") ]

Quellcode 4.4: Startup Plug

Plug Plux.View

Der Plug Plux.View erm¨oglicht es der Extension seine View, also den Anzeigebereich, in einer anderen Extension anzeigen zu lassen. Dieser Plug ben¨otigt eine Implementie- rung des Interfaces IView. Konkret wird ein String mit dem Namen und ein Feld mit einerControl implementiert. Bei diesem Steuerelement handelt es sich um den Inhalt des Explorer-Fensters, welcher in einem anderen Fenster angezeigt werden soll. Dieser Plug wird verwendet, damit der Explorer innerhalb der Workbench oder eines anderen Contai- ners angezeigt werden kann. Die Methode OnViewPlugged sorgt daf¨ur, dass der Explorer nur in den rufenden Slot gepluggt wird.

[ Pl ug (" P lux . V iew ", O n P l u g g e d = " O n V i e w P l u g g e d ") ] Quellcode 4.5: Plux.View Plug

Plug Plux.Tool

Beim PlugPlux.Tool wird, im Gegensatz zuPlux.View, der Anzeigebereich innerhalb eines eigenen Fensters angezeigt und nicht innerhalb eines anderen Fensters. F¨ur diesen Plug muss das Interface ITool implementiert werden. Wenn der Explorer in einen Plux.Tool Slot gepluggt wird, wird er in der Methode OnToolPlugged aus allen anderen Plux.Tool und Plux.View Slots entfernt und nur in den rufenden Slot gepluggt.

[ Pl ug (" P lux . T ool ", O n P l u g g e d = " O n T o o l P l u g g e d ") ] Quellcode 4.6: Plux.Tool Plug

Plug Plux.PropertyGroup

Mit dem Plug Plux.PropertyGroup k¨onnen zur Laufzeit Eigenschaften ge¨andert werden.

Dazu muss jedes ¨anderbare Feld mit einem Attribut f¨ur die Kategorie gekennzeichnet wer- den. Im Explorer k¨onnen so Farbeigenschaften und bool’sche Werte ge¨andert werden. Im Klassendiagramm sind die vier verwendeten Kategorien, sowie je ein Beispiel angef¨uhrt.

In Plux.NET gibt es die Extension PropertyDialog, ¨uber welche diese Eigenschaften ge¨an- dert werden k¨onnen. Aufgerufen wird diese Extension ¨uber das Kontextmen¨u des Graphs.

Es gibt f¨ur diesen Plug auch ein Interface, dieses ist jedoch leer.

[ Pl ug (" P lux . P r o p e r t y G r o u p ", A u t o P l u g = t rue) ] Quellcode 4.7: Plux.PropertyGroup Plug

(16)

4.1. KLASSEN 13

Slot Explorer.Layout

Dieser Slot erlaubt es, eine Extension f¨ur das Anordnen der Knoten des Graphs an den Explorer zu pluggen. Das Interface ILayout ist in Punkt 4.2.3 beschrieben. Wird nun eine entsprechende Extension gepluggt, wird die Methode AddStructure aufgerufen, in welcher die gepluggte Extension dem Graphen zugewiesen wird. Wird die Extension wieder entfernt, oder wurde nie eine gepluggt, kann der Graph die Knoten nicht anordnen und alle Knoten werden in der linken oberen Ecke positioniert.

[ Sl ot (" E x p l o r e r . L a y o u t ",

O n P l u g g e d = " A d d S t r u c t u r e ", O n U n p l u g g e d = " R e m o v e S t r u c t u r e ") ] Quellcode 4.8: Explorer.Layout Slot

Slot Explorer.Notification

Der Slot Explorer.Notification wird dazu verwendet, um eine Extension f¨ur Benachrich- tigungen an den Explorer zu pluggen. Eine entsprechende Extension muss das Interface (Punkt 4.2.2) implementieren. Wenn keine Notification-Extension gepluggt wird, so gibt der Explorer keine Nachrichten aus. Generell gibt der Explorer ¨uber diesen Slot Statusmel- dungen aus, wenn ein Ereignis auftritt. Fehler werden, wie bei allen anderen Extensions, auf der Kommandozeile ausgegeben.

[ Sl ot (" E x p l o r e r . N o t i f i c a t i o n ",

O n P l u g g e d = " A d d N o t i f y ", O n U n p l u g g e d = " R e m o v e N o t i f y ") ] Quellcode 4.9: Explorer.Notification Slot

Slot Plux.Preferences

Der Slot Plux.Preferences dient zum Verwalten von Einstellungen. Wird eine Extension gepluggt, welche einen Plug f¨ur diesen Slot besitzt, so werden alle Eigenschaften in Pre- ferencesPlugged ¨uberschrieben und der Explorer ver¨andert sein Aussehen und Verhalten entsprechend. Wird diese Extension wieder entfernt, so werden in der Funktion Prefe- rencesUnplugged alle Eigenschaften hinausgeschrieben. Ein typischer Anwendungsfall f¨ur diesen Slot ist das Persistieren von Einstellungen, damit beim n¨achsten Start des Explorers alle Eigenschaften wiederhergestellt werden k¨onnen.

[ Sl ot (" P lux . P r e f e r e n c e s ",

O n P l u g g e d = " P r e f e r e n c e s P l u g g e d ",

O n U n p l u g g e d = " P r e f e r e n c e s U n p l u g g e d ") ]

Quellcode 4.10: Plux.Preferences Slot

Das wichtigste Feld der KlasseExplorer ist das Feldform, darin wird ein Objekt der Klasse ExplorerRuntimegespeichert. Diese Klasse ist auch die n¨achste Stufe im Klassendiagramm und ist im n¨achsten Punkt beschrieben.

(17)

4.1. KLASSEN 14

4.1.2 ExplorerRuntime, Graph, Info

Die Klasse ExplorerRuntime (Klassendiagramm 4.2) implementiert das Hauptfenster des Explorers und ist von der Klasse Form abgeleitet. Dieses Fenster ist in drei Teile aufge- teilt: oben befindet sich der Info-Bereich, in der Mitte der Graph und unten die Toolbar.

Der Info-Bereich ist von Panel abgeleitet und beinhaltet Buttons, um die Properties der Runtime umschalten zu k¨onnen. Dieser Bereich ist sichtbar, wenn ¨uber das Kontextmen¨u des Graphs das Anzeigen der Properties aktiviert ist. ¨Uber das Kontextmen¨u ist auch die Toolbar ein- und ausblendbar. Die Toolbar wird gesondert beschrieben, das Klassendia- gramm ist in Punkt 4.1.4 zu sehen. Der Graph ist von ScrollableControl abgeleitet und kann im Gegensatz zu den anderen Teilen nicht ausgeblendet werden. Zus¨atzliche besitzen sowohl die Klasse ExplorerRuntime als auch die Klasse Graph eine Variable Notify f¨ur eine Extension des Typs INotification.

ExplorerRuntime

Info

Graph ViewPlugins: bool

ViewExtensionTypes: bool ViewFreeTypes: bool ViewSlots: bool ViewParameters: bool ViewPlugs: bool ViewProperties: bool Composition: bool AutoArrange: bool ArrangeWithTypes: bool

AddInstance(ei: ExtensionInfo): void

AddInstanceConnection(si: SlotInfo, pi: PlugInfo): void AddType(si: SlotInfo, pti: PlugTypeInfo): void

AddFreeType(sender: object, e: SelectEventArgs): void AddTypeConnection(si: SlotInfo, pti: PlugTypeInfo): void RemoveInstance(ei: ExtensionTypeInfo): void

RemoveInstanceConnection(si: SlotInfo, pti: PlugTypeInfo): void RemoveType(si: SlotInfo, pti: PlugTypeInfo): void

RemoveDeregisteredType(eti: ExtensionTypeInfo): void RemoveTypeConnection(si: SlotInfo, pti: PlugTypeInfo): void SelectNodes(sender: object, e: SelectEventArgs): void RemoveFreeTypes(): void

FindInstanceNode(ei: ExtensionInfo): InstanceNode ZoomIn(): void

ZoomOut(): void ZoomNormal(): void

«Interface»

INotification

Toolbar Info

Toolbar

Graph

Form Panel

InstanceNode

TypeNode instances

types freeTypes

«Interface»

ILayout Structure

Notify

ScrollableControl

Abbildung 4.2: Klassendiagramm ExplorerRuntime

(18)

4.1. KLASSEN 15

Die Klasse Graph ¨ubernimmt die gesamte Verwaltung der Knoten, einzig das Anordnen der Knoten ist ausgelagert. Dazu wird die Variable Structure verwendet, in welcher eine Layout-Extension gespeichert wird. Im Zusammenspiel mit dieser Klasse ist der Graph voll funktionsf¨ahig. Ohne diese Extension k¨onnen die Knoten nicht platziert und ange- ordnet werden. Auch das Zeichnen der Verbindungen zwischen den Knoten wird durch die Layout-Extension ¨ubernommen. Die Klasse Graph verwaltet die gesamten Knoten in Listen. Da die Knoten eine komplexe Struktur bilden, sind sie im Punkt 4.1.3 gesondert beschrieben. F¨ur die ExtensionInfos wird eine Liste von InstanceNodes gef¨uhrt. F¨ur die ExtensionTypeInfos sind zwei Listen notwendig, eine f¨ur die registrierten Typen und eine f¨ur die freien Typen.

Im Klassendiagramm 4.2 sind alle bool’schen Eigenschaften der KlasseGraph aufgef¨uhrt,

¨uber diese Eigenschaften k¨onnen die verschiedenen Ansichten und das Verhalten des Gra- phs gesteuert werden. Zus¨atzlich gibt es auch Farbeigenschaften, doch diese sind nicht explizit aufgef¨uhrt, da eigentlich jede sichtbare Farbe ge¨andert werden kann. Die Metho- den des Graphs h¨angen meist mit Monitor-Ereignissen der Plux.NET Runtime zusammen, daraus ergibt sich folgende Zuordnung.

• OnExtensionCreated - AddInstance

• OnExtensionReleased - RemoveInstance

• OnRegistered - AddType und AddTypeConnection

• OnDeregistered - RemoveTypeConnection und RemoveType

• OnPlugged - AddInstanceConnection

• OnUnplugged - RemoveInstanceConnection

Uber die Methode¨ AddFreeType k¨onnen ¨uber die Toolbar freie TypeNodes, also Knoten mit ExtensionTypeInfos ohne einer Zuordnung zu einem Slot, zum Graph hinzugef¨ugt werden. Mit den FunktionenRemoveDeregisteredType undRemoveFreeTypes k¨onnen diese TypNodes auch wieder entfernt werden. Weiters gibt es noch Funktionen f¨ur die Steuerung des Zooms, sowie dem Selektieren und Suchen von Knoten.

4.1.3 BaseNode, BasePlug, BaseSlot, ToggleButton

Die Knoten sind die komplexeste Klassenstruktur im Explorer. Diese Komplexit¨at ent- steht dadurch, dass die Knoten die Struktur der Plux.NET Komponenten nachbilden.

Ein Knoten ist ein zusammengesetztes Windows-Forms Steuerelement, besteht aus drei Basisteilen und ist in Abbildung 4.3 zu sehen. Mittelpunkt ist die KlasseBaseNode mit je einer Liste f¨urBasePlugs undBaseSlots. Zus¨atzlich besitzenBaseNode und BaseSlot eine Liste von ToggleButtons. Die Klasse ToggleButton dient zur Umschaltung von bool’schen Properties der jeweiligen Plux.NET Komponente. Alle drei Basisklassen, sowie die Klasse ToggleButton sind von Control abgeleitet und besitzen eine FunktionCalculateSize. Die- se Funktion berechnet, unter Ber¨ucksichtigung der vom Benutzer angepassten Ansicht, die Gr¨oße des zu Grunde liegenden Steuerelements. Dabei ist es wichtig, dass jede Ba- sisklasse den Namen der darzustellenden Komponente enth¨alt, da dieser maßgeblich an der Gr¨oßenberechnung beteiligt ist. Damit die Knoten innerhalb des Graphs richtig an- geordnet werden k¨onnen implementiert jede Basisklasse ein eigenes Interface, der Aufbau

(19)

4.1. KLASSEN 16

dieser Interfaces ist in Punkt 4.2.1 beschrieben. Die eigentliche Zuordnung von Plux.NET Komponenten zu den Teilen eines Knotens passiert durch Ableiten der Basisklassen. Von BasePlug werden die zwei Klassen TypePlug und InstancePlug abgeleitet. Beide Klassen besitzen ein Feld Plug.TypePlug speichert eine PlugTypeInfo und InstancePlug speichert eine PlugInfo darin. Auch bei BaseSlot wird auf die gleiche Art und Weise abgeleitet. Es gibt die UnterklasseTypeSlot mit dem FeldSlot vom Typ SlotTypeInfo undInstanceSlot mit dem FeldSlot vom Typ SlotInfo. Auch beiBaseNode wird diese Ableitung f¨ur Exten- sionTypeInfo und ExtensionInfo durchgef¨uhrt, es entstehen die Klassen TypeNode sowie InstanceNode. Wird zum Beispiel ein Knoten f¨ur eine ExtensionInfo angelegt, so wird f¨ur die Plug- und SlotInfos die jeweilige Liste derBaseNode mit denInstance-Klassen gef¨ullt.

Zus¨atzlich werden f¨ur Extension- und SlotInfo die ben¨otigten ToggleButtons in den Ba- sisklassen abgelegt. Um schnellen Zugriff auf die konkreten Klassen zu erhalten, besitzen sowohlTypeNode als auch InstanceNode einen Indexer f¨ur Plugs und Slots. DieTypeNode kann auch eine ExtensionInfo im Feld CreatedExtension speichern. Sobald aus einem Typ eine Instanz erzeugt wird, wird dieses Feld belegt und die erzeugte Extension kann beim Typ dargestellt werden. Diese Klasse besitzt auch das bool’sche FeldUnregistered, welches wahr ist, wenn der Typ in keinem Slot mehr registriert ist, aber noch im Graph zu sehen ist. Die so genannten freien Typen k¨onnen ¨uber das Kontextmen¨u des Graphs verwaltet werden.

BaseNode NodeName: string GraphPanel: Graph CalculateSize(): void

«Interface»

INode Control

BaseSlot SlotName: string CalculateSize(): void

«Interface»

ISlot

«Interface»

IPlug

BasePlug PlugName: string CalculateSize(): void

ToggleButton CalculateSize(): void

slots plugs

InstancePlug Plug: PlugInfo TypePlug

Plug: PlugTypeInfo

InstanceNode Instance: ExtensionInfo this[pi: PlugInfo]: InstancePlug this[si: SlotInfo]: InstanceSlot TypeNode

Type: ExtensionTypeInfo CreatedExtension: ExtensionInfo Unregistered: bool

this[pti: PlugTypeInfo]: TypePlug this[sti: SlotTypeInfo]: TypeSlot

InstanceSlot Slot: SlotInfo TypeSlot

Slot: SlotTypeInfo toggleButtons

Abbildung 4.3: Klassendiagramm Knoten

4.1.4 Toolbar, ToolbarPlugin, ToolbarType

Die Toolbar verwendet der Explorer zum Auflisten der verf¨ugbaren Plugins und ist, da ein Plugin mehrere ExtensionTypeInfos enthalten kann, stufenweise aufgebaut. Es wird wie- derum die Struktur von Plux.NET dargestellt. Der Aufbau der Klassen ist in Abbildung 4.4 dargestellt.

(20)

4.2. SCHNITTSTELLEN 17

ScrollableControl

Toolbar SelectionEvent: event FocusEvent: event CreateEvent: event

AddPlugin(pi: PluginInfo): void RemovePlugin(pi: PluginInfo): void

plugins ToolbarPlugin Plugin: PluginInfo SelectionEvent: event CreateEvent: event CalculateSize(): void

Control

types

ToolbarType Type: ExtensionTypeInfo

CreatedExtension: ExtensionInfo SelectionEvent: event

FocusEvent: event CalculateSize(): void

Abbildung 4.4: Klassendiagramm Toolbar

Die Toolbar ist von ScrollableControl abgeleitet und verwaltet eine Liste von Elementen der Klasse ToolbarPlugin. Die Klasse ToolbarPlugin besitzt eine Liste von ToolbarTypes.

Sowohl ToolbarPlugin als auch ToolbarTyp sind von der Klasse Control abgeleitet und besitzen eine Methode CalculateSize, um die Gr¨oße der Steuerelemente zu berechnen.

Die Methoden AddPlugin und RemovePlugin erhalten ihre Parameter von der Monitor- Funktionalit¨at und erm¨oglichen, dass die Toolbar immer den aktuellen Stand der Runtime von Plux.NET entspricht. Zus¨atzlich werden von der Toolbar Events zu Verf¨ugung gestellt.

DasSelectionEvent wird ausgel¨ost wenn sich der Mauszeiger innerhalb eines Plugins oder eines Extension Types befindet. Als Parameter wird eine Liste aller betroffenen Extensi- onTypeInfo mitgesendet. DasFocusEvent tritt auf, wenn von einem Extension Type eine Instanz erzeugt wird. Es wird die erzeugte Instanz mitgeschickt und auf diese soll der Focus gelegt werden. Das letzte Event ist das CreateEvent, es wird gesendet wenn unre- gistrierte Extension Types erzeugt werden sollen. Alle diese Events werden vom Graph verwendet und entsprechend verarbeitet.

4.2 Schnittstellen

In einer Plux.NET Umgebung z¨ahlen nicht nur Interfaces zu den Schnittstellen, viel mehr werden auch Plugs und Slots als Schnittstellen zu anderen Plugins gesehen. Nachdem die Plugs und Slots des Explorers bereits beschrieben wurden, widmet sich dieser Teil nun den Interfaces, welche bereits in den Klassendiagrammen verwendet wurden.

4.2.1 INode, ISlot, IPlug

Die Schnittstellen INode, ISlot und IPlug werden f¨ur die Definition eines Knotens im Graph ben¨otigt. Sie legen fest, welche Eigenschaften die Knoten haben m¨ussen, damit das Zeichnen des Graphs m¨oglich ist und die Knoten austauschbar sind. INode definiert grafische Attribute eines einzelnen Knotens, dazu z¨ahlen zum Beispiel der Name, die Gr¨oße und die Position. Eine vollst¨andige Aufstellung der Eigenschaften ist in Abbildung 4.5a zu sehen. Zus¨atzlich muss eineINode das InterfaceIComparable<INode>implementieren, damit die einzelnen Knoten untereinander verglichen werden k¨onnen. ISlot (4.5b) und

(21)

4.2. SCHNITTSTELLEN 18

IPlug (4.5c) verlangen die Implementierung eines AttachPoint. Dieser Punkt wird zum Zeichnen von Verbindungslinien zwischen den einzelnen Knoten verwendet. Zus¨atzlich definiert IPlug noch Felder, damit auch das Selektieren eines Plugs visualisiert werden kann.

«Interface»

INode Size: Size

NodeName: string Location: Point Visible: bool Left: int Top: int

(a) INode

«Interface»

ISlot AttachPoint: Point

(b) ISlot

«Interface»

IPlug AttachPoint: Point Selected: bool Height: int

(c) IPlug

Abbildung 4.5: Interfaces f¨ur Knoten

INode, ISlot und IPlug werden zusammen in der Klasse Edge verwendet. Diese Klasse definiert eine Kante zwischen zwei Knoten. Diese Klasse wurde zum Explorer Contract hinzugef¨ugt, da sie f¨ur das Layout ben¨otigt wird. Wie in der Abbildung 4.6 zu sehen, wird der Startknoten mit seinem Startslot und der Endknoten mit seinem Endplug definiert.

F¨ur das Anordnen von Knoten ist es wichtig, dass Edges untereinander vergleichbar sind.

Edge FromNode: INode FromSlot: ISlot ToNode: INode ToPlug: IPlug

Abbildung 4.6: Klassendiagramm Edge

4.2.2 INotification

INotificationdefiniert eine Schnittstelle, ¨uber die der Explorer Nachrichten und Statusmel- dungen ausgeben kann. Im Klassendiagramm 4.7 ist das vollst¨andige Interface zu sehen.

Uber diese Eigenschaften kann der Explorer die Ein-, Anzeige- und Ausblendezeit sowie¨ die Schriftart festlegen. Die Methode notify wird zur Ausgabe eines Texts verwendet.

«Interface»

INotification FadeInTimeInMillis: int ShowTimeInMillis: int FadeOutTimeInMillis: int Font: Font

Notify(message: string): void

Abbildung 4.7: Interface INotification

Zus¨atzlich wird auch der Slot (Quellcode 4.11) definiert, ¨uber den Notifier an den Explorer gepluggt werden k¨onnen. Im Zuge dieser Arbeit wurde auch ein Notifier erstellt, welcher beim Start des Explorers immer gepluggt wird.

[ S l o t D e f i n i t i o n (" E x p l o r e r . N o t i f i c a t i o n ") ]

Quellcode 4.11: Notificatoin Slot Definition

(22)

4.2. SCHNITTSTELLEN 19

4.2.3 ILayout

Das InterfaceILayouterm¨oglicht es, verschiedene Algorithmen an den Explorer zu pluggen welche f¨ur das Layout des Graphen zust¨andig sind. Die Eigenschaften definieren, das Verhalten des Algorithmus. Zum Beispiel kann festgelegt werden ob Knoten automatisch angeordnet werden, oder ob alle Knoten beim Anordnen mit einbezogen werden sollen.

Das Interface definiert auch Methoden zum Hinzuf¨ugen und Entfernen von Extensions (Instance), Extension Types (Type) und Kanten (Edge). Eine Kante wird erzeugt, wenn Extension gepluggt oder ein Extension Type registriert wird. Im Falle des unpluggen einer Extension oder des unregistrieren eines Extension Types wird die Kante wieder entfernt.

Ausgehend von einer Wurzel kann ein Teil des Graphen neu angeordnet oder verschoben werden.

«Interface»

ILayout ArrangeWithTypes: bool

AutoArrange: bool

LineCollisionDetection: bool ArrowColor: Color

ZoomLevel: int

AddEdge(edge: Edge, typeConnection: bool): void RemoveEge(edge: Edge, typeConnection: bool): void AddInstance(instance: INode): void

RemoveInstance(instance: INode): void AddType(type: INode): void

RemoveType(type: INode): void

ArrangeNow(root: INode, offset: Point): void DrawArrows(grahics: Graphics): void

MoveSubgraph(root: INode, xOffset: int, yOffset: int, xClickOffset: int, yClickOffset: int): void

Abbildung 4.8: Interface ILayout

Im Quellcode 4.12 ist die zum Interface zugeh¨orige Slot Definition angegeben. Um also einen eignen Algorithmus zu entwickeln, muss dieses Interface implementiert werden und

¨

uber diesen Slot kann die Klasse an den Explorer gepluggt werden. Der Explorer kann immer nur einen Algorithmus zum Anordnen der Knoten verwenden, sollte gar keine Layout-Extension an den Explorer gepluggt werden, so bleiben alle Knoten unsortiert in der linken oberen Ecke des Graphs.

[ S l o t D e f i n i t i o n (" E x p l o r e r . L a y o u t ") ]

Quellcode 4.12: Layout Slot Definition

Der Explorer verf¨ugt ¨uber eine Standardimplementierung f¨ur diesen Slot, einzelne Teile dieser Implementierung sind im Kapitel 5 genauer beschrieben.

(23)

Kapitel 5

Implementierung

Nach dem Aufbau und Zusammenspiel der Klassen wird in diesem Kapitel noch eine Ebe- ne tiefer gegangen. Es werden konkrete Implementierungen und L¨osungen verschiedener Problemstellungen behandelt. Zu Beginn werden allgemeine Besonderheiten von Windows Forms beschrieben und danach die Highlights der einzelnen Komponenten des Explorers.

5.1 Windows Forms

Windows Forms ist eine Klassenbibliothek zur Erstellung von Benutzeroberfl¨achen. Diese Klassenbibliothek ist ein Teil des Microsoft .NET Frameworks und bietet eine Vielzahl von vorgefertigten Steuerelementen an. Weiterf¨uhrende Informationen sind unter [3], [5]

und [7] zu finden

Darstellung von benutzerdefinierten Steuerelementen

Anwendungen mit Windows Forms werden ¨ublicherweise aus vorgefertigten Steuerelemen- ten wie Buttons und Textfelder zusammengesetzt. Nat¨urlich gibt es die M¨oglichkeit eigene Elemente zu entwickeln und diese selbst zu zeichnen [4], dies kann jedoch zu Problemen f¨uhren. Es treten Fehler wie Flimmern und Flackern auf oder es bleiben Artefakte zu- r¨uck. Im Explorer werden viele Steuerelemente selbst gezeichnet, deshalb sind f¨ur jede, von Control abgeleitete, Klasse folgende Style Attribute definiert.

th is. S e t S t y l e (

C o n t r o l S t y l e s . A l l P a i n t i n g I n W m P a i n t | C o n t r o l S t y l e s . U s e r P a i n t |

C o n t r o l S t y l e s . R e s i z e R e d r a w |

C o n t r o l S t y l e s . O p t i m i z e d D o u b l e B u f f e r , true) ; Quellcode 5.1: Control Styles

Die Attribute AllPaintingInWmPaint, UserPaint und OptimizedDoubleBuffer sind f¨ur das Verhindern von Zeichenfehlern verantwortlich. Bei der Verwendung des Optimized- DoubleBuffer wird das Element zuerst in einem Buffer und dann erst auf dem Bildschirm gezeichnet.AllPaintingInWmPaint undUserPaint wird gesetzt, damit der Explorer selbst das Steuerelement zeichnen kann und nicht vom Betriebssystem gest¨ort wird. Mit Resi- zeRedraw wird bei jeder Gr¨oßen¨anderung eine Neuzeichnung des Elements angestoßen.

(24)

5.1. WINDOWS FORMS 21

Darstellung von Text

Im Laufe der Entwicklung des Explorers stellte sich heraus, dass gelegentlich keine Schrift in den selbst gezeichneten Steuerelementen angezeigt wurde. Konkret trat dieser Fehler unter Windows 2000 auf. Das Problem war, dass die Texte nur mit der MethodeTextRen- derer.DrawText gezeichnet wurden. In der einfachsten Form verlangt diese Methode nur einen Punkt, bei dem der Text starten soll. Damit die Texte unter allen Versionen von Windows korrekt dargestellt werden k¨onnen, muss der DrawText-Methode ein Rechteck mitgegeben werden, welches den zu zeichnenden Text umschließt. In Quelltext 5.2 ist der Code zu sehen, wie im Explorer Text auf selbst gezeichneten Elementen ausgegeben wird.

Si ze t m p S i z e = T e x t R e n d e r e r . M e a s u r e T e x t (" TEX T ", F ont ) ;

T e x t R e n d e r e r . D r a w T e x t ( Gr aph ics , " T EXT ", Font , new R e c t a n g l e (0 , 0 , t m p S i z e . Width , t m p S i z e . H e i g h t ) , C o l o r ) ;

Quellcode 5.2: DrawText

Tastatureingaben

Da einzelne Funktionen des Explorers mit der Tastatur gesteuert werden, wurden einige M¨oglichkeiten getestet, wie die Eingaben am besten verarbeitet werden k¨onnen. Eine Me- thode ist die Verarbeitung von Tastaureingaben, wenn in der Hauptform die Eigenschaft KeyPreview aktiviert wird. Dann ¨ubernimmt die Form die Abarbeitung der Ereignisse und die Steuerelemente innerhalb dieser Form k¨onnen keine Tastaturereignisse mehr empfan- gen. Im Explorer wird diese M¨oglichkeit nicht verwendet, da die einzelnen Steuerelemen- te, neben den programmweiten Befehlen auch kontextbezogene Tastaturbefehle anbieten.

Die Klasse ExplorerRuntime weist dem Graph, der Toolbar und dem Info-Bereich einen gemeinsamen Eventhandler zu. So kann zum Beispiel im Graph noch eine zus¨atzliche Abarbeitung, wie das Scrollen mit den Pfeiltasten, hinzugef¨ugt werden. Bei der Imple- mentierung ist darauf zu achten, dass eine von Control abgeleitete Klasse immer auch gewisse Tastenfunktionen erbt, wie zum Beispiel, das Verschieben einer Markierung zwi- schen einzelnen Steuerelementen mit den Pfeiltasten. Damit die Pfeiltasten mit eigenen Funktionen belegt werden k¨onnen, ist das ¨Uberschreiben der Methode IsInputKey und das Herausfiltern der ben¨otigten Tasten notwendig. Quelltext 5.3 zeigt, wie dies im Falle der Pfeiltasten funktioniert.

p r o t e c t e d o v e r r i d e bo ol I s I n p u t K e y ( Key s k e y D a t a ) { s w i t c h ( k e y D a t a ) {

ca se Ke ys . Le ft : ca se Ke ys . R i g h t : ca se Ke ys . Up : ca se Ke ys . Do wn :

r e t u r n tru e; }

r e t u r n bas e. I s I n p u t K e y ( k e y D a t a ) ; }

Quellcode 5.3: Methode IsInputKey

(25)

5.2. GRAPH 22

5.2 Graph

Verwaltung der Knoten

Eine der Hauptaufgaben der Klasse Graph ist das Verwalten von Knoten. Durch das Mo- nitoring der Runtime werden Funktionen f¨ur das Erzeugen und Entfernen von Knoten aufgerufen. Wie bereits beschrieben, gibt es Instanzknoten, Typknoten und ungebundene Typknoten. Jede dieser drei Arten wird in einer eigenen Liste verwaltet. F¨ur die Instanz- knoten wird ein Dictionary mit der zugeh¨origen ExtensionInfo als Schl¨ussel verwendet.

Bei den ungebundenen Typknoten geschieht dies auf ¨ahnliche Weise, nur mit der entspre- chenden ExtensionTypeInfo als Schl¨ussel. Die registrierten ExtensionTypInfos werden in einem zweistufigen Dictionary verwaltet. Als Schl¨ussel wird in der ersten Ebene die Slot- Info und in der zweiten Ebene die PlugTypeInfo verwendet. Dies ist erforderlich, da aus Gr¨unden der ¨Ubersicht zu jedem Slot bei dem ein Extension Type registriert ist, auch ein Knoten im Graph angezeigt wird.

D i c t i o n a r y < E x t e n s i o n I n f o , I n s t a n c e N o d e > i n s t a n c e s ;

D i c t i o n a r y < Sl otI nfo , D i c t i o n a r y < P l u g T y p e I n f o , T ype Node > > t y p e s ; D i c t i o n a r y < E x t e n s i o n T y p e I n f o , Typ eNo de > f r e e T y p e s ;

Quellcode 5.4: Knotenlisten

Neben Knoten gibt es in einem Graph auch Kanten, diese werden aber nicht von der Klas- se Graph selbst verwaltet. Das Speichern und Verwalten wird von der Layout-Extension

¨ubernommen. Sobald eine entsprechende Extension an den Explorer gepluggt wird, werden dieser Extension alle bisherigen Kanten ¨ubergeben, danach werden ¨uber die entsprechen- den Funktionen des ILayout Interfaces die Listen der Layout-Extension aktuell gehalten.

Der Codeabschnitt 5.5 aus der Klasse Graph zeigt, wie die Kanten aus der Plux.NET Runtime ausgelesen werden.

f o r e a c h ( S l o t I n f o si in R u n t i m e . R e p o s i t o r y . S l o t I n f o s ) { f o r e a c h ( P l u g I n f o pi in si . P l u g g e d P l u g I n f o s )

A d d I n s t a n c e C o n n e c t i o n ( si , pi ) ;

f o r e a c h ( P l u g T y p e I n f o pti in si . R e g i s t e r e d P l u g T y p e I n f o s ) A d d T y p e C o n n e c t i o n ( si , pti ) ;

}

Quellcode 5.5: Ermitteln der Kanten Zoommechanismus

F¨ur große Graphen wird eine Funktion zum Zoomen ben¨otigt. Anders als bei der Win- dows Presentation Foundation, basieren die Steuerelemente von Windows Forms nicht auf Vektoren, sondern sind in absoluten Gr¨oßen angegeben. Das heißt, beim Zoomen muss die Gr¨oße und alle Abst¨ande des Steuerelements neu berechnet werden, konkret wird die Gr¨oße der Knoten anhand der Schriftgr¨oße berechnet. Die Klasse Graph stellt allen Steu- erelementen diese Gr¨oße zu Verf¨ugung und wenn sie neu gesetzt wird, werden alle Gr¨oßen neu berechnet. Aus der Schriftgr¨oße wird auch die Linenbreite f¨ur Einfassungen und Kan- ten berechnet. Von der Klasse Graph erh¨alt die Layout-Extension die Schriftgr¨oße als Zoomlevel und die Linienbreite. Diese zwei Variablen k¨onnen benutzt werden, damit Lay- out des Graphs dem Zoomlevel entspricht. Die FunktionenZoomIn undZoomOut erh¨ohen beziehungsweise verringern den Schriftgrad um 1.0f. Mit der Funktion ZoomNormal wird der Schriftgrad wieder auf 8.25f gestellt.

(26)

5.2. GRAPH 23

Anordnen der Knoten

Der zentrale Punkt des Explorers ist der Extension-Graph. Das Anordnen seiner Kno- ten ¨ubernimmt die Layout-Extension. In dieser Arbeit wurde ein eigener Algorithmus zum Anordnen der Knoten entwickelt. Dieser Algorithmus kann einerseits Graphen mit mehreren Wurzeln anordnen und andererseits Teilgraphen mit einer definierten Wurzel anordnen. Graphen mit mehreren Wurzeln werden nebeneinander angeordnet. Zus¨atzlich kann der Graph um ein bestimmtes Offset verschoben werden. Der erste Schritt ist das hierarchische Sortieren der Knoten. In Quellcode 5.6 ist der Sortieralgorithmus zu sehen.

Zu Beginn wird ein Dictionary mit der Wurzel als Schl¨ussel definiert. Zu jeder Wurzel gibt es wiederum ein Dictionary. Als Schl¨ussel wird der Level verwendet, die zugeh¨origen Daten sind eine Knotenliste. Nun wird mit der Funktion findRoot f¨ur jeden sichtbaren Knoten seine Wurzel und sein Level bestimmt. Die Variable root legt eine Wurzel f¨ur einen zus¨atzlich sortierten Teilgraph fest, wenn sie null ist, gibt es keine zus¨atzlichen Teil- graphen. Der Level ist der Abstand zur Wurzel und wird sp¨ater f¨ur die Anordnung der Knoten ben¨otigt.

D i c t i o n a r y < INode , S o r t e d D i c t i o n a r y <int, List < INode > > > s o r t e d N o d e s

= new D i c t i o n a r y < INode , S o r t e d D i c t i o n a r y <int, List < INode > > >() ; f o r e a c h ( I N o d e n ode in a l l V i s i b l e N o d e s ) {

K e y V a l u e P a i r < INode , int> r o o t A n d L e v e l = f i n d R o o t ( node , 0 , roo t ) ; if (! s o r t e d N o d e s . C o n t a i n s K e y ( r o o t A n d L e v e l . Key ) )

s o r t e d N o d e s . Add ( r o o t A n d L e v e l . Key , new S o r t e d D i c t i o n a r y <int, List < INode > >() ) ;

if (! s o r t e d N o d e s [ r o o t A n d L e v e l . Key ]. C o n t a i n s K e y ( r o o t A n d L e v e l . V a l u e ) )

s o r t e d N o d e s [ r o o t A n d L e v e l . Key ]. Add ( r o o t A n d L e v e l . Value , new List

< INode >() ) ;

s o r t e d N o d e s [ r o o t A n d L e v e l . Key ][ r o o t A n d L e v e l . V a l u e ]. Add ( nod e ) ; }

Quellcode 5.6: Sortieren der Knoten

Nach dem hierarchischen Sortieren der Knoten beginnt das Anordnen f¨ur jeden Teilgraph, dazu wird f¨ur jede Wurzel die Positionierung der Knoten durchgef¨uhrt. Die Idee des Algo- rithmus ist, dass die sortierten Knoten ihren Level entsprechend untereinander angeordnet werden. Zus¨atzlich sollen die Knoten auf der Y-Achse zentriert sein, es gibt sozusagen eine horizontale Mittellinie. Um die Knoten regelm¨aßig anordnen zu k¨onnen, wird der gr¨oßte Knoten jedes Levels ben¨otigt. In der ersten Schleife wird dieser Wert berechnet und im Dictionary maxXY abgelegt. Zus¨atzlich wird auch die maximale Ausdehnung in X- und Y-Richtung des Levels ermittelt und in maxX sowie maxX gespeichert. Die Variablen xOff und yOff legen jeweils die Abst¨ande zwischen den Knoten fest und werden bei den Berechnungen immer mit einbezogen. In der n¨achsten Schleife wird f¨ur jedes Level das Dic- tionarystartHeigh bef¨ullt. Dabei wird der Y-Wert eingetragen, bei dem der erste Knoten dieses Level platziert werden soll. Dies ist f¨ur die Zentriertheit auf der Y-Achse notwendig.

In der letzen Schleife wird nun jedem Knoten seine endg¨ultige Position zugewiesen. Diese Position h¨angt von einem globalen Offset und den vorangegangenen Knoten ab. Da der Algorithmus mehrere Wurzeln verwalten kann, wird zum Schluss noch ein Offset f¨ur die n¨achste Wurzel berechnet. Der n¨achste Teilgraph wird rechts vom gerade bearbeiteten positioniert.

(27)

5.2. GRAPH 24

int x O f f S e t = 0;

f o r e a c h ( S o r t e d D i c t i o n a r y <int, List < INode > > li st in s o r t e d N o d e s . V a l u e s ) {

D i c t i o n a r y <int, Size > m a x X Y = new D i c t i o n a r y <int, Size >() ; D i c t i o n a r y <int, int> s t a r t H e i g h t = new D i c t i o n a r y <int, int>() ; int ma xX = 0 , ma xY = 0;

int xO ff = z o o m L e v e l * 6 , yOf f = z o o m L e v e l * 4;

f o r e a c h (int l e v e l in li st . Ke ys ) { li st [ l e v e l ]. So rt () ;

m a x X Y . Add ( level , new Si ze (0 , 0) ) ; f o r e a c h ( I N o d e n ode in l ist [ l e v e l ]) {

m a x X Y [ l e v e l ] = new Si ze ( m a x X Y [ l e v e l ]. W i d t h > nod e . Siz e . W i d t h + x Off ? m a x X Y [ l e v e l ]. W i d t h : nod e . Siz e . W i d t h + xOff , m a x X Y [ l e v e l ]. H e i g h t + n ode . S ize . H e i g h t + yO ff ) ;

}

m a x X Y [ l e v e l ] = new S ize ( m a x X Y [ l e v e l ]. Width , m a x X Y [ l e v e l ].

H e i g h t - yOf f ) ;

ma xX += m a x X Y [ l e v e l ]. W i d t h ;

ma xY = maxY > m a x X Y [ l e v e l ]. H e i g h t ? max Y : m a x X Y [ l e v e l ]. H e i g h t ; }

f o r e a c h (int l e v e l in li st . Ke ys ) {

s t a r t H e i g h t . Add ( level , ( m axY /2) - ( m a x X Y [ l e v e l ]. H e i g h t /2) ) ; }

int t m p W i d t h = 0;

f o r e a c h (int l e v e l in li st . Ke ys ) { f o r e a c h ( I N o d e n ode in l ist [ l e v e l ]) {

no de . L o c a t i o n = new P o i n t ( t m p W i d t h + x O f f S e t + o f f s e t . X , s t a r t H e i g h t [ l e v e l ] + o f f s e t . Y ) ;

s t a r t H e i g h t [ l e v e l ] += nod e . Siz e . H e i g h t + y Off ; }

t m p W i d t h += m a x X Y [ l e v e l ]. W i d t h + xO ff ; }

x O f f S e t += xOff + t m p W i d t h ; }

Quellcode 5.7: Anordnen der Knoten

Zeichnen der Kanten

Alle Kanten werden bei der Neuzeichnung des Graphs in der Klasse Graph gezeichnet.

Sie werden als Pfeile dargestellt, beginnen bei einem Plug und enden bei einem Slot.

Plug und Slot stellen daf¨ur ¨uber ein Interface einen Punkt zu Verf¨ugung. Die eigentliche Funktion wird von der Layout-Extension implementiert. Wenn ein Plug selektiert ist, wird zur Kennzeichnung am Beginn des Pfeils ein kleines Rechteck gezeichnet. Darauf folgt das Zeichnen der Linie. Diese Linie ist eine Bezierkurve mit St¨utzpunkten kurz nach dem

(28)

5.3. KNOTEN 25

Slot und kurz vor dem Plug. Quellcode 5.8 zeigt, wie in der Layout-Extension die Kanten zwischen den einzelnen Instanzknoten gezeichnet werden.

Pen i n s t a n c e P e n = new Pen ( A r r o w C o l o r , l i n e W i d t h ) ; f o r e a c h ( Edg e edg e in i n s t a n c e E d g e s ) {

if ( edg e . T o P l u g . S e l e c t e d ) {

int h e i g h t = edg e . T o P l u g . H e i g h t / 2;

if ( h e i g h t == 0) h e i g h t = 1;

G r a h i c s . F i l l R e c t a n g l e (new S o l i d B r u s h ( A r r o w C o l o r ) , e dge . T o P l u g . A t t a c h P o i n t . X - l i n e W i d t h * 3 , e dge . T o P l u g . A t t a c h P o i n t . Y - height , l i n e W i d t h * 3 , h e i g h t * 2) ;

}

G r a h i c s . D r a w B e z i e r ( i n s t a n c e P e n , ed ge . F r o m S l o t . A t t a c h P o i n t , new P o i n t ( ed ge . F r o m S l o t . A t t a c h P o i n t . X + z o o m L e v e l * 4 , e dge . F r o m S l o t . A t t a c h P o i n t . Y ) , new P o i n t ( edg e . T o P l u g . A t t a c h P o i n t . X - z o o m L e v e l * 4 , ed ge . T o P l u g . A t t a c h P o i n t . Y ) , e dge . T o P l u g . A t t a c h P o i n t ) ;

}

Quellcode 5.8: Zeichnen der Kanten

Wenn zus¨atzlich auch Typknoten angeordnet werden, wird analog vorgegangen. Markie- rungen werden nicht ben¨otigt, aber damit eine Linie gezeichnet wird, m¨ussen Beginn- und Endknoten sichtbar sein.

5.3 Knoten

Knotengr¨oße und Ansicht

Die Knotengr¨oße wird mehrstufig berechnet und h¨angt direkt vom Zoomlevel ab, deshalb haben die Klassen BaseNode,BaseSlot, BasePlug und ToggleButton auch Zugriff auf das Feld Font der Klasse Graph. Auch die Einstellungen der angepassten Ansicht werden f¨ur die Gr¨oßenberechnung ben¨otigt. Die Berechnung der Gr¨oße startet in der BaseNode und zu Beginn werden von ihren BaseSlots,BasePlugs undToggleButtons die Gr¨oßen berech- nen. EinBasePlug ist normalerweise so groß, wie der Name des zugeh¨origen Plugs. Wenn die Parameter angezeigt werden, dann kommt pro Parameter eine Zeile hinzu. Auch ein BaseSlot ist nur so groß wie der Name des Slots. Durch Anzeige von Parametern und Togglebuttons ver¨andert sich die Gr¨oße. Bei den Togglebuttons gibt es immer nur eine Gr¨oße. Nachdem alle Gr¨oßen bekannt sind, berechnet die BaseNode eine Referenzgr¨oße aus dem Zoomlevel und dem Namen des Knotens. Diese Gr¨oße ist sehr wichtig, da sie f¨ur alle Abstands- und Gr¨oßenberechnungen herangezogen wird. Die Gr¨oße der BaseNode berechnet sich schlussendlich dadurch, wie groß die Bereiche f¨urBasePlugs undBaseSlots sind, beziehungsweise ob diese ¨uberhaupt angezeigt werden sollen. Nach der Gr¨oßenbe- rechnung wird durch die CalculateSize-Funktion die Gr¨oße der BaseNode gesetzt und zus¨atzlich werden auch noch Punkte berechnet, die angeben, wo die einzelnen Steuerele- mente innerhalb der BaseNode platziert werden sollen. Die eigentliche Platzierung der Steuerelemente passiert beim Neuzeichnen des Steuerelements. Werden keine Slots oder Plugs angezeigt, so werden diese beim Neuzeichnen unsichtbar gesetzt.

(29)

5.3. KNOTEN 26

Aufbau eines dynamischen Men¨us

Eine Hauptfunktion des Explorers sind die dynamischen Kontextmen¨us, denn sie stellen sicher, dass immer die aktuellsten Men¨ueintr¨age zu Verf¨ugung stehen. F¨ur jede Plux.NET Komponente gibt es ein Steuerelement, bei dem es wiederum ein Kontextmen¨u gibt. Da der Aufbau der Men¨us immer nach dem gleichen Schema abl¨auft, wird er anhand des Steuerelements InstancePlug f¨ur PlugInfos demonstriert. Die Funktion PlugContextMe- nuOpening aus Quellcode 5.9 wird an das Opening-Event des Kontextmen¨us geh¨angt, damit das Men¨u bei jedem Aufruf neu aufgebaut werden kann. Als erstes wird das Kon- textmen¨u gel¨oscht und eine Liste angelegt, welche alle unpluggbaren Slots enthalten wird.

Diese Liste wird mit den aktuell gepluggten Slots aufgef¨ullt und sortiert. Nun wird der Men¨ueintrag erstellt, falls es keine Slots zum unpluggen gibt, so wird er deaktiviert darge- stellt. Wenn es aber Eintr¨age gibt, dann wird als erstes ein Men¨ueintrag hinzugef¨ugt, mit dem alle Slots unpluggt werden k¨onnen und danach eineUnplug-Aktion f¨ur jeden einzel- nen. Als Tag wird immer der Slot an den Eintr¨ag hinzugef¨ugt, f¨ur den dieUnplug-Aktion ausgef¨uhrt werden soll. Dieser Vorgang wird bei allen anderen Kontextmen¨us genau so wiederholt, einzig dass F¨ullen der Listen unterscheidet sich.

vo id P l u g C o n t e x t M e n u O p e n i n g (o b j e c t s , C a n c e l E v e n t A r g s e ) { T o o l S t r i p M e n u I t e m item , s u b I t e m ;

p l u g C o n t e x t M e n u . I t e m s . C l e a r () ;

List < Sl otI nfo > c a n U n p l u g = new List < Slo tIn fo >() ; c a n U n p l u g . A d d R a n g e ( p lug . P l u g g e d I n S l o t s ) ;

c a n P l u g . S ort (new S l o t I n f o C o m p a r e r () ) ; it em = new T o o l S t r i p M e n u I t e m (" U n p l u g ") ; if ( c a n U n p l u g . C o u n t > 0) {

it em . D r o p D o w n I t e m s . Add (new T o o l S t r i p M e n u I t e m (" All ", null, d e l e g a t e { pl ug . U n p l u g () ; }) ) ;

it em . D r o p D o w n I t e m s . Add (" - ") ;

f o r e a c h ( S l o t I n f o si in c a n U n p l u g ) {

s u b I t e m = new T o o l S t r i p M e n u I t e m ( si . N ame + " ( " + si . E x t e n s i o n I n f o . Na me + " ) ", null, U n p l u g ) ;

s u b I t e m . Tag = si ;

it em . D r o p D o w n I t e m s . Add ( s u b I t e m ) ; }

} e lse {

it em . E n a b l e d = f a l s e; }

p l u g C o n t e x t M e n u . I t e m s . Add ( it em ) ; }

vo id U n p l u g (o b j e c t sender , E v e n t A r g s e ) {

T o o l S t r i p M e n u I t e m it em = ( T o o l S t r i p M e n u I t e m ) s e n d e r ; pl ug . U n p l u g (( S l o t I n f o ) it em . Tag ) ;

}

Quellcode 5.9: Aufbau Kontextmen¨u

(30)

5.3. KNOTEN 27

Erstellen von neuen Extensions

Sowohl im Graph, als auch in der Toolbar kann von einem Extension Type eine neue Extension erzeugt werden. Dieses Erzeugen hat zur Folge, dass ein neuer Knoten zum Graph hinzugef¨ugt wird. Normalerweise w¨urde der Layout-Algorithmus den neuen Knoten im Graph platzieren und er m¨usste gesucht werden. Es gibt aber eine Funktion, dass der erzeugte Knoten immer beim Erzeuger platziert wird und damit direkt mit dem neuen Knoten weitergearbeitet werden kann. Wenn im Kontextmen¨u des Typknoten eine neue Extension erzeugt wird, wird diese dem Feld CreatedExtension zugewiesen. Dieser Setter ist in Quelltext 5.10 zu sehen. Falls eine Shared-Extension erzeugt wurde, wird diese vom Extension Type geholt. Danach wird der entsprechende Instanzknoten vom Graph gesucht, wenn dieser existiert, wird seine Position ge¨andert und der Knoten wird markiert.

p u b l i c E x t e n s i o n I n f o C r e a t e d E x t e n s i o n { set {

c r e a t e d E x t e n s i o n = v a l u e ;

if ( c r e a t e d E x t e n s i o n == nul l) {

c r e a t e d E x t e n s i o n = typ e . G e t S h a r e d E x t e n s i o n () ; }

if ( c r e a t e d E x t e n s i o n != nul l) {

I n s t a n c e N o d e i n s t a n c e = g r a p h P a n e l . F i n d I n s t a n c e N o d e ( c r e a t e d E x t e n s i o n ) ;

if ( i n s t a n c e != nul l) {

i n s t a n c e . L o c a t i o n = new P o i n t ( L o c a t i o n . X + 15 * g r a p h P a n e l . L i n e W i d t h , L o c a t i o n . Y + 15 * g r a p h P a n e l . L i n e W i d t h ) ; g r a p h P a n e l . I n v a l i d a t e () ;

i n s t a n c e . F o c u s () ; } } } }

Quellcode 5.10: Setter CreatedExtension Togglebuttons

Die Togglebuttons sind Schalter f¨ur die bool’schen Eigenschaften der Plux.NET Kompo- nenten. So k¨onnen zum Beispiel f¨ur eine SlotInfo die Eigenschaften AutoRegister, Au- toOpen, AutoPlug, LazyLoad und Unique umgeschalten werden. Die Togglebuttons sind halbautomatisch, das heißt nach einem Mausklick ¨andern sie ihren Zustand und ihr Ausse- hen erst dann, wenn sie von der Runtime ein Event empfangen. Zus¨atzlich ¨andern sie ihren Zustand auch, wenn zum Beispiel die Konsole die Eigenschaften ¨andert. Um sich selbst¨an- dig ¨andern zu k¨onnen, sind der Attributname (attributeNameLong) und die Komponente (attributeObject) notwendig. Jeder Togglebutton h¨angt an das PropertyChanged-Event seiner Komponente den Listener aus Quellcode 5.11. Sobald sich nun eine Eigenschaft einer Komponente ¨andert, kann jeder Togglebutton feststellen, ob es ihn betrifft und sich gegebenenfalls neu zeichnen.

vo id A t t r i b u t e C h a n g e d (o b j e c t a , P r o p e r t y C h a n g e d E v e n t A r g s e ) { if ( s e n d e r . E q u a l s ( a t t r i b u t e O b j e c t ) && e . P r o p e r t y N a m e . E q u a l s (

a t t r i b u t e N a m e L o n g ) ) { R e f r e s h () ;

} }

Quellcode 5.11: PropertyChanged Funktion

(31)

Kapitel 6

Fazit und Ausblick

Die Entwicklung des Explorers war eine herausfordernde Aufgabe. Vor allem die Windows Forms Programmierung war nicht immer einfach, da einige Schw¨achen dieses Frameworks aufkamen, wenn nicht nur die vorgegebenen Steuerelemente verwendet werden. So mussten einige Ideen f¨ur die Benutzeroberfl¨ache angepasst werden, damit sie trotzdem implemen- tiert werden konnten. Auch die Arbeit mit Plux.NET war h¨ochst interessant, vor allem da die Programmierung der Bachelorarbeit parallel zur Entwicklung von Plux.NET statt fand. Durch diese Parallelit¨at gewann ich Einblick in die Entwicklung eines komplett neuen Plugin-Frameworks.

Der Explorer dieser Bachelorarbeit ist voll funktionsf¨ahig, doch es gibt immer Raum f¨ur Anderungen und Verbesserungen. Wie die Zukunft des Explorers aussehen k¨¨ onnte, ist nachfolgend aufgef¨uhrt.

• Da die Implementierung des Layout-Algorithmus f¨ur den Graph einfach gehalten ist, ist hier Verbesserungspotential vorhanden. Durch ein Austauschen der bishe- rigen Layout-Extension, kann zum Beispiel mit Hilfe von GraphViz ein besseres Ergebnis erzielt werden. GraphViz ist eine OpenSource-Software zum Visualisieren von Graphen [8].

• Eine Implementierung mit der Windows Presentation Foundation w¨urde mehr Frei- raum in der Gestaltung der Benutzeroberfl¨ache zulassen als die bisherige Windows Forms 2.0 Implementierung.

• Der Explorer k¨onnte noch mehr die Ideen von Plux.NET verwenden und so noch modularer werden. Zum Beispiel k¨onnten die Knoten auch als Erweiterung imple- mentiert werden und so zur Laufzeit ausgetauscht werden.

(32)

Abbildungsverzeichnis

1.1 Entwurf der Benutzerschnittstelle des Plugin-Explorers . . . 1

1.2 Entwurf f¨ur Drag and Drop Plugging . . . 2

3.1 Startbildschirm des gestarteten Explorers . . . 5

3.2 Ansicht mit aktivierten Extension Types, Properties und Parameter . . . . 6

3.3 Explorer mit eingeblendeter Toolbar . . . 7

3.4 Aufrufe zum Registrieren der Extensions Types . . . 7

3.5 Pluggen von HelloWorld an die Workbench . . . 8

3.6 Struktur und Benutzerschnittstelle der Workbench . . . 9

4.1 Klassendiagramm Explorer . . . 10

4.2 Klassendiagramm ExplorerRuntime . . . 14

4.3 Klassendiagramm Knoten . . . 16

4.4 Klassendiagramm Toolbar . . . 17

4.5 Interfaces f¨ur Knoten . . . 18

4.6 Klassendiagramm Edge . . . 18

4.7 Interface INotification . . . 18

4.8 Interface ILayout . . . 19

(33)

Quellcodeverzeichnis

4.1 Attribut Extension . . . 11

4.2 Monitor Attribute . . . 11

4.3 Plug Parameterwerte . . . 11

4.4 Startup Plug . . . 12

4.5 Plux.View Plug . . . 12

4.6 Plux.Tool Plug . . . 12

4.7 Plux.PropertyGroup Plug . . . 12

4.8 Explorer.Layout Slot . . . 13

4.9 Explorer.Notification Slot . . . 13

4.10 Plux.Preferences Slot . . . 13

4.11 Notificatoin Slot Definition . . . 18

4.12 Layout Slot Definition . . . 19

5.1 Control Styles . . . 20

5.2 DrawText . . . 21

5.3 Methode IsInputKey . . . 21

5.4 Knotenlisten . . . 22

5.5 Ermitteln der Kanten . . . 22

5.6 Sortieren der Knoten . . . 23

5.7 Anordnen der Knoten . . . 23

5.8 Zeichnen der Kanten . . . 25

5.9 Aufbau Kontextmen¨u . . . 26

5.10 Setter CreatedExtension . . . 27

5.11 PropertyChanged Funktion . . . 27

Referenzen

ÄHNLICHE DOKUMENTE

Wenn Ihnen eine wichtige Regel fehlen sollte, können Sie diese selber in den Kontext der Extension einarbeiten.. Näheres dazu finden Sie auf der Internetseite

Wenn Ihnen eine wichtige Regel fehlen sollte, können Sie diese selber in den Kontext der Extension einarbeiten.. Näheres dazu finden Sie auf der Internetseite

•  Procedures/methods: If the actual parameters have the types of the formal parameters, no type error occurs and the result is of the declared result type.. •  The

private ImmList (int head , ImmList tail ) { this.. b) public final class CompactString { private char[] data ;. private int start ; private int end ; private int hash

1 Index Tuning Query Types Index Types Data Structures Composite Indexes Indexes and Joins Index Tuning Examples.. Augsten (Univ. Salzburg) DBT – Index Tuning Sommersemester 2019 2

1 Index Tuning Query Types Index Types Data Structures Composite Indexes Indexes and Joins Index Tuning Examples.. Augsten (Univ. Salzburg) DBT – Index Tuning SS 2017/18 2

1 Index Tuning Query Types Index Types Data Structures Composite Indexes Indexes and Joins Index Tuning Examples.. Nikolaus Augsten (DIS) DBT – Index Tuning Unit 3 – WS 2015/16 2

Enum-Typen k¨ onnen auch Methoden haben Konstanten k¨ onnen assoziierte Werte haben.. Aufz¨ ahlungstypen