Die Sprache EpkMl 0.0

Die Sprache EpkMl 0.0

Alexander Knapp, Nora Koch, Luis Mandel, Martin Wirsing

Ludwig-Maximilians-Universität München


Inhalt


Danksagung.
Wir danken allen Mitstreitern im EpkFix-Projekt für den intensiven Austausch und die nützliche Kritik, insbesondere den Teilnehmern am vorweihnachtlichen Workshop in Erlangen.

Einleitung

(zurück zum Inhalt)

Die Sprache EpkMl soll der raschen Entwicklung sogenannter elektronischer Produktkataloge dienen.

Die Sprache EpkMl 0.0 ist eine Untermenge davon, die für die prototypische Realisierung des EPKfix-Systems von allen Teilprojekten unterstützt werden soll, um die Abstimmung der Teilsysteme untereinander zu gewährleisten.

Unter einem elektronischen Produktkatalog wird hier im weiteren Sinne jedes hauptsächlich multimedial (aber insbesondere visuell) basierte, in eingeschränktem Maße interaktive Informationssystem verstanden.

Unser Sprachentwurf verfolgte folgende Ziele:

Den ersten beiden Punkten haben wir durch die hier im ersten Teile vorliegende Definition eines objektorientierten Framework Rechnung getragen. Durch die starke Anlehnung dieses Framework an aus HtMl Bekanntes lag die Verwendung einer SgMl-Syntax nahe; der deklarativ formulierte Text kann dann in eine beliebige Implementationssprache, die das Framework zu beachten hat, übersetzt werden. Auf der anderen Seite ist eine objektorientierte Programmierung in SgMl nicht elegant verwirklichbar. Wir strebten daher eine Hybridsprache an; sie ist in des Dokumentes zweitem Teil dargestellt.

Der Automatisierbarkeit schließlich liegt ein Produktgruppenkonzept zugrunde, das für automatische Navigationen ausgenutzt wird. Auch hier konnte einiges aus HtMl übernommen werden, die Erweiterungen sind hier aber doch beträchtlich.

Ein elektronischer Produktkatalog ist von Schneeberger zutreffend als die Summe der in ihm aufscheinenden Produkte, des gebotenen Service, der zugrundeliegenden Regie und schließlich des oberflächlichen Layout charakterisiert worden. Wir erläutern kurz, in welcher Weise EpkMl diese Konzepte berücksichtigt. Dabei greifen wir in Beispielen den Dingen informell etwas vor; ein formalerer Sprachgebrauch wird dann bei der Festlegung des Framework angestrebt.

Der Darstellung, dem Layout, gilt das Hauptaugenmerk der EpkMl. Hierher gehört das Angebot an multimedialen Elementen verschiedener Formate ebenso, wie die Unterstützung einer absoluten (durch Koordinaten) wie relativen (in Bezug auf andere Objekte) Plazierung und die Schichtung von Objekten. EpkMl bezieht hier wesentlich Ideen aus HtMl, FrameMaker und TeX ein.

Kataloge sind fenster- und nicht primär seitenorientiert, in Abweichung von HtMl (s. o. ). Dies dient vor allem dem Produktvergleich. Aus Einfachheitsgründen sollte allerdings nicht zu intensiver Gebrauch von Fenstertechniken gemacht werden.

Fenster sind in der Version 0.0 der EpkMl ganz ausgeklammert worden

In unserem Framework ist die Regie konzeptuell vom Layout getrennt; die beiden Bereiche sind aber durch Mehrfachvererbung schon hier wieder zusammengeführt , die in Java geeignet auf Einfachvererbung zurückgeführt werden muß. Die Regie besteht aus von einander unabhängig agierenden Prozessen, die über Ereignisse miteinander kommunizieren. Prozessen können Uhren zugeordnet werden und durch eine Synchronisation von Uhren auch gleichförmig synchronisiert werden. Es existieren spezialisierte Prozesse zur Steuerung der im Layout deklarierten multimedialen Elemente.

Weiter dienen eine Navigationsverwaltung und eine virtuelle Strukturierung des Katalogs in Themen und Seiten unter anderem dem einfachen Aufbau eines Regiemodells.

Die Produkte selbst werden in einer Datenbank gehalten, aus der die notwendigen Informationen für Layout, Regie und Service entnommen werden. Desweiteren stehen Datenbanken zur Verwaltung von anbietenden Firmen, Kunden und ihrer eingekauften oder in Betracht gezogenen Waren zur Verfügung.

Die letzteren sind insbesondere für die Serviceleistungen gedacht, wozu neben dem Warenkorb auch der Produktvergleich (hier durch Fenster), das komfortable Bestellen über FAX, Modem oder electronic mail und auch Kalkulationsmöglichkeiten gehören sollen; sie finden auch in der einfachen Anbindung externer Hardware- wie Software-Funktionalität Berücksichtigung.

Eine Analyse bereits vorhandener elektronischer Produktkataloge läßt zwei Typen von Katalogen erkennen, für die beide obige Charakterisierung zutrifft, bei denen aber die Summanden unterschiedlich gewichtet erscheinen: den Typ des Präsentationskatalogs und den Typ des Bestellkatalogs. Bei jenem werden nur wenige Produkte in vielerlei Licht vorgestellt, der Einsatz multimedialer und der Regieelemente ist überdurchschnittlich hoch, der Benutzer wird mit mancher neuer Interaktionsmöglichkeit überrascht, die Navigationsstruktur aber ist wenig hierarchisiert. Bei diesem ist eine hohe Anzahl an Produkten stark in Gruppen gegliedert, auf die durch Blättern oder durch Suche zugegriffen werden kann, die Produkte einer Gruppe werden ähnlich dargestellt, die spezielle Regie tritt zugunsten der Navigationsmöglichkeiten in den Hintergrund. Allerdings findet man auch in den Bestellkatalogen meist aufwendig gestaltete Präsentationen; sie sind dort aber auf wenige Stellen beschränkt.

Eine Automatisierung kann hauptsächlich für Bestellkataloge erreicht werden. Die Produkte werden dabei in Kategorien und Subkategorien eingeteilt, Produkten einer Kategorie eine Darstellung (eventuell mit Ausnahmen) zugewiesen. Anhand dieser Strukturierung werden die Navigationsmöglichkeiten - zu Subkategorien, innerhalb einer Kategorie - vorgefertigt. Natürlich ist das so Erzeugte einer Verfeinerung und Verbesserung offen.

Das Framework

Grundlegendes

(zurück zum Inhalt)

Zur Notation des Framework verwenden wir eine an Java angelehnte Sprache, es ist als Klassenhierarchie gestaltet. An der Spitze dieser Hierarchie steht eine abstrakte Klasse Object; sie hat Klassenmethoden zur Erzeugung und Vernichtung eigener Instanzen.

Wir setzen weiter eine gewisse Menge an einfachen Klassen voraus, die meist Basistypen umfassen; sie seien alle von Object abgeleitet. Die daraus entstehenden Anforderungen werden im folgenden kurz umrissen. Die dabei verwendeten Begriffe Bildschirm und Datenbank entsprechen dem allgemeinen Verständnis.

Basistypen.
Es stehen die Klassen Boolean, Character, Integer, Real und String mit der üblichen Bedeutung und den üblichen Methoden zur Verfügung.

Listen.
Listen ( List) und Listen mit Prioritätsangaben (als Listen von Paaren aus einer Priorität und einem Objekt, PriorityList) werden hier als parametrisierte Klassen betrachtet. Läßt die Implementierungssprache solches nicht zu, so muß der Parameter jeweils durch Object ersetzt werden.

Dimensionen.
Zur Angabe von Maßen dient Dimension. Diese Klasse kann sowohl absolute, mit einer Maßeinheit ( mm, in, pt oder auch px für Pixels) versehene, wie auch relative (prozentuale) Angabe (zu den umgebenden Objekten) aufnehmen.

Mit Position wird eine Position auf dem Bildschirm als Paar von Dimension beschrieben. Der Koordinatenursprung liegt links oben auf dem Bildschirm. Auch Extension besteht aus einem Paar von Dimension; sie definiert eine rechteckige Ausdehnung mit gewisser Höhe und Breite.

Farbe.
Die Farbe wird in Color modelliert. Es sollen mehrere Farbmodelle unterstützt werden (RGB, CYK, etc.) , zunächst aber nur RGB.

Ausrichtung.
Zur Ausrichtung von Bildschirmelementen stehen left (linksbündig), right (rechtsbündig), top (kopfbündig), bottom (fußbündig), vcenter (vertikal zentriert), hcenter (horizontal zentriert) und, soweit es Text betrifft, justified (Blocksatz) zur Verfügung. Diese Angaben können beliebig kombiniert werden, es werden aber nur (implementationsabhängig) sinnvolle Verbindungen unterstützt. Sie sind in der Klasse Alignment enthalten.

Ränder.
Bildschirmelementen kann in Padding zusätzlicher Abstand zur Umgebung mitgegeben werden (der mit zum Element gehört). Die Abstände können links, rechts, oben und unten verschieden sein; sie sind jeweils aus Dimension. Als nicht zum Objekt gehörig kann ein weiterer Rand festgelegt werden, der die Abstände zu den umgebenden Objekten regelt.

Zeit.
Eine Zeitspanne in Time wird als absolute Größe mit einer Maßeinheit ( ms, s) angegeben, in Date ein Datum.

Rechnerspezifisches.
Bei der Rechnertastatur und der angeschlossenen Maus (die hier vorausgesetzt werden) sind einige Interna abzudecken: Die Klasse Modifiers beschreibt die zusammen mit einer anderen Taste betätigbaren Steuertasten (typischerweise Control-, Shift-, etc. Tasten), MouseButtons die zur Verfügung stehenden Maustasten (i. a. zwei oder drei , aber in der EpkMl 0.0 Version nur eine).

Ebenso enthält die Klasse Display Bildschirm- und Auflösungsformate , zunächst nur 640 $\times$ 480.

Benutzerspezifisches.
Es ist manchmal notwendig, unterschiedlichen Katalogbenutzern unterschiedliche Nutzungsmöglichkeiten einzuräumen. Die Klasse UserMode stellt dazu eine Defaulteinstellung bereit. Weitere Sicherheitsabstufungen werden später entsprechend von der Datenbank unterstützt werden.

Sprachen.
Für mehrsprachige Kataloge nimmt die Klasse Language alle verwendeten und anbietbaren Sprachen auf; sie kann auch zusätzliche sprach- oder landesspezifische Informationen (wie etwa eine bildliche Darstellung der Landesflagge, die Währung, etc.) enthalten , bleibt aber in der ersten Version auf Deutsch beschränkt.

Typen externer Daten.
Einige Datentypen können in der Datenbank abgelegt werden: Integer, Real, String, Boolean, Text, Link, Audio, Image, Video, SlideShow und Animation. Über die Codierung wird nichts ausgesagt. Lediglich für Text ist eine ASCII-Codierung nach Standard ISO 8879-1986 (Added Latin) vorzusehen; er kann mit den Steuerzeichen <special type=...> ... </special>, <strong> ... </strong> und <emphasis> ... </emphasis> angereichert werden.

Formate.
Die verschiedenen Formate für die multimedialen Elemente - AudioFormat für Sound files, VideoFormat für Filme, ImageFormat für Bilder, AnimationFormat für Animationen, TransitionFormat für Effekte und SlideShowFormat für Diashows - sollten alle üblichen Standardformate (so vorhanden) umfassen. Ebensolches gilt auch für die möglichen Datenbankformate DatabaseFormat. Es wird vorläufig ein Format für die multimedialen Elemente - AudioFormat für Sound files, ImageFormat f�r Bilder und AnimationFormat für Animationen unterstützt; alle üblichen Standardformate (so vorhanden) sollen später behandelt werden können. Ebensolches gilt auch für die möglichen Datenbankformate DatabaseFormat.

Stile.
Für viele Layout-Elemente sollen jeweils eine gewisse Anzahl vorgefertigter Erscheinungsbilder (Stile) geliefert werden. Die speichernden Klassen enden immer in ...Style.

Files.
Auf extern gespeicherte Inhalte (etwa Files oder die Datenbank) wird durch die Klasse Source zugegriffen. Sie umfaßt einerseits Dateinamen ( Filename), für entfernte Daten aber auch Universal resource locators, sowie Verbindungen (Links) zur Datenbank, die zur Laufzeit hergestellt werden. Die direkte Verwendung von Dateinamen wird durch Filename ermöglicht.

