view gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractWQAdaptedInputPanel.java @ 9416:05405292a7ca

Navigationtheme panel now shows themes of dWt and WQ charts grayed out, if the current station is outside the valid range of the theme.
author gernotbelger
date Thu, 16 Aug 2018 16:28:03 +0200
parents 0fb76f2d4e5b
children 4cccbd32b680
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("black");
        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.getErrorMsg();
            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.getErrorMsg());
    }

    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