view gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractWQAdaptedInputPanel.java @ 9407:43c975f8ab92

Label for Eingabhilfe bundu.bezugswasserstände.EingabeFürWQDaten
author gernotbelger
date Wed, 15 Aug 2018 16:26:22 +0200
parents bc9a45d2b1fa
children 38201f5b0dd9
line wrap: on
line source
/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
 * Software engineering by Intevation GmbH
 *
 * 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 java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dive4elements.river.client.client.FLYSConstants;
import org.dive4elements.river.client.client.ui.wq.QDTable;
import org.dive4elements.river.client.client.ui.wq.WTable;
import org.dive4elements.river.client.shared.model.ArtifactDescription;
import org.dive4elements.river.client.shared.model.Data;
import org.dive4elements.river.client.shared.model.DataItem;
import org.dive4elements.river.client.shared.model.DataList;
import org.dive4elements.river.client.shared.model.DefaultData;
import org.dive4elements.river.client.shared.model.DefaultDataItem;
import org.dive4elements.river.client.shared.model.GaugeInfoObject;
import org.dive4elements.river.client.shared.model.WQDataItem;
import org.dive4elements.river.client.shared.model.WQInfoObject;
import org.dive4elements.river.client.shared.model.WQInfoRecord;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.user.client.ui.Label;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
import com.smartgwt.client.widgets.form.fields.events.ChangeEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangeHandler;
import com.smartgwt.client.widgets.grid.events.CellClickEvent;
import com.smartgwt.client.widgets.grid.events.CellClickHandler;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.tab.TabSet;

/**
 * This UIProvider creates a widget to enter W or Q data for discharge
 * longitudinal section computations.
 *
 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
 */
abstract public class AbstractWQAdaptedInputPanel extends AbstractUIProvider implements ChangeHandler, BlurHandler {
    private static final long serialVersionUID = -3218827566805476423L;

    /** The message class that provides i18n strings. */
    protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
    protected static final int ROW_HEIGHT = 20;

    /** List of QDTables in inputhelper section. */
    protected List<QDTable> qdTables;

    private static final String GAUGE_SEPARATOR = ":";

    private static final String GAUGE_PART_SEPARATOR = ";";

    private static final String VALUE_SEPARATOR = ",";

    /** Stores the input panels related to their keys. */
    protected Map<String, DoubleArrayPanel> wqranges;

    /** [startkm,endkm] per gauge in selected range. */
    protected List<Double[]> gaugeRanges;

    /** Stores the min/max values for each q range (gauge). */
    protected Map<String, double[]> qranges;

    /** The RadioGroupItem that determines the w/q input mode. */
    protected DynamicForm modes;
    /** List of doubleArrayPanels shown. */
    protected final ArrayList<DoubleArrayPanel> doubleArrayPanels = new ArrayList<DoubleArrayPanel>();
    /** List of wTables in inputhelper section. */
    protected List<WTable> wTables;

    /** Tabs in inputhelper area. */
    protected TabSet tabs;

    private Canvas submit;

    private final List<String> gaugeNames = new ArrayList<String>();
    private final Map<String, Double[]> gaugeNamesRange = new HashMap<String, Double[]>();

    public AbstractWQAdaptedInputPanel() {
        this.wqranges = new HashMap<String, DoubleArrayPanel>();
        this.qranges = new HashMap<String, double[]>();
        this.wTables = new ArrayList<WTable>();
        this.qdTables = new ArrayList<QDTable>();
    }

    protected final Map<String, Double[]> getGaugeNamesRange() {
        return this.gaugeNamesRange;
    }

    protected final String[] getGaugeNames() {
        return this.gaugeNames.toArray(new String[this.gaugeNames.size()]);
    }

