changeset 9580:839b2aa84dd0

minuend/subtrahend-UI-switch
author gernotbelger
date Tue, 08 Jan 2019 17:01:09 +0100 (2019-01-08)
parents 67a42c9c46a7
children b61e2a9fa5d6
files artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/DatacagePairSelectState.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthPairSelectState.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthdev/WaterlevelSoundingCurrentPairSelectState.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthdev/WaterlevelSoundingHistoricalPairSelectState.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxPairSelectState.java artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelPairSelectState.java artifacts/src/main/java/org/dive4elements/river/artifacts/states/minfo/DifferenceSelect.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractPairRecommendationPanel.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/UIProviderFactory.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WaterlevelTwinPanel.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/DiffPairTwinPanel.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthMinMaxTwinPanel.java
diffstat 14 files changed, 184 insertions(+), 235 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/DatacagePairSelectState.java	Tue Dec 11 17:08:36 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/DatacagePairSelectState.java	Tue Jan 08 17:01:09 2019 +0100
@@ -32,6 +32,8 @@
 
     private static final long serialVersionUID = 1L;
 
+    private final boolean minuendSubtrahendUiReversed;
+
     /** The log that is used in this state. */
     private static Logger log = Logger.getLogger(DatacagePairSelectState.class);
 
@@ -42,9 +44,10 @@
     /**
      * Name of the state data this state is responsible for.
      */