Die Konstruktoren einer Klasse werden im allgemeinen nicht weiter kommentiert, ihre Initialisierungen gehen aus der Syntax hervor. Ebenso verhält es sich mit Getter/Setter-Methoden.

Notationen.
Für Klassen verwenden wir Namen mit Anfangs- und Mittelgroßbuchstaben (z. B. NavigationManager), für Methoden nur Mittelgroßbuchstaben (z. B. setBaseLineSkip()) und für Variablen nur Kleinbuchstaben (z. B. baselineskip).

Gesamtaufbau des Katalogs

(zurück zum Inhalt)

Der Katalogentwerfer ist bei der Gestaltung der Struktur des Katalogs prinzipiell frei. EpkMl stellt dennoch einige Klassen für eine logische Gliederung zur Verfügung; diese eignen sich besonders zur Erzeugung auch in eine Papierversion übersetzbarer Kataloge.

Diese Strukturierung ist in einer abstrakten Klasse zusammengefaßt:



  abstract class Structure extends Object
  { }

Die Aufteilung eines Katalogs erfolgt in Themen und deren wieder in Themen und Seiten. Beiden wird jeweils Regie und (indirekt) Layout zugeordnet. Wechselt man zu einem Thema, so wird dessen erste, ausgezeichnete Seite angezeigt.



  class Theme extends Structure
  {
    private String name;
    private List<Theme> subthemes;
    private List<VirtualPage> pages;
    private List<Thread> direction;

public Theme(String name, List<Theme> subthemes, List<VirtualPage> pages, List<Thread> direction);

public start(); }


Die Methode start() ruft die start()-Methode des ersten Prozesses in direction und die start()-Methode der ersten virtuellen Seite in pages. Ist pages leer, so wird start() für das erste Subthema in subthemes aufgerufen. Zusätzlich speichert sie das Thema in der Navigationskontrolle (s. hier).



  class VirtualPage extends Structure
  {
    private String name;
    private List<Layout> layout;
    private List<Thread> direction;

public VirtualPage(String name, List<Layout> layout, List<Thread> direction);

public start(); }


Auch hier startet start() den ersten Prozeß in direction und ruft draw() für das erste Layout-Objekt in layout auf; die Seite wird ebenfalls in der Navigationskontrolle gespeichert.

Ein Katalog besteht dann aus einer Menge von Themen, einer übergeordneten Regie, einer Menge von Datenbanken und einer Konfigurierung:



  class Catalogue extends Object
  {
    private String name;
    private String version;
    private String author;
    private String copyright;
    private List<Theme> contents;
    private List<Database> data;
    private List<Thread> direction;
    private Configuration configuration;

public Catalogue(String name, String version, String author, String copyright, List<Theme> contents, List<Database> data, List<Direction> direction);

public start(); }


Hier ruft start() die Initialisierungroutine von configuration auf, startet den ersten Prozeß in direction und das erste Thema in contents.

Das Regiemodell

(zurück zum Inhalt)

Die Benutzerführung durch den Katalog, d. h. das Angebot an Interaktionsmöglichkeiten einerseits und die automatische Vornahme gewisser Navigationen andererseits, wird durch ein Regiemodell erfaßt. Konzeptuell sehen wir dabei eine Trennung dieser dynamischen Strukturierung von der statischen des Layout vor. Diese Separation wird durch die Verwendung multipler Vererbung zum Ausdruck gebracht.

Als grundlegende Regieobjekte werden von einandender unabhängige, parallele Prozesse verwendet, die über Ereignisse miteinander kommunizieren und über Uhren verfügen und so synchronisiert werden können. Zur Steuerung der verschiedenen multimedialen Elemente stehen entsprechend spezialisierte Prozesse zur Verfügung, ebenso zur Verwaltung der Navigationsinformationen.

Die Unterstützung dieses Regiemodells hat implementationsseitig zwei Voraussetzungen: die Existenz eines Hintergrundprozesses, der die vom zugrundeliegenden Betriebssystem gelieferten Zustände der Ein-/Ausgabegeräte auf (EpkMl-)Ereignisse abbildet - des Ereignisverwalters, und die Existenz einer (hinreichend) genauen Uhr. An die Geschwindigkeit dieses Prozesses werden keine Anforderungen gestellt; lediglich die Reihenfolge von äußeren Ereignissen sollte, bis auf eine gewisse Toleranz, bei obigem Abbildungsvorgang erhalten bleiben.

Die Regie ist in einer abstrakten Klasse zusammengefaßt, die aber lediglich der Gruppierung dient.



  abstract class Direction extends Object
  {
    private UserMode usermode;
    private Integer limit;

public setUserMode(UserMode usermode); public UserMode getUserMode(); public setLimit(Integer limit); public Integer getLimit(); }


Das Attribut usermode legt die Rechte des Benutzers fest. Gewisse Regieteile können damit für Unbefugte gesperrt werden. Davon beeinflußt oder aber durch die Rechnerkapazitäten determiniert, bestimmt limit eine gewisse Obergrenze an auszuführender Funktionalität (Beschränkung der aktiven Prozesse, der Uhren, der erzeugten Ereignisse, etc.)

Sie stellt zwei zusätzliche multimediale Elemente zur Verfügung, die nur indirekt mit dem Layout befaßt sind: Klänge (s. hier) und Effekte (s. hier).

Uhren

Mit Hilfe von Uhren können Prozesse über die Zeit gleichförmig synchronisiert werden. Für die Modellierung komplizierterer zeitlicher Vorgänge besteht die Möglichkeit nicht nur Prozesse, sondern auch andere Uhren von einer Uhr abhängig zu machen, sie zu takten.

Eine Uhr besitzt dabei eine Skalierung, d. h. bildlich eine Einteilung ihres Ziffernblatts, und eine Rate, die, im Bilde, angibt, wie oft innerhalb einer Sekunde der Zeiger der Uhr das Ziffernblatt überstreicht. Eine Uhr mit Rate null ist angehalten. Eine Rate kann auch negativ sein; die Uhr läuft dann rückwärts.

Wie erwähnt kann eine Uhr von einer anderen abhängig gemacht werden; diese heißt Master, jene Slave. Das bedeutet nicht nur einen - bei nicht abhängigen Uhren nicht zu garantierenden - Gleichlauf dieser Uhren, sondern ermöglicht auch die Steuerung einer abhängigen Uhr durch eine andere vermittels der sogenannten effektiven Rate. Für Uhren ohne Master ist diese die aktuelle (lokale) Rate, für Slaves das Produkt aus der effektiven Rate ihres Master und der eigenen (lokalen) Rate. Insbesondere hält das Setzen der Rate eines Master alle von ihm abhängigen Slave-Uhren an.



  class Clock extends Direction
  {
    private Clock master;
    private Integer rate;
    private Integer scale;
    private Time actual;

public Clock(Clock master); public Clock(Clock master, Time actual); public Clock(Clock master, Integer rate, Integer scale, Time actual); public Clock(Integer rate, Integer scale, Time actual);

public Clock getMaster(); public setRate(Integer rate); public Integer getRate(); public setScale(Integer scale); public Integer getScale(); public setTime(Time actual); public Time getTime(); }


Die Hardware-technisch vorausgesetzte Rechneruhr wird als Instanz der Klasse Clock ohne Master modelliert. Uhren, die durch den letzten der Konstruktoren instantiiert werden, erhalten diese Hardware-Uhr als Master.

In der eben angeführten Fassung dienen Uhren lediglich zur globalen Synchronisation. Sie können aber weiter mit der Funktionalität eines eventuell periodischen Weckers ausgestattet werden.



  class Timer extends Clock
  {
    private List<Time> when;

public Timer(List<Time> when);

public setAlarms(List<Time> when); public List<Time> getAlarms(); }


Zu den Zeiten in when werden von der Uhr Ereignisse der Klasse ClockEvent (s. hier) erzeugt.



  class PeriodicalTimer extends Timer
  {
    private Time cycle;

public PeriodicalTimer(List<Time> when, Time cycle);

public setCycle(Time cycle); public Time getCycle(); }


Hier werden die Ereignisauslösungen, zunächst wie bei Timer periodisch nach der Zeit cycle wiederholt. Dazu muß cycle größer sein, als die letzte Zeitangabe in when.

Ereignisse

Ereignisse dienen der Benachrichtigung von Prozessen über gewisse Zustandsänderungen. Sie werden einerseits vom postulierten Hintergrundprozess als Weitergabe betriebssystemlicher Meldungen erzeugt, können andererseits aber auch benutzerdefinierten Ursprungs sein. Dazwischen liegt eine Klasse höherer Ereignisse, die vom Hintergrundprozess in Zusammenfassung und Abstraktion mehrerer kleinerer Ereignisse erzeugt werden.

Eine abstrakte Klasse faßt die Ereignisse zusammen:



  abstract class Event extends Direction
  {
    private Time stamp;

public setStamp(Time stamp); public Time getStamp(); public Boolean signal(); public Boolean asignal(); }


Alle Ereignisse besitzen eine Zeitmarke (stamp). Sie können synchron nach dem rendez-vous-Konzept (signal()) oder asynchron (asignal()) verschickt werden. Ereignisse werden von Prozessen in Handlers (s. u. ) akzeptiert; es kommt ein rendez-vous zustande, wofern signal() verwendet wird.

Die Instanzen (von Subklassen) der Klasse Event dienen weiter als Muster für das Kommunikations-Pattern matching.

Für die wichtigsten Ereignistypen in der Interaktion eines elektronischen Produktkatalog sind Event-Subklassen vordefiniert, so für Tastatur-, Maus- und Cursor-Ereignisse.

Tastaturereignisse.
Jede Tastaturbetätigung löst ein Ereignis aus. Dabei werden die gedrückte Taste selbst, als Scan code der Tastaturmatrix, und die dabei verwendeten Modifikationstasten, z. B. die Shift-, Control-, Alternate-Taste, unterschieden.



  abstract class KeyboardEvent extends Event
  {
    private Character key;
    private Modifiers modifiers;

public setKey(Character key); public Character getKey(); public setModifiers(Modifiers modifiers); public Modifiers getModifiers(); }


Es wird noch genauer zwischen dem Drücken einer Tasten-Modifikator-Kombination



  class KeyboardDownEvent extends KeyboardEvent
  {
    public KeyboardDownEvent();
    public KeyboardDownEvent(Character key, Modifiers modifiers);
    public KeyboardDownEvent(Time stamp, Character key,
                             Modifiers modifiers);
  }

und dem Loslassen derselben unterschieden:



  class KeyboardUpEvent extends KeyboardEvent
  {
    public KeyboardUpEvent();
    public KeyboardUpEvent(Character key, Modifiers modifiers);
    public KeyboardUpEvent(Time stamp, Character key,
                           Modifiers modifiers);
  }

Mausereignisse.
Jede Veränderung des Mauszustandes löst ein Mausereignis aus. Die Aufgabe des Ereignisverwalters ist hier nicht nur die Übersetzung dieser Statusänderungen in Ereignisse, sondern auch die Ermittlung desjenigen Layout-Objektes, über dem sich der Mauszeiger zum Zeitpunkt der Ereignisauslösung befindet.



  abstract class MouseEvent extends Event
  {
\secondlevel{
    private MouseButtons buttons;
}
    private Modifiers modifiers;
    private Position position;
    private Layout obj;

public actual(); \secondlevel{ public setButtons(MouseButtons buttons); public MouseButtons getButtons(); } public setModifiers(Modifiers modifiers); public Modifiers getModifiers(); public setPosition(Position position); public Position getPosition(); public setObject(Layout obj); public Layout getObject(); }


In modifiers werden die bei der Auslösung des Mausereignisses gedrückten Modifikationstasten festgehalten, in obj das Layout-Objekt über dem sich der Mauszeiger befand, und in position die Mauszeigerkoordinaten relativ zum Objekt obj. Mit der Methode actual() kann der aktuelle Mauszustand in ein Mausereignis eingetragen werden.

Wieder werden die einzelnen Zustandsänderungsmöglichkeiten einzeln erfaßt. Das Drücken einer Maustaste löst aus ein



  class MouseDownEvent extends MouseEvent
  {
    public MouseDownEvent();
    public MouseDownEvent(\secondlevel{MouseButtons buttons,}
 Modifiers modifiers,
                          Position position, Layout layout);
    public MouseDownEvent(Time stamp, \secondlevel{MouseButtons buttons,}
                          Modifiers modifiers, Position position,
                          Layout layout);
  }

