Ein Command erhält zur Ausführung eine Anzahl von Objekten,
Argumente genannt, die den Zustand der Benutzeroberfläche zum Zeitpunkt der Ausführung der
Aktion widerspiegeln. Zu dieser Anzahl von Objekten kann jedes
GUI-Element eigene Objekte beisteuern. Command-Argumente sind zunächst nur eine ›flache‹
Ansammlung (Collection) von Objekten, auf die sich aus Sicht des
Benutzers ein Kommando bezieht. Durch die Verwendung der losen Sammlung von Argumenten wird
eine lose Kopplung erreicht. Müsste jedes Command einzeln mit genau den von ihm benötigten
Argumenten versorgt werden, führte dies zu erheblichem ›Verdrahtungsaufwand‹ und einer
starren Kopplung.
Die Verwaltung der Argumentliste erfordert in der Praxis häufig eine dynamische Änderung
der Argumente, die Commands sehen. Zum Beispiel erfordert eine
UI die Tabs benutzt beim Wechsel zwischen Tabs eine Aktualisierung der
Argumentliste: Argumente, die aus dem aktiven Tab stammen, müssen entfernt und Argumente des
neuen Tabs hinzugefügt werden. Darüber hinaus erfordern komplexere UIs
häufig eine hierarchische Strukturierung der Argumente, zum Beispiel wenn innerhalb eines
Tabs eine lokale Werkzeugleiste existiert, aber zusätzlich ein globales Menü, das einen
Tab-übergreifenden Bezug hat. Zur Verwaltung dieser dynamischen und hierarchischen
Argumentliste dient die Hilfsklasse Context.
In bisherigen Versionen musste beziehungsweise konnte der Context manuell verwaltet, das heißt per new
Context(...) erstellt und gehalten werden. Dabei wurde manuell eine
Kontexthierarchie erzeugt (durch Erzeugung von Contexten sowie durch manuelles Setzen der
Eltern-Kind-Bezüge zwischen denselben). Es existierten zwar Methoden, um Contexte mit Komponenten zu assoziieren, deren Verwendung
war aber optional. Die manuelle Verwaltung wird in Jadice 5 nicht mehr unterstützt, da sie
zu äußerst verwirrenden und schwer wartbaren Konstruktionen führen konnte. Stattdessen folgt
nun die Kontext-Hierarchie automatisch der Komponentenhierarchie der GUI.
Hierbei muss nicht zwingend jedes GUI-Element einen eigenen Context bekommen. Vielmehr genügt es, an ›neuralgischen
Punkten‹, das heißt an Stellen, an denen die GUI dynamisch veränderbar
ist, Contexte zu installieren. In einfachen Fällen genügt es
damit, einen Top-Level-Context pro Frame zu erstellen.
Die Verwaltung der Contexte erfolgt mittels folgender Methoden:
static Context.install(JComponent component, Children ca, Ancestors aa)erzeugt einenContextund verbindet ihn mit der gegebenen Komponente. Im Falle des Top-Level-Contextsollte dieser an der content pane desJFrames installiert werden. Bei der Installation werden gegebenenfalls vorhandeneContexte in der Komponentenhierarchie automatisch mit Eltern-Kind-Beziehungen ›verdrahtet‹.static Context.get(JComponent component)liefert denContext, der für die gegebene Komponente zuständig ist. Hierzu wird die Komponentenhierchie, ausgehend von der gegebenen Komponente nach oben hin durchsucht und derContextder ersten Komponente, auf der einContextinstalliert wurde, zurückgegeben.static Context.getPrivateContext(JComponent component)liefert denContextder Komponente, sofern auf ihr einContextinstalliert wurde. Anderenfalls wirdnullzurückgegeben. Eine Suche findet also nicht statt.
Die Sichtbarkeit von Argumenten innerhalb der Context-Hierarchie wird über Aggregationsregeln
gesteuert, die bei der Installation des Context angegeben werden. Wird ein Context nach dem in ihm enthaltenen Argumenten befragt,
so werden zunächst die Argumente, die dem betreffenden Context selbst hinzugefügt wurden, geliefert. Darüber
hinaus können aber auch Argumente von über- oder untergeordneten Kontexten sichtbar werden.
Folgende Aggregationsregeln sind möglich:
Ancestors.NONE: Elemente von übergeordnetenContexten sind niemals sichtbarAncestors.ALL: Die Elemente aller übergeordnetenContexte sind sichtbar. Dies bezieht sich jedoch nur auf die Elemente der übergeordnetenContexte selbst, nicht auf die derer Kindkontexte, unabhängig davon, welche Aggregationsregeln diese benutzen. Elemente von ›Geschwisterkontexten‹ werden also niemals sichtbar.Ancestors.PARENT: Die Elemente des direkt übergeordnetenContexts sind sichtbar, nicht aber die dessen Kinder.Children.NONE: Elemente von untergeordnetenContexten sind niemals sichtbar.Children.ALL: Die Elemente aller untergeordneterContexte sind sichtbar, unabhängig davon, ob diese aktiv oder inaktiv sind.Children.ACTIVE: Die Elemente der aktiven untergeordnetenContexte sind sichtbar.
Kontexte können aktiv oder inaktiv sein. Dadurch wird dem Umstand, dass
GUI-Elemente aktiv oder inaktiv sein können, Rechnung getragen. So ist
zum Beispiel der Context eines inaktiven (also nicht sichtbaren) Tabs
inaktiv, während der Context des aktiven Tabs selbst ebenfalls aktiv ist. Die
Aktivität von Contexten kann manuell über
Context.setActive(boolean active) verwaltet werden. Dies ist jedoch
nicht notwendig für JTabbedPanes sowie
JDesktopPanes, da für diese beiden häufig verwendeten
Komponententypen die Aktivierung derer Contexte automatisch erledigt wird. Es genügt hierzu, der
JTabbedPane beziehungsweise JDesktopPane
einen Context zu installieren.
In Version 4 bot der Context noch einige Hilfsmethoden, mit denen Argumente
bestimmten Typs im Context gesucht werden konnten. Im Sinne einer
übersichtlicheren API haben wir diese Methoden als statische Methoden in
ContextUtils ausgelagert. So erhalten Sie zum Beispiel
durch Aufruf von ContextUtils.findFirst(myContext, PageView.class) die
erste Instanz eines PageViews, die beim Durchsuchen des Contexts gefunden wird. Die Methoden von ContextUtilserlauben es auch, den Inhalt von Contexten zu befragen, ohne zunächst den betreffenden
Context zu ermitteln. So erlaubt es zum Beispiel
ContextUtils.findFirst(myJComponent, PageView.class) einen PageView zu ermitteln, der sich in einem für
myJComponent zuständigen Context befindet.
Darüber hinaus stehen in den ContextUtilsweitere Hilfsmethoden zu Verfügung, die die
Bearbeitung des Inhalts eines Contexts vereinfachen.
ContextUtils.replace(myJComponent, PageView.class, myPageView)
ersetzt zum Beispiel alle eventuell im Context der gegebenen Komponente enthaltenen PageViews durch die gegebene neue PageView-Instanz.
Wollten bisher Commands mit Argumenten arbeiten, die ihnen über eine
Argumentliste (in Form eines Contexts oder einer simplen
Collection) bereitgestellt wurden, so mussten sie sich
verschiedener Filtermethoden bedienen, die in der abstrakten Superklasse
AbstractCommand bereitgestellt wurden. Dies war umständlich und
fehlerträchtig. In Version 5 haben wir deshalb die Möglichkeit geschaffen, Argumente per
Injection automatisch ›bestücken‹ zu lassen. Dadurch werden künftig viele Arbeitsschritte
durch das Framework übernommen, sodass für ein Command benötigte Objekte im Regelfall automatisch bereit
stehen. Aufgabe des Integrators ist es, den Context initial mit den benötigten Objekten zu befüllen
und für jedes Command zu definieren, welche Objekte es aus dem Kontext
voraussetzt. Dass diese Objekte tatsächlich zur Verfügung stehen, musste bisher in jedem
Command manuell überprüft werden. Diese Arbeit wird
künftig durch das Framework übernommen. Nur noch in Ausnahmefällen ist es notwendig, den
Kontext selbst zu befragen.
Sollte dieser Fall auftreten, kann auf die Kontextobjekte über die statischen Methoden
in ContextUtils zugegriffen
werden.