-    public DatacagePairSelectState(final String uiProvider, final String dataId) {
+    public DatacagePairSelectState(final String uiProvider, final String dataId, final boolean minuendSubtrahendUiReversed) {
         this.uiProvider = uiProvider;
         this.dataId = dataId;
+        this.minuendSubtrahendUiReversed = minuendSubtrahendUiReversed;
     }
 
     /** Specify to display a datacage_twin_panel. */
@@ -104,7 +107,7 @@
         final Element itemElement = creator.create("item");
         creator.addAttr(itemElement, "value", value, true);
 
-        final String[] labels = WaterlevelPairSelectState.getLabels(cc, value);
+        final String[] labels = WaterlevelPairSelectState.getLabels(cc, value, this.minuendSubtrahendUiReversed);
         final Object[] obj = new Object[] { labels[0] };
 
         final String attrValue = Resources.getMsg(cc.getMeta(), "wsp.selected.string", "wsp.selected.string", obj);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthPairSelectState.java	Tue Dec 11 17:08:36 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthPairSelectState.java	Tue Jan 08 17:01:09 2019 +0100
@@ -22,6 +22,6 @@
     private static final long serialVersionUID = 1L;
 
     public FlowDepthPairSelectState() {
-        super("sinfo_flowdepth_twin_panel", "diffids");
+        super("sinfo_flowdepth_twin_panel", "diffids", true); // also switch on client-side, if switched here
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthdev/WaterlevelSoundingCurrentPairSelectState.java	Tue Dec 11 17:08:36 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthdev/WaterlevelSoundingCurrentPairSelectState.java	Tue Jan 08 17:01:09 2019 +0100
@@ -22,6 +22,6 @@
     private static final long serialVersionUID = 1L;
 
     public WaterlevelSoundingCurrentPairSelectState() {
-        super("sinfo_flowdepth_development_twin_panel", FlowDepthDevelopmentAccess.FIELD_DIFFID_CURRENT);
+        super("sinfo_flowdepth_development_twin_panel", FlowDepthDevelopmentAccess.FIELD_DIFFID_CURRENT, true); // also switch on client-side, if switched here
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthdev/WaterlevelSoundingHistoricalPairSelectState.java	Tue Dec 11 17:08:36 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthdev/WaterlevelSoundingHistoricalPairSelectState.java	Tue Jan 08 17:01:09 2019 +0100
@@ -21,6 +21,6 @@
     private static final long serialVersionUID = 1L;
 
     public WaterlevelSoundingHistoricalPairSelectState() {
-        super("sinfo_flowdepth_development_twin_panel", FlowDepthDevelopmentAccess.FIELD_DIFFID_HIST);
+        super("sinfo_flowdepth_development_twin_panel", FlowDepthDevelopmentAccess.FIELD_DIFFID_HIST, true); // also switch on client-side, if switched here
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxPairSelectState.java	Tue Dec 11 17:08:36 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepthminmax/FlowDepthMinMaxPairSelectState.java	Tue Jan 08 17:01:09 2019 +0100
@@ -22,6 +22,6 @@
     private static final long serialVersionUID = 1L;
 
     public FlowDepthMinMaxPairSelectState() {
-        super("sinfo_flowdepthminmax_twin_panel", "diffids");
+        super("sinfo_flowdepthminmax_twin_panel", "diffids", true); // also switch on client-side, if switched here
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelPairSelectState.java	Tue Dec 11 17:08:36 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelPairSelectState.java	Tue Jan 08 17:01:09 2019 +0100
@@ -11,85 +11,60 @@
 import java.util.List;
 
 import org.apache.log4j.Logger;
-
-import org.w3c.dom.Element;
-
+import org.dive4elements.artifactdatabase.ProtocolUtils;
+import org.dive4elements.artifactdatabase.state.Facet;
 import org.dive4elements.artifacts.Artifact;
 import org.dive4elements.artifacts.CallContext;
-
-import org.dive4elements.artifactdatabase.ProtocolUtils;
-import org.dive4elements.artifactdatabase.state.Facet;
-
 import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator;
-
 import org.dive4elements.river.artifacts.D4EArtifact;
 import org.dive4elements.river.artifacts.model.FacetTypes;
 import org.dive4elements.river.artifacts.resources.Resources;
-
 import org.dive4elements.river.backend.utils.StringUtil;
+import org.w3c.dom.Element;
 
 /**
  * State in which the user selects 1 to n pairs of Waterlevels and alikes.
  */
-public class WaterlevelPairSelectState
-extends      DefaultState
-implements   FacetTypes
-{
+public class WaterlevelPairSelectState extends DefaultState implements FacetTypes {
     /** The log that is used in this state. */
-    private static Logger log = Logger.getLogger(
-         WaterlevelPairSelectState.class);
-
+    private static Logger log = Logger.getLogger(WaterlevelPairSelectState.class);
 
     /** Trivial constructor. */
     public WaterlevelPairSelectState() {
     }
 
-
     /** Specify to display a datacage_twin_panel. */
     @Override
     protected String getUIProvider() {
         return "waterlevel_twin_panel";
     }
 
-
     /**
      * Overridden to do nothing.
      */
     @Override
-    public Object computeAdvance(
-        D4EArtifact artifact,
-        String       hash,
-        CallContext  context,
-        List<Facet>  facets,
-        Object       old
-    ) {
-        //Get data and do stuff, do not calculate
+    public Object computeAdvance(final D4EArtifact artifact, final String hash, final CallContext context, final List<Facet> facets, final Object old) {
+        // Get data and do stuff, do not calculate
         return "";
     }
 
-
     /**
      * Create elements for document (prepopulated with data, if any).
-     * @param artifact D4EArtifact to get data from.
-     * @param name DataName, expceted to be "diffids".
+     *
+     * @param artifact
+     *            D4EArtifact to get data from.
+     * @param name
+     *            DataName, expceted to be "diffids".
      */
     @Override
-    protected Element[] createItems(
-        ElementCreator cr,
-        Artifact    artifact,
-        String      name,
-        CallContext context)
-    {
+    protected Element[] createItems(final ElementCreator cr, final Artifact artifact, final String name, final CallContext context) {
         log.debug("createItems: " + name);
         if (name.equals("diffids")) {
-            Element item  = ProtocolUtils.createArtNode(
-                cr, "item", null, null);
-            Element label = ProtocolUtils.createArtNode(
-                cr, "label", null, null);
-            Element value = ProtocolUtils.createArtNode(
-                cr, "value", null, null);
-            D4EArtifact flys = (D4EArtifact) artifact;
-            String s = flys.getDataAsString("diffids");
+            final Element item = ProtocolUtils.createArtNode(cr, "item", null, null);
+            final Element label = ProtocolUtils.createArtNode(cr, "label", null, null);
+            final Element value = ProtocolUtils.createArtNode(cr, "value", null, null);
+            final D4EArtifact flys = (D4EArtifact) artifact;
+            final String s = flys.getDataAsString("diffids");
             value.setTextContent(s);
             item.appendChild(label);
             item.appendChild(value);
@@ -98,33 +73,25 @@
         return new Element[] {};
     }
 
-
     /**
      * Creats the data element used for the static part of DESCRIBE document.
      */
     @Override
-    protected Element createStaticData(
-        D4EArtifact   flys,
-        ElementCreator creator,
-        CallContext    cc,
-        String         name,
-        String         value,
-        String         type
-    ) {
-        Element dataElement = creator.create("data");
+    protected Element createStaticData(final D4EArtifact flys, final ElementCreator creator, final CallContext cc, final String name, final String value,
+            final String type) {
+        final Element dataElement = creator.create("data");
         creator.addAttr(dataElement, "name", name, true);
         creator.addAttr(dataElement, "type", type, true);
 
-        Element itemElement = creator.create("item");
+        final Element itemElement = creator.create("item");
         creator.addAttr(itemElement, "value", value, true);
 
-        String[] labels = getLabels(cc, value);
-        Object[] obj    = new Object[] { labels[0] };
+        final String[] labels = getLabels(cc, value, false);
+        final Object[] obj = new Object[] { labels[0] };
 
         // TODO own i18n
-        String attrValue = Resources.getMsg(
-            cc.getMeta(), "wsp.selected.string", "wsp.selected.string", obj);
-        //I18N_STATIC_KEY, I18N_STATIC_KEY, obj);
+        final String attrValue = Resources.getMsg(cc.getMeta(), "wsp.selected.string", "wsp.selected.string", obj);
+        // I18N_STATIC_KEY, I18N_STATIC_KEY, obj);
 
         creator.addAttr(itemElement, "label", attrValue, true);
         dataElement.appendChild(itemElement);
@@ -132,42 +99,39 @@
         return dataElement;
     }
 
-
     /**
      * Get name to display for selected watelerlevels (for example "Q=123")
      * from the CalculationResult.
      */
-    public static String[] getLabels(CallContext cc, String value) {
-        String[] recommendations = value.split("#");
+    public static String[] getLabels(final CallContext cc, final String value, final boolean minuendSubtrahendUiReversed) {
+        final String[] recommendations = value.split("#");
         String displayString = "";
 
         // Walk over all selected recommendations and create label
         // like "W (Q=1) - W (Q=2)".
-        for (int i = 0; i < recommendations.length; i+=2) {
-            String[] minuendParts = StringUtil
-                .unbracket(recommendations[i+0])
-                .split(";");
-            if(minuendParts.length >= 4) {
+        final int minuendIndex = minuendSubtrahendUiReversed ? 1 : 0;
+        final int subtrahendIndex = minuendSubtrahendUiReversed ? 0 : 1;
+
+        for (int i = 0; i < recommendations.length; i += 2) {
+            final String[] minuendParts = StringUtil.unbracket(recommendations[i + minuendIndex]).split(";");
+            if (minuendParts.length >= 4) {
                 displayString += "(" + minuendParts[3];
-            }
-            else {
+            } else {
                 displayString += "([error]";
             }
 
             displayString += " - ";
 
-            String[] subtrahendParts = StringUtil
-                .unbracket(recommendations[i+1])
-                .split(";");
-            if(subtrahendParts.length >= 4) {
+            final String[] subtrahendParts = StringUtil.unbracket(recommendations[i + subtrahendIndex]).split(";");
+            if (subtrahendParts.length >= 4) {
                 displayString += subtrahendParts[3] + ") ";
-            }
-            else {
+            } else {
                 displayString += "[error])";
             }
         }
 
         return new String[] { displayString };
     }
+
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/minfo/DifferenceSelect.java	Tue Dec 11 17:08:36 2018 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/minfo/DifferenceSelect.java	Tue Jan 08 17:01:09 2019 +0100
@@ -8,12 +8,11 @@
 
 package org.dive4elements.river.artifacts.states.minfo;
 
-import org.w3c.dom.Element;
-
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator;
 import org.dive4elements.river.artifacts.D4EArtifact;
 import org.dive4elements.river.artifacts.states.WaterlevelPairSelectState;
+import org.w3c.dom.Element;
 
 /**
  * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
@@ -35,28 +34,18 @@
      * Creates the data element used for the static part of DESCRIBE document.
      */
     @Override
-    protected Element createStaticData(
-        D4EArtifact   flys,
-        ElementCreator creator,
-        CallContext    cc,
-        String         name,
-        String         value,
-        String         type
-    ) {
-        Element dataElement = creator.create("data");
+    protected Element createStaticData(final D4EArtifact flys, final ElementCreator creator, final CallContext cc, final String name, final String value,
+            final String type) {
+        final Element dataElement = creator.create("data");
         creator.addAttr(dataElement, "name", name, true);
         creator.addAttr(dataElement, "type", type, true);
 
-        Element itemElement = creator.create("item");
+        final Element itemElement = creator.create("item");
         creator.addAttr(itemElement, "value", value, true);
 
-        String[] labels = getLabels(cc, value);
+        final String[] labels = getLabels(cc, value, false);
 
-        creator.addAttr(
-            itemElement,
-            "label",
-            labels[0],
-            true);
+        creator.addAttr(itemElement, "label", labels[0], true);
         dataElement.appendChild(itemElement);
 
         return dataElement;
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractPairRecommendationPanel.java	Tue Dec 11 17:08:36 2018 +0100
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractPairRecommendationPanel.java	Tue Jan 08 17:01:09 2019 +0100
@@ -49,8 +49,7 @@
  * Panel containing a Grid and a "next" button. The Grid is fed by a
  * DatacagePairWidget which is put in the input-helper area.
  */
-public abstract class AbstractPairRecommendationPanel
-extends      TextProvider {
+public abstract class AbstractPairRecommendationPanel extends TextProvider {
 
     /**
      * Allows for abstraction on how to handle/serialize the recommendation and the used factories.
@@ -58,12 +57,13 @@
      *
      * @author Gernot Belger
      */
-    public static interface IRecommendationInfo	{
+    public static interface IRecommendationInfo {
 
         String getFactory(String originalFactory);
 
         /**
          * Separate factory for the 'createDataString' method, because in the case of waterlevels. See HOTFIX/FIXME there.
+         *
          * @param recommendation
          */
         String getDataStringFactory(Recommendation recommendation);
@@ -75,8 +75,7 @@
         void adjustRecommendation(Recommendation recommendation);
     }
 
-    public static interface IValidator
-    {
+    public static interface IValidator {
         List<String> validate(ListGrid differencesList, FLYSConstants msgProvider);
     }
 
@@ -93,16 +92,13 @@
      * List to track previously selected but now removed pairs. (Needed to
      * be able to identify artifacts that can be removed from the collection.
      */
-    private final List<RecommendationPairRecord> removedPairs =
-            new ArrayList<RecommendationPairRecord>();
+    private final List<RecommendationPairRecord> removedPairs = new ArrayList<RecommendationPairRecord>();
 
     /** Service handle to clone and add artifacts to collection. */
-    private final LoadArtifactServiceAsync loadArtifactService = GWT.create(
-            org.dive4elements.river.client.client.services.LoadArtifactService.class);
+    private final LoadArtifactServiceAsync loadArtifactService = GWT.create(org.dive4elements.river.client.client.services.LoadArtifactService.class);
 
     /** Service to remove artifacts from collection. */
-    private final RemoveArtifactServiceAsync removeArtifactService = GWT.create(
-            org.dive4elements.river.client.client.services.RemoveArtifactService.class);
+    private final RemoveArtifactServiceAsync removeArtifactService = GWT.create(org.dive4elements.river.client.client.services.RemoveArtifactService.class);
 
     private final IRecommendationInfo leftInfo;
 
@@ -110,12 +106,19 @@
 
     private final IValidator validator;
 
+    protected final boolean minuendSubtrahendUiReversed;
+
     /**
-     * @param Validates the content of this form when the user clicks 'apply'
-     * @param leftInfo Delegate for handling the left part of the recommendation-pair
-     * @param rightInfo Delegate for handling the right part of the recommendation-pair
+     * @param Validates
+     *            the content of this form when the user clicks 'apply'
+     * @param leftInfo
+     *            Delegate for handling the left part of the recommendation-pair
+     * @param rightInfo
+     *            Delegate for handling the right part of the recommendation-pair
      */
-    public AbstractPairRecommendationPanel(final User user, final IValidator validator, final IRecommendationInfo leftInfo, final IRecommendationInfo rightInfo ) {
+    public AbstractPairRecommendationPanel(final User user, final IValidator validator, final IRecommendationInfo leftInfo, final IRecommendationInfo rightInfo,
+            final boolean minuendSubtrahendUiReversed) {
+        this.minuendSubtrahendUiReversed = minuendSubtrahendUiReversed;
         this.user = user;
         this.validator = validator;
         this.leftInfo = leftInfo;
@@ -129,7 +132,9 @@
 
     /**
      * Remove first occurrence of "[" and "]" (if both do occur).
-     * @param value String to be stripped of [] (might be null).
+     *
+     * @param value
+     *            String to be stripped of [] (might be null).
      * @return input string but with [ and ] removed, or input string if no
      *         brackets were found.
      * @see StringUtil.unbracket
@@ -137,10 +142,11 @@
     // FIXME: check if this is the same as STringUItils#unbracket
     private static final String unbracket(final String value) {
         // null- guard.
-        if (value == null) return value;
+        if (value == null)
+            return value;
 
         final int start = value.indexOf("[");
-        final int end   = value.indexOf("]");
+        final int end = value.indexOf("]");
 
         if (start < 0 || end < 0) {
             return value;
@@ -151,7 +157,9 @@
 
     /**
      * Create a recommendation from a string representation of it.
-     * @param from string in format as shown above.
+     *
+     * @param from
+     *            string in format as shown above.
      * @param leftInfo2
      * @return recommendation from input string.
      */
@@ -159,38 +167,33 @@
         // TODO Construct "real" filter.
         final String[] parts = unbracket(from).split(";");
         final Recommendation.Filter filter = new Recommendation.Filter();
-        final Recommendation.Facet  facet  = new Recommendation.Facet(
-                parts[1],
-                parts[2]);
+        final Recommendation.Facet facet = new Recommendation.Facet(parts[1], parts[2]);
 
         final List<Recommendation.Facet> facets = new ArrayList<Recommendation.Facet>();
         facets.add(facet);
         filter.add("longitudinal_section", facets);
 
-        final String factory = info.getFactory( parts[1] );
+        final String factory = info.getFactory(parts[1]);
 
-        final  Recommendation r = new Recommendation(factory, parts[0], this.artifact.getUuid(), filter);
+        final Recommendation r = new Recommendation(factory, parts[0], this.artifact.getUuid(), filter);
         r.setDisplayName(parts[3]);
         return r;
     }
 
-
     /**
      * Add RecomendationPairRecords from input String to the ListGrid.
      */
-    private void populateGridFromString(final String from){
+    private void populateGridFromString(final String from) {
         // Split this string.
         // Create according recommendations and display strings.
         final String[] recs = from.split("#");
-        if (recs.length % 2 != 0) return;
-        for (int i = 0; i < recs.length; i+=2) {
-            final Recommendation minuend =
-                    createRecommendationFromString(recs[i+0], this.leftInfo);
-            final Recommendation subtrahend =
-                    createRecommendationFromString(recs[i+1], this.rightInfo);
+        if (recs.length % 2 != 0)
+            return;
+        for (int i = 0; i < recs.length; i += 2) {
+            final Recommendation minuend = createRecommendationFromString(recs[i + 0], this.leftInfo);
+            final Recommendation subtrahend = createRecommendationFromString(recs[i + 1], this.rightInfo);
 
-            final RecommendationPairRecord pr = new RecommendationPairRecord(
-                    minuend, subtrahend);
+            final RecommendationPairRecord pr = new RecommendationPairRecord(minuend, subtrahend);
             // This Recommendation Pair comes from the data string and was thus
             // already cloned.
             pr.setIsAlreadyLoaded(true);
@@ -200,7 +203,9 @@
 
     /**
      * Creates the graphical representation and interaction widgets for the data.
-     * @param dataList the data.
+     *
+     * @param dataList
+     *            the data.
      * @return graphical representation and interaction widgets for data.
      */
     @Override
@@ -216,18 +221,18 @@
     }
 
     /**
-     * Creates the individual parts of the input-helper area ('Eingabeunterstützung') for choosing the content of this widget.
+     * Creates the individual parts of the input-helper area ('Eingabeunterstützung') for choosing the content of this
+     * widget.
      */
     protected abstract Canvas createChooserWidgets(final Canvas widget, final DataList dataList, final User auser, final ListGrid diffList);
 
     private void populateGrid(final DataList dataList) {
-        final Data data     = dataList.get(0);
+        final Data data = dataList.get(0);
         this.dataName = data.getLabel();
         for (int i = 0; i < dataList.size(); i++) {
             if (dataList.get(i) != null && dataList.get(i).getItems() != null) {
                 if (dataList.get(i).getItems() != null) {
-                    populateGridFromString(
-                            dataList.get(i).getItems()[0].getStringValue());
+                    populateGridFromString(dataList.get(i).getItems()[0].getStringValue());
                 }
             }
         }
@@ -242,7 +247,7 @@
      * Creates layout with grid that displays selection inside.
      */
     protected final Canvas createWidget() {
-        final VLayout layout  = new VLayout();
+        final VLayout layout = new VLayout();
         this.differencesList = new ListGrid();
 
         this.differencesList.setCanEdit(false);
@@ -251,42 +256,40 @@
         this.differencesList.setHeight(150);
         this.differencesList.setShowAllRecords(true);
 
-        final ListGridField nameField    = new ListGridField("first",  "Minuend");
-        final ListGridField capitalField = new ListGridField("second", "Subtrahend");
+        final ListGridField nameField = new ListGridField(this.minuendSubtrahendUiReversed ? "second" : "first", "Minuend");
+        final ListGridField capitalField = new ListGridField(this.minuendSubtrahendUiReversed ? "first" : "second", "Subtrahend");
         // Track removed rows, therefore more or less reimplement
         // setCanRecomeRecords.
-        final ListGridField removeField  =
-                new ListGridField("_removeRecord", "Remove Record"){{
-                    setType(ListGridFieldType.ICON);
-                    setIcon(GWT.getHostPageBaseURL() + msg().removeFeature());
-                    setCanEdit(false);
-                    setCanFilter(false);
-                    setCanSort(false);
-                    setCanGroupBy(false);
-                    setCanFreeze(false);
-                    setWidth(25);
-                }};
-
-                this.differencesList.setFields(new ListGridField[] {nameField,
-                        capitalField, removeField});
+        final ListGridField removeField = new ListGridField("_removeRecord", "Remove Record") {
+            {
+                setType(ListGridFieldType.ICON);
+                setIcon(GWT.getHostPageBaseURL() + msg().removeFeature());
+                setCanEdit(false);
+                setCanFilter(false);
+                setCanSort(false);
+                setCanGroupBy(false);
+                setCanFreeze(false);
+                setWidth(25);
+            }
+        };
+        this.differencesList.setFields(new ListGridField[] { nameField, capitalField, removeField });
 
-                this.differencesList.addRecordClickHandler(new RecordClickHandler() {
-                    @Override
-                    public void onRecordClick(final RecordClickEvent event) {
-                        // Just handle remove-clicks
-                        if(!event.getField().getName().equals(removeField.getName())) {
-                            return;
-                        }
-                        trackRemoved(event.getRecord());
-                        event.getViewer().removeData(event.getRecord());
-                    }
-                });
-                layout.addMember(this.differencesList);
+        this.differencesList.addRecordClickHandler(new RecordClickHandler() {
+            @Override
+            public void onRecordClick(final RecordClickEvent event) {
+                // Just handle remove-clicks
+                if (!event.getField().getName().equals(removeField.getName())) {
+                    return;
+                }
+                trackRemoved(event.getRecord());
+                event.getViewer().removeData(event.getRecord());
+            }
+        });
+        layout.addMember(this.differencesList);
 
-                return layout;
+        return layout;
     }
 
-
     /**
      * Add record to list of removed records.
      */
@@ -314,40 +317,38 @@
 
         final ListGridRecord[] records = this.differencesList.getRecords();
 
-        final List<Recommendation> ar  = new ArrayList<Recommendation>();
+        final List<Recommendation> ar = new ArrayList<Recommendation>();
         final List<Recommendation> all = new ArrayList<Recommendation>();
 
         for (final ListGridRecord record : records) {
-            final RecommendationPairRecord r =
-                    (RecommendationPairRecord) record;
+            final RecommendationPairRecord r = (RecommendationPairRecord) record;
             // Do not add "old" recommendations.
             if (!r.isAlreadyLoaded()) {
                 // Check whether one of those is a dike or similar.
                 // TODO differentiate and merge: new clones, new, old.
                 final Recommendation firstR = r.getFirst();
                 this.leftInfo.adjustRecommendation(firstR);
-
                 final Recommendation secondR = r.getSecond();
                 this.rightInfo.adjustRecommendation(secondR);
+
                 ar.add(firstR);
                 ar.add(secondR);
-            }
-            else {
+            } else {
                 all.add(r.getFirst());
                 all.add(r.getSecond());
             }
         }
 
         final Recommendation[] toClone = ar.toArray(new Recommendation[ar.size()]);
-        final Recommendation[] toUse   = all.toArray(new Recommendation[all.size()]);
+        final Recommendation[] toUse = all.toArray(new Recommendation[all.size()]);
 
         // Find out whether "old" artifacts have to be removed.
         final List<String> artifactIdsToRemove = new ArrayList<String>();
-        for (final RecommendationPairRecord rp: this.removedPairs) {
-            Recommendation first  = rp.getFirst();
+        for (final RecommendationPairRecord rp : this.removedPairs) {
+            Recommendation first = rp.getFirst();
             Recommendation second = rp.getSecond();
 
-            for (final Recommendation recommendation: toUse) {
+            for (final Recommendation recommendation : toUse) {
                 if (first != null && first.getIDs().equals(recommendation.getIDs())) {
                     first = null;
                 }
@@ -369,15 +370,13 @@
 
         // Remove old artifacts, if any. Do this asychronously without much
         // feedback.
-        for(final String uuid: artifactIdsToRemove) {
-            this.removeArtifactService.remove(this.collection,
-                    uuid,
-                    locale,
-                    new AsyncCallback<Collection>() {
+        for (final String uuid : artifactIdsToRemove) {
+            this.removeArtifactService.remove(this.collection, uuid, locale, new AsyncCallback<Collection>() {
                 @Override
                 public void onFailure(final Throwable caught) {
                     GWT.log("RemoveArtifact (" + uuid + ") failed.");
                 }
+
                 @Override
                 public void onSuccess(final Collection coll) {
                     GWT.log("RemoveArtifact succeeded");
@@ -387,28 +386,25 @@
 
         // Clone new ones (and spawn statics), go forward.
         this.parameterList.lockUI();
-        this.loadArtifactService.loadMany(
-                this.collection,
-                toClone,
-                //"staticwkms" and "waterlevel"
-                null,
-                locale,
-                new AsyncCallback<Artifact[]>() {
+        this.loadArtifactService.loadMany(this.collection, toClone,
+                // "staticwkms" and "waterlevel"
+                null, locale, new AsyncCallback<Artifact[]>() {
+
                     @Override
                     public void onFailure(final Throwable caught) {
                         caught.printStackTrace();
                         GWT.log("Failure of cloning with factories!");
                         AbstractPairRecommendationPanel.this.parameterList.unlockUI();
                     }
+
                     @Override
                     public void onSuccess(final Artifact[] artifacts) {
-                        GWT.log("Successfully cloned " + toClone.length +
-                                " with factories.");
+                        GWT.log("Successfully cloned " + toClone.length + " with factories.");
 
-                        fireStepForwardEvent(new StepForwardEvent(
-                                getData(toClone, artifacts, toUse)));
+                        fireStepForwardEvent(new StepForwardEvent(getData(toClone, artifacts, toUse)));
                         AbstractPairRecommendationPanel.this.parameterList.unlockUI();
                     }
+
                 });
     }
 
@@ -416,19 +412,18 @@
      * Create Data and DataItem from selection (a long string with identifiers
      * to construct diff-pairs).
      *
-     * @param newRecommendations "new" recommendations (did not survive a
-     *        backjump).
-     * @param newArtifacts artifacts cloned from newRecommendations.
-     * @param oldRecommendations old recommendations that survived a backjump.
+     * @param newRecommendations
+     *            "new" recommendations (did not survive a
+     *            backjump).
+     * @param newArtifacts
+     *            artifacts cloned from newRecommendations.
+     * @param oldRecommendations
+     *            old recommendations that survived a backjump.
      *
      * @return dataitem with a long string with identifiers to construct
      *         diff-pairs.
      */
-    protected final Data[] getData(
-            final Recommendation[] newRecommendations,
-            final Artifact[] newArtifacts,
-            final Recommendation[] oldRecommendations)
-    {
+    protected final Data[] getData(final Recommendation[] newRecommendations, final Artifact[] newArtifacts, final Recommendation[] oldRecommendations) {
         // Construct string with info about selections.
         String dataItemString = "";
         for (int i = 0; i < newRecommendations.length; i++) {
@@ -437,7 +432,7 @@
             final String uuid = newArtifact.getUuid();
             r.setMasterArtifact(uuid);
 
-            if (i>0)
+            if (i > 0)
                 dataItemString += "#";
 
             // REMARK: ugly, but we know that the recommandations comes in left/right pairs.
@@ -462,26 +457,28 @@
         // TODO some hassle could be resolved by using multiple DataItems
         // (e.g. one per pair).
         final DataItem item = new DefaultDataItem(this.dataName, this.dataName, dataItemString);
-        return new Data[] { new DefaultData(
-                this.dataName, null, null, new DataItem[] {item}) };
+        return new Data[] { new DefaultData(this.dataName, null, null, new DataItem[] { item }) };
     }
 
     /**
      * Creates part of the String that encodes minuend or subtrahend.
-     * @param recommendation Recommendation to wrap in string.
-     * @param info Provides the factory to encode.
+     *
+     * @param recommendation
+     *            Recommendation to wrap in string.
+     * @param info
+     *            Provides the factory to encode.
      */
     protected static final String createDataString(final String artifactUuid, final Recommendation recommendation, final IRecommendationInfo info) {
-        final String factory = info.getDataStringFactory( recommendation );
+        final String factory = info.getDataStringFactory(recommendation);
 
         final Filter filter = recommendation.getFilter();
-        Facet  f      = null;
+        Facet f = null;
 
-        if(filter != null) {
-            final Map<String, List<Facet>>               outs = filter.getOuts();
+        if (filter != null) {
+            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) {
+            for (final Map.Entry<String, List<Facet>> entry : entries) {
                 final List<Facet> fs = entry.getValue();
 
                 f = fs.get(0);
@@ -490,17 +487,9 @@
                 }
             }
 
-            return "[" + artifactUuid + ";"
-            + f.getName()
-            + ";"
-            + f.getIndex()
-            + ";"
-            + recommendation.getDisplayName() + "]";
+            return "[" + artifactUuid + ";" + f.getName() + ";" + f.getIndex() + ";" + recommendation.getDisplayName() + "]";
         }
 
-        return "["
-        + artifactUuid
-        + ";" + factory + ";0;"
-        + recommendation.getDisplayName() + "]";
+        return "[" + artifactUuid + ";" + factory + ";0;" + recommendation.getDisplayName() + "]";
     }
 }
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageTwinPanel.java	Tue Dec 11 17:08:36 2018 +0100
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageTwinPanel.java	Tue Jan 08 17:01:09 2019 +0100
@@ -42,9 +42,8 @@
     }
 
     public DatacageTwinPanel(final User user, final IValidator validator, final IDatacagePairControler controler, final IDatacageTwinPanelInfo leftInfo,
-            final IDatacageTwinPanelInfo rightInfo,
-            final int maxCount, final String msgMaxCount) {
-        super(user, validator, leftInfo, rightInfo);
+            final IDatacageTwinPanelInfo rightInfo, final int maxCount, final String msgMaxCount, final boolean minuendSubtrahendUiReversed) {
+        super(user, validator, leftInfo, rightInfo, minuendSubtrahendUiReversed);
 
         this.controler = controler;
         this.maxCount = maxCount;
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/UIProviderFactory.java	Tue Dec 11 17:08:36 2018 +0100
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/UIProviderFactory.java	Tue Jan 08 17:01:09 2019 +0100
@@ -242,13 +242,14 @@
         } else if (uiProvider.equals("uinfo.salix.supraregional.table")) {
             return new SupraRegionalTablePanel();
         } else if ("sinfo_flowdepth_development_twin_panel".equals(uiProvider))
-            return new DiffPairTwinPanel(user, 1, getMSG().sinfo_flow_depth_development_twin_panel_max_count_msg());
+            return new DiffPairTwinPanel(user, 1, getMSG().sinfo_flow_depth_development_twin_panel_max_count_msg(), true);// if switched here, also switch on
+                                                                                                                          // server side
 
         else if ("sinfo_flowdepth_twin_panel".equals(uiProvider))
-            return new DiffPairTwinPanel(user, 9999, "");
+            return new DiffPairTwinPanel(user, 9999, "", true); // if switched here, also switch on server side
 
         else if ("sinfo_flowdepthminmax_twin_panel".equals(uiProvider))
-            return new FlowDepthMinMaxTwinPanel(user);
+            return new FlowDepthMinMaxTwinPanel(user); // minuend-subtrahend switch is in constructor
 
         // GWT.log("Picked default provider.");
         return new SelectProvider();
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WaterlevelTwinPanel.java	Tue Dec 11 17:08:36 2018 +0100
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WaterlevelTwinPanel.java	Tue Jan 08 17:01:09 2019 +0100
@@ -22,6 +22,6 @@
 
     public WaterlevelTwinPanel(final User user) {
         super(user, new WaterlevelTwinPanelValidator(), DatacagePairWidget.NIL_CONTROLER, new WaterlevelRecommendationInfo("winfo_diff_twin_panel"),
-                new WaterlevelRecommendationInfo("winfo_diff_twin_panel"), 9999, "");
+                new WaterlevelRecommendationInfo("winfo_diff_twin_panel"), 9999, "", false);
     }
 }
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/minfo/BedHeightsDatacagePanel.java	Tue Dec 11 17:08:36 2018 +0100
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/minfo/BedHeightsDatacagePanel.java	Tue Jan 08 17:01:09 2019 +0100
@@ -40,7 +40,7 @@
         // 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);
+        super(user, new WaterlevelTwinPanelValidator(), INFO, INFO,false);
     }
 
     @Override
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/DiffPairTwinPanel.java	Tue Dec 11 17:08:36 2018 +0100
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/DiffPairTwinPanel.java	Tue Jan 08 17:01:09 2019 +0100
@@ -27,7 +27,8 @@
     private static final NilDatacageTwinPanelInfo WATERLEVEL_INFO = new NilDatacageTwinPanelInfo(MSG.sinfo_columnlabel_waterlevels(),
             "sinfo_flowdepth_waterlevels");
 
-    public DiffPairTwinPanel(final User user, final int maxCount, final String msgMaxCount) {
-        super(user, new FlowDepthTwinPanelValidator(), new WaterlevelSoundingSelectionController(MSG), SOUNDING_INFO, WATERLEVEL_INFO, maxCount, msgMaxCount);
+    public DiffPairTwinPanel(final User user, final int maxCount, final String msgMaxCount, final boolean minuendSubtrahendUiReversed) {
+        super(user, new FlowDepthTwinPanelValidator(), new WaterlevelSoundingSelectionController(MSG), SOUNDING_INFO, WATERLEVEL_INFO, maxCount, msgMaxCount,
+                minuendSubtrahendUiReversed);
     }
 }
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthMinMaxTwinPanel.java	Tue Dec 11 17:08:36 2018 +0100
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthMinMaxTwinPanel.java	Tue Jan 08 17:01:09 2019 +0100
@@ -27,6 +27,9 @@
     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 WaterlevelSoundingSelectionController(MSG), LEFT_INFO, RIGHT_INFO, 9999, "");
+        super(user, new FlowDepthTwinPanelValidator(), new WaterlevelSoundingSelectionController(MSG), LEFT_INFO, RIGHT_INFO, 9999, "", true); // if switched
+                                                                                                                                               // here, also
+                                                                                                                                               // switch on
+                                                                                                                                               // client-side
     }
 }
\ No newline at end of file

http://dive4elements.wald.intevation.org