    /** Inits the helper panel. */
    // TODO duplicate in WQInputPanel
    protected void initHelperPanel() {
        final VLayout layout = new VLayout();
        this.tabs = new TabSet();
        this.tabs.setWidth100();
        this.tabs.setHeight100();
        final String msg = this.getWQInfoMsg();
        final Label test = PanelHelper.getValidationLabel();
        test.setText(msg);
        test.getElement().getStyle().setColor("red");
        test.getElement().getStyle().setPadding(1, Unit.MM);

        // For each gauge, add two tabs with helper tables.
        createTabs();
        layout.addMember(this.tabs);
        if (msg != null)
            layout.addMember(test);

        this.helperContainer.addMember(layout);
        // DOM.setStyleAttribute(test.getElement(), "color", "red");

    }

    /** Create labels, canvasses, layouts. */
    @Override
    public Canvas create(final DataList data) {
        beforeCreate(data);

        readGaugeRanges(data);
        initHelperPanel();

        this.submit = getNextButton();
        final Canvas widget = createWidget(data);
        final Label label = new Label(this.MSG.wqadaptedTitle());

        label.setHeight("25px");

        final VLayout layout = new VLayout();
        layout.setMembersMargin(10);
        layout.setWidth(350);

        layout.addMember(label);
        layout.addMember(widget);
        layout.addMember(this.submit);

        fetchWQData();

        initTableListeners();

        afterCreate();

        return layout;
    }

    protected final Canvas getSubmitBtn() {
        return this.submit;
    }

    protected abstract void createTabs();

    protected abstract void beforeCreate(final DataList data);

    protected abstract void afterCreate();

    /**
     * Initializes the listeners of the WQD tables.
     */
    // TODO dupe from WQInputPanel
    protected void initTableListeners() {
        int i = 0;
        for (final QDTable qdTable : this.qdTables) {
            // Register listener such that values are filled in on click.
            final QDTable table = qdTable;
            final int fi = i;
            final CellClickHandler handler = new CellClickHandler() {
                @Override
                public void onCellClick(final CellClickEvent e) {
                    if (table.isDisabled() || table.isLocked()) {
                        return;
                    }

                    final Record r = e.getRecord();
                    final double val = r.getAttributeAsDouble("value");

                    AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(fi).setValues(new double[] { val });
                    // If a named value for first gauge is chosen,
                    // try to find and set
                    // the values to the other panels too.
                    if (fi == 0) {
                        final String valueName = r.getAttribute("name");
                        int oi = 0;
                        // TODO instead of oi use random access.
                        for (final QDTable otherQDTable : AbstractWQAdaptedInputPanel.this.qdTables) {
                            if (oi == 0) {
                                oi++;
                                continue;
                            }
                            final Double value = otherQDTable.findRecordValue(valueName);
                            if (value == null) {
                                SC.warn(AbstractWQAdaptedInputPanel.this.MSG.noMainValueAtGauge());
                            } else {
                                AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(oi).setValues(new double[] { value });
                            }
                            oi++;
                        }
                    } else {
                        // Focus next.
                        if (fi != AbstractWQAdaptedInputPanel.this.doubleArrayPanels.size() - 1) {
                            AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(fi + 1).focusInItem(1);
                        }
                    }
                }
            };

            qdTable.addCellClickHandler(handler);
            i++;
        }

        i = 0;
        for (final WTable wTable : this.wTables) {
            // Register listener such that values are filled in on click.
            final WTable table = wTable;
            final int fi = i;
            final CellClickHandler handler = new CellClickHandler() {

                @Override
                public void onCellClick(final CellClickEvent e) {
                    if (table.isDisabled()) {
                        return;
                    }

                    final Record r = e.getRecord();
                    final double val = r.getAttributeAsDouble("value");

                    AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(fi).setValues(new double[] { val });
                    // If a named value for first gauge is chosen,
                    // try to find and set
                    // the values to the other panels too.
                    if (fi == 0) {
                        final String valueName = r.getAttribute("name");
                        int oi = 0;
                        // TODO instead of oi use random access.
                        for (final WTable otherWTable : AbstractWQAdaptedInputPanel.this.wTables) {
                            if (oi == 0) {
                                oi++;
                                continue;
                            }
                            final Double value = otherWTable.findRecordValue(valueName);
                            if (value == null) {
                                // TODO: afterwards it freaks out
                                SC.warn(AbstractWQAdaptedInputPanel.this.MSG.noMainValueAtGauge());
                            } else {
                                AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(oi).setValues(new double[] { value });
                            }
                            oi++;
                        }
                    } else {
                        // Focus next.
                        if (fi != AbstractWQAdaptedInputPanel.this.doubleArrayPanels.size() - 1) {
                            AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(fi + 1).focusInItem(1);
                        }
                    }
                }

            };

            wTable.addCellClickHandler(handler);
            i++;
        }
    }

