Lade...
 

Fenster und Vererbung

Fenster und Vererbung

Bei der Modulvererbung werden nicht nur Variablen, Prozeduren und Aktionslisten geerbt, sondern auch Fensterdefinitionen. Im einfachsten Fall ist ein Fenster nur im abgeleiteten Modul definiert ist, dann wird die Definition direkt aus dem Sourcecode übernommen. In allen anderen Fällen (Fenster nur im Basismodul definiert oder in Basismodul und im abgeleiteten Modul) bestimmen die nachfolgenden Regeln die resultierende Fensterdefinition.

Grundlegender Ablauf

Beim ersten Öffnen eines Fensters wird die Vererbung eines Fensters "aufgelöst". Hierzu wird in allen Basismodulen nach einer gleichnamigen Fensterdefinition gesucht und diese werden dann zu einer Gesamtdefinition zusammengeführt. Diese Zusammenführung passiert Stufenweise beginnend beim Wurzelmodul (das Modul ohne Basismodule)

Beispiel: Gegeben sei folgende Konstellation: Modul A erbt von Modul B erbt von Modul C erbt von Modul D

Module(A) : B
Window(win) {...}

Module(B) : C

Module(C) : D
Window(win) {...}

Module(D)

 

Dann werden die Fenster in der folgenden Reihenfolge aufgelöst:

  1. C.win - Ist bereits aufgelöst, da es im Basismodul D keine Definition für win gibt
  2. B.win - Die aufgelöste Definition von C.win wird in das Modul B kopiert und umsortiert.
  3. A.win - Das Fenster wird umsortiert und anschließend wird die aufgelöste Definition B.win in A.win gemerged.

Hinweis: Vor Dll-Version 227360 wurde die Vererbung in der umgekehrten Reihenfolge aufgelöst, was dazu geführt hat, dass die Anordnung der Widgets bei einer mehrstufigen Vererbungshierarchie manchmal schwer nachvollziehbar war.

Widgetsortierung

Sobald ein Fenster von einem Basismodul geerbt oder mit einem Basismodul gemerged wird, werden alle Widgets des Fensters umsortiert (falls sie noch nicht in Sortierreihenfolge sind). Die Sortierreihenfolge wird über folgende Relation definiert, welche die Widgets in etwa in Leserichtung nach Koordinaten sortiert. Da die Fokusreihenfolge über die Widgetreihenfolge definiert wird, versucht das ClassiX-System auf diese Weise die Fokusreihenfolge möglichst der Leserichtung anzupassen.

Sortierreihenfolge
Es gilt A < B falls: * |A.y - B.y| < 7 und A.x < B.x * |A.y - B.y| ≥ 7 und A.y < B.y

 

In Worten heißt dies, das Widgets grundsätzlich zuerst nach der Y-Koordinate sortiert werden und bei gleichem Y-Wert nach der X-Koordinate. Hierbei wird die Y-Koordinate bis zu einem Unterschied von 7 Minicells als gleich betrachtet, da die Widgets "quasi" auf der gleichen Zeile liegen. Durch diese letzte Sonderregel verletzt die verwendete Sortierreihenfolge eine grundlegende Eigenschaft einer Ordnungsrelation (die Transitivität), wodurch bereits sortierte Widgets durch eine erneute Sortierung in einer anderen Reihenfolge enden können. Aus diesem Grund wird vor dem Umsortieren der Widgets auf jeder Ebene (Fenster, Gruppe/Composite) geprüft, ob die Widgets die Sortierreihenfolge erfüllen und falls ja, wird die Sortierung nicht angewandt. Anderenfalls würde das Einfügen eines abgeleiteten Moduls ausreichen, um Widgets komplett umzusortieren.

Gegenbeispiel zur Transitivität der Sortierreihenfolge
A(100,0) < B(50,12) < C(75,6) < A(100,0) !!!

 

Merging mit der Basisdefinition

Falls eine Fensterdefinition sowohl im abgeleiteten Modul, als auch im Basismodul vorkommt, dann wird zunächst die Fensterdefinition des abgeleiteten Moduls umsortiert und anschließend mit der aufgelösten Definition des Basismoduls gemerged. Das Merging läuft wie folgt ab:

  1. Alle Eigenschaften des Widgets (Position, Flags, Titel, Widget-Typ) werden aus dem abgeleiteten Widget übernommen.
  2. Die Aktionsliste des Basis-Widgets wird mit dem abgeleiteten Widget verknüpft, sodass das Verhalten des Basiswidgets geerbt wird (falls nicht überschrieben).
  3. Falls das Basis-Widget Kind-Elemente hat (Window, Group, Composite, Menu, Item, ...), dann wird für jedes Kindelement das gleichnamige Kindelement im abgeleiteten Widget gesucht und
    1. falls ein passendes Kindelement gefunden wurde, dann werden die beiden Kindelemente gemerged (beginnend bei Punkt 1)
    2. falls kein passendes Kindelement gefunden wurde, dann wird das Kindelement des Basis-Widgets umsortiert und in das abgeleitete Widget als neues Kindelement eingefügt. Die Einfügeposition wird dabei wie folgt bestimmt:
      1. Falls das einzufügende Kindelement ein Item ist, dann wird am Ende eingefügt
      2. Ansonsten wird das erste Kindelement im abgeleiteten Widget gesucht, welches entsprechend der Sortierreihenfolge größer ist als das einzufügende Kindelement.
        Achtung: Hierbei gibt es die folgende Sonderregel, dass ein Kindelement aus dem abgeleiteten Widget mit gleichen Koordinaten (X-Koordinate gleich, Y-Koordinate ähnlich) größer ist als das einzufügende Kindelement, falls das abgeleitete Kindelement im Zuge des Mergings noch nicht überschrieben oder abgeleitet wurde.1

