view gwt-client/src/main/java/org/dive4elements/river/client/client/ui/bundu/BunduWstWQPanel.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 0fb76f2d4e5b
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.bundu;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.dive4elements.river.client.client.Config;
import org.dive4elements.river.client.client.services.DynamicMainValuesService;
import org.dive4elements.river.client.client.services.DynamicMainValuesServiceAsync;
import org.dive4elements.river.client.client.services.DynamicMainValuesTimeRangeDeterminationService;
import org.dive4elements.river.client.client.services.DynamicMainValuesTimeRangeDeterminationServiceAsync;
import org.dive4elements.river.client.client.ui.AbstractWQAdaptedInputPanel;
import org.dive4elements.river.client.client.ui.DoubleArrayPanel;
import org.dive4elements.river.client.client.ui.wq.QDTable;
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 com.google.gwt.core.client.GWT;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.types.TitleOrientation;
import com.smartgwt.client.types.VerticalAlignment;
import com.smartgwt.client.types.Visibility;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.RadioGroupItem;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.form.fields.events.ChangeEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangeHandler;
import com.smartgwt.client.widgets.form.fields.events.FocusEvent;
import com.smartgwt.client.widgets.form.fields.events.FocusHandler;
import com.smartgwt.client.widgets.form.validator.IntegerRangeValidator;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.tab.Tab;

/**
 * This UIProvider creates a widget to enter W or Q data for
 * Fixation analysis
 *
 * @author <a href="mailto:aheinecke@intevation.de">Andre Heinecke</a>
 */
public class BunduWstWQPanel extends AbstractWQAdaptedInputPanel implements FocusHandler {

    private static final long serialVersionUID = -1L;

    private static enum mode {
        Q, UD
    }

    /** The currently focussed Input element. */
    private DoubleArrayPanel itemWithFocus;

    /** Service to fetch W/Q MainValues. */
    private final DynamicMainValuesServiceAsync mainValueService = GWT.create(DynamicMainValuesService.class);
    private final DynamicMainValuesTimeRangeDeterminationServiceAsync serviceForTime = GWT.create(DynamicMainValuesTimeRangeDeterminationService.class);

    private final RadioGroupItem radiogroup = new RadioGroupItem();

    private int bezugsjahr = 0;

    private int qSeriesLength = 0;

    private Canvas list;

    private final DynamicForm udForm = new DynamicForm();

    private final TextItem udInputItem = new TextItem();

    @Override
    protected void beforeCreate(final DataList data) {
        for (final Data container : data.getAll()) {
            final DataItem[] items = container.getItems();
            if (items != null) {
                for (final DataItem item : items) {
                    if ("ignore_bezugsjahr".equals(item.getLabel())) {
                        this.bezugsjahr = Integer.valueOf(item.getStringValue());
                    } else if ("ignore_q_series_length".equals(item.getLabel())) {
                        this.qSeriesLength = Integer.valueOf(item.getStringValue());
                    }
                }
            }
        }
    }

    @Override
    protected void afterCreate() {
    }

    @Override
    protected Canvas createWidget(final DataList dataList) {
        final VLayout layout = new VLayout();
        final Canvas mode = createMode(dataList);

        this.list = createList(dataList);

        this.udInputItem.setShowTitle(false);
        this.udInputItem.setWidth(120);
        final IntegerRangeValidator validator = new IntegerRangeValidator();
        validator.setMax(364);
        validator.setMin(0);
        validator.setErrorMessage(this.MSG.bundu_bezugswst_validation_range());
        this.udInputItem.setRequiredMessage(this.MSG.bundu_bezugswst_validation_range());
        this.udInputItem.setValidators(validator);
        this.udInputItem.setValidateOnChange(true);
        this.udForm.setFields(this.udInputItem);

        final List<WQDataItem> items = getWQItems(dataList);
        final int listHeight = ROW_HEIGHT * items.size();

        mode.setHeight(25);
        mode.setWidth(200);

        layout.addMember(mode);
        layout.addMember(this.list);
        layout.addMember(this.udForm);
        layout.setHeight(25 + listHeight);
        layout.setWidth(350);
        enableQ();
        return layout;
    }

    /**
     * Create radio button for switching
     * Radiobutton-change also triggers helper panel tab selection.
     */

    private Canvas createMode(final DataList dataList) {
        this.radiogroup.setShowTitle(false);
        this.radiogroup.setVertical(false);
        this.radiogroup.setWidth(200);

        final LinkedHashMap<String, String> wqValues = new LinkedHashMap<String, String>();
        wqValues.put(String.valueOf(mode.Q), this.MSG.wqQatGauge());
        wqValues.put(String.valueOf(mode.UD), this.MSG.bundu_bezugswst_mode_ud());
        this.radiogroup.setValueMap(wqValues);
        this.radiogroup.setValue(String.valueOf(mode.Q));

        this.modes = new DynamicForm();
        this.modes.setFields(this.radiogroup);
        this.modes.setWidth(200);
        this.radiogroup.addChangeHandler(new ChangeHandler() {
            @Override
            public void onChange(final ChangeEvent e) {

                final String value = e.getValue().toString();
                if (value.equals(String.valueOf(mode.UD))) {
                    enableUD();
                } else if (value.equals(String.valueOf(mode.Q))) {
                    enableQ();
                }
            }
        });
        return this.modes;
    }