    /** Create area showing previously entered w or q data. */
    protected final Canvas createOldWQValues(final Data wqData, final boolean isQ) {

        final VLayout layout = new VLayout();
        if (wqData != null) {
            final DataItem item = wqData.getItems()[0];
            final String value = item.getStringValue();

            final String[] gauges = value.split(GAUGE_SEPARATOR);

            final String unit = isQ ? "m³/s" : "cm";

            for (final String gauge : gauges) {
                final HLayout h = new HLayout();

                final String[] parts = gauge.split(GAUGE_PART_SEPARATOR);
                final String[] values = parts[3].split(VALUE_SEPARATOR);

                final Label l = new Label(parts[2] + ": ");

                final StringBuilder sb = new StringBuilder();
                boolean first = true;

                for (final String v : values) {
                    if (!first) {
                        sb.append(", ");
                    }

                    sb.append(v);
                    sb.append(" ");
                    sb.append(unit);

                    first = false;
                }

                final Label v = new Label(sb.toString());

                l.setWidth("65px");
                v.setWidth("65px");

                h.addMember(l);
                h.addMember(v);

                layout.addMember(h);
            }
        }

        return layout;
    }

    protected void initUserWQValues(final DataList dataList) {
        final List<Data> allData = dataList.getAll();

        final Data dDef = getData(allData, "wq_values");
        final DataItem def = dDef != null ? dDef.getDefault() : null;
        final String value = def != null ? def.getStringValue() : null;

        if (value == null || value.length() == 0) {
            return;
        }

        final String[] lines = value.split(GAUGE_SEPARATOR);

        if (lines == null || lines.length == 0) {
            return;
        }

        for (final String line : lines) {
            final String[] cols = line.split(GAUGE_PART_SEPARATOR);
            // final String title = createLineTitle(line);

            if (cols == null || cols.length < 3) {
                continue;
            }

            final String[] strValues = cols[2].split(VALUE_SEPARATOR);
            final double[] values = new double[strValues.length];

            int idx = 0;

            for (final String strValue : strValues) {
                try {
                    values[idx++] = Double.valueOf(strValue);
                }
                catch (final NumberFormatException nfe) {
                    // do nothing
                }
            }

            final String key = cols[0] + GAUGE_PART_SEPARATOR + cols[1];
            final DoubleArrayPanel dap = this.wqranges.get(key);

            if (dap == null) {
                continue;
            }

            dap.setValues(values);
        }
    }

    /** Populate Gauge Ranges array. */
    protected final void readGaugeRanges(final DataList dataList) {
        final List<WQDataItem> items = getWQItems(dataList);
        this.gaugeRanges = new ArrayList<Double[]>();

        for (final DataItem item : items) {
            if (item instanceof WQDataItem) {
                final String[] startEndKm = item.getLabel().split(";");
                final Double[] kvp = new Double[] { Double.parseDouble(startEndKm[0]), Double.parseDouble(startEndKm[1]) };
                this.gaugeRanges.add(kvp);
                final String gaugeName = item.getStringValue();
                this.gaugeNames.add(gaugeName);
                this.gaugeNamesRange.put(gaugeName, kvp);
            }
        }
    }