das Loslassen einer Maustaste ein



  class MouseUpEvent extends MouseEvent
  {
    public MouseUpEvent();
    public MouseUpEvent(
\secondlevel{
             MouseButtons buttons,
}
 Modifiers modifiers,
                        Position position, Layout layout);
    public MouseUpEvent(Time stamp, 
\secondlevel{
             MouseButtons buttons,
}
                        Modifiers modifiers, Position position,
                        Layout layout);
  }

eine Bewegung des Mauszeigers ein



  class MouseMoveEvent extends MouseEvent
  {
    public MouseMoveEvent();
    public MouseMoveEvent(
\secondlevel{
             MouseButtons buttons, 
}
Modifiers modifiers,
                          Position position, Layout layout);
    public MouseDownEvent(Time stamp,
\secondlevel{
             MouseButtons buttons,
}
                          Modifiers modifiers, Position position,
                          Layout layout);
  }

eine Bewegung des Mauszeigers bei gedrückter Maustaste ein



  class MouseDragEvent extends MouseEvent
  {
    public MouseDragEvent();
    public MouseDragEvent(\secondlevel{MouseButtons buttons,}
Modifiers modifiers,
                          Position position, Layout layout);
    public MouseDragEvent(Time stamp, \secondlevel{MouseButtons buttons,}
                          Modifiers modifiers, Position position,
                          Layout layout);
  }

das Eintreten des Mauszeigers in einen einem Layout-Objekt zugeordneten Bereich ein



  class MouseEnterEvent extends MouseEvent
  {
    public MouseEnterEvent();
    public MouseEnterEvent(\secondlevel{MouseButtons buttons,}
 Modifiers modifiers,
                           Position position, Layout layout);
    public MouseEnterEvent(Time stamp, \secondlevel{MouseButtons buttons,}
                           Modifiers modifiers, Position position,
                           Layout layout);
  }

und das Verlassen eines einem Layout-Objekt zugeordnetem Bereichs durch den Mauszeiger ein



  class MouseExitEvent extends MouseEvent
  {
    public MouseExitEvent();
    public MouseExitEvent(\secondlevel{MouseButtons buttons,}
 Modifiers modifiers,
                          Position position, Layout layout);
    public MouseExitEvent(Time stamp, \secondlevel{MouseButtons buttons,}
                          Modifiers modifiers, Position position,
                          Layout layout);
  }

Uhrereignisse.
Wie im Abschnitt hier über Uhren erwähnt, lösen Instanzen der Klassen Timer und PeriodicalTimer Ereignisse aus, Ereignisse der Klasse ClockEvent.



  class ClockEvent extends Event
  {
    private Clock clock;
    private Time relative;

public ClockEvent(); public ClockEvent(Clock clock, Time relative); public ClockEvent(Time stamp, Clock clock, Time relative);

public setClock(Clock clock); public Clock getClock(); public setTime(Time relative); public Time getTime(); }


Die auslösende Uhr steht in clock, ihre Zeit bei Auslösung des Ereignisses in relative.

Interaktionsereignisse.
Gewisse Ereignisabfolgen für bestimmte Objekte, wie sie typischer Weise bei Benutzerinteraktionen auftreten, sollen zu einem einzigen Ereignis zusammengefaßt werden.



  abstract class InteractionEvent extends Event
  { }

Der einfachste Interaktionstyp ist:



  class SelectEvent extends InteractionEvent
  {
    public SelectEvent(Layout obj);
  }

Er wird bei einfachen, anwählbaren Objekten bei ihrer tatsächlichen Anwahl versandt; im Moment ist dies nur die Klasse HyperLink.

Einige Objekte bieten mehrere Auswahlmöglichkeiten, wie Browser, CheckBox, etc.



  class OptionSelectEvent extends InteractionEvent
  {
    private Option which;

public OptionSelectEvent(Layout obj, Option which);

public setOption(Option which); public Option getOption(); }


Hier soll zusätzlich zu dem angewählten zusammenfassenden Objekt (in obj) auch das tatsächlich ausgewählte Unterobjekt in which gemeldet werden.

Aktionsereignisse.
Es ist auch von einigen internen Zustandsänderungen zu abstrahieren.



  abstract class ActionEvent extends Event
  { }

Davon sind insbesondere Abspielprozesse (s. u. ) und die Eingabe (s. u. ) betroffen.



  class EndEvent extends ActionEvent
  {
    public EndEvent(Layout obj);
  }

Wird das Ende eines Mediums erreicht, so löst das eine Instanz von EndEvent aus. Auf der anderen Seite ergibt auch die Betätigung der Return-Taste für ein Eingabefeld dieses Ereignis.

Prozesse

Der Katalogablauf und damit die Benutzerführung wird als Zusammenspiel vieler, parallel ablaufender Prozesse organisiert. Prozesse können über Ereignisse oder direkt miteinander kommunizieren und durch Uhren gleichförmig synchronisiert werden.

Auf sequentiellen Architekturen ist ein Dispatcher zur Abarbeitung dieser Prozesse vorzusehen. Er hat Fairness zu garantieren und Deadlocks zu vermeiden und sie eventuell aufzulösen. Für kritische Abschnitte muß ein Synchronisationsprimitv zur Verfügung gestellt werden. Über die Geschwindigkeit der Prozesse relativ zueinander wird keine Annahme gemacht. Die Kommunikation kann synchron über Ereignisse und Methoden oder asynchron über Ereignisse erfolgen.



  class Thread extends Direction
  {
    private Integer priority;
    private PriorityList<Event> interests;

public Thread(); public Thread(Integer priority, PriorityList<Event> interests);

public Boolean start(); public Boolean stop(); public run(); public Boolean suspend(); public Boolean resume(); public Boolean kill(); public Boolean yield(); public Boolean join(Time wait); public Boolean handler(Event event); public setPriority(Integer Priority); public Integer getPriority(); public setInterests(PriorityList<Event> interests); public PriorityList<Event> getInterests(); }


Prozesse mit niedrigeren priority-Werten (d. i. höherer Priorität) sind bevorzugt zu behandeln. Implementationsseitig können Prozesse ab einer bestimmten priority als suspendiert betrachtet werden.

Die von einem Prozess auszuführenden Anweisungen sind in run() zu definieren. Mit start() wird der Prozess gestartet: es wird run() ausgeführt; gelingt dies nicht, so liefert die Methode false zurück, ansonsten ergibt sie den Wert true. Die Methode stop() beendet einen Prozeß; das Rückgabeverhalten ist das gleiche wie bei start(). Es ist ein Fehler, auf einen bereits gestarteten Prozeß start() anzuwenden oder auf einen noch nicht gestarteten stop().

Die Methoden suspend() bzw. resume() suspendieren einen Prozeß bzw. setzen ihn wieder fort. Es ist ein Fehler, auf einen nicht suspendierten Prozeß resume() anzuwenden. Mit kill() wird ein Prozeß abgebrochen, ohne exit() aufzurufen. yield() gibt eventuelle für den Prozeß reservierte Zentralprozessorzeit frei. join() wartet die in wait angegebene Zeit auf die Beendigung des Prozesses.

In interests befindet sich eine Vorrangliste von Ereignissen (Instanzen (von Subklassen) von Event). Ein beliebig ausgelöstes Ereignis wird mit den Ereignissen in interests auf Gleichheit verglichen (undefinierte Werte dienen als Wildcard). Wird ein passendes Musterereignis gefunden, so wird der Prozeß eventuell durch einen Aufruf von handler() mit dem ausgelösten Ereignis unterbrochen: Läuft gerade run() oder wurde der Prozeß bereits durch ein anderes Ereignis niedrigerer Priorität als das jetzige unterbrochen, so findet eine Unterbrechung durch den Aufruf von handler() statt; ansonsten wird nach Beendigung des nicht unterbrechbaren handler()-Ablaufs ein erneuter Mustervergleich durchgeführt.

Zeitabhängige Prozesse.
Zur direkteren Modellierung von gleichförmig synchronisierten Abläufen können Prozesse mit einer Uhr versehen werden.



  class TimedThread extends Thread
  {
    private Clock clock;
    private Time when;
    private Time duration;

public TimedThread(Clock clock, Time when, Time duration);

public setStart(Time when); public Time getStart(); public setDuration(Time duration); public Time getDuration(); }


Nach Ablauf der Zeit when in der Uhr clock wird für den Prozeß start ausgeführt. Nach Ablauf der zusätzlichen Zeit duration wird der Prozeß mit stop() beendet.

Abspielprozesse

Um nun weiter multimediale Layout-Elemente zu steuern, stehen spezialisierte in Analogie zu üblichen Abspielgeräten gestaltete Klassen zur Verfügung, für Video- und Audioelemente, Animationen, Diashows, Effekte und Demonstrationen. Ihr allgemeines Verhalten ist in der abstrakten Klasse Player zusammengefaßt.



  abstract class Player extends TimedThread
  {
    private List<Marker> markers;

public play(); public halt(); public reverse(); public forward(Time time); public rewind(Time time); public goto(Marker marker); public setMarkers(List<Marker> markers); public List<Marker> getMarkers(); }


In markers (aus einer Indexklasse Marker) wird ein Index gehalten, über den mit goto in der Zeit gesprungen werden kann. Die Methode play() startet das eigentliche Abspielen, halt() hält ihn an und reverse() läßt ihn rückwärts laufen; forward() setzt um die Zeitspanne time vor und rewind() um time zurück.

Das Abspielen wird nicht in run() sondern in handler() realisiert. Wird in einer Subklasse run() überdefiniert, so wird dieses run() durch stop() abgebrochen, sobald reverse(), forward(), rewind() oder goto() aufgerufen wird. Der Prozeß wird als dauerndes yield() fortgesetzt.

Erreicht ein Abspielprozess das Ende seine abzuspielenden Mediums (dies ist für jedes einzelne Medium gesondert definiert, s. hier), so löst er das Ereignis EndEvent mit obj als self aus.

Die speziellen Subklassen von Player sind:



  class MoviePlayer extends Player
  { }

Für Animationen (sie werden in handler() definiert, ein Mediumende ist nicht allgemein festgelegt)



  class Animation extends Player
  {
    private AnimationFormat format;

public setFormat(AnimationFormat format); public AnimationFormat getFormat(); }




  class SlideShowPlayer extends Player
  { }

und für Demonstrationen (das Mediumende ist das Ende der Vorführung)



  class Demo extends Player
  { }

Ein Abspielgerät für einen Klang deklariert gleichzeitig sein Audioelement.



  class Audio extends Player
  {
    private Source src;
    private AudioFormat format;
    private Integer volume;
    private Boolean Mute;

public Audio(Source src); public Audio(Source src, AudioFormat format);

public setSource(Source src); public Source getSource(); public setFormat(AudioFormat format); public AudioFormat getFormat(); public setVolume(Integer volume); public Integer getVolume(); public setMute(Boolean mute); public Boolean getMute(); }


Das in format angegebene Format muß mit dem Format der Quelle source übereinstimmen. Das Setzen von mute auf true schaltet den Ton dieses Abspielgerätes stumm. Das Mediumende ist hier das Ende der Klangfolge.



  class NavigationManager extends Thread
  {
    private List<VirtualPage> stack;
    private VirtualPage actual;
    private List<VirtualPage> bookmarks;

public NavigationManager();

public VirtualPage back(); public VirtualPage next(); public register(VirtualPage obj); public skip(); public bookmark(VirtualPage obj); public unbookmark(VirtualPage obj); public List<VirtualPage> getHistory(); public List<VirtualPage> getBookmarks(); }


Es wird eine Liste stack mit einem Vermerk der aktuellen virtuellen Seite actual zur Verfügung gestellt. Die Methoden back() bzw. next() liefern die vorhergehende bzw. nächste Seite bzgl.\ actual zurück (sofern vorhanden). Mit register() wird eine Seite vor actual eingefügt, der vordere Teil von stack aber gelöscht; skip() löscht actual und den vorderen Teil von stack, actual wird neu gesetzt. Jede dieser Operationen macht somit ein next() zunächst unmöglich.

Spezieller können virtuelle Seiten mit bookmark() mit einem Lesezeichen markiert und mit unbookmark() entmarkiert werden; sie werden in der Liste bookmarks abgelegt.

Die Methoden getHistory() und getBookmarks() ergeben den aktuellen stack bzw. die bookmarks.