    private void enableUD() {
        BunduWstWQPanel.this.list.setVisibility(Visibility.HIDDEN);
        BunduWstWQPanel.this.udForm.setVisibility(Visibility.VISIBLE);
        BunduWstWQPanel.this.tabs.disable();
    }

    private void enableQ() {
        BunduWstWQPanel.this.list.setVisibility(Visibility.VISIBLE);
        BunduWstWQPanel.this.udForm.setVisibility(Visibility.HIDDEN);
        BunduWstWQPanel.this.tabs.enable();
    }

    private final String getMode() {
        return (String) this.radiogroup.getValue();
    }

    @Override
    public Data[] getData() {
        final Data[] data = new Data[2];
        final String modeStr = getMode();
        final DataItem item = new DefaultDataItem("bundu.wst.mode", "bundu.wst.mode", modeStr);
        final Data modeData = new DefaultData("bundu.wst.mode", null, null, new DataItem[] { item });
        data[0] = modeData;
        if (modeStr.equals(mode.Q.toString())) {
            data[1] = getWQValues("wq_values");
        } else if (modeStr.equals(mode.UD.toString())) {
            final String udValue = this.udInputItem.getValueAsString(); // in validate findet der int-check statt; er verhindert ein weitergehen, falls der Wert
                                                                        // nicht int-kompatibel ist
            final DataItem itemV = new DefaultDataItem("bundu.wst.ud_value", "bundu.wst.ud_value", udValue);
            data[1] = new DefaultData("bundu.wst.ud_value", null, null, new DataItem[] { itemV });
        }
        return data;
    }

    @Override
    protected void createTabs() {
        for (int i = 0; i < this.gaugeRanges.size(); i++) {
            final Tab qTab = new Tab(this.MSG.wq_table_q());
            qTab.setPaneMargin(0);
            final QDTable qdTable = new QDTable();
            this.qdTables.add(qdTable);
            qdTable.showSelect();
            qTab.setPane(qdTable);
            this.tabs.addTab(qTab, i);
        }
        this.tabs.setSelectedTab(0);

    }

    private Canvas createList(final DataList dataList) {
        final VLayout layout = new VLayout();

        final List<WQDataItem> items = getWQItems(dataList);

        int i = 0;
        for (final DataItem item : items) {
            if (item instanceof WQDataItem) {
                final String title = item.getLabel();
                final String label = item.getStringValue();

                this.tabs.getTab(i).setTitle(this.tabs.getTab(i).getTitle() + " (" + label + ")");

                final DoubleArrayPanel dap = new DoubleArrayPanel(label, null, this, this, TitleOrientation.LEFT);
                this.wqranges.put(title, dap);
                this.doubleArrayPanels.add(dap);
                if (item instanceof WQDataItem) {
                    final WQDataItem wq = (WQDataItem) item;
                    final double[] mmQ = wq.getQRange();
                    this.qranges.put(title, mmQ);

                }
                layout.addMember(dap);
                i++;
            }
        }

        layout.setHeight(items.size() * ROW_HEIGHT);

        return layout;
    }

    @Override
    public List<String> validate() {
        final List<String> errors = new ArrayList<String>();
        if (getMode().equals(mode.Q.toString())) {
            errors.addAll(this.validateRange(this.qranges));
        } else if (getMode().equals(mode.UD.toString())) {
            try {
                if (!this.udInputItem.validate()) {
                    errors.add(this.udInputItem.getRequiredMessage());
                }
                final String value = this.udInputItem.getValueAsString();
                if (value == null || value.isEmpty()) {
                    errors.add(this.MSG.missingInput());
                    return errors;
                }
                Integer.valueOf(value);// irgendwie klappt die validator-validierung nur bei der eingabe von
                                       // ganzzahlen :-(
            }
            catch (final NumberFormatException e) {
                errors.add(this.MSG.error_invalid_integer());
            }
        }
        return errors;
    }

    private List<String> validateRange(final Map<String, double[]> ranges) {
        final List<String> errors = new ArrayList<String>();

        final NumberFormat nf = NumberFormat.getDecimalFormat();

        for (final DoubleArrayPanel dap : this.wqranges.values()) {

            if (!dap.validateForm()) {
                errors.add(this.MSG.error_invalid_double_value());
                return errors;
            }

            int idx = 0;

            final double[] values = dap.getInputValues();
            if (values == null) {
                errors.add(this.MSG.missingInputs());
                return errors;
            }
            final double[] good = new double[values.length];

            for (final double value : values) {
                if (value <= 0) {
                    String tmp = this.MSG.error_validate_positive();
                    tmp = tmp.replace("$1", nf.format(value));
                    errors.add(tmp);
                } else {
                    good[idx++] = value;
                }
            }

            final double[] justGood = new double[idx];
            for (int i = 0; i < justGood.length; i++) {
                justGood[i] = good[i];
            }

            if (!errors.isEmpty()) {
                dap.setValues(justGood);
            }
        }
        return errors;
    }