    /** Get items which are not WQ_MODE. */
    protected List<WQDataItem> getWQItems(final DataList dataList) {
        final List<Data> data = dataList.getAll();
        final List<WQDataItem> results = new ArrayList<WQDataItem>();
        for (final Data d : data) {
            final DataItem[] items = d.getItems();
            if (items != null) {
                for (final Object item : items) {
                    if (item instanceof WQDataItem)
                        results.add((WQDataItem) item);
                }
            }
        }
        return results;
    }

    protected final Data getWQValues(final String dataKey) {
        String wqvalue = null;

        for (final Map.Entry<String, DoubleArrayPanel> entry : this.wqranges.entrySet()) {
            final String key = entry.getKey();
            final DoubleArrayPanel dap = entry.getValue();
            final String label = dap.getItemTitle();

            final double[] values = dap.getInputValues();
            if (wqvalue == null) {
                wqvalue = createValueString(key + ";" + label, values);
            } else {
                wqvalue += GAUGE_SEPARATOR + createValueString(key + ";" + label, values);
            }
        }

        final DataItem valueItem = new DefaultDataItem(dataKey, dataKey, wqvalue);
        final Data values = new DefaultData(dataKey, null, null, new DataItem[] { valueItem });

        return values;
    }

    protected String createValueString(final String key, final double[] values) {
        final StringBuilder sb = new StringBuilder();

        boolean first = true;

        for (final double value : values) {
            if (!first) {
                sb.append(",");
            }

            sb.append(Double.toString(value));

            first = false;
        }

        return key + ";" + sb.toString();
    }

    @Override
    public void onChange(final ChangeEvent event) {
        // TODO IMPLEMENT ME
    }

    /** Store the currently focussed DoubleArrayPanel and focus helper tab. */

    @Override
    public final void onBlur(final BlurEvent event) {
        final DoubleArrayPanel dap = (DoubleArrayPanel) event.getForm();
        dap.validateForm(event.getItem());
    }

    /** Get the WQD data from service and stuck them up that tables. */
    protected abstract void fetchWQData();

    // protected abstract void callMainValuesService(String locale, String river, double start, double end,
    // AsyncCallback<WQInfoObject[]> cb);

    /** Add Info to helper table for gauge at index gaugeIdx. */
    public void addWQInfo(final WQInfoObject[] wqi, final int gaugeIdx, final GaugeInfoObject gauge) {
        if (wqi == null) {
            // this.wTables.get(gaugeIdx).setLoadingDataMessage(""); (keine W-tables vorhanden - wo W-Table benutzt werden, gibt es
            // ein Popup)
            final String emptyMsg = gauge.getErrorMessage();
            final QDTable table = this.qdTables.get(gaugeIdx);
            table.setEmptyMessage(emptyMsg == null ? "" : emptyMsg);
            table.redraw();
        } else {
            for (final WQInfoObject wi : wqi) {
                final WQInfoRecord rec = new WQInfoRecord(wi);

                if (wi.getType().equals("W")) {
                    if (gaugeIdx < this.wTables.size())
                        this.wTables.get(gaugeIdx).addData(rec);
                } else { // Q,D,- alle gehören hier rein!
                    if (gaugeIdx < this.qdTables.size())
                        this.qdTables.get(gaugeIdx).addData(rec);
                }
            }
        }
        if (gauge != null)
            AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(gaugeIdx).setError(gauge.getErrorMessage());
    }

    public void resetLoadingMessageOfQTable(final String msg) {
        for (final QDTable table : this.qdTables) {
            table.setEmptyMessage(msg);
            table.redraw();
        }
    }

    /**
     * Returns the name of the selected river.
     *
     * @param data
     *            The DataList with all data.
     *
     * @return the name of the current river.
     */
    protected String getRiverName(final DataList[] data) {
        final ArtifactDescription adesc = this.artifact.getArtifactDescription();
        return adesc.getRiver();
    }

    protected abstract Canvas createWidget(final DataList dataList);

    protected abstract String getWQInfoMsg();
}

http://dive4elements.wald.intevation.org