6.6.1. Austauschen und Dekorieren von Widgets mit Hilfe der Generic Widget Factory

Die Generic Widget Factory bietet die folgenden Möglichkeiten zum Austauschen und Dekorieren von Widgets:

Beispiel

Diese Möglichkeiten sollen Anhand eines durchgängigen Beispiels erläutert werden:

Für ein existierendes Produkt wird bei einem Neukunden Akquise gemacht. Das Produkt bietet die Möglichkeit, Entitäten und deren Beziehungen individuell zu definieren, um diese in einer Datenbank zu verwalten und Workflows auf den Daten durchzuführen. Nachdem der Kunde eine Demoversion des Produktes getestet, und dabei einige für ihn spezifische Masken für Maschinenteile und Baugruppen modelliert hat, kommt der folgende Wunsch auf:

In seinem System werden sehr viele komplexe technische Parameter Bezeichnungen und Identifikationsnummern als Attributname für Teile und Baugruppen verwendet. Der Kunde würde diese Informationen gelegentlich gerne in einem Legacy System für Suchanfragen verwenden. Dies gilt sowohl für die Attributnamen als auch für den Inhalt. Da die Attributnamen derzeit mit Hilfe von Text Label Widgets angezeigt werden, kann man Sie nicht in die Zwischenablage kopieren, sondern muss diese abschreiben. Die folgende Abbildung zeigt eine für den Kunden typische Datenmaske für ein Maschinenteil[35]:

Abbildung 48. Beispiel Eingabemaske

Beispiel Eingabemaske

Die Anpassung sollte so kostengünstig wie möglich sein (Kundenwunsch), und möglichst wenig Auswirkungen auf das zugrundeliegende Produkt und somit Systeme bei andere Kunden haben (Wunsch des Auftragnehmer). Dem Kunden werden die folgende Lösungsmöglichkeiten angeboten:

  • Alle Text Label werden durch ein ITextField ersetzt, welche wie ein Text Label aussehen, weil sie keinen Border haben und die Hintergrundfarbe vom Parent Container erben. Diese sind readonly, können also nicht geändert werden, es ist aber möglich, den Text zu markieren und so in die Zwischenablage zu kopieren. Dies könnte umgesetzt werden, indem die registrierte Widget Implementierung für ITextLabelBluePrint durch eine andere Implementierung ersetzt wird.

  • Alle Text Label erhalten ein Kontextmenü, welches eine Copy to clipboard Aktion enthält. Dies könnte umgesetzt werden, indem für ITextLabelBluePrint die registrierte Implementierung des Widget dekoriert wird.

Der Kunde stellt beide Lösungen einer Gruppe von Benutzern vor, wobei der eine Teil die Erste, der andere Teil die zweite Lösung bevorzugt. Der Kunde fragt, ob man auf einfache und kostengünstige Weise beide Lösungen anbieten können.

Es wird angeboten, das man in den Einstellungen einen Parameter hinzufügt, der das Verhalten festlegt. Um die Lösung möglichst kostengünstig zu halten, wird vom Kunden akzeptiert, das sich die Änderung nur auf neu erstellte Masken und nicht auf bereits erzeugte auswirken, und somit u.U. ein Neustart der Client Applikation notwendig ist. Da laut Nutzer dieser Parameter nach einmaliger Konfiguration in der Regel nicht mehr geändert wird, stellt dies für den Kunden kein Problem dar. Diese Lösung könnte umgesetzt werden, indem für ITextLabelBluePrint die Widget Factory dekoriert wird.

Widget Implementierungen austauschen