    @Override
    public Canvas createOld(final DataList dataList) {
        final List<Data> all = dataList.getAll();
        final Data wqData = getData(all, "wq_values");
        final Data wqMode = getData(all, "bundu.wst.mode");
        final Data udValue = getData(all, "bundu.wst.ud_value");

        final boolean isQ = wqMode.getItems()[0].getStringValue().equals(String.valueOf(mode.Q));
        final Canvas back = getBackButton(dataList.getState());

        final HLayout valLayout = new HLayout();
        final HLayout modeLayout = new HLayout();
        final VLayout vlayout = new VLayout();

        final Label wqLabel = new Label(dataList.getLabel());
        final Label modeLabel = new Label("");

        wqLabel.setValign(VerticalAlignment.TOP);

        wqLabel.setWidth(200);
        wqLabel.setHeight(25);
        modeLabel.setHeight(25);
        modeLabel.setWidth(200);

        valLayout.addMember(wqLabel);
        if (isQ) {
            valLayout.addMember(createOldWQValues(wqData, true));
        } else {
            valLayout.addMember(new Label(udValue.getItems()[0].getStringValue() + " [d/a]"));
        }
        valLayout.addMember(back);
        modeLayout.addMember(modeLabel);

        vlayout.addMember(valLayout);
        vlayout.addMember(modeLayout);

        return vlayout;
    }

    protected void callMainValuesService(final String locale, final String river, final double start, final double end, final Date startDate,
            final Date endDate, final AsyncCallback<WQInfoObject[]> cb) {

        this.mainValueService.getWQInfo(locale, river, start, end, startDate, endDate, cb);
    }

    @Override
    public void onFocus(final FocusEvent event) {
        this.itemWithFocus = (DoubleArrayPanel) event.getForm();
        // Switch to respective tab.
        if (getMode().equals(mode.Q.toString())) {
            final int inputIndex = this.doubleArrayPanels.indexOf(this.itemWithFocus);
            this.tabs.selectTab(inputIndex);
        }
    }

    @Override
    protected void fetchWQData() {
        {
            final Config config = Config.getInstance();
            final String locale = config.getLocale();

            final ArtifactDescription adescr = this.artifact.getArtifactDescription();
            final DataList[] data = adescr.getOldData();

            final String river = getRiverName(data);
            final int startYear = this.bezugsjahr - this.qSeriesLength;
            final int endYear = this.bezugsjahr;

            // Gauge ranges overlap, move start and end a bit closer
            // to each other.

            final AsyncCallback<GaugeInfoObject[]> cb = new AsyncCallback<GaugeInfoObject[]>() {
                @Override
                public void onFailure(final Throwable caught) {
                    GWT.log("Could not recieve wq informations.");
                    final String msg = caught.getMessage();
                    resetLoadingMessageOfQTable(msg);
                    // disable weiter-knopf
                    getSubmitBtn().disable();
                    SC.warn(msg);
                }

                @Override
                public void onSuccess(final GaugeInfoObject[] result) {
                    // TODO Auto-generated method stub
                    final int num = result != null ? result.length : 0;
                    GWT.log("Received  timeranges for gauges");

                    if (num == 0) {
                        return;
                    }

                    for (int i = 0; i < result.length; i++) {
                        final GaugeInfoObject gauge = result[i];
                        // Gauge ranges overlap, move start and end a bit closer
                        // to each other.
                        final Double[] range = getGaugeNamesRange().get(gauge.getName());
                        final double rDiff = (range[1] - range[0]) / 10d;
                        final int fi = i;

                        final AsyncCallback<WQInfoObject[]> cb = new AsyncCallback<WQInfoObject[]>() {
                            @Override
                            public void onFailure(final Throwable caught) {
                                GWT.log("Could not recieve wq informations.");
                                addWQInfo(null, fi, gauge);
                            }

                            @Override
                            public void onSuccess(final WQInfoObject[] wqi) {
                                final int num = wqi != null ? wqi.length : 0;
                                GWT.log("Received " + num + " wq informations (" + fi + ".");

                                addWQInfo(wqi, fi, gauge);
                                if (fi == (result.length - 1))
                                    getSubmitBtn().enable();
                            }
                        };
                        callMainValuesService(locale, river, range[0] + rDiff, range[1] - rDiff, gauge.getStartTime(), gauge.getStopTime(), cb);
                    }
                }

            };

            this.serviceForTime.getGaugeInfo(locale, river, getGaugeNames(), startYear, endYear, cb);
            getSubmitBtn().disable();
        }

    }

    @Override
    protected String getWQInfoMsg() {
        return this.MSG.bundu_ws_wq_info();
    }

}

http://dive4elements.wald.intevation.org