1= Diese Sonderregel (aus 3.2.2) hat den Effekt, dass Widget, die üblicher Weise ohne Angabe von Koordinaten angegeben werden (Toolbar-Elemente und Notebook-Fenster) so angeordnet werden, dass alle Basis-Kindelemente vor dem ersten Element eingefügt werden, welches ausschließelich in dem abgeleiteten Widget definiert wurde.

Beispiel für Sonderregel aus 3.2.2
Module(A) : B Window(win) { Toolbar(tb) { Button(a1) Button(b2) Button(a2) } } Module(B) Window(win) { Toolbar(tb) { Button(b1) Button(b2) Button(b3) } } // --> Window(win) { Toolbar(tb) { Button(b1) Button(b3) Button(a1) // <-- kommt in B.win nicht vor, deshalb werden b1 und b3 davor eingefügt Button(b2) // <-- b2 wurde in A.win explizit an diese Stelle gesetzt Button(a2) } }

 

Hinweis: Es ist zwar unüblich bei Toolbar-Elementen Koordinaten anzugeben, aber da die Sortierreihenfolge hierfür keine Ausnahme definiert, kann über die Angabe von Koordinaten die Reihenfolge der Buttons in der Toolbar definiert werden.

 

Suche/Matching der Kindelemente

Beim Merging der Widgetdefinitionen muss in Schritt 3 entschieden werden, ob ein Kindelement des Basis-Widgets im abgeleiteten Element überschrieben wird, oder geerbt (also nur kopiert) wird. Hierzu muss anhand des Basis-Kindelements ein passendes abgeleitetes Kindelement gesucht werden.

Bei der Suche nach dem passenden Kindelement werden nur die Kindelemente des abgeleiteten Widgets betrachtet, die während des Mergings bisher noch nicht überschrieben oder vom Basis-Widget geerbt wurden. Diese Kindelemente erhalten nach folgendem Schema einen Matching-Wert und das Kindelement mit dem höchsten Matching-Wert wird als das überschriebende Kindelement zum Basis-Kindelement zugeordnet. Falls alle Kindelemente den Matching-Wert 0 haben, wurde kein überschreibendes Element gefunden und das Kindelement wird vom Basis-Widget geerbt (also in das abgeleitete Widget kopiert).

Sonderfälle:

  1. Ist das Basis-Kindelement eine Toolbar oder Statusbar, dann wird das erste passende Kindelement mit dem gleichen Widget-Typen als Ergebnis genommen. Es liegt die Annahme zugrunde, dass jedes Fenster maximal eine Toolbar und Statusbar haben kann. Es spielt hierbei keine Rolle, ob die Elemente unterschiedliche Bezeichner haben.
  2. Hat das Widget keinen Bezeichner (üblich für Menu und Notebook), dann wird das erste passende Kindelement mit dem gleichen Widget-Typen als Ergebnis genommen. Hierbei spielt es ebenfalls keine Rolle, ob das zuerst gefundene Element einen Bezeichner hat oder nicht.

Bewertungsschema:

Name Alias-Name Typ Matching-Wert
gleich gleich gleich 5
gleich gleich ungleich 4
gleich nur in abgeleitetem Element gesetzt gleich 4
gleich nur in abgeleitetem Element gesetzt ungleich 3
gleich nur in Basis-Element gesetzt gleich 3
gleich nur in Basis-Element gesetzt ungleich 2
gleich ungleich gleich 1 ⟶ 0

Der Name entspricht dabei dem Widget-Identifikator oder dem Zugriffspfad. Der Alias-Name ist der Teil im Widget-Namen hinter dem ~-Zeichen (Tilde). Alle nicht in dieser Tabelle aufgeführten Kombinationen haben den Matching-Wert 0.

Achtung: Die letzte Zeile ist nur aus Rückwärtskompatibilität enthalten und wird in Zukunft mit 0 bewertet, denn den Alias-Namen im abgeleiteten Widget zu ändern hieße, dass die Prozeduren des Basis-Moduls, die explizit auf das Widget über den (alten) Alias-Namen zugreifen, plötzlich im abgeleiteten Modul das Widget nicht mehr finden können.

Die Zuordnung von Basis-Kindelement zu abgeleitetem Kindelement findet primär über den Namen statt. Da der Name auch der Zugriffspfad ist und Fenster mehrere Elemente mit dem gleichen Zugriffspfad enthalten kann, wird das Matching anschließend über den Alias-Namen (falls gesetzt) und über den Typ durchgeführt.

Hinweis: Vor Dll-Version 227360 wurde kein Matching-Wert berechnet, sondern nur die beiden Sonderfälle ausgewertet (für namenlose Widgets) und ansonsten wurde einfach das erste Widget mit gleichem Namen genommen.