Layout-Templates

Technisch gesehen bietet der Layout-Editor solche Komponenten an, für die Templates zur Verfügung stehen. Ein solches Layout-Template ist eine Datei *.template.xml im Ordner WEB-INF/layouts der laufenden Applikation. Ein Template kann entweder von der Applikation selbst, oder von einem TopLogic-Modul zur Verfügung gestellt sein.

Aufbau eines Layout-Templates

Ein Layout-Template ist eine XML-Datei im Namensraum http://www.top-logic.com/ns/config/6.0 mit dem Root-Tag template:

<config:template
  xmlns:config="http://www.top-logic.com/ns/config/6.0"
  groups="..."
>
  <properties extends="...">
    <property name="myProp"
      type="..."
    >
      ...
    </property>

    ...
  </properties>

  <component name="..." 
    class="..."
    option="${myProp}"
  >
    ...
  </component>
</config:template>
Die Datei besteht aus zwei Abschnitten. Im properties Header werden die vom Layout-Editor angebotenen Optionen definiert (property). Das nächste (und einzige) Element nach dem Abschnitt properties ist die Komponentenkonfiguration, die duch das Template erzeugt werden soll. Die Konfigurationsoptionen der konfigurierten Komponente können über ${myProp} Bezug nehmen auf den Wert des Property mit Namen myProp.

Ein Property eines Layout-Templates verhält sich wie ein Property der Typisierten Konfiguration, das anstatt über den Getter eines Java-Interfaces in XML definiert ist. Der Name des Property wird im Attribut name gegeben. Der Typ des Property wird entweder direkt im Attribut type als vollqualifizierter Klassenname angegeben, wenn es sich um ein primitives Property handelt. Bei einem listenwertigen Property ist der type gleich List und der Wertetyp der Liste in element-type gegeben. Handelt es sich um eine Instanz-Unterkonfiguration, so ist der type oder element-type gleich PolymorphicConfiguration und der Typ der konfigurierten Instanz über instance-type gegeben. Beispiele für Properties sind:

Ein einfaches Boolean-Property "tabVisible" (der Default-Wert kann über das Attribut default angegeben werden):

<property name="tabVisible"
  default="true"
  type="boolean"
/>

Eine Instanz-Konfiguration eines Model-Builders (Annotationen an das Property können im Inhaltsbereich des Properties gegeben werden):

<property name="modelBuilder"
  instance-type="com.top_logic.mig.html.ListModelBuilder"
  type="PolymorphicConfiguration"
>
  <mandatory/>
  <options fun="com.top_logic.layout.form.values.edit.AllInAppImplementations"/>
</property>

Eine Liste von Button-Instanzkonfigurationen:

<property name="buttons"
  element-type="com.top_logic.basic.config.PolymorphicConfiguration"
  instance-type="com.top_logic.tool.boundsec.CommandHandler"
  type="List"
>
  <acceptable-classifiers value="commons, dialog"/>
</property>

Assistenten-Templates

Normale Templates erwarten für die Erstellung einer neuen Komponente dieselbe Menge an Optionen wie bei der nachträglichen Bearbeitung einer bereits erstellten Komponente. Manchmal ist es aber sinnvoll bei der Neuanlage nur eine kleine Menge an Initialwerten abzufragen und diese zu verwenden, um die Parameter des eigentlichen Templates mit sinnvollen Default-Werten zu füllen. So kann aus der Eingabe eines Typs eine gute Vorbelegung für diverse Lookup- und Test-Funktionen eines Model-Builders erzeugt werden.

Um die Komponentenerzeugung so zu vereinfachen, gibt es Assistenten-Templates, welche mit wenigen initial zu füllenden Parametern ein anderes Template aufrufen und die "echten" Parameter aus den eingegebenen Werten belegen. Wird eine über ein Assistenten-Template angelegte Komponente später editiert, werden dann die vollständigen Parameter des eigentlichen Templates zur Bearbeitung angeboten. Das folgende Template ist ein Assistent für das eigentliche Template my-real-component.template.xml, das in dem Attribut assistant-for angegeben wird. Im Inhaltsbereich eines Assistententemplates wird keine Komponentenkonfiguration erstellt, sondern die Konfiguration der Parameter des Ziel-Templates (config):