Die Navigationskontrolle kann ihre Informationen dauerhaft in einer Datenbank aus DbDialog speichern (s. hier).

Handler

Zur vereinfachten Handhabung von Ereignissen gibt es spezielle Prozesse, die in eigenen Methoden auf die einzelnen Ereignisklassen (MouseEvent, KeyboardEvent, FocusEvent, ClockEvent) reagieren. Diese sogenannten Handler bieten somit die Möglichkeit einer unkomplizierten Verbindung von Layout und Regie. Sie sind Subklassen von



  abstract class Handler extends Thread
  { }

Es werden in interests einige neue EreignisPatterns hinzugefügt. Die Priorität ist jeweils maximal, die Ereignisbehandlungen sind also nicht unterbrechbar.

Für die Maus hat man



  class MouseHandler extends Handler
  {
    public onLeftClick(MouseEvent event);
    public onRightClick(MouseEvent event);
    public onLeftDoubleClick(MouseEvent event);
    public onMove(MouseEvent event);
    public onDrag(MouseEvent event);
    public onEnter(MouseEvent event);
    public onExit(MouseEvent event);
  }

für die Tastatur



  class KeyboardHandler extends Handler
  {
    public onKeyDown(KeyboardEvent event);
    public onKeyUp(KeyboardEvent event);
  }

und für Uhrereignisse



  class ClockHandler extends Handler
  {
    public onAlarm(ClockEvent event);
  }

Das Layout

(zurück zum Inhalt)

Unter Layout wird alles statisch Bildschirmgestalterische verstanden. Es ist aber im Sinne eines objektorientierten Ansatzes notwendig, bereits hier Regieaspekte an gewisse Objekte (Instanzen interaktiver und multimedialer Elemente) anbinden zu können; dies wird durch Mehrfachvererbung erreicht.

Layout-Elemente werden zu Rahmen (rechteckigen Flächen) zusammengefaßt, diese selbst wieder zu Rahmen und so fort. Jedem Rahmen kann ein Rand (Padding) zugewiesen werden, als Abstände des Inhalts vom linken, rechten, oberen und unteren Rand des Rahmens, wobei diese zusätzliche Einbettung zum definierenden Objekt gerechnet wird.

Die Rahmen werden, so nicht anders angegeben, zunächst horizontal nebeneinander und dann, bei Platzmangel, vertikal untereinander angeordnet; dies wird im folgenden als deklarative oder relative Positionierung bezeichnet. Es ist aber ebenso möglich, die Rahmen (oder auch Elemente direkt) absolut anzuordnen, indem Koordinaten vergeben werden. Nicht absolut positionierte sollten die absolut positionierten Objekte umgehen.

Jedes Element hat eine eindeutige Schichtennummer; Elemente höherer Schichten verdecken dabei Elemente niedrigerer Schichten, eventuell teilweise, falls Überschneidungen auftreten.



  abstract class Layout extends Object  
  {
    private Boolean visible;
    private Integer layer;
    private Position position;
    private Extension size;
    private Padding padding;
    private Padding margin;
    private UserMode usermode;
    private Display display;

public setVisible(Boolean visible); public Boolean getVisible(); public setLayer(Integer layer); public Integer getLayer(); public setPosition(Position position); public Position getPosition(); public setSize(Extension size); public Extension getSize(); public setPadding(Padding padding); public Padding getPadding(); public setMargin(Padding padding); public Padding getMargin(); public setUserMode(UserMode usermode); public UserMode getUserMode();

public draw(); }


In size kann die Größe des Objekts spezifiziert werden; reicht dieser Platz zur Darstellung des Inhalts (s. u. ) nicht aus, so wird nur ein Ausschnitt gezeigt; dabei ist ein eventuelles Attribut der Klasse Alignment zu berücksichtigen. Eine absolute Positionierung erfolgt über position. Die Instanzvariablen position und size enthalten nach bzw. während der Anordnung auf dem Bildschirm in jedem Fall die aktuellen Werte. Der in padding beschriebene Rand gehört zum Objekt, wird aber nicht mit dem Objektinhalt gefüllt. In margin wird der Abstand zu den umgebenden Objekten beschrieben; dieser Rand gehört nicht zum Objekt.

Weiters kann ein Element als unsichtbar (visible ist false) deklariert (die Positionierung hat das Element dennoch zu umgehen) und in layer die zugehörende Schicht angegeben werden.

Die zu überladende Methode draw() schließlich stellt alle zugehörigen Layout-Objekte auf dem Bildschirm dar.

Layout-Elementen können mit usermode Benutzermodi zugewiesen werden; diese Elemente werden dann je nach Modus unterschiedlich behandelt, etwa eingeblendet oder ausgeblendet. Ebenso kann die Eignung für bestimmte Bildschirmauflösungsstufen in display deklariert werden.

Wir unterscheiden abstrakt zwischen gruppierten (wieder Layout-Element enthaltenden) und einfachen Layout-Elementen:



  abstract class GroupLayout extends Layout  
  { }

Alle Elemente in Gruppen werden relativ zueinander und relativ zur umgebenden Gruppe ausgerichtet.

Rahmen

Rahmen sorgen neben einer Gruppierung für eine eventuelle Umrahmung der enthaltenen Elemente und für die eventuelle Unterlegung eines farbigen Hintergrunds:



  class Frame extends GroupLayout  
  {
    private List<Layout> contents;
    private FrameStyle style;
    private Color fillcolor;
    private Pattern fillpattern;
    private Color color;
    private Alignment alignment;
    private Boolean distribute;

public Frame(FrameStyle style, List<Layout> contents); public Frame(List<Layout> contents, Color fillcolor, Pattern fillpattern, Color color, Extension framesize, Padding margin, Alignment alignment, Boolean distribute);

public setContents(List<Layout> contents); public List<Layout> getContents(); public setStyle(FrameStyle style); public FrameStyle getStyle(); public setFillcolor(Color fillcolor); public Color getFillcolor(); public setFillpattern(Pattern fillpattern); public Pattern getFillpattern(); public setColor(Color color); public Color getColor(); public setAlignment(Alignment alignment); public Alignment getAlignment(); public setDistribute(Boolean distribute); public Boolean getDistribute();

public open(); public close(); }


Die Ausdehnungen des umgebenden Rahmens werden durch margin (s. o. ) bestimmt, seine Farbe in color. Zusätzlich kann in style ein bestimmter Rahmentyp ausgewählt werden (seine Größe, Farbe, etc. wird dann durch die aktuellen Attribute verändert). Ebenso geben fillcolor und fillpattern die Hintergrundfarbe und das Hintergrundmuster an.

Das Attribut alignment beeinflußt alle in contents aufgeführten Elemente: Sie werden mit minimalen Abstand zu den Rändern angeordnet, die darin angegeben sind. Weiters achtet distribute (falls auf true) darauf, daß die Abstände der Elemente zueinander gleich sind.