Die folgende Klasse implementiert die Schnittstelle ITextLabel mit Hilfe eines Textfeldes:

  1  public final class TextFieldLabel extends ControlWrapper implements ITextLabel {
  2  
  3      private final ITextControl textField;
  4  
  5      public TextFieldLabel(final ITextControl textField) {
  6          super(textField);
  7          this.textField = textField;
  8      }
  9  
 10      @Override
 11      public void setFontSize(final int size) {
 12          textField.setFontSize(size);
 13      }
 14  
 15      @Override
 16      public void setFontName(final String fontName) {
 17          textField.setFontName(fontName);
 18      }
 19  
 20      @Override
 21      public void setMarkup(final Markup markup) {
 22          textField.setMarkup(markup);
 23      }
 24  
 25      @Override
 26      public void setText(final String text) {
 27          textField.setText(text);
 28      }
 29  
 30      @Override
 31      public String getText() {
 32          return textField.getText();
 33      }
 34  
 35  }

Die meisten Methoden werden vom [Control Wrapper] geerbt, die anderen werden an das textField delegiert.

Die folgende Factory erzeugt Instanzen dieser TextFieldLabel’s:

  1  public final class TextFieldLabelFactory 
  2      implements IWidgetFactory<ITextLabel, ITextLabelBluePrint> {
  3  
  4      @Override
  5      public ITextLabel create(
  6          final Object parentUiReference, 
  7          final ITextLabelBluePrint textLabelBp) {
  8          
  9          final ITextFieldBluePrint textFieldBp = BPF.textField();
 10          
 11          textFieldBp.setSetup(textLabelBp);
 12          textFieldBp.setBorder(false).setEditable(false).setInheritBackground(true);
 13  
 14          final ITextControl textField = Toolkit.getWidgetFactory().create(
 15              parentUiReference, 
 16              textFieldBp);
 17  
 18          return new TextFieldLabel(textField);
 19      }
 20  
 21  }

In Zeile 9 wird ein neues BluePrint für ein Text Field erzeugt. In Zeile 11 wird das Setup des Textlabels auf dem BluePrint des Texfeldes gesetzt. Dabei werden alle Properties, welche das Textfeld und das Textlabel gemeinsam haben (wie zum Beispiel die Vordergrundfarbe, die Schriftart, etc,) auch für das Textfeld übernommen. In Zeile 14 wird dann ein Texfeld mit Hilfe des textFieldBp erzeugt. Dieses wird der Klasse TextFieldLabel übergeben, welche die Schnittstelle ITextLabel implementiert (sie weiter oben).

Der folgende Code tauscht in der Generic Widget Factory die aktuelle Implementierung für Text Labels durch die TextFieldLabelFactory aus. Dies passiert mit Hilfe eines Toolkit Interceptors:

  1  @Override
  2  public void onToolkitCreate(final IToolkit toolkit) {
  3      toolkit.getWidgetFactory().unRegister(ITextLabelDescriptor.class);
  4      
  5      toolkit.getWidgetFactory().register(
  6          ITextLabelDescriptor.class, 
  7          new TextFieldLabelFactory());
  8  }

Die folgende Abbildung zeigt den Effekt:

Abbildung 49. TextFieldLabel

TextFieldLabel

Durch dass globale Austauschen der Label Implementierung wird nun für alle Labels ein Textfeld für die Darstellung verwendet. Insbesondere lassen sich die Attribute nun markieren und zum Beispiel per STRG-C in die Zwischenablage kopieren.

Widget Implementierungen dekorieren

Bei der zweiten Variante soll allen Labels ein Kontextmenü hinzufügen, welche eine Copy Action enthält, die den Text des Labels in die Zwischenablage kopiert. Um dies umzusetzen wird zuerst ein IDecorator<ITextLabel> wie folgt implementiert:

  1  public final class LabelPopupDecorator implements IDecorator<ITextLabel> {
  2  
  3      @Override
  4      public ITextLabel decorate(final ITextLabel original) {
  5          final IMenuModel copyMenu = new MenuModel();
  6  
  7          final IActionItemModelBuilder copyActionBuilder = ActionItemModel.builder();
  8          copyActionBuilder
  9              .setText("Copy to Clipboard")
 10              .setToolTipText("Copies the label text to the system clipboard")
 11              .setIcon(IconsSmall.COPY);
 12          
 13          final IActionItemModel copyAction = copyMenu.addItem(copyActionBuilder);
 14          copyAction.addActionListener(new IActionListener() {
 15              @Override
 16              public void actionPerformed() {
 17                  Clipboard.setContents(new StringTransfer(original.getText()));
 18              }
 19          });
 20          
 21          original.setPopupMenu(copyMenu);
 22          return original;
 23      }
 24  }

