changeset 9220:e3c2ae1887e8

Allow to filter contents of datacage on client side. Allow to override column label of datacage Some code cleanup
author gernotbelger
date Wed, 04 Jul 2018 12:00:51 +0200
parents 8642a76f22be
children 5c34fe17ef15
files gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacagePairWidget.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacagePanel.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageTwinPanel.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageWidget.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageWidgetData.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageWindow.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DefaultDatacageTwinPanelInfo.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DemDatacagePanel.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/HWSDatacagePanel.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/NilDatacageTwinPanelInfo.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WaterlevelRecommendationInfo.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WspDatacagePanel.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/minfo/BedHeightsDatacagePanel.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthMinMaxTwinPanel.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthTwinPanel.java
diffstat 18 files changed, 682 insertions(+), 732 deletions(-) [+]
line wrap: on
line diff
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java	Wed Jul 04 10:46:37 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java	Wed Jul 04 12:00:51 2018 +0200
@@ -1544,4 +1544,8 @@
     String sinfo_collision_export();
 
     String sinfo_flood_height();
+
+    String sinfo_columnlabel_soundings();
+
+    String sinfo_columnlabel_waterlevels();
 }
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties	Wed Jul 04 10:46:37 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties	Wed Jul 04 12:00:51 2018 +0200
@@ -831,4 +831,7 @@
 bundu = Betrieb und Unterhaltung 
 
 chart_settings_export_metadata = Show Meta-Data
-export_csv_title = Title: 
\ No newline at end of file
+export_csv_title = Title: 
+
+sinfo_columnlabel_soundings = Wahl der Peilung
+sinfo_columnlabel_waterlevels = Wahl des Wasserspiegels
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties	Wed Jul 04 10:46:37 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties	Wed Jul 04 12:00:51 2018 +0200
@@ -831,4 +831,7 @@
 bundu = Betrieb und Unterhaltung
 
 chart_settings_export_metadata = Metadaten anzeigen
-export_csv_title = Titel: 
\ No newline at end of file
+export_csv_title = Titel: 
+
+sinfo_columnlabel_soundings = Wahl der Peilung
+sinfo_columnlabel_waterlevels = Wahl des Wasserspiegels
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacagePairWidget.java	Wed Jul 04 10:46:37 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacagePairWidget.java	Wed Jul 04 12:00:51 2018 +0200
@@ -9,9 +9,7 @@
 package org.dive4elements.river.client.client.ui;
 
 import org.dive4elements.river.client.client.FLYSConstants;
-import org.dive4elements.river.client.shared.model.Artifact;
 import org.dive4elements.river.client.shared.model.ToLoad;
-import org.dive4elements.river.client.shared.model.User;
 
 import com.google.gwt.core.client.GWT;
 import com.smartgwt.client.util.SC;