Rahmen können geöffnet (open() und geschlossen (close()) werden; dies beeinflußt das visible-Attribut.

In Rahmen kann von der standardisierten relativen Positionierung abgewichen werden:



  class FlowBox extends Frame
  {
    private List<Layout> main;
    private Alignment mainalignment;

public FlowBox(List<Layout> main, Alignment mainalignment, List<Layout> contents, Alignment alignment, Boolean distribute);

public setMain(List<Layout> main); public List<Layout> getMain(); public setMainAlignment(Alignment mainalignment); public Alignment getMainAlignment(); }


In main befindet sich ein Element, das von den restlichen Elementen (contents) in hauptsächlich horizontaler Folge umflossen werden soll. Mit mainalignment wird die Ausrichtung des Layout innerhalb der FlowBox bestimmt. Die ererbten Attribute alignment und distribute verändern hier das Layout unter Berücksichtigung von main.

Man kann Rahmen auch mit Scroll bars versehen (s. hier), um einen nur ausschnittsweise gezeigten Inhalt vollständig zugänglich zu machen. Die Initialstellung der Sliders ist dabei dem Inhalt anzupassen.



  class ScrollableFrame extends Frame, MouseHandler
  {
    private Slider horizontalslider;
    private Slider verticalslider;

public ScrollableFrame(List<Layout> contents, Slider horizontalslider, Slider verticalslider); public setHorizontalslider(Slider horizontalslider); public Slider getHorizontalslider(); public setVerticalslider(Slider verticalslider); public Slider getVerticalslider();

public onScroll(RepositionEvent event); }


Die Sliders horizontalslider und verticalslider zeigen bei Betätigung den entsprechenden neuen Ausschnitt aus dem contents des Rahmens; dabei wird jeweils ein Ereignis der Klasse RepositionEvent ausgelöst. Dieses Standardverhalten der Instanzen von ScrollableFrame kann durch ein Überladen von onScroll(), das bei einem RepositionEvent für einen Slider, den der ScrollableFrame besitzt, ausgelöst wird, verändert werden.

Text

Für Texte werden die üblichen Standardverarbeitungsmethoden angeboten, insbesondere die Wahl verschiedener Schriftarten, deren Ausprägungen und Farben, sowie spezielle Anordnungs- und Strukturierungsmöglichkeiten.

Für die ersteren sollten die Klassen Font für die Schriftart (etwa Times, Garamond, etc.) und FontStyle (halbfett, kursiv, oblique, etc.) eine hinreichende Auswahl bieten.

Aller Text wird auf der Schriftlinie (einer Horizontalen durch den Referenzpunkt des ersten Zeichens) angeordnet; die prinzipielle Ausrichtung wechselt von vertikal zu horizontal (innerhalb eines Textes können alle übrigen Layout-Elemente vorkommen). Paßt der Text nicht in den durch extension vorgegebenen Rahmen, so wird, wo möglich, umgebrochen, bzw. der restliche Text nicht mehr angezeigt.



  class Text extends Layout
  {
    private Font font;
    private Dimension fontsize;
    private FontStyle style;
    private Color color;
    private Source source;
 
    public Text(Font font, Dimension fontsize,
                FontStyle style, Color color,
                Source source);

public setFont(Font font); public Font getFont(); public setSize(Size size); public Size getSize(); public setStyle(Style style); public Style getStyle(); public setColor(Color color); public Color getColor(); public setSource(Source source); public Source getSource();

public bold(); public italics(); public slanted(); public typewriter(); public emphasize(); public big(); public small(); public supersript(); public subsript(); public changeLanguage(Language language); }


Die Schriftart wird in font festgelegt, ihre Ausprägung in style, die Größe der Schrift in size und die Schriftfarbe schließlich in color.

Die Ausprägung der Schrift läßt sich für den aktuellen Textinhalt in contents über die aufgeführten Methoden verändern: bold() erzeugt (halb)fette, italics() kursive und slanted oblique Schrift innerhalb der Schriftart. Die Methode typewriter wählt eine nichtproportionale Schrift und emphasize() eine hervorhebende (etwa eine Kursive). Weiter verändern big() und small() die Schriftgröße zu einer größeren bzw. kleineren Schrift (beliebig iterierbar) und superscript() und subscript() verändern die Schriftlinie nach oben bzw. nach unten.

Die Änderung der Sprache mit changeLanguage() (etwa von Deutsch auf Englisch) soll durch die Behandlung der eigentlichen textuellen Information in der Datenbank ermöglicht werden.

Zur Zusammenfassung längerer Textpassagen dient



  class Paragraph extends Text  
  {
    private Dimension indent;
    private Alignment align;
    private Dimension baselineskip;
    private Boolean nolinebreak;

public Text(Dimension indent, Alignment align, Dimension baselineskip, List<Layout> contents);

public setIndent(Dimension indent); public Dimension getIndent(); public setAlign(Alignment align); public Alignment getAlign(); public setBaseLineSkip(Dimension baselineskip); public Dimension getBaseLineSkip(); public setNoLineBreak(Boolean nolinebreak); public Boolean getNoLineBreak();

public break(); public quotation(); public verbatim(); }


Das Attribut indent bestimmt die Einzugtiefe der ersten Zeile des Paragraphen, die Ausrichtung darf hier auch den Wert justified enthalten. Mit baselineskip wird der Abstand der Schriftlinien zweier Zeilen (Zeilenabstand) angegeben. Schließlich verhindert das Setzen von nolinebreak auf true den Zeilenumbruch am Schluß eines Paragraphen (anschließende Layout-Elemente werden in dieselbe Zeile gesetzt).

Die Methode break() erzeugt einen Zeilenumbruch ohne einen neuen Paragraphen zu beginnen, quotation() setzt den Inhalt contents als Zitat, etwa beidseitig eingerückt (durch Veränderung von padding), und verbatim() ignoriert sämtliche Steuerzeichen im Text (nicht aber die weiteren Layout-Objekte).

Überschriften schließlich gestaltet man mit



  class Heading extends Text  
  {
    private List<Integer> number;
    private EnumStyle style;
    private Alignment align;
    private Dimension leftmargin;
    private Dimension baselineskip;

public Heading(List<Integer> number, EnumStyle style, Alignment align, Dimension leftmargin, Dimension baselineskip, List<Layout> contents);

public setNumber(List<Integer> number); public List<Integer> getNumber(); public setStyle(EnumStyle style); public EnumStyle getStyle(); public setAlign(Alignment align); public Alignment getAlign(); public setLeftMargin(Dimension leftmargin); public Dimension getLeftMargin(); public setBaseLineSkip(Dimension baselineskip); public Dimension getBaseLineSkip(); }


Eine eventuelle Numerierung und deren Stil ist in number bzw. style anzugeben (s. hier). In leftmargin wird ein linker Rand für die Überschrift spezifiziert; dies ist insbesondere im Zusammenhang mit der Numerierung sinnvoll, die dann in diesen linken Rand zu stehen kommt. Das Attribut baselineskip hat dieselbe Bedeutung wie bei Paragraph (s. hier).

Listen und Tabellen

Die Gliederung von Texten in Listen erfolgt zunächst durch die Zusammenfassung in Listeneinträge:



  class Item extends GroupLayout
  {
    private List<Layout> bullet;
    private List<Layout> contents;

public Itemize(List<Layout> bullet, List<Layout> contents); }


Neben dem Eintragsinhalt contents kann eine Layoutliste bullet angegeben werden, die als Markierungssymbol für einen neuen Listeneintrag dient.



  class Listing extends GroupLayout  
  {
    private Dimension leftmargin;
    private Dimension itemsep;
    private List<Item> contents;

public Listing(Dimension leftmargin, Dimension itemsep, Padding padding, List<Layout> contents);

public setLeftMargin(Dimension leftmargin); public Dimension getLeftMargin(); public setItemSep(Dimension itemsep); public Dimension getItemSep(); public setContents(List<Item> contents); public List<Item> getContents(); }


Die Instanzvariable leftmargin legt den für die ganze Liste vorgesehenen linken Rand (innerhalb des umgebenden Rahmens) fest, itemsep den Abstand zweier Listeneinträge.

Die Klasse setzt ihre Einträge jeweils mit dem bullet untereinander. Listen können auch geschachtelt werden.

Will man eine einheitliche Gestaltung der Markierungen erreichen, verwendet man



  class Itemize extends Listing  
  {
    private BulletStyle style;

public Itemize(BulletStyle style, Padding padding, Dimension leftmargin, Dimension itemsep, List<Item> contents);

public setStyle(BulletStyle style); public BulletStyle getStyle(); }


Der Stil style enthält einen Markierungstyp, die Attribute bullet in den Listeneinträgen werden damit ignoriert.

Eine letzte Gliederungsmöglichkeit sind Tabellen. Sie bestehen aus Einträgen, die zu Zeilen zusammengefaßt werden und diese dann zu Tabellen.



  class TabularEntry extends GroupLayout
  {
    private Integer columnspanning;
    private Integer rowspanning;
    private List<Layout> contents;

public TabularEntry(Integer spanning, List<Layout> contents);

public setColumnSpanning(Integer columnspanning); public Integer getColumnSpanning(); public setRowSpanning(Integer rowspanning); public Integer getRowSpanning(); public setContents(List<Layout> contents); public List<Layout> getContents(); }


Der Inhalt contents eines Tabelleneintrags ist beliebig, er kann auch leer sein. Ist columnspanning ein Wert größer als eins, so gilt der Eintrag als die entsprechende Anzahl von Einträgen spaltenweise, ist rowspanning ein Wert größer als eins, so als die entsprechende Anzahl von Einträgen zeilenweise (s. u. ).

Die Tabellenzeilen bestehen nun aus einer gewissen Anzahl von Tabelleneinträgen.



  class TabularRow extends GroupLayout
  {
    private Boolean line;
    private List<TabularEntry> contents;

public TabularRow(List<TabularEntry> contents);

public setLine(Boolean line); public Boolean getLine(); public setContents(List<TabularEntry> contents); public List<TabularEntry> getContents(); }


Ist line auf true gesetzt, so wird die Tabellenzeile von der folgenden durch eine Linie abgetrennt; dabei sind Einträge, die mehrere Zeilen umfassen sollen, zu beachten.

Schließlich werden daraus Tabellen aufgebaut:



  class Tabular extends GroupLayout
  {
    private String columnspecification;
    private List<TabularRow> contents;

public Tabular(String columnSpecification, List<TabularRow> contents);

public setColumnSpecification(String columnspecification); public String getColumnSpecification(); public setContents(List<TabularRow> contents); public List<TabularRow> getContents(); }


Die Spaltenbeschreibung columnspecification legt die Ausrichtung der Tabelle spaltenweise fest: Für jede Spalte enthält sie den Buchstaben l für linksbündig, r für rechtsbündig oder c für zentriert. Überspannt ein Tabelleneintrag mehrere Einträge, so werden die entsprechenden Spaltenbeschreibungen ignoriert.

Für jede Spalte wird soviel Platz reserviert, wie der breiteste Eintrag in dieser Spalte benötigt; auch hier sind überspannende Einträge zu beachten.

Multimediale Elemente

Multimediale Elemente spielen, obwohl für den Gesamtkatalog unabdingbar, in Layout eine untergeordnete Rolle. Erst ihre Verbindung mit den verschieden Abspielprozesstypen machen die Elemente wirklich verwendbar. Es gibt allerdings auch multimediale Elemente, die kein dynamisches Verhalten zeigen.



  abstract class Multimedia extends Layout
  {
    private Source source;
 
    public setSource(Source source);
    public Source getSource();
    public changeLanguage(Language language);
  }

Für alle Objekte aus Multimedia spezifiziert source die Datenquelle. Diese liegt unter Umständen in einem bestimmten Format vor, das bei den einzelnen Klassen angegeben werden kann. Das tatsächliche Format von source und das deklarierte müssen übereinstimmen.

Mehrsprachige Versionen können wie bei Text durch changeLanguage() unterhalten werden.

Für Bilder sollten die unterstützten Formate zumindest GIF, JPEG, TIFF und BMP umfassen.



  class Image extends Multimedia  
  {
    private ImageFormat format;
 
    public Image(Source source, ImageFormat format, Extension size);

public setFormat(ImageFormat format); public ImageFormat getFormat(); }


Knöpfe und Hyperlinks

Layout-seitig werden die Navigationsmöglichkeiten in einem Katalog durch Knöpfe und spezieller durch Hyperlinks repräsentiert. Die eigentliche Navigation übernimmt die Regie.



  class Button extends GroupLayout, MouseHandler
  {
    private List<Layout> contentsdisabled;
    private List<Layout> contentsnotclicked;
    private List<Layout> contentsclicked;
    private Integer default;

public Button(List<Layout> contentsdisabled, List<Layout> contentsnotclicked, List<Layout> contentsclicked, Integer default);

public setContentsDisabled(List<Layout> contentsdisabled); public List<Layout> getContentsDisabled(); public setContentsNotClicked(List<Layout> contentsnotclicked); public List<Layout> getContentsNotClicked(); public setContentsClicked(List<Layout> contentsclicked); public List<GroupLayout> getContentsClicked(); public setDefault(Integer default); public Integer getDefault(); public enable(); public disable(); }


Knöpfe können nicht nur unsichtbar, sondern auch nicht anwählbar sein. Dies wird mit enable() und disable() umgestellt; die Aufrufe müssen paarig sein. Der für einen nicht anwählbaren Knopf darzustellende Inhalt ist in contentsdisabled spezifiziert.

Während der Mauszeiger sich über dem Knopf befindet und die linke Maustaste gedrückt ist, wird contentsclicked angezeigt, sonst contentsnotclicked. Mit onLeftClick() läßt sich das ändern. In default wird der zunächst anzuzeigende Inhalt, 0 für contentsnotclicked und 1 für contentsdisabled, erklärt.

Schon vorgefertige Knöpfe (und Schmuckdaten) können zu einer eigenen Datenbank zusammengefaßt werden.

Knöpfe merken sich also prinzipiell nicht, ob sie bereits einmal angewählt wurden; darin unterscheiden sich Hyperlinks:



  class HyperLink extends GroupLayout, MouseHandler
  {
    private List<Layout> beforeclick;
    private List<Layout> afterclick;
    private List<Layout> disabledcontents;
    private Integer default;

public HyperLink(List<Layout> beforeclick, List<Layout> afterclick, List<Layout> disabledcontents, Integer default);

public setBeforeClick(List<Layout> beforeclick); public List<Layout> getBeforeClick(); public setAfterClick(List<Layout> afterclick); public List<Layout> getAfterClick(); public setAfterClick(List<Layout> afterclick); public List<Layout> getAfterClick();

public enable(); public disable(); }


In beforeclick wird der Inhalt deklariert, der vor dem ersten Anwählen des Links anzuzeigen ist, in afterclick der Inhalt nach einer Verfolgung. Die restlichen Attribute sind wie bei Button zu verstehen.

Interaktive Elemente

Neben Knöpfen und Hyperlinks gibt es eine Vielzahl von Layout-Elementen, die der Kommunikation mit dem Benutzer dienen. Sie ermöglichen die Eingabe von Texten und das Zeichnen von Bildern, die Mehrfachauswahl aus längeren Listen, die Einfach- und Mehrfachauswahl gewisser Optionen, die bekannten Pull-down menus und Scroll bars.

Eingabeelemente.
Der Eingabe von Text dient



  class Input extends Text, MouseHandler, KeyboardHandler
  {
    private String contents;
    private CursorStyle style;
    private Integer maxlength;

public Input(String contents, CursorStyle style, Extension size, Integer maxlength);

public setContents(String contents); public String getContents(); public setDefault(String default); public String getDefault(); public setCursorStyle(CursorStyle style); public CursorStyle getCursorStyle(); public setMaxLength(Integer maxlength); public Integer getMaxLength();

public enable(); public disable(); }


Entsprechend Text kann das Textaussehen manipuliert werden; Input hat aber nur Buchstaben zum Inhalt (contents). In maxlength wird die maximale Anzahl akzeptierter Zeichen festgelegt. Die Größe des die Eingabe aufnehmenden Rahmens ist davon unabhängig. Erlaubt der Rahmen mehrere Zeilen, so wird, wenn nötig, vorzugsweise vertikal gescrollt, sonst horizontal. Die Methode draw() setzt den Wert von source beim Zeichnen ein.

Die Textmanipulation sollte über die üblichen Möglichkeiten (Cursor-Bewegungen, etc.) verfügen. Mit onEnd() wird die durch die Betätigung der Eingabetaste ausgelöste Ereignisfolge (zusammengefaßt als eine Instanz von EndEvent) abgefangen.

Selektionen.
Alle Auswahlmöglichkeiten finden über Optionen statt.



  class Option extends GroupLayout
  {
    private List<Layout> notselected;
    private List<Layout> selected;
    private List<Layout> disabled;
    private Boolean editable;
    private Integer default;

public Option(List<Layout> notselected, List<Layout> selected, List<Layout> disabled, Boolean editable, Integer default);

public setNormal(List<Layout> normal); public List<Layout> getNormal(); public setSelected(List<Layout> selected); public List<Layout> getSelected(); public setDisabled(List<Layout> disabled); public List<Layout> getDisabled(); public setDefault(Integer default); public Integer getDefault(); public setEditable(Boolean editable); public Boolean getEditable();

public enable(); public disable(); }


Es wird hier das Layout für den nicht selektierten Zustand (notselected), den selektierten Zustand (selected) und den nicht anwählbaren Zustand (disabled) definiert. In default wird angegeben, ob beim Zeichnen mit draw() der nicht selektierte (0), der selektierte (1) oder der nicht anwählbare Zustand (2) wiedergegeben werden soll. Schließlich erlaubt das Setzen von editable auf true eine Veränderung des Eintrags zur Laufzeit: Erfolgt ein Doppelklick auf die Option, so wird sie zeitweise in ein Eingabefeld verwandelt; das Betätigen der Eingabetaste für dieses temporäre Eingabefeld erzeugt wieder das ursprüngliche Optionserscheinungsbild, allerdings mit eventuell modifiziertem Inhalt.

Es werden vier der üblichen Auswahlmöglichkeiten angeboten: Browser, CheckBox, PopUpMenu und RadioButton.

Ein Listenfenster (Browser) stellt seine Optionen untereinander angeordnet dar und erhält, wenn nötig, horizontale und vertikale Scroll bars. Es ist Mehrfachauswahl möglich (die Optionen gehen in den selektierten Zustand über).



  class Browser extends GroupLayout, MouseHandler
  {
    private List<Layout> title;
    private List<Option> contents;
    private Integer menusize;
    private Slider horizontalslider;
    private Slider verticalslider;

public Browser(List<Layout> title, List<Option> contents, Integer menusize, Slider horizontalslider, Slider verticalslider);

public setTitle(List<Layout> title); public List<Layout> getTitle(); public setContents(List<Option> contents); public List<Option> getContents(); public setMenusize(Integer menusize); public Integer getMenusize(); public setHorizontalslider(Slider horizontalslider); public Slider getHorizontalslider(); public setVerticalslider(Slider verticalslider); public Slider getVerticalslider();

public enable(); public disable(); public onOption(OptionSelectEvent event); public onDrag(DragSelectEvent event); public onScroll(RepositionEvent event); }


Es werden höchstens menusize viele Optionen dargestellt; ansonsten muß gescrollt werden. Die Form der Slider wird in horizontalslider und verticalslider festgelegt, ihr Vorhandensein aber ist dynamisch. Mit title kann die gesamte Liste mit einem Titel versehen werden; dieser wird nicht bewegt.

Per Standard wird das Listenfenster bei Betätigung der Scroll bars entsprechend bewegt, Optionen bei Anwahl selektiert (außer sie sind als nicht anwählbar deklariert) und beim Überziehen mit gedrückter Maustaste insgesamt selektiert. Mit onScroll() (wie bei ScrollableFrame), onDrag() und onOption() kann dies modifiziert werden.

Ebenfalls eine mögliche Mehrfachauswahl, allerdings ohne eventuelles Scrolling bietet



  class CheckBox extends GroupLayout, MouseHandler
  {
    private CheckBoxStyle style;
    private List<Option> contents;
    private Dimension leftmargin;
    private Dimension itemsep;

public CheckBox(List<Option> contents); public CheckBox(CheckBoxStyle style, List<Option> contents, Dimension leftmargin, Dimension itemsep);

public setStyle(CheckBoxStyle style); public CheckBoxStyle getStyle(); public setContents(List<Layout> contents); public List<Layout> getContents(); public setLeftMargin(Dimension leftmargin); public Dimension getLeftMargin(); public setItemSep(Dimension itemsep); public Dimension getItemSep();

public enable(); public disable(); public onOption(OptionSelectEvent event); }


In angewähltem Zustand werden die Optionen in contents, je nach style, mit einem Häkchen versehen, angekreuzt, etc. Die Attribute leftmargin und itemsep sind wie bei Listing zu behandeln. Das Standardverhalten wird mit onOption() verändert.

Für die singuläre Auswahl entspricht der Klasse Browser die Klasse



  class PopUpMenu extends GroupLayout, MouseHandler
  {
    private List<Layout> title;
    private List<Option> contents;
 
    public PopUpMenu(List<Layout> title, List<Option> contents);

public setTitle(Layout title); public Layout getTitle(); public setContents(List<Option> contents); public List<Option> getContents();

public enable(); public disable(); public onOption(OptionSelectEvent event); }


Es wird im unangewählten Zustand die aktuelle Wahl aus contents angezeigt. Wird dieses Element angewählt, klappt die gesamte Auswahl aus, der Titel title wird mitbewegt; es soll dabei immer aller Inhalt dargestellt werden. Auch kann vom Standard abweichendes Verhalten über onOption() erreicht werden.

Das Gegenstück zu CheckBox liefert



  class RadioButton extends GroupLayout, MouseHandler
  {
    private RadioButtonStyle style;
    private List<Option> contents;
    private Dimension leftmargin;
    private Dimension itemsep;
 
    public RadioButton(RadioButtonStyle style, List<Option> contents,
                       Dimension leftmargin, Dimension itemsep);

public setContents(List<Option> contents); public List<Option> getContents(); public setStyle(RadioButtonStyle style); public RadioButtonStyle getStyle(); public setLeftMargin(Dimension leftmargin); public Dimension getLeftMargin(); public setItemSep(Dimension itemsep); public Dimension getItemSep();

public enable(); public disable(); public onOption(OptionSelectEvent event); }


Es unterscheidet sich darin, daß bei einer Auswahl das bisher ausgewählte Element aus contents deselektiert wird. Auch dieses Standardverhalten ist über onOption() abänderbar.

Zur Steuerung komplexerer Auswahl- und Anwahlstrukturen dient



  class Slider extends GroupLayout, MouseHandler
  {
    private Boolean horizontal;
    private Button slidebutton;
    private Button previousbutton;
    private Button nextbutton;
    private Dimension step;

public Slider(Boolean horizontal, Button slidebutton, Button nextbutton, Button previousbutton, Real step);

public setHorizontal(Boolean horizontal); public Boolean getHorizontal(); public setSlideButton(Button slidebutton); public Button getSlideButton(); public setPreviousButton(Button previousbutton); public Button getPreviousButton(); public setNextButton(Button nextbutton); public Button getNextButton(); public setStep(Dimension step); public Dimension getStep();

public enable(); public disable(); public onReposition(RepositionEvent event); }


Ein eventuell in der Größe variierender Knopf in der Mitte des Scroll bars, slidebutton soll verschiebbar sein, die Knöpfe nextbutton und previousbutton ermöglichen die Anzeige eines kontextuell vorhergenden oder nachfolgenden Elements; dadurch wird auch die Stellung des Mittelknopfes beeinflußt.

Horizontale Scroll bars werden durch horizontal auf true erzeugt, vertikale durch horizontal auf false. In step schließlich wird die Schrittweite angegeben, mit der slidebutton verschoben werden kann.

Jede slidebutton-Stellungsänderung kann durch onReposition() abgefangen werden.

Menüführung.
Die von den meisten Benutzeroberflächen gewohnten Pull-down menus findet man unter



  class PullDownMenu extends GroupLayout, MouseHandler
  {
    private List<List<Option>> contents;

public PullDownMenu(List<List<Option>> contents);

public setContents(List<List<Option>> contents); public List<List<Option>> getContents();

public enable(); public disable(); public onOption(OptionSelectEvent event); }


Der erste Eintrag in den Listeneinträgen von contents ist der Titel des Pull-down menu. Mit align wird der Rand des ersten besitzenden Fensters (oder des äußersten besitzenden Rahmens) angegeben, an dem das Menü erscheinen soll. Wird der Titel angewählt, so erscheinen die restlichen Einträge des Listeneintrags des betreffenden Titels untereinander, je nach Plazierung unter, neben oder über dem Titel. Das Menü selbst und auch dessen Einträge können nicht anwählbar sein.

Wieder kann das Standardverhalten über onOption() geändert werden.

Die Datenbank

(zurück zum Inhalt)

Die gespeicherte Information, die zum Aufbau und Ablauf des elektronischen Produktkatalogs notwendig ist, wird in Datenbanken zusammengefaßt.

Für den Prototypen ist eine Datenbankanbindung allerdings nicht vorgesehen, sondern soll dieser Zugriff über ein Dateisystem erfolgen. Um spätere Anpassungsschwierigkeiten zu vermeiden, sollten Kataloginhalte eventuell aber auch hier schon strukturiert verwaltet werden, was durch Datenbankobjekte erreicht werden soll.

Datenbankobjekte.
Die Klasse DbObject dient zur Gruppierung der Objekte der verschiedenen Datenbanken. Das Attribut Language gibt die Sprache an, medium bestimmt die Ausgabemedien (CD-ROM, HtMl\ oder Papier) für die Daten und security begrenzt die Endbenutzergruppe ( intern, extern, public).



  abstract class DbObject extends Object
  { 
    private Language language;
    private Medium medium;
    private Security security;
   
    public setLanguage(Language language);
    public String getLanguage();
    public setMedium(Medium medium);
    public Medium getMedium();
    public setSecurity(Security security);
    public Security getSecurity();
 }

Die Daten selbst werden durch die Klasse DataEntry dargestellt. Das Attribut datatype gibt den Datentyp an und data enthält die Daten, die vom Typ \english{Binary large object} sind.



 class DataEntry extends DbObject
  {
    private DataType datatype;
    private String dataclass;
    private BLOb data;

public setDataType(DataType datatype); public Datatype getDataType(); public setDataClass(String dataclass); public String getDataClass(); public setData(BLOb data); public BLOb getData(); }


Als Spezialisierungen sind IntegerEntry, StringEntry, etc. (siehe die externen Datentypen in hier) vorgesehen.

Produkte

Das Ziel eines elektronischen Produktkataloges ist die Präsentation und ausführliche Darstellung der zu verkaufenden Produkte. Deshalb wird die Information, die zu diesen Produkten vom Kataloghersteller geliefert wird, meistens sehr umfangreich sein; sie kann auf unterschiedliche Art gespeichert sein.

Infolgedessen wird es als Aufgabe des Katalogsdesigners betrachtet, die relevante Information aus der bestehenden Datenbanken und Dateien zu entnehmen und eine adäquate Struktur der Produktdaten zu konstruieren, die unabhängig vom Layout und von der Regie ist.Damit können die Daten auch anderweitig verwendet werden, zum Beispiel um einen Papierkatalog oder auch einen HtMl-Katalog zu gestalten.

Einzelne Produkte können zu Produktgruppen zusammengefaßt werden, die wiederum Produktgruppen enthalten können, wodurch es möglich ist, eine hierarchische Struktur zu realisieren.



  class ProductGroup extends DbObject
  {
    private StringEntry name;
    private List<Product> products;
    private List<ProductGroup> groups;
    private List<DataEntry> contents;

public StringEntry getName(); public List<Product> getProducts(); public List<ProductGroup> getGroups(); public List<DataEntry> getContents(); }


Die Klasse Product enthält alle Daten, die zu einem Produkt gehören.



  class Product extends DbObject
  {
    private StringProperty number; 
    private StringProperty name;
    private List<Property> description;
    private RealProperty price;
    private List<Property> properties;

public Property getNumber(); public List<Property> getName(); public List<Property> getDescription(); public RealProperty getPrice(); public List<Property> getProperties(); }


Die Merkmale der Produkte sind von der Natur der Produkte abhängig. Aus diesem Grunde enthält die Attributliste nur die am häufigsten auftretende Merkmale: Die laufende Nummer id, den Produktnamen name, seine Beschreibung description und seinen Preis price.

Weitere Eigenschaften für jedes Produkt kann man in den Instanzen der Klasse Property finden.



  class Property extends DbObject
  {
    private StringEntry name;
    private List<DataEntry> contents;

public Property(StringEntry name, List<DataEntry> contents); public setName(StringEntry name); public StringEntry getName(); public setContents(List<DataEntry> contents); public List<DataEntry> contents getContents(); }


Das Attribut name bezeichnet einen Identifikator für das Merkmal, contents dessen Wert.

Die Klassen StringProperty und RealProperty sind Unterklassen von Property; ihr Attribut contents ist durch List<StringEntry> bzw. List<RealEntry> überdefiniert.

Servicesunterstützung

Services sind alle Dienste, die dem Endkunden zur besseren und komfortableren Benutzung des Kataloges geboten werden. Dazu zählen datenseitig die Information, die der Kunde bei der Katalogbetrachtung erhält und die ihn dabei unterstützt, die Verwaltung der Daten, die im Warenkorb abgelegt werden, und die Adressen der Endkunden.

Warenkorb.
Mit der Klasse Order wird eine Produktmarkierung oder Produktbestellung des Endkunden modelliert.



  class Order extends DbObject
  {
    private String number;
    private User user;
    private Date date;
    private Product product;
    private Integer quantity;
    private Boolean marked;

public Order(Date date, User user, Product product, Integer quantity, Boolean marked); public Order(String number, User user, Product product, Integer quantity, Boolean marked);

public setNumber(String number); public String getNumber(); public setUser(User user); public User getUser(); public setDate(Date date); public Date getDate(); public setProduct(Product product); public Product getProduct(); public setQuantity(Integer quantity); public Integer getQuantity(); public setMarked(Boolean marked); public Boolean getMarked(); }


Es wird eine laufende Nummer number vergeben, die aber auch frei gewählt werden kann. In quantity wird die Stückanzahl des vom in product angegebenen Produkts spezifiziert. Ebenso wird der bestellende Benutzer in user und das Datum in date abgelegt. Ist marked auf true gesetzt, so ist die Bestellung nur vorgemerkt (bzw. das in ihr enthaltene Produkt).

Hilfe.
Benutzerhinweise und allgemeine Erklärungen zur Bedienung des Katalogs - Hilfetexte - werden in Help aufbewahrt. Dabei können sich diese Hilfetexte aller Layout- und Regiemittel, die hier definiert wurden, bedienen; insbesondere ergibt sich dadurch ein mit Hyperlinks verbundenes Hilfesystem.



  class Help extends DbObject
  {
    private List<StringEntry> keywords;
    private List<DataEntry> page;

public show(); public hide(); }


Die Suche nach Hilfeinformationen erfolgt über die Datenbank. Die Information ist in page zusammengefaßt. Mit der Methode show() wird die Hilfe angezeigt, mit hide() verborgen.

Navigationsgeschichte
Die Datenbank DbDialog beinhaltet den Navigationspfad, den der Benutzer bei der Katalogdurchsicht durchläuft.



  class Dialog extends DbObject
  {
    private List<Structure> stack;
    private Structure actual;

public Dialog(List<Structure> stack, Structure actual); }


Sie ist das Gegenstück zu NavigationManager (s. hier).

Services

(zurück zum Inhalt)

Die Dienstleistungen umfassen komplexe, mehreres umfassende oder steuernde Klassen, die zur Modellierung oft in Katalogen auftretender Situationen gedacht sind. Sie bieten gleichzeitig die Flexibilität einer gleichzeitigen erstellerseitigen Konfigurierung.

Dazu führen wir eine Reihe von spezialisierten Knopfarten zur Bestätigung, zum Abbruch oder zur Rücksetzung von Vorgängen, zur Erreichung von Hilfe oder einer Vorführung (Demonstration), zur Rückkehr zu früheren Seiten von Fenstern, etc. ein. Bei einigen kann die Methode onLeftClick() vereinfacht überladen werden. Sie dienen vor allem der Layoutstandardisierung von Wahlmöglichkeiten.

Die Korrektheitsbestätigung repräsentiert



  class OKButton extends Button
  {
    public OKButton();
  }

den Abbruch eines Vorgangs



  class CancelButton extends Button
  {
    public CancelButton();
  }

und die Rücksetzung einiger Eingabefelder



  class ResetButton extends Button
  {
    public ResetButton(List<Input> fields);
  }

Abhängig von gewissen Randbedingungen kehrt



  class BackButton extends Button
  {
    public BackButton();
  }

zur (sinnvoll) letzten Seite oder zum letzten Fenster zurück. Hier kann ein Unterschied zwischen einer Hilfe- und der Produktstruktur (über Theme) gemacht werden.



  class HelpButton extends Button
  {
    public HelpButton(HelpForm help);
  }

verzweigt zu einer Hilfeseite; sie kann fest sein oder kontextsensitiv errechnet.



  class DemoButton extends Button
  {
    public DemoButton(Demo demo);
  }

zeigt eine, wieder eventuell kontextsensitiv gestaltete Demonstration.

Ebenso wird wohl dauernd ein



  class OrderButton extends Button
  {
    public OrderButton(ShoppingBag bag);
  }

angeboten. Er verzweigt zu einem Warenkorb; dieser ist meistens fest.

Konfigurierung des Katalogs

Zur Anpassung eines elektronischen Produktkatalogs an verschiedene Hard- und Software-Umgebungen grundsätzlich, als auch an dynamische Gegebenheiten, wie etwa bei einem Sprachwechsel, ist eine Konfigurationsklasse vorgesehen, die die wesentlichen Parameter erfaßt und ihre Auswirkungen an Layout durch Anpassung der Zeichenroutinen und an Direction durch Sperrung gewisser Prozesse weitergibt.



  class Configuration extends Object
  {
    private Language language;
    private UserMode usermode;

public Configuration(Language language);

public setLanguage(Language language); public Language getLanguage(); public setUserMode(UserMode mode); public UserMode getUserMode(); public setupCpu(); public setupScreen(); public setupMouse(); public setupKeyboard(); public setupPrinter(); public setupFaxModem(); }


Es werden hier der Prozessor (setupCpu()), der Bildschrim (setupScreen()), die Maus (setupMouse()), die Tastatur (setupKeyboard()), ein Drucker (setupPrinter()) und ein FAX-Modem (setupFaxModem()) berücksichtigt.

Daneben besteht die Möglichkeit der Festlegung der verwendeten Hauptsprache language und des Wechsels des Benutzermodus usermodus, etwa aus Sicherheitsgründen.

Firmenübersicht und Kataloginhalt

Sowohl die vertretenen Firmen als auch der Kataloghersteller erreichen eine Präsentation, eine Selbstdarstellung durch



  class Presentation extends Window
  {
    private CancelButton cancel;
    private DemoButton demo;
    private HelpButton help;

public Presentation(List<Layout> contents, CancelButton cancel, DemoButton demo, HelpButton help); }


Die drei Knöpfe cancel, demo und help sind dabei Referenzen auf Objekte, die in contents auftreten müssen. Mit cancel bricht man die Präsentation ab, demo verzweigt zu einer Demonstration und help zu einer HelpForm (s. hier).

Die Möglichkeit der Darstellung einer Inhaltsübersicht (auch über Teilgebiete eines Katalogs) bietet



  class TableOfContents extends Window
  {
    private List<Button> themebuttons;
    private List<Theme> themes;
    private CancelButton exit;
    private DemoButton demo;
    private HelpButton help;

public TableOfContents(List<Button> themebuttons, List<Theme> themes, DemoButton demo, ExitButton exit, HelpButton help); }


Die in themebuttons angegebenen Knöpfe (wieder aus contents) werden in Aufschreibungsreihenfolge den Themen themes zugeordnet und bei Betätigung wird entsprechend verzweigt. Der cancel-Knopf bricht den Katalog ab.

Warenkorb

Der Warenkorb besteht im wesentlichen aus einem spezialisierten Listenfenster, das mehrere Spalten umfaßt, von denen einige zeitweise veränderbar (als Input) sind.

Das Eintragen der Bestellung erfolgt in:



  class ShoppingBag extends Window
  {
    private MultipleBrowser orders;
    private Text total;
    private OKButton ok;
    private CancelButton cancel;
    private HelpButton help;
    private OrderButton order;

public OrdersBag(Window window, MultipleBrowser orders, Text total, OKButton ok, CancelButton cancel, OrderButton order, HelpButton help);

public sum(); }


Die Gesamtkosten können über die Summierungsmethode sum() berechnet werden. Sie werden in total eingetragen.

Produktsuche

Neben den vorgegebenen Navigationsmöglichkeiten durch einen Katalog soll auch eine Stichwortsuche zur Verfügung stehen.



  class SearchForm extends Window, KeyboardHandler
  {
    private PopUpMenu index;
    private Browser show;
    private OKButton ok;
    private Backbutton back;
    private Helpbutton help;
   
    public SearchForm(List<Layout> contents, PopUpMenu index,
                      Browser show, OKButton ok,
                      BackButton back, HelpButton help);
  }

In index ist eine, etwa das Alphabet enthaltende, Grobsuchmöglichkeit enthalten, die ihr Ergebnis in show darstellt. Daraus kann eine Option ausgewählt und eventuell damit eine verfeinerte Suche begonnen werden.

Produktpräsentation

Die Benutzung der verschieden multimedialen Elemente zur Produkt- und auch der Firmenpräsentation soll vereinfacht werden. Es werden dazu für Klänge Bedienelemente zur eigentlichen Darstellung hinzugenommen.

F ür Klänge:



  class AudioRecorder extends Audio
  {
    private Button play;
    private Button stop;
    private Button forward;
    private Button rewind;

public AudioRecorder(Button play, Button stop, Button forward, Button rewind); }


hat man einen Knopf zum Abspielen (play stößt play() an), zum Anhalten (stop stößt stop() an) und zum Vor- und Zurücksetzen (forward bzw. rewind).

Hilfe

Für die Bereitsstellung von Hilfe kann man entweder die in diesem Framework angebotenen Strukturierungs- und Darstellungsmöglichkeiten nutzen, oder ein externes System verwenden. Eine einheitliche Darstellung erreicht man durch



  class HelpForm extends Window, KeyboardHandler
  {
    private OKButton ok;
    private CancelButton cancel;

public HelpForm(List<Layout> contents, OKButton ok, CancelButton cancel); }


Die Syntax

Motivation und Übersicht

(zurück zum Inhalt)

Das skizzierte Framework stellt alle notwendigen Konstrukte bereit, auch umfangreiche und aufwendige elektronische Produktkataloge in einer einheitlichen Umgebung rasch und komfortabel entwickeln zu können. Es fehlen aber Möglichkeiten, die verschiedenen Objekte in organischer und auch automatisierter Weise zu einem übersichtlichen und damit leicht wartbaren Katalogprogramm zusammenfügen zu können: die Sprache EpkMl soll dem abhelfen.

Die Syntax ist intuitiv, zur weiteren Vereinfachung und den Automatisierungsprozeß unterstützend gedacht und gestaltet. Als automatisierbar werden dabei alle Layout-Teile des Framework angesehen, ein kleiner Teil der Regie (insbesondere die Handler) und speziell die Services; die Datenbank wird als (eventuell remodelliert) gegeben betrachtet, auf sie wird durch SQL-Anweisungen zugegriffen. Zur Unterstützung der Intuition wurde die Syntax als eine Document type definition in SgMl gestaltet. Es läßt sich allerdings nicht alles Wünschenswerte in SgMl formulieren, die Semantik stimmt damit nicht immer mit dem Gewohnten überein.

Großen Wert wurde auf die Strukturierungsmöglichkeiten des Katalogs gelegt. Gemäß dem eingangs erwähnten Automatisierungskonzept wird eine Gliederung in Themen (entspricht der Klasse Theme) ermöglicht, denen einerseits Unterthemen und andererseits Produkte in einheitlicher Darstellung - über sogenannte Vorlagen oder Templates - zugewiesen werden können (über die Klasse VirtualPage hinaus). Innerhalb dieser Struktur kann über Standardfunktionen (zum nächsten, zum vorherigen Produkt; zum nächsten, zum vorherigen Thema, etc.) navigiert werden (diese Funktionalität liegt im Framework bei der Klasse NavigationManager).

Die Vorlagen haben kein namentliches Pendant im Framework, da sie dort einfach durch eine Klasseninstantiierung realisiert werden können. Die fehlende Subklassenbildung und Objektkreierung erweist sich insgesamt als gewisser Mangel des SgMl-Ansatzes (neben dem Fehlen operationeller Möglichkeiten). Wir imitieren Aggregationen in EpkMl durch Makros (die, technisch gesprochen, eine Erweiterung der Document type definition innerhalb von SgMl ermöglichen), bieten variable Inhalte von Rahmen,

usw., sowie dynamische Formulare und eröffnen schließlich durch Einbindung externer, d. h. nicht in EpkMl formulierbarer Funktionalität, alle Möglichkeiten des Framework.

Grundlegendes

Ein EpkMl-Text ist in eine das oben definierte Framework erfüllende Sprache und Umgebung zu übersetzen. Die Repräsentation (und damit die Bedeutung) der meisten Tags und Attribute der im Anschluß wiedergegebenen Document type definition im Framework ist auf Grund der Namensgebung klar. Auf einige Besonderheiten muß aber hingewiesen werden.

Die Möglichkeiten von SgMl reichen für einige Grundlagen der EpkMl nicht aus: für Variablen, Anweisungen und den Kontrollfluß.

Variablen.
Die SgMl-Unterscheidung von Attributwerten und dem Inhalt von Elementen wird bei der EpkMl durch die Variablen durchbrochen. Wertzuweisungen (mit <set>) können sowohl im Inhalt als auch über ein Attribut erfolgen. (Dennoch haben wir bei der möglichen Parametrisierung von Elementen diese Trennung aufrechterhalten und sehen es als guten Programmierstil an, nicht zwischen Attributen und Elementinhalten zu wechseln.)

Variablennamen werden als $name$ geklammert. Sie dürfen überall als Elementinhalt und auf rechten Seiten von Attributzuweisungen auftreten.

Variablen werden entweder über <var>, über Parameter oder die Benennung von Elementen eingeführt. Der Sichtbarkeitsbereich ist durch die natürliche Blockstruktur vorgegeben. Es gilt statische Bindung. Die Verwendung einer im aktuellen Block nicht deklarierten Variable ist ein Fehler.



 <var name=months value=12>
 <var name=pic>
 <img src=pic.gif>
 </var>
 <var name=money value=500$\backslash$$>
 <var name=foo>
 $pic$
 $pic$
 </var>

Einige Namen sind reserviert:

$author$
der in <author> angegebene Inhalt.
$title$
der in <title> angegebene Inhalt.
$date$
der in <date> angegebene Inhalt.
$last-modified$
der in <last-modified> angegebene Inhalt.
$curdate$
das aktuelle Datum.
$curtime$
die aktuelle Zeit.
$dimension-unit$
eine Grundeinheit für Längenangaben ( mm, cm, in, pt, %). Sie wird bei dimensionslosen Längenangaben verwendet.
$time-unit$
eine Grundeinheit für Zeitangaben ( ms, s). Sie wird bei dimensionslosen Längenangaben verwendet.
$ name .selected$
Wird in <browser>, <pop-up>, <checkbox>, <radio-button>, <pull-down> eine Option selektiert oder deselektiert, so enthält eine Variable mit dem Namen des Gesamtelements, qualifiziert durch selected die Nummer der Option innerhalb des Gesamtelements.

Systemseitig werden zusätzlich einige Vektoren und Felder zur Verfügung gestellt (etwa aus der Datenbank). Auf die einzelnen Elemente kann dann mit $name[m]...[n]$ zugegriffen werden. Ist die Zugriffsnummer eine Variable, so muß diese nicht in $ eingeklammert werden.

Vektoren und Felder können benutzerseitig nicht angelegt werden.

Schließlich wird auf Attribute benannter Elemente durch Qualifikation mit dem Attributnamen zugegriffen.

Anweisungen.
In der EpkMl selbst steht nur eine kleine Menge von Operationen zur Verfügung. Diese betreffen

Das Kommando <set> setzt Variableninhalte entweder durch Zuweisung des im Attribut value angegebenen Wertes oder seines Inhalts (dieser hat höhere Priorität).

Mit <open> und <close> können alle Elemente (im Attribut name zu spezifizieren) geöffnet (d. h. gestartet) bzw. geschlossen (d. h. beendet) werden, die das Attribut status (mit den Werten opened, closed und suspended) besitzen. Ebenso kann ein solches Element mit <suspend> vorübergehend suspendiert werden. Diese Befehle entsprechen für Regieelemente beziehentlich den Methoden start(), stop() und suspend() der Klasse Thread, für Layoutelemente wird lediglich das invisible-Attribut gelöscht bzw. gesetzt (<suspend> hat hier keine Auswirkungen). Dabei weist der Befehl <open> für Themen und Datenbankeinträge einige Besonderheiten auf (s. u. , insbesondere auch für <next>, etc.).

Der Befehl <wait> wartet auf eine Benutzereingabe, das Verstreichen einer Zeitspanne oder die Beendigung einer Audiosequenz, oder eines <applet>. Dies entspricht der Behandlung eines MouseEvent, KeyboardEvent,

bzw. eines ClockEvent bzw. eines EndEvent.

Weiters greift ein in <sql> ... </sql> geklammertes SQL-Statement auf die Datenbank zu; das Ergebnis dieses Zugriffs wird in der im Attribut result angegebenen Variable gespeichert. Mit <empty> und <non-empty>) kann ein leeres oder nichtleeres Ergebnis abgefragt und unterschieden werden.