Der Dekorierer wird dann mit Hilfe eines Toolkit Interceptors wie folgt hinzugefügt:

  1  @Override
  2  public void onToolkitCreate(final IToolkit toolkit) {
  3      toolkit.getWidgetFactory().addWidgetDecorator(
  4          ITextLabelDescriptor.class, 
  5          new LabelPopupDecorator());
  6  }

Die folgende Abbildung zeigt den Effekt:

Abbildung 50. LabelPopupDecorator

LabelPopupDecorator

Alle Labels haben jetzt ein Kontextmenü zum Kopieren des Labelinhalts.

Widget Factories dekorieren

Nun soll noch gezeigt werden, wie man mit Hilfe eines Widget Factory Decorator je nach Konfiguration die eine oder andere Variante wählen kann.

  1  public final class LabelFactoryDecorator 
  2      implements IDecorator<IWidgetFactory<ITextLabel, ITextLabelBluePrint>> {
  3  
  4      private final LabelPopupDecorator labelPopupDecorator;
  5      private final TextFieldLabelFactory textFieldLabelFactory;
  6  
  7      //will be injected
  8      private ILabelConfig labelConfig;
  9  
 10      public LabelFactoryDecorator() {
 11          this.textFieldLabelFactory = new TextFieldLabelFactory();
 12          this.labelPopupDecorator = new LabelPopupDecorator();
 13      }
 14  
 15      @Override
 16      public IWidgetFactory<ITextLabel, ITextLabelBluePrint> decorate(
 17          final IWidgetFactory<ITextLabel, ITextLabelBluePrint> originalFactory) {
 18  
 19          //no config or default type so use original
 20          if (labelConfig == null || LabelType.DEFAULT == labelConfig.getLabelType()) {
 21              return originalFactory;
 22          }
 23          //use TextFieldLabel
 24          else if (LabelType.TEXT_FIELD == labelConfig.getLabelType()) {
 25              return textFieldLabelFactory;
 26          }
 27          //use copy action
 28          else if (LabelType.COPY_ACTION == labelConfig.getLabelType()) {
 29              return new IWidgetFactory<ITextLabel, ITextLabelBluePrint>() {
 30                  @Override
 31                  public ITextLabel create(
 32                      final Object parentUiReference,
 33                      final ITextLabelBluePrint descriptor) {
 34                      
 35                      //create the original widget with the original factory
 36                      final ITextLabel originalWidget = originalFactory.create(
 37                          parentUiReference, 
 38                          descriptor);
 39                      
 40                      //decorate the popup menus
 41                      return labelPopupDecorator.decorate(originalWidget);
 42                  }
 43              };
 44          }
 45          else {
 46              throw new IllegalStateException(
 47                  "Lable type '" + labelConfig.getLabelType() + "' is not supported.");
 48          }
 49      }
 50  
 51  }

Dieser Dekorierer kann wie folgt registriert werden:

  1  @Override
  2  public void onToolkitCreate(final IToolkit toolkit) {
  3      toolkit.getWidgetFactory().addWidgetFactoryDecorator(
  4          ITextLabelDescriptor.class, 
  5          new LabelFactoryDecorator());
  6  }   

Das Überschreiben und Dekorieren aus den beiden vorigen Abschnitten wird dadurch obsolet.



[35] Diese ist frei erfunden. Jede Ähnlichkeit mit realen Produkten ist rein zufällig.


Siehe auch PDF Version dieses Dokuments, Jowidgets API Spezifikation