<config:template
  xmlns:config="http://www.top-logic.com/ns/config/6.0"
  assistant-for="my-real-component.template.xml"
>
  <properties>
    <property name="initProp" type="String">
    ...
  </properties>

  <config>
    <realProp>${initProp}</realProp>
  </config>
</config:template>

Sichten-Templates

Ein Template kann nicht nur eine einzelne Komponente erzeugen, sondern eine ganze Sicht bestehend aus mehreren gleichzeitig angezeigten Komponenten, Dialogen und Buttons. Hierfür kann ein Template andere Templates über temlate-call aufrufen. Einem template-call übergibt man das zu instanziierende Template mit dem template-Attribut und im Inhaltsbereich die Argumente für die Parameter dieses Templates mit dem arguments-Element. Macht man ein Sichten-Template zu einem Assistenten-Template (siehe oben), dann hat das den positiven Nebeneffekt, dass aus dem Template-Aufrufen eigenständig konfigurierbare Komponenten werden. D.h. nach Erstellung einer Sicht mit einem Sichten-Assistenten, entstehen mehrere unabhängig voneinander weiterbearbeitbare Komponenten. Von jeder dieser Komponenten lassen ich anschließend im Layout-Editor die Eigenschaften anpassen.

Folgender Sichten-Assistent erstellt drei Komponenten: Eine Tabelle neben einem Formular und einen Create-Dialog an der Tabelle:

<config:template
  xmlns:config="http://www.top-logic.com/ns/config/6.0"
  assistant-for="com.top_logic/layout.template.xml"
>
  <properties extends="com.top_logic.layout.editor.config.TypeTemplateParameters">
    ...
  </properties>

  <config>
    <components>
      <config:template-call
        layout-scope="__tableTemplateScope__"
        template="com.top_logic/table.template.xml"
      >
        <arguments name="..."
          type="..."
        >
          <dialogs>
            <config:template-call template=".../genericCreateDialog.template.xml">
              <arguments>
                ...
              </arguments>
            </config:template-call>
          </dialogs>
        </arguments>
      </config:template-call>

      <config:template-call template=".../form.template.xml">
        <arguments 
          model="selection(__tableTemplateScope__#Table)"
        />
      </config:template-call>
    </components>
  </config>
</config:template>

Eine Besonderheit ist hier, dass gleichzeitig eine Verknüpfung zwischen der Selektion der Tabelle und dem Modell des Formulars hergestellt wird. Da Tabelle und Formular nach Expansion des Templates durch zwei unterschiedliche Templates erzeugt werden und eine Komponenten-Referenz sich immer auf die Datei bezieht, in der die Komponente definiert ist, kann diese Beziehung eigentlich vor Expansion des Templates noch gar nicht formuliert werden, weil die beiden Zieldateien, in die die Templates for Tabelle und Formular expandiert werden noch nicht existieren.

Um dies dennoch zu realisieren, kann bei einem Template-Aufruf eine Variable für die Zieldatei ("Layout-Scope") angegeben werden. Mit der Deklaration layout-scope="__tableTemplateScope__" am Template-Aufruf für die Tabelle wird gesagt, dass die Zieldatei, in die dieses Template expandiert wird, __tableTemplateScope__ heißen soll. Diese Variable kann anschließend verwendet werden, um in der Modell-Definition des Formulars, auf die Tabellenkomponente Bezug zu nehmen: selection(__tableTemplateScope__#Table)

Die Scope-Variable __tableTemplateScope__ kann wie ein Dateiname verwendet werden, um eine Komponenten-Referenz zu bauen. Mit Expansion des Sichten-Assistenten wird diese Variabel konsistent durch die Dateinamen ersetzt, in die die Templates expandiert werden.