Ein <applet>-Befehl schließlich ruft die in seinem Attribut function angegebene Funktion (Methode) der verwendeten Hintergrundsprache auf, wobei die Parameterübergabe wie in Java gestaltet ist.

Kontrollfluß.
Der Kontrollfluß innerhalb der EpkMl ist sequentiell. Er verzweigt nach der Ausführung eines Statement, wenn nicht explizit anders angegeben, zum nächsten in Aufschreibungsreihenfolge. Der Kontrollfluß beginnt bei der ersten Anweisung in <main> (s. u. ).

Einige Anweisungen werden dabei nebenläufig ausgeführt (sie starten einen neuen Thread und kehren sofort zum Aufrufort zurück). Es sind dies <open> für <audio> (bzw. diese Elemente selbst, falls ihr Attribut status den Wert opened hat) und <applet> (falls dadurch tatsächlich ein neuer Prozeß erzeugt wird).

Die Gliederung eines Katalogs

Ein Katalog in EpkMl teilt sich in



 <epkml>
 <header>
 <title>The Shortest EPKML Catalogue
 <author>Me
 <date>03/06/96
 <last-modified>03/06/96
 </header>
 
 

<styles> <definitions> <main> <exit> </epkml>


Die Verwaltungsinformation wird durch ihre Beschreibung gleichzeitig in den beziehentlichen Variablen $title$, $author$, $date$ und $last-modified$ zum späteren Gebrauch zur Verfügung gestellt.