@@ -28,52 +26,40 @@
  */
 public class DatacagePairWidget extends VLayout {
     /** i18n resource. */
-    protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
+    private final FLYSConstants MSG = GWT.create(FLYSConstants.class);
 
     /** The "remote" ListGrid to insert data to when add-button is clicked. */
-    protected ListGrid grid;
+    private final ListGrid grid;
 
     /** First (upper) DataCage Grid. */
-    protected DatacageWidget firstDatacageWidget;
+    private final DatacageWidget firstDatacageWidget;
 
     /** Second (lower) DataCage Grid. */
-    protected DatacageWidget secondDatacageWidget;
+    private final DatacageWidget secondDatacageWidget;
 
     /** Max number of recommendation pairs to be added */
     private final int maxCount;
+
     /** errorMsg maxCount */
     private final String msgMaxCount;
 
-    /**
-     *
-     * @param artifact
-     *            Artifact to query datacage with.
-     * @param user
-     *            User to query datacage with.
-     * @param leftOuts
-     *            outs to query the left datacage with.
-     * @param rightOuts
-     *            outs to query the right datacage with.
-     * @param grid
-     *            Grid into which to insert selection of pairs.
-     * @param max
-     */
-    public DatacagePairWidget(final Artifact artifact, final User user, final String leftOuts, final String rightOuts, final ListGrid grid, final int maxCount,
+    public DatacagePairWidget(final DatacageWidgetData leftData, final DatacageWidgetData rightData, final ListGrid grid, final int maxCount,
             final String msgMaxCount) {
         this.msgMaxCount = msgMaxCount;
         this.maxCount = maxCount;
         this.grid = grid;
 
         final HLayout hLayout = new HLayout();
-        this.firstDatacageWidget = new DatacageWidget(artifact, user, leftOuts, "load-system:true", false);
-        this.secondDatacageWidget = new DatacageWidget(artifact, user, rightOuts, "load-system:true", false);
+
+        this.firstDatacageWidget = new DatacageWidget(leftData);
+        this.secondDatacageWidget = new DatacageWidget(rightData);
+
         this.firstDatacageWidget.setIsMutliSelectable(false);
         this.secondDatacageWidget.setIsMutliSelectable(false);
 
         hLayout.addMember(this.firstDatacageWidget);
         hLayout.addMember(this.secondDatacageWidget);
 
-        // TODO: icon
         final Button plusBtn = new Button(this.MSG.datacage_add_pair());
         plusBtn.setAutoFit(true);
         plusBtn.addClickHandler(new ClickHandler() {
@@ -95,10 +81,13 @@
         final ToLoad toLoad1 = this.firstDatacageWidget.getSelection();
         final ToLoad toLoad2 = this.secondDatacageWidget.getSelection();
 
+        // FIXME: allows to select folders... but it should not
+
         if (toLoad1 == null || toLoad2 == null || toLoad1.toRecommendations().isEmpty() || toLoad2.toRecommendations().isEmpty()) {
             SC.say(this.MSG.warning_select_two_values());
             return;
         }
+
         if (this.grid.getTotalRows() >= this.maxCount) {
             SC.say(this.msgMaxCount);
             return;
@@ -106,5 +95,4 @@
 
         this.grid.addData(new RecommendationPairRecord(toLoad1.toRecommendations().get(0), toLoad2.toRecommendations().get(0)));
     }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
+}
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacagePanel.java	Wed Jul 04 10:46:37 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacagePanel.java	Wed Jul 04 12:00:51 2018 +0200
@@ -8,18 +8,18 @@
 
 package org.dive4elements.river.client.client.ui;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.dive4elements.river.client.shared.model.Data;
+import org.dive4elements.river.client.shared.model.DataList;
+import org.dive4elements.river.client.shared.model.ToLoad;
+import org.dive4elements.river.client.shared.model.User;
+
 import com.smartgwt.client.widgets.Canvas;
 import com.smartgwt.client.widgets.Label;
 import com.smartgwt.client.widgets.layout.VLayout;
 
-import org.dive4elements.river.client.shared.model.Data;
-import org.dive4elements.river.client.shared.model.DataList;
-import org.dive4elements.river.client.shared.model.User;
-
-import java.util.ArrayList;
-import java.util.List;
-
-
 /**
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
@@ -27,34 +27,35 @@
 
     private static final long serialVersionUID = 6937994648371673222L;
 
-    protected String dataName;
-
-    protected User user;
+    private String dataName;
 
-    protected DatacageWidget widget;
+    private final User user;
 
+    private DatacageWidget widget;
 
-    public DatacagePanel() {
-        super();
+    private final String outs;
+
+    private final String parameters;
+
+    private final boolean multiSelectable;
+
+    public DatacagePanel(final User user, final String outs, final String parameters, final boolean multiSelectable) {
+        this.user = user;
+        this.outs = outs;
+        this.parameters = parameters;
+        this.multiSelectable = multiSelectable;
     }
 
-
-    public DatacagePanel(User user) {
-        super();
-        this.user = user;
-    }
-
-
     @Override
-    public Canvas create(DataList dataList) {
-        Data   data   = dataList.get(0);
+    public Canvas create(final DataList dataList) {
+        final Data data = dataList.get(0);
         this.dataName = data.getLabel();
 
         createWidget();
 
-        Canvas label   = new Label(data.getDescription());
-        Canvas submit  = getNextButton();
-        VLayout layout = new VLayout();
+        final Canvas label = new Label(data.getDescription());
+        final Canvas submit = getNextButton();
+        final VLayout layout = new VLayout();
         label.setHeight(25);
 
         layout.addMember(label);
@@ -64,39 +65,36 @@
         return layout;
     }
 
+    private void createWidget() {
 
-    protected void createWidget() {
-        widget = new DatacageWidget(
-            artifact,
-            getUser(),
-            getOuts(),
-            getParameters(),
-            false);
+        final DatacageWidgetData data = new DatacageWidgetData(this.artifact, this.user, this.outs, this.parameters, false);
 
-        widget.setHeight100();
+        this.widget = new DatacageWidget(data);
 
-        helperContainer.addMember(widget);
+        this.widget.setHeight100();
+
+        this.helperContainer.addMember(this.widget);
+
+        this.widget.setIsMutliSelectable(this.multiSelectable);
     }
 
-
     @Override
     public List<String> validate() {
         return new ArrayList<String>();
     }
 
-
-    public User getUser() {
-        return user;
+    /**
+     * Unclear if this may implement super.getDataName...
+     */
+    protected final String getMyDataName() {
+        return this.dataName;
     }
 
-
-    public String getOuts() {
-        return null;
+    protected final ToLoad getSelection() {
+        return this.widget.getSelection();
     }
 
-
-    public String getParameters() {
-        return null;
+    protected final String[] getSelectionTitles() {
+        return this.widget.getSelectionTitles();
     }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
+}
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageTwinPanel.java	Wed Jul 04 10:46:37 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageTwinPanel.java	Wed Jul 04 12:00:51 2018 +0200
@@ -32,6 +32,8 @@
 
     public static interface IDatacageTwinPanelInfo extends IRecommendationInfo {
         String getOuts();
+
+        String getColumnLabel();
     }
 
     public DatacageTwinPanel(final User user, final IValidator validator, final IDatacageTwinPanelInfo leftInfo, final IDatacageTwinPanelInfo rightInfo,
@@ -54,9 +56,14 @@
         final HLayout helperLayout = new HLayout();
 
         final String leftOuts = this.leftInfo.getOuts();
+        final String leftLabel = this.leftInfo.getColumnLabel();
+        final DatacageWidgetData leftData = new DatacageWidgetData(this.artifact, user, leftOuts, "load-system:true", false, leftLabel);
+
         final String rightOuts = this.rightInfo.getOuts();
+        final String rightLabel = this.rightInfo.getColumnLabel();
+        final DatacageWidgetData rightData = new DatacageWidgetData(this.artifact, user, rightOuts, "load-system:true", false, rightLabel);
 
-        helperLayout.addMember(new DatacagePairWidget(this.artifact, user, leftOuts, rightOuts, differencesList, this.maxCount, this.msgMaxCount));
+        helperLayout.addMember(new DatacagePairWidget(leftData, rightData, differencesList, this.maxCount, this.msgMaxCount));
 
         if (dataList != null && dataList.get(0) != null && dataList.get(0).getDescription() != null) {
             final Label title = new Label(dataList.get(0).getDescription());
@@ -71,5 +78,4 @@
 
         return layout;
     }
-
 }
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageWidget.java	Wed Jul 04 10:46:37 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageWidget.java	Wed Jul 04 12:00:51 2018 +0200
@@ -8,468 +8,409 @@
 
 package org.dive4elements.river.client.client.ui;
 
-import com.google.gwt.core.client.GWT;
-
-import com.google.gwt.user.client.rpc.AsyncCallback;
-
-import com.smartgwt.client.types.SelectionStyle;
-import com.smartgwt.client.types.TreeModelType;
-
-import com.smartgwt.client.util.SC;
-
-import com.smartgwt.client.widgets.Button;
-
-import com.smartgwt.client.widgets.events.ClickEvent;
-import com.smartgwt.client.widgets.events.ClickHandler;
-
-import com.smartgwt.client.widgets.grid.HoverCustomizer;
-import com.smartgwt.client.widgets.grid.ListGridRecord;
-
-import com.smartgwt.client.widgets.grid.events.RecordDoubleClickEvent;
-import com.smartgwt.client.widgets.grid.events.RecordDoubleClickHandler;
-
-import com.smartgwt.client.widgets.layout.VLayout;
-
-import com.smartgwt.client.widgets.tree.Tree;
-import com.smartgwt.client.widgets.tree.TreeGrid;
-import com.smartgwt.client.widgets.tree.TreeNode;
-
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.MissingResourceException;
 import java.util.Stack;
 
 import org.dive4elements.river.client.client.Config;
 import org.dive4elements.river.client.client.FLYSConstants;
-
 import org.dive4elements.river.client.client.event.DatacageDoubleClickHandler;
 import org.dive4elements.river.client.client.event.DatacageHandler;
-
 import org.dive4elements.river.client.client.services.MetaDataService;
 import org.dive4elements.river.client.client.services.MetaDataServiceAsync;
-
-import org.dive4elements.river.client.shared.model.Artifact;
 import org.dive4elements.river.client.shared.model.AttrList;
 import org.dive4elements.river.client.shared.model.DataCageNode;
 import org.dive4elements.river.client.shared.model.DataCageTree;
 import org.dive4elements.river.client.shared.model.ToLoad;
 import org.dive4elements.river.client.shared.model.User;
 
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.smartgwt.client.types.SelectionStyle;
+import com.smartgwt.client.types.TreeModelType;
+import com.smartgwt.client.util.SC;
+import com.smartgwt.client.widgets.Button;
+import com.smartgwt.client.widgets.events.ClickEvent;
+import com.smartgwt.client.widgets.events.ClickHandler;
+import com.smartgwt.client.widgets.grid.HoverCustomizer;
+import com.smartgwt.client.widgets.grid.ListGridRecord;
+import com.smartgwt.client.widgets.grid.events.RecordDoubleClickEvent;
+import com.smartgwt.client.widgets.grid.events.RecordDoubleClickHandler;
+import com.smartgwt.client.widgets.layout.VLayout;
+import com.smartgwt.client.widgets.tree.Tree;
+import com.smartgwt.client.widgets.tree.TreeGrid;
+import com.smartgwt.client.widgets.tree.TreeNode;
+
 // TODO: refactor, extract ~DataCageGrid
 /**
  * Display tree of, for example, previous calculations and allows
  * selection in order to access/clone these.
  */
-public class DatacageWidget
-extends      VLayout
-{
+public class DatacageWidget extends VLayout {
     public static final int MAX_OPEN = 30;
 
-    protected MetaDataServiceAsync metaDataService =
-        GWT.create(MetaDataService.class);
-
-    protected FLYSConstants messages =
-        GWT.create(FLYSConstants.class);
-
-    protected Artifact artifact;
-    protected User     user;
-    protected String   outs;
-    protected String   parameters;
-
-    protected TreeGrid treeGrid;
-    protected Tree     tree;
-
-    protected ToLoad   toLoad;
-
-    protected List<DatacageHandler>            handlers;
-    protected List<DatacageDoubleClickHandler> doubleHandlers;
-
-    /** Layout to show spinning wheel of joy. */
-    protected VLayout lockScreen;
-
-
-    public DatacageWidget() {
-        handlers       = new ArrayList<DatacageHandler>();
-        doubleHandlers = new ArrayList<DatacageDoubleClickHandler>();
+    public interface DatacageFilter {
+        boolean accept(DataCageNode node);
     }
 
-
-    public DatacageWidget(Artifact artifact, User user) {
-        this(artifact, user, null);
-    }
-
-    public DatacageWidget(Artifact artifact, User user, String outs) {
-        this(artifact, user, outs, true);
-    }
+    public static final DatacageFilter ACCEPT_ALL_FILTER = new DatacageFilter() {
+        @Override
+        public boolean accept(final DataCageNode node) {
+            return true;
+        }
+    };
 
-    public DatacageWidget(
-        Artifact   artifact,
-        User       user,
-        String     outs,
-        boolean    showButton
-    ) {
-        this(artifact, user, outs, null, showButton);
-    }
-
+    private final MetaDataServiceAsync metaDataService = GWT.create(MetaDataService.class);
 
-    public DatacageWidget(
-        Artifact   artifact,
-        User       user,
-        String     outs,
-        String     parameters,
-        boolean    showButton
-    ) {
-        this();
+    private final FLYSConstants messages = GWT.create(FLYSConstants.class);
 
-        this.artifact   = artifact;
-        this.user       = user;
-        this.outs       = outs;
-        this.parameters = parameters;
+    private final List<DatacageHandler> handlers = new ArrayList<DatacageHandler>();
 
-        toLoad = new ToLoad();
+    private final List<DatacageDoubleClickHandler> doubleHandlers = new ArrayList<DatacageDoubleClickHandler>();
+
+    private final TreeGrid treeGrid;
+
+    private Tree tree;
+
+    private ToLoad toLoad;
+
+    /** Layout to show spinning wheel of joy. */
+    private VLayout lockScreen;
+
+    private DataCageTree dcTree;
+
+    private DatacageFilter filter = ACCEPT_ALL_FILTER;
+
+    private DatacageWidgetData data;
+
+    public DatacageWidget(final DatacageWidgetData data) {
+
+        this.data = data;
+
+        this.toLoad = new ToLoad();
 
         setWidth100();
 
-        tree = new Tree();
-        tree.setModelType(TreeModelType.CHILDREN);
-        tree.setNameProperty("name");
-        tree.setIdField("id");
-        tree.setChildrenProperty("children-nodes");
-        tree.setShowRoot(false);
+        this.treeGrid = new TreeGrid();
 
-        treeGrid = new TreeGrid();
-        treeGrid.setLoadDataOnDemand(false);
-        treeGrid.setWidth100();
-        treeGrid.setHeight100();
-        treeGrid.setShowRoot(false);
-        treeGrid.setNodeIcon("[SKIN]/../blank.gif");
-        treeGrid.setShowConnectors(true);
-        treeGrid.setLoadingMessage(messages.databasket_loading());
-        treeGrid.setEmptyMessage(messages.databasket_loading());
-        treeGrid.setLoadingDataMessage(messages.databasket_loading());
+        final String columnLabel = this.data.getColumnLabel();
+        if (columnLabel != null)
+            this.treeGrid.setTreeFieldTitle(columnLabel);
 
-        treeGrid.setHoverMoveWithMouse(true);
-        treeGrid.setCanHover(true);
-        treeGrid.setShowHover(true);
-        treeGrid.setHoverOpacity(75);
-        treeGrid.setHoverWidth(120);
+        this.treeGrid.setLoadDataOnDemand(false);
+        this.treeGrid.setWidth100();
+        this.treeGrid.setHeight100();
+        this.treeGrid.setShowRoot(false);
+        this.treeGrid.setNodeIcon("[SKIN]/../blank.gif");
+        this.treeGrid.setShowConnectors(true);
+        this.treeGrid.setLoadingMessage(this.messages.databasket_loading());
+        this.treeGrid.setLoadingDataMessage(this.messages.databasket_loading());
 
-        treeGrid.setHoverCustomizer(new HoverCustomizer() {
+        // FIXME: other message
+        this.treeGrid.setEmptyMessage(this.messages.databasket_loading());
+
+        this.treeGrid.setHoverMoveWithMouse(true);
+        this.treeGrid.setCanHover(true);
+        this.treeGrid.setShowHover(true);
+        this.treeGrid.setHoverOpacity(75);
+        this.treeGrid.setHoverWidth(120);
+
+        this.treeGrid.setHoverCustomizer(new HoverCustomizer() {
             @Override
-            public String hoverHTML(Object value,
-                ListGridRecord record,
-                int rowNum,
-                int colNum
-                ) {
-                if(record instanceof TreeNode) {
-                    TreeNode hoveredTreeNode = (TreeNode)record;
+            public String hoverHTML(final Object value, final ListGridRecord record, final int rowNum, final int colNum) {
+                if (record instanceof TreeNode) {
+                    final TreeNode hoveredTreeNode = (TreeNode) record;
                     String info = hoveredTreeNode.getAttribute("info");
                     if (info == null) {
                         info = hoveredTreeNode.getName();
                     }
                     return info;
                 }
-                else {
-                    return "";// should not happen
-                }
+
+                return "";// should not happen
             }
         });
 
-        treeGrid.addRecordDoubleClickHandler(new RecordDoubleClickHandler() {
+        this.treeGrid.addRecordDoubleClickHandler(new RecordDoubleClickHandler() {
             @Override
-            public void onRecordDoubleClick(RecordDoubleClickEvent event) {
+            public void onRecordDoubleClick(final RecordDoubleClickEvent event) {
                 doubleClickedOnTree(event);
             }
         });
 
-        addMember(treeGrid);
+        addMember(this.treeGrid);
 
-        if (showButton) {
+        if (data.isShowButton())
             addMember(createPlusButton());
-        }
 
         triggerTreeBuilding();
     }
 
+    public void setFilter(final DatacageFilter filter) {
+        assert (filter != null);
+
+        this.filter = filter;
+
+        if (this.dcTree != null)
+            updateTree(this.dcTree);
+    }
+
     /** Disable input, show spinning wheel of joy. */
-    public void lockUI() {
-        lockScreen = ScreenLock.lockUI(this, lockScreen);
+    private void lockUI() {
+        this.lockScreen = ScreenLock.lockUI(this, this.lockScreen);
     }
 
     /** Enable input, remove grey, remove spinning wheel of joy. */
-    public void unlockUI() {
-        ScreenLock.unlockUI(this, lockScreen);
+    protected final void unlockUI() {
+        ScreenLock.unlockUI(this, this.lockScreen);
     }
 
     /**
-     * @param handler Handler to be added (notified on add-action).
+     * Sets whether more than one item can be selected.
+     *
+     * @param multi
+     *            if true, allow mutliple selections.
      */
-    public DatacageWidget(Artifact artifact, User user, String outs,
-        DatacageHandler handler) {
-        this(artifact, user, outs);
-        this.addDatacageHandler(handler);
-    }
-
-
-    public DatacageWidget(
-        Artifact        artifact,
-        User            user,
-        String          outs,
-        DatacageHandler handler,
-        String          parameters
-    ) {
-        this(artifact, user, outs, handler);
-        this.parameters = parameters;
-    }
-
-
-    /**
-     * Sets whether more than one item can be selected.
-     * @param multi if true, allow mutliple selections.
-     */
-    public void setIsMutliSelectable(boolean multi) {
+    public void setIsMutliSelectable(final boolean multi) {
         if (multi) {
-            treeGrid.setSelectionType(SelectionStyle.MULTIPLE);
-        }
-        else {
-            treeGrid.setSelectionType(SelectionStyle.SINGLE);
+            this.treeGrid.setSelectionType(SelectionStyle.MULTIPLE);
+        } else {
+            this.treeGrid.setSelectionType(SelectionStyle.SINGLE);
         }
     }
 
-
     /**
-     * @param handler Handler to be added (notified on add-action).
+     * @param handler
+     *            Handler to be added (notified on add-action).
      */
-    public void addDatacageHandler(DatacageHandler handler) {
-        if (!handlers.contains(handler)) {
-            handlers.add(handler);
-        }
-    }
-
-
-    /**
-     * @param h Handler to be added (notified on Double click on node).
-     */
-    public void addDatacageDoubleClickHandler(DatacageDoubleClickHandler h) {
-        if (!doubleHandlers.contains(h)) {
-            doubleHandlers.add(h);
+    public void addDatacageHandler(final DatacageHandler handler) {
+        if (!this.handlers.contains(handler)) {
+            this.handlers.add(handler);
         }
     }
 
+    /**
+     * @param h
+     *            Handler to be added (notified on Double click on node).
+     */
+    public void addDatacageDoubleClickHandler(final DatacageDoubleClickHandler h) {
+        if (!this.doubleHandlers.contains(h)) {
+            this.doubleHandlers.add(h);
+        }
+    }
 
     /**
-     * @param handler Handler to remove from list.
+     * @param handler
+     *            Handler to remove from list.
      */
-    public void removeDatacageHandler(DatacageHandler handler) {
-        handlers.remove(handler);
+    public void removeDatacageHandler(final DatacageHandler handler) {
+        this.handlers.remove(handler);
     }
 
-
-    public ToLoad getToLoad() {
-        return toLoad;
-    }
-
-
     public ToLoad getSelection() {
         // Reset content of toLoads.
-        toLoad = new ToLoad();
+        this.toLoad = new ToLoad();
 
-        if (treeGrid == null) {
-            return toLoad;
+        if (this.treeGrid == null) {
+            return this.toLoad;
         }
 
-        ListGridRecord [] selection = treeGrid.getSelectedRecords();
+        final ListGridRecord[] selection = this.treeGrid.getSelectedRecords();
 
         if (selection != null) {
-            for (ListGridRecord record: selection) {
+            for (final ListGridRecord record : selection) {
                 if (record instanceof TreeNode) {
-                    collectToLoads((TreeNode)record);
+                    collectToLoads((TreeNode) record);
                 }
             }
         }
 
-        return toLoad;
+        return this.toLoad;
     }
 
-
     public List<TreeNode> getPlainSelection() {
-        ListGridRecord [] selection = treeGrid.getSelectedRecords();
-        List<TreeNode> nodes = new ArrayList<TreeNode>();
+        final ListGridRecord[] selection = this.treeGrid.getSelectedRecords();
+        final List<TreeNode> nodes = new ArrayList<TreeNode>();
         if (selection != null) {
-            for (ListGridRecord record: selection) {
+            for (final ListGridRecord record : selection) {
                 if (record instanceof TreeNode) {
-                    nodes.add((TreeNode)record);
+                    nodes.add((TreeNode) record);
                 }
             }
         }
         return nodes;
     }
 
-
     /**
      * Returns the titles of selected items (if any).
      */
     public String[] getSelectionTitles() {
-        if (treeGrid == null) {
+        if (this.treeGrid == null) {
             return new String[] {};
         }
 
-        ListGridRecord [] selection = treeGrid.getSelectedRecords();
+        final ListGridRecord[] selection = this.treeGrid.getSelectedRecords();
 
         if (selection == null) {
             return new String[] {};
         }
 
-        List<String> titleList = new ArrayList<String>();
-        for (ListGridRecord record: selection) {
+        final List<String> titleList = new ArrayList<String>();
+        for (final ListGridRecord record : selection) {
             if (record instanceof TreeNode) {
-                titleList.add(((TreeNode)record).getAttribute("name"));
+                titleList.add(((TreeNode) record).getAttribute("name"));
             }
         }
 
         return titleList.toArray(new String[titleList.size()]);
     }
 
-
     /**
      * Callback for add-button.
      * Fires to load for every selected element and handler.
      */
-    public void plusClicked() {
+    protected final void plusClicked() {
         if (!getSelection().isEmpty()) {
             fireToLoad();
         }
     }
 
-
-    protected Button createPlusButton() {
-        Button plusBtn = new Button(messages.datacageAdd());
+    private Button createPlusButton() {
+        final Button plusBtn = new Button(this.messages.datacageAdd());
         plusBtn.addClickHandler(new ClickHandler() {
             @Override
-            public void onClick(ClickEvent event) {
+            public void onClick(final ClickEvent event) {
                 plusClicked();
             }
         });
         return plusBtn;
     }
 
-
-    protected void fireToLoad() {
-        for (DatacageHandler handler: handlers) {
-            handler.toLoad(toLoad);
+    private void fireToLoad() {
+        for (final DatacageHandler handler : this.handlers) {
+            handler.toLoad(this.toLoad);
         }
     }
 
-
     /** Notify DatacageDoubleClickHandlers that a doubleclick happened. */
-    protected void fireOnDoubleClick() {
-        for (DatacageDoubleClickHandler handler: doubleHandlers) {
-            handler.onDoubleClick(toLoad);
+    private void fireOnDoubleClick() {
+        for (final DatacageDoubleClickHandler handler : this.doubleHandlers) {
+            handler.onDoubleClick(this.toLoad);
         }
     }
 
-
-    protected void doubleClickedOnTree(RecordDoubleClickEvent event) {
-        TreeNode node = (TreeNode)event.getRecord();
+    protected final void doubleClickedOnTree(final RecordDoubleClickEvent event) {
+        final TreeNode node = (TreeNode) event.getRecord();
         collectToLoads(node);
         fireOnDoubleClick();
     }
 
-
     /**
      * Adds to toLoad, from info in node.
      * Afterwards, add all children of node to stack to parse (next time
      * collectToLoads is called).
      */
-    protected void collectToLoads(TreeNode node) {
-        Stack<TreeNode> stack = new Stack<TreeNode>();
+    private void collectToLoads(TreeNode node) {
+        final Stack<TreeNode> stack = new Stack<TreeNode>();
 
         stack.push(node);
 
         while (!stack.isEmpty()) {
             node = stack.pop();
-            String factory = node.getAttribute("factory");
+            final String factory = node.getAttribute("factory");
             if (factory != null) { // we need at least a factory
-                String artifact = node.getAttribute("artifact-id");
-                String out      = node.getAttribute("out");
-                String name     = node.getAttribute("facet");
-                String ids      = node.getAttribute("ids");
-                String displayname = node.getAttribute("name");
-                String targetOut = node.getAttribute("target_out");
+                final String artifact = node.getAttribute("artifact-id");
+                final String out = node.getAttribute("out");
+                final String name = node.getAttribute("facet");
+                final String ids = node.getAttribute("ids");
+                final String displayname = node.getAttribute("name");
+                final String targetOut = node.getAttribute("target_out");
                 String debugAttributeValues = "";
-                for (String attr: node.getAttributes()) {
-                    debugAttributeValues += ("[" + attr +": "
-                        + node.getAttributeAsString(attr) + "] ");
+                for (final String attr : node.getAttributes()) {
+                    debugAttributeValues += ("[" + attr + ": " + node.getAttributeAsString(attr) + "] ");
                 }
-                GWT.log("DatacageWidget.collectToLoad, attributes are "
-                    + debugAttributeValues);
+                GWT.log("DatacageWidget.collectToLoad, attributes are " + debugAttributeValues);
 
-                toLoad.add(artifact,
-                     factory,
-                     out,
-                     name,
-                     ids,
-                     displayname,
-                     targetOut);
+                this.toLoad.add(artifact, factory, out, name, ids, displayname, targetOut);
             }
-            TreeNode [] children = tree.getChildren(node);
+            final TreeNode[] children = this.tree.getChildren(node);
             if (children != null) {
-                for (TreeNode child: children) {
+                for (final TreeNode child : children) {
                     stack.push(child);
                 }
             }
         }
     }
 
-
     /** Get meta-data and populate tree with it. */
-    protected void triggerTreeBuilding() {
-        Config config = Config.getInstance();
-        String locale = config.getLocale();
-
-        String artifactId = artifact.getUuid();
-        String userId     = (user != null) ? user.identifier() : null;
-
+    private void triggerTreeBuilding() {
         lockUI();
 
-        metaDataService.getMetaData(
-            locale,
-            artifactId,
-            userId,
-            outs,
-            parameters,
-            new AsyncCallback<DataCageTree>() {
-                @Override
-                public void onFailure(Throwable caught) {
-                    GWT.log("Could not load meta data.");
-                    SC.warn(caught.getMessage());
-                    unlockUI();
-                }
+        final String locale = Config.getInstance().getLocale();
 
-                @Override
-                public void onSuccess(DataCageTree dcTree) {
-                    GWT.log("Successfully loaded meta data.");
-                    IdGenerator idGenerator = new IdGenerator();
-                    DataCageNode dcRoot = dcTree.getRoot();
-                    TreeNode root = buildRecursiveChildren(
-                        dcRoot, idGenerator);
-                    tree.setRoot(root);
+        final String artifactId = this.data.getArtifact().getUuid();
+        final User user = this.data.getUser();
+        final String userId = user != null ? user.identifier() : null;
+        final String outs = this.data.getOuts();
+        final String parameters = this.data.getParameters();
 
-                    TreeNode[] nodes = tree.getChildren(root);
-                    for (TreeNode node: nodes) {
-                        if (node.getAttribute("factory") == null &&
-                                !tree.hasChildren(node)) {
-                            node.setIsFolder(true);
-                        }
-                    }
+        this.metaDataService.getMetaData(locale, artifactId, userId, outs, parameters, new AsyncCallback<DataCageTree>() {
+            @Override
+            public void onFailure(final Throwable caught) {
+                GWT.log("Could not load meta data.");
+                SC.warn(caught.getMessage());
+                unlockUI();
+            }
 
-                    if (idGenerator.current() < MAX_OPEN) {
-                        tree.openAll();
-                    }
-                    treeGrid.setData(tree);
-                    unlockUI();
-                }
-            });
+            @Override
+            public void onSuccess(final DataCageTree dcData) {
+                GWT.log("Successfully loaded meta data.");
+
+                setDatacageData(dcData);
+                unlockUI();
+            }
+        });
+    }
+
+    protected final void setDatacageData(final DataCageTree dcTree) {
+
+        this.dcTree = dcTree;
+
+        if (this.tree != null)
+            this.tree.destroy();
+
+        updateTree(this.dcTree);
+    }
+
+    private void updateTree(final DataCageTree data) {
+
+        this.tree = new Tree();
+        this.tree.setModelType(TreeModelType.CHILDREN);
+        this.tree.setNameProperty("name");
+        this.tree.setIdField("id");
+        this.tree.setChildrenProperty("children-nodes");
+        this.tree.setShowRoot(false);
+
+        final IdGenerator idGenerator = new IdGenerator();
+        final DataCageNode dcRoot = data.getRoot();
+        final TreeNode root = buildRecursiveChildren(dcRoot, idGenerator);
+        if (root != null) {
+            this.tree.setRoot(root);
+
+            // FIXME: why is this necessary? an it only happens for the first level...
+            final TreeNode[] nodes = this.tree.getChildren(root);
+            for (final TreeNode node : nodes) {
+                if (node.getAttribute("factory") == null && !this.tree.hasChildren(node))
+                    node.setIsFolder(true);
+            }
+        }
+
+        if (idGenerator.current() < MAX_OPEN)
+            this.tree.openAll();
+
+        this.treeGrid.setData(this.tree);
     }
 
     private static final class IdGenerator {
@@ -479,11 +420,11 @@
         }
 
         public int next() {
-            return current++;
+            return this.current++;
         }
 
         public int current() {
-            return current;
+            return this.current;
         }
     } // class IdGenerator
 
@@ -492,48 +433,58 @@
             return s;
         }
 
-        s = s.substring(2, s.length()-1);
+        s = s.substring(2, s.length() - 1);
 
         try {
-            return messages.getString(s);
+            return this.messages.getString(s);
         }
-        catch (MissingResourceException mre) {
+        catch (final MissingResourceException mre) {
             GWT.log("cannot find i18n for + '" + s + "'");
             return s;
         }
     }
 
-    protected TreeNode buildRecursiveChildren(
-        DataCageNode   node,
-        IdGenerator    idGenerator
-    ) {
-        TreeNode tn = new TreeNode();
+    private TreeNode buildRecursiveChildren(final DataCageNode node, final IdGenerator idGenerator) {
+
+        if (!this.filter.accept(node))
+            return null;
+
+        final List<DataCageNode> children = node.getChildren();
+
+        final Collection<TreeNode> tns = new ArrayList<TreeNode>();
+
+        if (children != null && !children.isEmpty()) {
+
+            for (final DataCageNode child : children) {
+
+                final TreeNode childNode = buildRecursiveChildren(child, idGenerator);
+                if (childNode != null)
+                    tns.add(childNode);
+            }
+
+            /* if we should have children, but all got filtered, hide this node as well */
+            if (tns.isEmpty())
+                return null;
+        }
+
+        final TreeNode tn = new TreeNode();
         tn.setAttribute("id", idGenerator.next());
 
-        List<DataCageNode> children = node.getChildren();
-
-        if (children != null) {
-            TreeNode [] tns = new TreeNode[children.size()];
-            for (int i = 0; i < tns.length; ++i) {
-                DataCageNode child = children.get(i);
-                tns[i] = buildRecursiveChildren(child, idGenerator);
-            }
-            tn.setAttribute("children-nodes", tns);
-        }
+        if (!tns.isEmpty())
+            tn.setAttribute("children-nodes", tns.toArray(new TreeNode[tns.size()]));
 
         tn.setAttribute("name", i18n(node.getDescription()));
         tn.setAttribute("facet", node.getName());
 
-        AttrList attrs = node.getAttributes();
+        final AttrList attrs = node.getAttributes();
         if (attrs != null) {
             for (int i = 0, N = attrs.size(); i < N; ++i) {
-                String key   = attrs.getKey(i);
-                String value = attrs.getValue(i);
+                final String key = attrs.getKey(i);
+                final String value = attrs.getValue(i);
                 tn.setAttribute(key, value);
             }
         }
 
         return tn;
     }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageWidgetData.java	Wed Jul 04 12:00:51 2018 +0200
@@ -0,0 +1,78 @@
+/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+package org.dive4elements.river.client.client.ui;
+
+import org.dive4elements.river.client.shared.model.Artifact;
+import org.dive4elements.river.client.shared.model.User;
+
+/**
+ * Holds all data that configures the {@link DatacageWidget}
+ *
+ * @author Gernot Belger
+ */
+public class DatacageWidgetData {
+
+    private final Artifact artifact;
+    private final User user;
+    private final String outs;
+    private final String parameters;
+    private final boolean showButton;
+    private final String columnLabel;
+
+    public DatacageWidgetData(final Artifact artifact, final User user) {
+        this(artifact, user, null);
+    }
+
+    public DatacageWidgetData(final Artifact artifact, final User user, final String outs) {
+        this(artifact, user, outs, true);
+    }
+
+    public DatacageWidgetData(final Artifact artifact, final User user, final String outs, final boolean showButton) {
+        this(artifact, user, outs, null, showButton);
+    }
+
+    public DatacageWidgetData(final Artifact artifact, final User user, final String outs, final String parameters, final boolean showButton) {
+        this(artifact, user, outs, parameters, showButton, null);
+    }
+
+    public DatacageWidgetData(final Artifact artifact, final User user, final String outs, final String parameters, final boolean showButton,
+            final String columnLabel) {
+        this.artifact = artifact;
+        this.user = user;
+        this.outs = outs;
+        this.parameters = parameters;
+        this.showButton = showButton;
+        this.columnLabel = columnLabel;
+    }
+
+    public Artifact getArtifact() {
+        return this.artifact;
+    }
+
+    public User getUser() {
+        return this.user;
+    }
+
+    public String getOuts() {
+        return this.outs;
+    }
+
+    public String getParameters() {
+        return this.parameters;
+    }
+
+    public boolean isShowButton() {
+        return this.showButton;
+    }
+
+    public String getColumnLabel() {
+        return this.columnLabel;
+    }
+}
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageWindow.java	Wed Jul 04 10:46:37 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageWindow.java	Wed Jul 04 12:00:51 2018 +0200
@@ -76,12 +76,9 @@
         setWidth(400);
         setHeight(500);
 
-        DatacageWidget dw = new DatacageWidget(
-            artifact,
-            user,
-            outs,
-            "load-system:true",
-            true);
+        final DatacageWidgetData data = new DatacageWidgetData( artifact, user, outs, "load-system:true", true );
+        
+        DatacageWidget dw = new DatacageWidget( data );
         dw.addDatacageHandler(this);
         dw.addDatacageDoubleClickHandler(this);
 
@@ -192,6 +189,7 @@
                 factory,
                 locale,
                 new AsyncCallback<Artifact>() {
+                    @Override
                     public void onFailure(Throwable caught) {
                         decreateInProgress();
                         GWT.log("Create-artifact failed: "
@@ -199,6 +197,7 @@
                         SC.warn(caught.getMessage());
                     }
 
+                    @Override
                     public void onSuccess(Artifact artifact) {
                         decreateInProgress();
                         GWT.log("Created new artifact: " + artifact.getUuid());
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DefaultDatacageTwinPanelInfo.java	Wed Jul 04 10:46:37 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DefaultDatacageTwinPanelInfo.java	Wed Jul 04 12:00:51 2018 +0200
@@ -1,6 +1,6 @@
 /** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
- * Software engineering by 
- *  Björnsen Beratende Ingenieure GmbH 
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
  *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
  *
  * This file is Free Software under the GNU AGPL (>=v3)
@@ -13,38 +13,45 @@
 import org.dive4elements.river.client.shared.model.Recommendation;
 
 /**
- * This info implementation overwrites the real factory of the recommendation with a fixed value. 
+ * This info implementation overwrites the real factory of the recommendation with a fixed value.
  * Evil, but this is how it is done in the current code.
- * 
+ *
  * @author Gernot Belger
  */
 public final class DefaultDatacageTwinPanelInfo implements IDatacageTwinPanelInfo {
 
-	private final String factory;
-	private final String outs;
+    private final String factory;
+    private final String outs;
+    private final String columnLabel;
 
-	public DefaultDatacageTwinPanelInfo(final String factory, final String outs) {
-		this.factory = factory;
-		this.outs = outs;
-	}
-	
-	@Override
-	public String getFactory(final String originalFactory) {
-		return this.factory;
-	}
-	
-	@Override
-	public String getDataStringFactory(final Recommendation recommendation) {
-		return this.factory;
-	}
+    public DefaultDatacageTwinPanelInfo(final String columnLabel, final String factory, final String outs) {
+        this.columnLabel = columnLabel;
+        this.factory = factory;
+        this.outs = outs;
+    }
 
     @Override
-	public void adjustRecommendation(final Recommendation recommendation) {
+    public String getFactory(final String originalFactory) {
+        return this.factory;
+    }
+
+    @Override
+    public String getDataStringFactory(final Recommendation recommendation) {
+        return this.factory;
+    }
+
+    @Override
+    public void adjustRecommendation(final Recommendation recommendation) {
         recommendation.setFactory(this.factory);
     }
 
-	@Override
-	public String getOuts() {
-		return this.outs;
-	}
+    @Override
+    public String getColumnLabel() {
+        return this.columnLabel;
+    }
+
+    @Override
+    public String getOuts() {
+        return this.outs;
+    }
 }
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DemDatacagePanel.java	Wed Jul 04 10:46:37 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DemDatacagePanel.java	Wed Jul 04 12:00:51 2018 +0200
@@ -8,6 +8,9 @@
 
 package org.dive4elements.river.client.client.ui;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.dive4elements.river.client.shared.model.Data;
 import org.dive4elements.river.client.shared.model.DataItem;
 import org.dive4elements.river.client.shared.model.DefaultData;
@@ -16,75 +19,43 @@
 import org.dive4elements.river.client.shared.model.ToLoad;
 import org.dive4elements.river.client.shared.model.User;
 
-import java.util.ArrayList;
-import java.util.List;
-
-
 public class DemDatacagePanel extends DatacagePanel {
 
     private static final long serialVersionUID = -2301633938080411687L;
 
-    public static final String OUT        = "floodmap_dem_panel";
-    public static final String PARAMETERS = "dem:true";
-
-
-    public DemDatacagePanel() {
-        super();
-    }
-
-
-    public DemDatacagePanel(User user) {
-        super(user);
-    }
-
+    private static final String OUT = "floodmap_dem_panel";
 
-    @Override
-    protected void createWidget() {
-        super.createWidget();
-        widget.setIsMutliSelectable(false);
-    }
-
+    private static final String PARAMETERS = "dem:true";
 
-    @Override
-    public String getOuts() {
-        return OUT;
+    public DemDatacagePanel(final User user) {
+        super(user, OUT, PARAMETERS, false);
     }
 
-
-    @Override
-    public String getParameters() {
-        return PARAMETERS;
-    }
-
-
     @Override
     public List<String> validate() {
-        List<String> errors = new ArrayList<String>();
+        final List<String> errors = new ArrayList<String>();
 
-        Recommendation r = getSelectedRecommendation();
-        if (r == null) {
+        final Recommendation r = getSelectedRecommendation();
+        if (r == null)
             errors.add(MSG.requireDGM());
-        }
 
         return errors;
     }
 
-
     @Override
     protected Data[] getData() {
-        Recommendation r = getSelectedRecommendation();
+        final Recommendation r = getSelectedRecommendation();
 
-        DataItem item = new DefaultDataItem(dataName, dataName, r.getIDs());
-        return new Data[] { new DefaultData(
-            dataName, null, null, new DataItem[] { item }) };
+        final String dataName = getMyDataName();
+
+        final DataItem item = new DefaultDataItem(dataName, dataName, r.getIDs());
+        return new Data[] { new DefaultData(dataName, null, null, new DataItem[] { item }) };
     }
 
-
     protected Recommendation getSelectedRecommendation() {
-        ToLoad toLoad = widget.getSelection();
-        List<Recommendation> recoms = toLoad.toRecommendations();
+        final ToLoad toLoad = getSelection();
+        final List<Recommendation> recoms = toLoad.toRecommendations();
 
         return recoms != null && recoms.size() >= 1 ? recoms.get(0) : null;
     }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
+}
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/HWSDatacagePanel.java	Wed Jul 04 10:46:37 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/HWSDatacagePanel.java	Wed Jul 04 12:00:51 2018 +0200
@@ -8,13 +8,8 @@
 
 package org.dive4elements.river.client.client.ui;
 
-import com.google.gwt.core.client.GWT;
-
-import com.smartgwt.client.widgets.Canvas;
-import com.smartgwt.client.widgets.Label;
-
-import com.smartgwt.client.widgets.layout.HLayout;
-import com.smartgwt.client.widgets.layout.VLayout;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.dive4elements.river.client.shared.model.Data;
 import org.dive4elements.river.client.shared.model.DataItem;
@@ -23,70 +18,48 @@
 import org.dive4elements.river.client.shared.model.DefaultDataItem;
 import org.dive4elements.river.client.shared.model.User;
 
-import java.util.ArrayList;
-import java.util.List;
-
+import com.google.gwt.core.client.GWT;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
 
-public class HWSDatacagePanel
-extends DatacagePanel
-{
-    public static final String OUT        = "floodmap_hws_panel";
-    public static final String PARAMETERS = "hws:true;load-system:true";
-
+public class HWSDatacagePanel extends DatacagePanel {
 
-    public HWSDatacagePanel() {
-        super();
-    }
+    private static final long serialVersionUID = 1L;
 
+    private static final String OUT = "floodmap_hws_panel";
 
-    public HWSDatacagePanel(User user) {
-        super(user);
+    private static final String PARAMETERS = "hws:true;load-system:true";
+
+    public HWSDatacagePanel(final User user) {
+        super(user, OUT, PARAMETERS, true);
     }
 
-
-    @Override
-    protected void createWidget() {
-        super.createWidget();
-        widget.setIsMutliSelectable(true);
-    }
-
-
-    @Override
-    public String getOuts() {
-        return OUT;
-    }
-
-
-    @Override
-    public String getParameters() {
-        return PARAMETERS;
-    }
-
-
     @Override
     public List<String> validate() {
-        List<String> errors = new ArrayList<String>();
+        final List<String> errors = new ArrayList<String>();
 
         return errors;
     }
 
     @Override
-    public Canvas createOld(DataList dataList) {
+    public Canvas createOld(final DataList dataList) {
         GWT.log("old datacage##########################################");
-        HLayout layout  = new HLayout();
-        VLayout vLayout = new VLayout();
+        final HLayout layout = new HLayout();
+        final VLayout vLayout = new VLayout();
         layout.setWidth("400px");
 
-        Label label = new Label(dataList.getLabel());
+        final Label label = new Label(dataList.getLabel());
         label.setWidth("200px");
 
-        int size = dataList.size();
+        final int size = dataList.size();
         for (int i = 0; i < size; i++) {
-            Data data        = dataList.get(i);
-            DataItem[] items = data.getItems();
+            final Data data = dataList.get(i);
+            final DataItem[] items = data.getItems();
 
-            for (DataItem item: items) {
-                HLayout hLayout = new HLayout();
+            for (final DataItem item : items) {
+                final HLayout hLayout = new HLayout();
 
                 hLayout.addMember(label);
                 hLayout.addMember(new Label(item.getLabel()));
@@ -96,7 +69,7 @@
             }
         }
 
-        Canvas back = getBackButton(dataList.getState());
+        final Canvas back = getBackButton(dataList.getState());
 
         layout.addMember(label);
         layout.addMember(vLayout);
@@ -105,19 +78,17 @@
         return layout;
     }
 
-
     @Override
     protected Data[] getData() {
-        String[] selection = this.widget.getSelectionTitles();
+        final String[] selection = getSelectionTitles();
         String result = "";
         boolean first = true;
         if (selection != null) {
-            for (String record: selection) {
+            for (final String record : selection) {
                 if (first) {
                     result += record;
                     first = false;
-                }
-                else {
+                } else {
                     result += ";" + record;
                 }
             }
@@ -125,13 +96,10 @@
         if (result.length() == 0) {
             result = MSG.notselected();
         }
-        Data[] data = new Data[1];
-        DataItem item = new DefaultDataItem(
-                "uesk.hws", "uesk.hws", result);
-        data[0] = new DefaultData(
-            "uesk.hws", null, null, new DataItem[] {item});
+        final Data[] data = new Data[1];
+        final DataItem item = new DefaultDataItem("uesk.hws", "uesk.hws", result);
+        data[0] = new DefaultData("uesk.hws", null, null, new DataItem[] { item });
 
         return data;
     }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
+}
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/NilDatacageTwinPanelInfo.java	Wed Jul 04 10:46:37 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/NilDatacageTwinPanelInfo.java	Wed Jul 04 12:00:51 2018 +0200
@@ -1,6 +1,6 @@
 /** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
- * Software engineering by 
- *  Björnsen Beratende Ingenieure GmbH 
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
  *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
  *
  * This file is Free Software under the GNU AGPL (>=v3)
@@ -14,35 +14,42 @@
 
 /**
  * An info implementation that does NOT tweak any factories.
- * 
+ *
  * @author Gernot Belger
  */
 public final class NilDatacageTwinPanelInfo implements IDatacageTwinPanelInfo {
 
-	private final String outs;
+    private final String outs;
+    private final String columnLabel;
 
-	public NilDatacageTwinPanelInfo(final String outs) {
-		this.outs = outs;
-	}
-	
-	@Override
-	public String getFactory(final String originalFactory) {
-	    return originalFactory;
-	}
-
-	
-	@Override
-	public String getDataStringFactory(final Recommendation recommendation) {
-		return recommendation.getFactory();
-	}
+    public NilDatacageTwinPanelInfo(final String columnLabel, final String outs) {
+        this.columnLabel = columnLabel;
+        this.outs = outs;
+    }
 
     @Override
-	public void adjustRecommendation(final Recommendation recommendation) {
+    public String getFactory(final String originalFactory) {
+        return originalFactory;
+    }
+
+
+    @Override
+    public String getDataStringFactory(final Recommendation recommendation) {
+        return recommendation.getFactory();
+    }
+
+    @Override
+    public void adjustRecommendation(final Recommendation recommendation) {
         /* does nothing */
     }
 
-	@Override
-	public String getOuts() {
-		return this.outs;
-	}
+    @Override
+    public String getOuts() {
+        return this.outs;
+    }
+
+    @Override
+    public String getColumnLabel() {
+        return this.columnLabel;
+    }
 }
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WaterlevelRecommendationInfo.java	Wed Jul 04 10:46:37 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WaterlevelRecommendationInfo.java	Wed Jul 04 12:00:51 2018 +0200
@@ -1,6 +1,6 @@
 /** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
- * Software engineering by 
- *  Björnsen Beratende Ingenieure GmbH 
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
  *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
  *
  * This file is Free Software under the GNU AGPL (>=v3)
@@ -16,42 +16,42 @@
 
 /**
  * Factored out code from the old WaterlevelTwinPanel; contains some evil hacks about the involved artifact factories. See original comments below...
- * 
+ *
  * @author Gernot Belger
  */
 public final class WaterlevelRecommendationInfo implements IDatacageTwinPanelInfo {
 
-	private final String outs;
-	
+    private final String outs;
+
     /**
      * @param tweakFactory See evil hack below
      */
-	public WaterlevelRecommendationInfo(final String outs) {
-		this.outs = outs;
-	}
-	
-	@Override
-	public String getFactory(final String originalFactory) {
-		// FIXME: why are the factory here and the one used in createDataString different?
-		// Probably also because of the 'throw all this code away comment'
-		return "waterlevel";
-	}
-	
-	@Override
-	public String getDataStringFactory(final Recommendation recommendation) {
-		return "staticwkms";
-	}
-	
+    public WaterlevelRecommendationInfo(final String outs) {
+        this.outs = outs;
+    }
+
     @Override
-	public void adjustRecommendation(final Recommendation recommendation) {
-        
+    public String getFactory(final String originalFactory) {
+        // FIXME: why are the factory here and the one used in createDataString different?
+        // Probably also because of the 'throw all this code away comment'
+        return "waterlevel";
+    }
+
+    @Override
+    public String getDataStringFactory(final Recommendation recommendation) {
+        return "staticwkms";
+    }
+
+    @Override
+    public void adjustRecommendation(final Recommendation recommendation) {
+
         // XXX: THIS IS AN EVIL HACK TO MAKE W-DIFFERENCES WORK AGAIN!
         // TODO: Throw all this code away and do it with server side recommendations!
         recommendation.setTargetOut("w_differences");
 
         if (recommendation.getIDs() != null) {
             GWT.log("Setting staticwkms factory for rec with ID "
-                + recommendation.getIDs());
+                    + recommendation.getIDs());
             recommendation.setFactory("staticwkms");
         }
         /*
@@ -61,15 +61,20 @@
             GWT.log("Setting waterlevel factory for a winfo rec.");
             recommendation.setFactory("waterlevel");
         }
-        */
+         */
         else {
-           GWT.log("Leave rec. id " + recommendation.getIDs() + ", factory "
-               + recommendation.getFactory() + " untouched.");
+            GWT.log("Leave rec. id " + recommendation.getIDs() + ", factory "
+                    + recommendation.getFactory() + " untouched.");
         }
     }
 
-	@Override
-	public String getOuts() {
-		return this.outs;
-	}
+    @Override
+    public String getOuts() {
+        return this.outs;
+    }
+
+    @Override
+    public String getColumnLabel() {
+        return null;
+    }
 }
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WspDatacagePanel.java	Wed Jul 04 10:46:37 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WspDatacagePanel.java	Wed Jul 04 12:00:51 2018 +0200
@@ -8,15 +8,12 @@
 
 package org.dive4elements.river.client.client.ui;
 
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-
-import com.smartgwt.client.util.SC;
-import com.smartgwt.client.widgets.events.ClickEvent;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import org.dive4elements.river.client.client.Config;
 import org.dive4elements.river.client.client.FLYS;
-import org.dive4elements.river.client.client.FLYSConstants;
 import org.dive4elements.river.client.client.event.StepForwardEvent;
 import org.dive4elements.river.client.client.services.LoadArtifactService;
 import org.dive4elements.river.client.client.services.LoadArtifactServiceAsync;
@@ -32,67 +29,40 @@
 import org.dive4elements.river.client.shared.model.ToLoad;
 import org.dive4elements.river.client.shared.model.User;
 
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.smartgwt.client.util.SC;
+import com.smartgwt.client.widgets.events.ClickEvent;
 
 public class WspDatacagePanel extends DatacagePanel {
 
     private static final long serialVersionUID = 2494432743877141135L;
 
-    public static final String WATERLEVEL_OUTS = "waterlevels_panel";
-
-    public static final FLYSConstants MSG = GWT.create(FLYSConstants.class);
-
-
-    protected LoadArtifactServiceAsync loadService =
-        GWT.create(LoadArtifactService.class);
-
-    protected Recommendation recommendation;
-    protected Artifact       artifact;
-
-
-    public WspDatacagePanel() {
-        super();
-    }
-
+    private static final String WATERLEVEL_OUTS = "waterlevels_panel";
 
-    public WspDatacagePanel(User user) {
-        super(user);
-    }
-
+    private final LoadArtifactServiceAsync loadService = GWT.create(LoadArtifactService.class);
 
-    @Override
-    public String getOuts() {
-        return WATERLEVEL_OUTS;
+    public WspDatacagePanel(final User user) {
+        super(user, WATERLEVEL_OUTS, null, false);
     }
 
-
-    @Override
-    protected void createWidget() {
-        super.createWidget();
-        widget.setIsMutliSelectable(false);
-    }
-
-
     /**
      * We need to override this method (defined in AbstractUIProvider) because
      * we have to create a new Artifact specified by the Datacage selection via
      * Async request.
      *
-     * @param e The ClickEvent.
+     * @param e
+     *            The ClickEvent.
      */
     @Override
-    public void onClick(ClickEvent e) {
-        List<String> errors = validate();
+    public void onClick(final ClickEvent e) {
+        final List<String> errors = validate();
         if (errors == null || errors.isEmpty()) {
             // 1) Fetch selected recommendation.
-            Config config           = Config.getInstance();
-            final  String locale    = config.getLocale();
-            final  Collection c     = this.collection;
-            final  Recommendation r = getSelectedRecommendation();
-
+            final Config config = Config.getInstance();
+            final String locale = config.getLocale();
+            final Collection c = this.collection;
+            final Recommendation r = getSelectedRecommendation();
 
             if (r == null) {
                 SC.warn(MSG.warning_no_wsp_selected());
@@ -101,38 +71,31 @@
 
             // TODO: This could eventually be handled server-side.
             // 2) Create, load Artifact and fire event.
-            loadService.load(
-                c, r, r.getFactory(), locale,
-                new AsyncCallback<Artifact>() {
-                    @Override
-                    public void onFailure(Throwable caught) {
-                        GWT.log("WspDatacagePanel", caught);
-                        SC.warn(FLYS.getExceptionString(MSG, caught));
-                    }
+            this.loadService.load(c, r, r.getFactory(), locale, new AsyncCallback<Artifact>() {
+                @Override
+                public void onFailure(final Throwable caught) {
+                    GWT.log("WspDatacagePanel", caught);
+                    SC.warn(FLYS.getExceptionString(MSG, caught));
+                }
 
-                    @Override
-                    public void onSuccess(Artifact newArtifact) {
-                        GWT.log("Created new artifact.");
-                        fireStepForwardEvent(new StepForwardEvent(
-                            getData(r, newArtifact)));
-                    }
+                @Override
+                public void onSuccess(final Artifact newArtifact) {
+                    GWT.log("Created new artifact.");
+                    fireStepForwardEvent(new StepForwardEvent(getData(r, newArtifact)));
                 }
-            );
-        }
-        else {
+            });
+        } else {
             showErrors(errors);
         }
     }
 
-
     protected Recommendation getSelectedRecommendation() {
-        ToLoad toLoad = widget.getSelection();
-        List<Recommendation> recoms = toLoad.toRecommendations();
+        final ToLoad toLoad = getSelection();
+        final List<Recommendation> recoms = toLoad.toRecommendations();
 
         return recoms.size() > 0 ? recoms.get(0) : null;
     }
 
-
     /**
      * Nothing is done in this method. It returns null, because we serve the
      * Data another way!
@@ -145,35 +108,32 @@
         return null;
     }
 
-
     /** Returns a Data Array with one default item. */
-    protected Data[] getData(Recommendation r, Artifact newArtifact) {
-        String uuid = newArtifact.getUuid();
+    protected final Data[] getData(final Recommendation r, final Artifact newArtifact) {
+        final String uuid = newArtifact.getUuid();
         r.setMasterArtifact(uuid);
 
-        String value = createDataString(uuid, r);
+        final String value = createDataString(uuid, r);
 
-        DataItem item = new DefaultDataItem(dataName, dataName, value);
-        return new Data[] { new DefaultData(
-            dataName, null, null, new DataItem[] { item }) };
+        final String dataName = getMyDataName();
+
+        final DataItem item = new DefaultDataItem(dataName, dataName, value);
+        return new Data[] { new DefaultData(dataName, null, null, new DataItem[] { item }) };
     }
 
-
-    protected String createDataString(
-        String artifact,
-        Recommendation recommendation
-    ) {
-        Facet f = null;
+    private String createDataString(final String artifactId, final Recommendation recommendation) {
 
         // The filter will only be available or previous calculation artifacts.
-        Filter filter = recommendation.getFilter();
+        final Filter filter = recommendation.getFilter();
 
         if (filter != null) {
-            Map<String, List<Facet>>               outs = filter.getOuts();
-            Set<Map.Entry<String, List<Facet>>> entries = outs.entrySet();
+            Facet f = null;
 
-            for (Map.Entry<String, List<Facet>> entry: entries) {
-                List<Facet> fs = entry.getValue();
+            final Map<String, List<Facet>> outs = filter.getOuts();
+            final Set<Map.Entry<String, List<Facet>>> entries = outs.entrySet();
+
+            for (final Map.Entry<String, List<Facet>> entry : entries) {
+                final List<Facet> fs = entry.getValue();
 
                 f = fs.get(0);
                 if (f != null) {
@@ -181,13 +141,9 @@
                 }
             }
 
-            return "[" + artifact + ";" + f.getName() + ";"
-                + f.getIndex() + "]";
+            return "[" + artifactId + ";" + f.getName() + ";" + f.getIndex() + "]";
         }
-        else {
-            return "[" + artifact + ";"
-                + recommendation.getFactory() + ";" + 0 + "]";
-        }
+
+        return "[" + artifactId + ";" + recommendation.getFactory() + ";" + 0 + "]";
     }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
+}
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/minfo/BedHeightsDatacagePanel.java	Wed Jul 04 10:46:37 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/minfo/BedHeightsDatacagePanel.java	Wed Jul 04 12:00:51 2018 +0200
@@ -12,6 +12,7 @@
 
 import org.dive4elements.river.client.client.ui.AbstractPairRecommendationPanel;
 import org.dive4elements.river.client.client.ui.DatacageWidget;
+import org.dive4elements.river.client.client.ui.DatacageWidgetData;
 import org.dive4elements.river.client.client.ui.DefaultDatacageTwinPanelInfo;
 import org.dive4elements.river.client.client.ui.RecommendationPairRecord;
 import org.dive4elements.river.client.client.ui.WaterlevelTwinPanelValidator;
@@ -29,35 +30,40 @@
 import com.smartgwt.client.widgets.layout.VLayout;
 import com.smartgwt.client.widgets.tree.TreeNode;
 
-public class BedHeightsDatacagePanel
-extends      AbstractPairRecommendationPanel {
+public class BedHeightsDatacagePanel extends AbstractPairRecommendationPanel {
 
-    public BedHeightsDatacagePanel(User user) {
-    	// FIXME: This will lead to a bad error message in English (i.e. contains something about waterlevels), for M-Info/Bed-Differences calculation
-    	// BUT: this is the behavior of 3.2.1 (because of sloppy derivation), so we do not change it now
-        super(user, new WaterlevelTwinPanelValidator(), new DefaultDatacageTwinPanelInfo("bedheight", null), new DefaultDatacageTwinPanelInfo("bedheight", null) );
+    private static final DefaultDatacageTwinPanelInfo INFO = new DefaultDatacageTwinPanelInfo(null, "bedheight", null);
+
+    private static final long serialVersionUID = 1L;
+
+    public BedHeightsDatacagePanel(final User user) {
+        // FIXME: This will lead to a bad error message in English (i.e. contains something about waterlevels), for
+        // M-Info/Bed-Differences calculation
+        // BUT: this is the behavior of 3.2.1 (because of sloppy derivation), so we do not change it now
+        super(user, new WaterlevelTwinPanelValidator(), INFO, INFO);
     }
 
     @Override
     protected Canvas createChooserWidgets(final Canvas widget, final DataList dataList, final User user, final ListGrid differencesList) {
         GWT.log("createData()");
 
-        Canvas submit = getNextButton();
+        final Canvas submit = getNextButton();
 
-        final DatacageWidget datacage = new DatacageWidget(
-            this.artifact, user, "minfo_diff_panel", "load-system:true", false);
+        final DatacageWidgetData data = new DatacageWidgetData(this.artifact, user, "minfo_diff_panel", "load-system:true", false);
 
-        Button plusBtn = new Button(msg().datacage_add_pair());
+        final DatacageWidget datacage = new DatacageWidget(data);
+
+        final Button plusBtn = new Button(msg().datacage_add_pair());
         plusBtn.setAutoFit(true);
         plusBtn.addClickHandler(new ClickHandler() {
             @Override
-            public void onClick(ClickEvent event) {
+            public void onClick(final ClickEvent event) {
                 plusClicked(datacage, differencesList);
             }
         });
 
-        VLayout layout       = new VLayout();
-        VLayout helperLayout = new VLayout();
+        final VLayout layout = new VLayout();
+        final VLayout helperLayout = new VLayout();
         helperLayout.addMember(datacage);
         helperLayout.addMember(plusBtn);
 
@@ -72,50 +78,36 @@
     /**
      * Callback for add-button.
      * Fires to load for every selected element and handler.
-     * @param differencesList 
+     *
+     * @param differencesList
      */
-    protected final static void plusClicked( final DatacageWidget datacage, ListGrid differencesList ) {
-        List<TreeNode> selection = datacage.getPlainSelection();
+    protected final static void plusClicked(final DatacageWidget datacage, final ListGrid differencesList) {
+        final List<TreeNode> selection = datacage.getPlainSelection();
 
         if (selection == null || selection.isEmpty()) {
             SC.say(msg().warning());
             return;
         }
 
-        for (TreeNode node : selection) {
-            ToLoad toLoad1 = new ToLoad();
-            ToLoad toLoad2 = new ToLoad();
-
-            String factory = node.getAttribute("factory");
-            if (factory != null) { // we need at least a factory
-                String artifact    = node.getAttribute("artifact-id");
-                String out         = node.getAttribute("out");
-                String name        = node.getAttribute("facet");
-                String ids         = node.getAttribute("ids");
-                String info        = node.getAttribute("info");
-                String targetOut   = node.getAttribute("target_out");
+        for (final TreeNode node : selection) {
+            final ToLoad toLoad1 = new ToLoad();
+            final ToLoad toLoad2 = new ToLoad();
 
-                String[] splitIds = ids.split("#");
-                String[] splitInfo = info.split("#");
-                toLoad1.add(artifact,
-                     factory,
-                     out,
-                     name,
-                     splitIds[0],
-                     splitInfo[0],
-                     targetOut);
-                toLoad2.add(artifact,
-                     factory,
-                     out,
-                     name,
-                     splitIds[1],
-                     splitInfo[1],
-                     targetOut);
+            final String factory = node.getAttribute("factory");
+            if (factory != null) { // we need at least a factory
+                final String artifact = node.getAttribute("artifact-id");
+                final String out = node.getAttribute("out");
+                final String name = node.getAttribute("facet");
+                final String ids = node.getAttribute("ids");
+                final String info = node.getAttribute("info");
+                final String targetOut = node.getAttribute("target_out");
+
+                final String[] splitIds = ids.split("#");
+                final String[] splitInfo = info.split("#");
+                toLoad1.add(artifact, factory, out, name, splitIds[0], splitInfo[0], targetOut);
+                toLoad2.add(artifact, factory, out, name, splitIds[1], splitInfo[1], targetOut);
             }
-            differencesList.addData(new RecommendationPairRecord(
-                toLoad1.toRecommendations().get(0),
-                toLoad2.toRecommendations().get(0)));
+            differencesList.addData(new RecommendationPairRecord(toLoad1.toRecommendations().get(0), toLoad2.toRecommendations().get(0)));
         }
     }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
+}
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthMinMaxTwinPanel.java	Wed Jul 04 10:46:37 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthMinMaxTwinPanel.java	Wed Jul 04 12:00:51 2018 +0200
@@ -18,8 +18,15 @@
  * @author Gernot Belger
  */
 public final class FlowDepthMinMaxTwinPanel extends DatacageTwinPanel {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final DefaultDatacageTwinPanelInfo LEFT_INFO = new DefaultDatacageTwinPanelInfo(MSG.sinfo_columnlabel_soundings(), "bedheight",
+            "sinfo_flowdepthminmax_heights");
+
+    private static final NilDatacageTwinPanelInfo RIGHT_INFO = new NilDatacageTwinPanelInfo(MSG.sinfo_columnlabel_waterlevels(), "sinfo_flowdepth_waterlevels");
+
     public FlowDepthMinMaxTwinPanel(final User user) {
-        super(user, new FlowDepthTwinPanelValidator(), new NilDatacageTwinPanelInfo("sinfo_flowdepth_waterlevels"),
-                new DefaultDatacageTwinPanelInfo("bedheight", "sinfo_flowdepthminmax_heights"), 9999, "");
+        super(user, new FlowDepthTwinPanelValidator(), LEFT_INFO, RIGHT_INFO, 9999, "");
     }
 }
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthTwinPanel.java	Wed Jul 04 10:46:37 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthTwinPanel.java	Wed Jul 04 12:00:51 2018 +0200
@@ -18,8 +18,15 @@
  * @author Gernot Belger
  */
 public final class FlowDepthTwinPanel extends DatacageTwinPanel {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final DefaultDatacageTwinPanelInfo LEFT_INFO = new DefaultDatacageTwinPanelInfo(MSG.sinfo_columnlabel_soundings(), "bedheight",
+            "sinfo_flowdepth_minfo_heights");
+
+    private static final NilDatacageTwinPanelInfo RIGHT_INFO = new NilDatacageTwinPanelInfo(MSG.sinfo_columnlabel_waterlevels(), "sinfo_flowdepth_waterlevels");
+
     public FlowDepthTwinPanel(final User user, final int maxCount, final String msgMaxCount) {
-        super(user, new FlowDepthTwinPanelValidator(), new NilDatacageTwinPanelInfo("sinfo_flowdepth_waterlevels"),
-                new DefaultDatacageTwinPanelInfo("bedheight", "sinfo_flowdepth_minfo_heights"), maxCount, msgMaxCount);
+        super(user, new FlowDepthTwinPanelValidator(), LEFT_INFO, RIGHT_INFO, maxCount, msgMaxCount);
     }
 }
\ No newline at end of file

http://dive4elements.wald.intevation.org