Standardvorlagen.
Im Stilteil werden für die Layoutobjekte Voreinstellungen mittels <stylesheet> vorgenommen. Dies erfolgt in Anlehung an die bekannten Cascading style sheets.

Verschieden Einzelvoreinstellungen (für Paragraphen, Fenster, etc.) können mit <stylesheet> zusammengefaßt und über das Attribut name insgesamt benannt werden.

Stylesheets können Erweiterungen anderer sein. Das Attribut extends enthält eine Liste von Stylesheetnamen, deren zugehörige Stylesheets erweitert werden sollen. Dabei priorisieren zunächst Voreinstellungen in zuerst genannten Stylesheets solche in später genannten. Zusätzlich überladen Voreinstellungen im erweiternden Stylesheet solche in den erweiterten. Ebenso können die einzelnen Voreinstellungen modifiziert werden.



 <styles>
 <stylesheet name=catalog-style>
 <default>
 <p lftmrg=1cm>
 </default>
 </stylesheet>
 <stylesheet name=my-catalog-style
 extends=catalog-style>
 <default>
 <p baselineskip=12pt>
 </default>
 </stylesheet>
 </styles>

Deklarationen und Definitionen.
Im <definitions>-Teil werden Variablen (s. o. ), Makros, beliebige Elemente und die Themenstruktur (s. u. ) definiert.

Makros dienen vor allem einer kürzeren Schreibung und einer klareren Übersicht.



 <macro name=my-image
 attribs="image"
 elems="text">
 <img src=$my-image.image$>
 <em>$text$</em>
 </macro>

Wie bei allen Elementen werden Parameter in den Attributen attribs und elems deklariert. Makros werden mit <expand> aufgerufen.



 <expand name=my-image>
 <attribute name=image value=hello.gif>
 <element name=text>
 Hello world!
 </element>
 </expand>

Die in <definitions> angegebenen Elemente werden ebenfalls nur deklariert: Das status-Attribut hat den Wert closed, das invisible-Attribut ist gesetzt.

Die Themenstruktur

Produktgruppen dienen benutzerseitig der Gliederung des Produktkatalogs, auf der Generierungsseite aber auch der automatischen Erstellung von Navigationsmöglichkeiten. In EpkMl werden solche Gruppierungen als sogenannte Themen (<theme>) wiedergegeben.

Ein Thema besteht aus

Ein Thema wird mit <open> geöffnet und mit <close> geschlossen. Zur Navigation innerhalb des Themenbaums stehen <next>, <previous>, <up>, <down>, <back> und <back hierarchical> zur Verfügung.



 <theme name=general>
 <presentation>

<frame name=general-frame> Hello world! <next-button name=general-next> Show 'em! <on-click> <next> </on-click> </next-button>

</frame> </presentation> <extension result=general-result> <sql> SELECT name FROM database WHERE * </sql> </extension> <template name=general-template> <frame name=general-frame> <p>This is a $general-result.name$.</p> <next-button> </frame> </template> <exceptions> <sql> SELECT name FROM database WHERE name=[AEIOU].* </sql> <template name=general-exception-template> <frame name=general-exception-frame> <p>This is an $general-result.name$.</p> <next-button> </frame> </template> </exceptions> <theme=sub-general> ... </theme> </theme>


In <presentation> wird die Übersichtsdarstellung eines Themas spezifiziert. Es sollten Knöpfe zur Weiterverzweigung in eventuelle Unterthemen und Datenbankeinträge (s. u. ) vorhanden sein. (Implizit wird ein <wait>-Statement zum Abschluß eingefügt, um die Benutzerreaktion abzuwarten.)

Die Datenbankeinträge, die von einem <theme> behandelt werden sollen, sind in <extension> durch eine <sql>-Anweisung zu beschreiben. Dem Ergebnis der Datenbanksuche kann im Attribut result ein Name gegeben werden. Es wird als Liste von Einträgen aufgefaßt; die Sortierung spielt damit eine Rolle (s. <previous, <next>).

Eine Formatvorlage (<template>) wird durch Variablen mit Inhalten aus der in <extension> erzeugten Datenbanktabelle gefüllt. Auch hier wird implizit ein <wait>-Statement zum Abschluß eingefügt.

Für einige Einträge von <extension>, für die zum Beispiel das definierte <template> unbefriedigende Ergebnisse liefert, können mit <exceptions> Ausnahmen spezifiziert werden. In einer <sql>-Anweisung werden die Ausnahmen angegeben (das Ergebnis muß eine Untermenge von <extension> sein), in <template> eine neue, alternative Formatvorlage.

Layout und Regie

Wie erwähnt stellen die in EpkMl gebotenen Layoutmöglichkeiten eine fast direkte Umsetzung der Forderungen des Framework in Syntax dar. In der Regie wurde nur ein sehr kleiner Teil übernommen (im wesentlichen das von den Klassen MouseHandler, KeyboardHandler, ClockHandler sowie den Interaktionsereignissen Gebotene. So hat man etwa:



 <button
 style=sport-style>
 <img src=stop.gif>
 <on-click>
 <close name=sport-presentation>
 </on-click>
 </button>

<audio name=summer-audio src=/audio/summer-audio.au format=au>

<wait end-of=summer-audio>

\mbox{}


Eine detaillierte Schilderung der intendierten Semantik scheint somit nicht notwendig.

Die EpkMl bietet daneben aber einige Möglichkeiten, die ihr fehlenden Ablaufstrukturen zu kompensieren. Neben der Leerheitsabfrage für Datenbanken (<empty>) sind dies vor allem <make-options> und <make-items>, die Datenbanktabellen in Browser- und Listeneinträge verwandeln.

Hierzu zunächst ein größeres Beispiel:



 <sql result=out>
 SELECT code price prod-name
 FROM products
 WHERE saison=winter
 </sql>

<browser name=static-browser> <option>$out.prod-name[1]$ $out.price[1]$ <option>$out.prod-name[2]$ $out.price[2]$ <option>Levis 501 DM 200,- <option>$out.prod-name[4]$ $out.price[4]$ <option>$out.prod-name[3]$ $out.price[3]$ </browser>

<frame name=abc elems="prod-name prod-price"> The product $prod-name$ has a price of $prod-price$. </frame>

<browser name=dynamic-browser> <make-options from=out> $out.prod-name$ $out.price$ <on-selected> <open name=abc> <element name=prod-name> $out.prod-name$ <element name=prod-price> $out.price$ </open> </on-selected> </make-options> </browser>


Der erste Browser greift auf feste Elemente einer Datenbanktabelle ($out$) zu und fügt ein weiteres Element in die Auswahl ein. Der zweite Browser dagegen generiert aus den Datenbankeinträgen dynamisch eine Liste seiner <option>s, die bei ihrem Aufruf ein entsprechend angepaßtes Verhalten zeigen.

Ebenso verhält sich <make-items>.



 <sql result=out>
 SELECT code price prod-name
 FROM products
 WHERE saison = winter
 </sql>

New line of products: <itemize> <make-items from=out> $out.prod-name$ - $out.prod-price$ </itemize>


Ein Pendant im Framework ist hier natürlicherweise nicht vorhanden.

Die Document type definition

(zurück zum Inhalt)

Für die folgende SgMl-Grammtik der EpkMl - die Bedeutung einer document type definition entnehme man der Literatur - wurde wieder einiges der entsprechenden Definition von HtMl übernommen.