view flys-client/src/main/java/de/intevation/flys/client/client/ui/WQInputPanel.java @ 1279:af6ad7522351

Bugfix: #336 Improved determination of min/max KM values - code moved to ArtifactDescription. flys-client/trunk@2861 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Thu, 29 Sep 2011 09:14:41 +0000
parents 393e5d37d85d
children b9b4d27bcf63
line wrap: on
line source
package de.intevation.flys.client.client.ui;

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

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.data.Record;

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.FormItem;
import com.smartgwt.client.widgets.form.fields.RadioGroupItem;
import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangeHandler;
import com.smartgwt.client.widgets.form.fields.events.ChangeEvent;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.grid.events.CellClickHandler;
import com.smartgwt.client.widgets.grid.events.CellClickEvent;
import com.smartgwt.client.widgets.tab.TabSet;
import com.smartgwt.client.widgets.tab.Tab;

import de.intevation.flys.client.shared.model.Data;
import de.intevation.flys.client.shared.model.DataItem;
import de.intevation.flys.client.shared.model.DataList;
import de.intevation.flys.client.shared.model.DefaultData;
import de.intevation.flys.client.shared.model.DefaultDataItem;
import de.intevation.flys.client.shared.model.WQInfoObject;
import de.intevation.flys.client.shared.model.WQInfoRecord;
import de.intevation.flys.client.shared.model.ArtifactDescription;

import de.intevation.flys.client.client.FLYSConstants;
import de.intevation.flys.client.client.FLYSImages;
import de.intevation.flys.client.client.Config;
import de.intevation.flys.client.client.services.WQInfoService;
import de.intevation.flys.client.client.services.WQInfoServiceAsync;
import de.intevation.flys.client.client.ui.wq.WTable;
import de.intevation.flys.client.client.ui.wq.QDTable;


/**
 * This UIProvider creates a widget to enter W or Q data.
 *
 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
 */
public class WQInputPanel
extends      AbstractUIProvider
implements   ChangeHandler, BlurHandler
{
    /** The message class that provides i18n strings.*/
    protected FLYSConstants MESSAGE = GWT.create(FLYSConstants.class);

    /** The interface that provides the image resources. */
    private FLYSImages IMAGES = GWT.create(FLYSImages.class);

    protected WQInfoServiceAsync wqInfoService =
        GWT.create(WQInfoService.class);

    /** The constant field name for choosing w or q mode.*/
    public static final String FIELD_WQ = "wq";

    /** The constant field value for W input mode.*/
    public static final String FIELD_WQ_W = "W";

    /** The constant field value for Q input mode.*/
    public static final String FIELD_WQ_Q = "Q";

    /** The constant field value for Q input mode.*/
    public static final String FIELD_WQ_Q_GAUGE = "Q_GAUGE";

    /** The constant field name for choosing single values or range.*/
    public static final String FIELD_MODE = "mode";

    /** The constant field value for single input mode.*/
    public static final String FIELD_MODE_SINGLE = "single";

    /** The constant field value for range input mode.*/
    public static final String FIELD_MODE_RANGE = "range";

    /** The constant value that determines the width of the left panel.*/
    public static final int WIDTH_LEFT_UPPER = 400;

    public static final int WIDTH_LEFT_LOWER = 223;


    /** The container that manages the w and q panels.*/
    protected HLayout container;

    /** The RadioGroupItem that determines the w/q input mode.*/
    protected DynamicForm modes;

    /** The min values for the 'from' property in the W-Range input mode.*/
    protected double minW;

    /** The min values for the 'from' property in the Q-Range input mode.*/
    protected double minQ;

    /** The max values for the 'from' property in the W-Range input mode.*/
    protected double maxW;

    /** The max values for the 'from' property in the Q-Range input mode.*/
    protected double maxQ;

    /** The 'from' value entered in the range W mode.*/
    protected double fromW;

    /** The 'to' value entered in the range W mode.*/
    protected double toW;

    /** The 'step' value entered in the range W mode.*/
    protected double stepW;

    /** The values entered in the single W mode.*/
    protected double[] valuesW;

    /** The 'from' value entered in the range Q mode.*/
    protected double fromQ;

    /** The 'to' value entered in the range Q mode.*/
    protected double toQ;

    /** The 'step' value entered in the range Q mode.*/
    protected double stepQ;

    /** The values entered in the single Q mode.*/
    protected double[] valuesQ;

    /** The input panel for W values*/
    protected DoubleArrayPanel wArrayPanel;

    /** The input panel for q values*/
    protected DoubleArrayPanel qArrayPanel;

    /** The input panel for w range*/
    protected DoubleRangePanel wRangePanel;

    /** The input panel for q range*/
    protected DoubleRangePanel qRangePanel;

    protected QDTable qdTable;

    protected WTable wTable;

    protected TabSet tabs;

    /**
     * Creates a new WQInputPanel instance.
     */
    public WQInputPanel() {
        qdTable      = new QDTable();
        wTable       = new WTable();

        initTableListeners();
    }


    /**
     * Initializes the listeners of the WQD tables.
     */
    protected void initTableListeners() {
        CellClickHandler handler = new CellClickHandler() {
            public void onCellClick(CellClickEvent e) {
                if (isWMode()) {
                    return;
                }

                int    idx = e.getColNum();
                Record r   = e.getRecord ();
                double val = r.getAttributeAsDouble("value");

                if (idx == 0) {
                    if (isRangeMode()) {
                        qRangePanel.setFrom(val);
                    }
                    else {
                        qArrayPanel.addValue(val);
                    }
                }
                else if (idx == 1) {
                    if (isRangeMode()) {
                        qRangePanel.setTo(val);
                    }
                    else {
                        qArrayPanel.addValue(val);
                    }
                }
            }
        };

        qdTable.addCellClickHandler(handler);
    }


    /**
     * This method calls createWidget and puts a 'next' button to the bottom.
     *
     * @param data The data that is displayed.
     *
     * @return the widget.
     */
    public Canvas create(DataList data) {
        initDefaults(data);

        Canvas  widget = createWidget(data);
        Canvas  submit = getNextButton();
        Label   label  = new Label(MESSAGE.wqTitle());

        label.setHeight(25);

        VLayout layout = new VLayout();
        layout.setMembersMargin(10);

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

        initHelperPanel();
        initUserDefaults(data);

        return layout;
    }


    protected void initHelperPanel() {
        tabs = new TabSet();
        tabs.setWidth100();
        tabs.setHeight100();

        // TODO i18n
        Tab wTab = new Tab("W");
        Tab qTab = new Tab("Q / D");

        wTab.setPane(wTable);
        qTab.setPane(qdTable);

        tabs.addTab(wTab, 0);
        tabs.addTab(qTab, 1);

        helperContainer.addMember(tabs);

        fetchWQData();
    }


    public Canvas createOld(DataList dataList) {
        List<Data> items = dataList.getAll();

        Data dMode      = getData(items, "wq_mode");
        Data dFree      = getData(items, "wq_free");
        Data dSelection = getData(items, "wq_selection");
        Data dSingle    = getData(items, "wq_single");
        Data dFrom      = getData(items, "wq_from");
        Data dTo        = getData(items, "wq_to");
        Data dStep      = getData(items, "wq_step");

        DataItem[] mode = dMode.getItems();
        String strMode  = mode[0].getStringValue();
        boolean wMode   = strMode.equals(FIELD_WQ_W);

        DataItem[] free = dFree.getItems();
        String  strFree = free[0].getStringValue();
        boolean isFree  = Boolean.valueOf(strFree);

        HLayout layout = new HLayout();
        layout.setWidth("400px");

        Label label  = new Label(dataList.getLabel());
        label.setWidth("200px");

        String text = null;

        DataItem[] selItem = dSelection.getItems();
        String     sel     = selItem != null
            ? selItem[0].getStringValue()
            : "";

        if (sel.equals("single")) {
            DataItem[] single = dSingle.getItems();

            text = wMode
                ? createWString(single[0])
                : createQString(single[0]);
        }
        else {
            DataItem[] from = dFrom.getItems();
            DataItem[] to   = dTo.getItems();
            DataItem[] step = dStep.getItems();

            text = wMode
                ? createWString(from[0], to[0], step[0])
                : createQString(from[0], to[0], step[0]);
        }

        VLayout selectedLayout = new VLayout();
        String  wqMode         = null;

        if (wMode) {
            wqMode = MESSAGE.wqW();
        }
        else {
            wqMode = isFree ? MESSAGE.wqQ() : MESSAGE.wqQGauge();
        }

        Label mLabel = new Label(wqMode);
        Label vLabel = new Label(text);
        mLabel.setWidth(175);
        mLabel.setHeight(20);
        vLabel.setWidth(175);
        vLabel.setHeight(20);

        selectedLayout.addMember(mLabel);
        selectedLayout.addMember(vLabel);
        selectedLayout.setHeight(40);

        Canvas back = getBackButton(dataList.getState());

        layout.addMember(label);
        layout.addMember(selectedLayout);
        layout.addMember(back);

        return layout;
    }


    /**
     * This method reads the default values defined in the DataItems of the Data
     * objects in <i>list</i>.
     *
     * @param list The DataList container that stores the Data objects.
     */
    protected void initDefaults(DataList list) {
        Data f = getData(list.getAll(), "wq_from");
        Data t = getData(list.getAll(), "wq_to");
        Data s = getData(list.getAll(), "wq_step");

        DataItem fQItem = getDataItem(f.getItems(), "minQ");
        DataItem fWItem = getDataItem(f.getItems(), "minW");
        DataItem tQItem = getDataItem(t.getItems(), "maxQ");
        DataItem tWItem = getDataItem(t.getItems(), "maxW");
        DataItem sQItem = getDataItem(s.getItems(), "stepQ");
        DataItem sWItem = getDataItem(s.getItems(), "stepW");

        minW  = Double.valueOf(fWItem.getStringValue());
        maxW  = Double.valueOf(tWItem.getStringValue());
        stepW = Double.valueOf(sWItem.getStringValue());

        minQ  = Double.valueOf(fQItem.getStringValue());
        maxQ  = Double.valueOf(tQItem.getStringValue());
        stepQ = Double.valueOf(sQItem.getStringValue());

        this.fromW = minW;
        this.toW   = maxW;
        this.stepW = stepW;

        this.fromQ = minQ;
        this.toQ   = maxQ;
        this.stepQ = stepQ;
    }


    /**
     * Initializes the form items with former inserted user data.
     *
     * @param list The DataList that contains the user data.
     */
    protected void initUserDefaults(DataList list) {
        List<Data> allData = list.getAll();

        Data     m        = getData(allData, "wq_mode");
        DataItem modeItem = m != null ? m.getDefault() : null;
        String   theMode  = modeItem != null
            ? modeItem.getStringValue()
            : "";

        Data     f        = getData(allData, "wq_free");
        DataItem freeItem = f != null ? f.getDefault() : null;
        String   theFree  = freeItem != null
            ? freeItem.getStringValue()
            : null;

        Data     s            = getData(allData, "wq_selection");
        DataItem sI           = s != null ? s.getDefault() : null;
        String   theSelection = sI != null ? sI.getStringValue() : null;

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

        boolean isW    = theMode.equals(FIELD_WQ_W);
        boolean isFree = Boolean.valueOf(theFree);

        initUserSingleValues(list, theMode);
        initUserRangeValues(list, theMode);

        if (isW) {
            modes.setValue(FIELD_WQ, theMode);
        }
        else {
            modes.setValue(FIELD_WQ, isFree ? FIELD_WQ_Q : FIELD_WQ_Q_GAUGE);
        }

        if (theSelection != null || theSelection.length() > 0) {
            modes.setValue(FIELD_MODE, theSelection);
            updatePanels(theMode, theSelection);
        }
    }


    /**
     * Initializes the single values of W or Q from DataList.
     *
     * @param list The DataList that contains the 'wq_single' object.
     * @param theMode The W or Q mode.
     */
    protected void initUserSingleValues(DataList list, String theMode) {
        List<Data> allData = list.getAll();

        Data     s = getData(allData, "wq_single");
        DataItem i = s != null ? s.getDefault() : null;

        if (i != null) {
            String   value = i.getStringValue();
            String[] split = value.split(" ");

            int num = split != null ? split.length : 0;

            double[] values = new double[num];

            for (int j = 0; j < num; j++) {
                try {
                    values[j] = Double.valueOf(split[j]);
                }
                catch (NumberFormatException nfe) {
                    // nothing to do
                }
            }

            if (theMode.equals("W")) {
                setSingleW(values);
            }
            else {
                setSingleQ(values);
            }
        }
    }


    /**
     * Initializes the range values of W or Q from DataList.
     *
     * @param list The DataList that contains the 'wq_single' object.
     * @param theMode The W or Q mode.
     */
    protected void initUserRangeValues(DataList list, String theMode) {
        List<Data> allData = list.getAll();

        // init range mode values
        Data f = getData(allData, "wq_from");
        Data t = getData(allData, "wq_to");
        Data s = getData(allData, "wq_step");

        if (f != null && t != null && s != null) {
            DataItem dF = f.getDefault();
            DataItem dT = t.getDefault();
            DataItem dS = s.getDefault();

            String fS = dF != null ? dF.getStringValue() : null;
            String tS = dT != null ? dT.getStringValue() : null;
            String sS = dS != null ? dS.getStringValue() : null;

            try {
                double from = Double.valueOf(fS);
                double to   = Double.valueOf(tS);
                double step = Double.valueOf(sS);

                if (theMode.equals("W")) {
                    setWRangeValues(from, to, step);
                }
                else {
                    setQRangeValues(from, to, step);
                }
            }
            catch (NumberFormatException nfe) {
                // do nothing
            }
        }
    }


    protected void setQRangeValues(double f, double t, double s) {
        setFromQ(f);
        setToQ(t);
        setStepQ(s);
    }


    protected void setWRangeValues(double f, double t, double s) {
        setFromW(f);
        setToW(t);
        setStepW(s);
    }


    protected String createWString(DataItem from, DataItem to, DataItem step) {
        StringBuilder sb = new StringBuilder();
        sb.append(from.getLabel());
        sb.append(" " + MESSAGE.unitWFrom() + " ");
        sb.append(to.getLabel());
        sb.append(" " + MESSAGE.unitWTo() + " ");
        sb.append(step.getLabel());
        sb.append(" " + MESSAGE.unitWStep());

        return sb.toString();
    }


    protected String createWString(DataItem single) {
        return single.getLabel().replace(" ", " " + MESSAGE.unitWSingle() + " ");
    }


    protected String createQString(DataItem from, DataItem to, DataItem step) {
        StringBuilder sb = new StringBuilder();
        sb.append(from.getLabel());
        sb.append(" " + MESSAGE.unitQFrom() + " ");
        sb.append(to.getLabel());
        sb.append(" " + MESSAGE.unitQTo() + " ");
        sb.append(step.getLabel());
        sb.append(" " + MESSAGE.unitQStep());

        return sb.toString();
    }


    protected String createQString(DataItem single) {
        return single.getLabel().replace(" ", " " + MESSAGE.unitQSingle() + " ");
    }


    /**
     * This method creates the whole widget. There is a panel on the left, that
     * allows the user to enter values manually by keyboard. On the right, there
     * is a table that allows the user to enter values by mouse click.
     *
     * @param data The data that is displayed in the table on the right.
     *
     * @return the widget.
     */
    protected Canvas createWidget(DataList data) {
        VLayout layout  = new VLayout();
        container       = new HLayout();
        Canvas modeForm = createModePanel();

        container.setMembersMargin(30);

        // the initial panel is the Single-W panel.
        double[] values = getSingleQ();
        qArrayPanel = new DoubleArrayPanel(
            MESSAGE.unitQSingle(), values, this);
        container.addMember(qArrayPanel);

        layout.addMember(modeForm);
        layout.addMember(container);

        return layout;
    }


    /**
     * This method creates the mode panel. It contains two radio button panels
     * that allows the user to switch the input mode between w/q and
     * single/range input.
     *
     * @return a panel.
     */
    protected Canvas createModePanel() {
        RadioGroupItem wq = new RadioGroupItem(FIELD_WQ);
        wq.setShowTitle(false);
        wq.setVertical(false);
        wq.setWidth(WIDTH_LEFT_UPPER);
        wq.setWrap(false);

        RadioGroupItem mode = new RadioGroupItem(FIELD_MODE);
        mode.setShowTitle(false);
        mode.setVertical(false);
        mode.setWidth(WIDTH_LEFT_LOWER);

        LinkedHashMap wqValues = new LinkedHashMap();
        wqValues.put(FIELD_WQ_W, MESSAGE.wqW());
        wqValues.put(FIELD_WQ_Q, MESSAGE.wqQ());
        wqValues.put(FIELD_WQ_Q_GAUGE, MESSAGE.wqQGauge());

        LinkedHashMap modeValues = new LinkedHashMap();
        modeValues.put(FIELD_MODE_SINGLE, MESSAGE.wqSingle());
        modeValues.put(FIELD_MODE_RANGE, MESSAGE.wqRange());

        wq.setValueMap(wqValues);
        mode.setValueMap(modeValues);

        wq.addChangeHandler(this);
        mode.addChangeHandler(this);

        modes = new DynamicForm();
        modes.setFields(wq, mode);
        modes.setWidth(WIDTH_LEFT_UPPER);
        modes.setNumCols(1);

        LinkedHashMap initial = new LinkedHashMap();
        initial.put(FIELD_WQ, FIELD_WQ_Q_GAUGE);
        initial.put(FIELD_MODE, FIELD_MODE_SINGLE);
        modes.setValues(initial);

        return modes;
    }


    @Override
    public List<String> validate() {
        if (isRangeMode()) {
            return validateRangeValues();
        }
        else {
            return validateSingleValues();
        }
    }


    protected List<String> validateRangeValues() {
        if (isWMode()) {
            return validateRange(wRangePanel, minW, maxW);
        }
        else {
            return validateRange(qRangePanel, minQ, maxQ);
        }
    }


    protected List<String> validateSingleValues() {
        if (isWMode()) {
            return validateSingle(wArrayPanel, minW, maxW);
        }
        else {
            return validateSingle(qArrayPanel, minQ, maxQ);
        }
    }


    protected List<String> validateRange(
        DoubleRangePanel panel,
        double min, double max)
    {
        List<String> errors = new ArrayList<String>();
        NumberFormat nf     = NumberFormat.getDecimalFormat();

        if (!panel.validateForm()) {
            errors.add(MESSAGE.wrongFormat());
        }

        double from = panel.getFrom();
        double to   = panel.getTo();
        double step = panel.getStep();

        if (from < min || from > max) {
            String tmp = MESSAGE.error_validate_lower_range();
            tmp = tmp.replace("$1", nf.format(from));
            tmp = tmp.replace("$2", nf.format(min));
            errors.add(tmp);
            from = min;
        }

        if (to < min || to > max) {
            String tmp = MESSAGE.error_validate_upper_range();
            tmp = tmp.replace("$1", nf.format(to));
            tmp = tmp.replace("$2", nf.format(max));
            errors.add(tmp);
            to = max;
        }

        if (!errors.isEmpty()) {
            panel.setValues(from, to, step);
        }

        return errors;
    }


    protected List<String> validateSingle(
        DoubleArrayPanel panel,
        double min, double max)
    {
        List<String> errors = new ArrayList<String>();
        NumberFormat nf     = NumberFormat.getDecimalFormat();

        if (!panel.validateForm()) {
            errors.add(MESSAGE.wrongFormat());
        }

        double[] values = panel.getInputValues();
        double[] good   = new double[values.length];
        int      idx    = 0;

        for (double value: values) {
            if (value < min || value > max) {
                String tmp = MESSAGE.error_validate_range();
                tmp = tmp.replace("$1", nf.format(value));
                tmp = tmp.replace("$2", nf.format(min));
                tmp = tmp.replace("$3", nf.format(max));
                errors.add(tmp);
            }
            else {
                good[idx++] = value;
            }
        }

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

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

        return errors;
    }


    /**
     * This method returns the selected data.
     *
     * @return the selected/inserted data.
     */
    public Data[] getData() {
        // XXX If we have entered a value and click right afterwards on the
        // 'next' button, the BlurEvent is not fired, and the values are not
        // saved. So, we gonna save those values explicitly.
        if (!isRangeMode()) {
            Canvas member = container.getMember(0);
            if (member instanceof DoubleArrayPanel) {
                DoubleArrayPanel form = (DoubleArrayPanel) member;
                if (isWMode()) {
                    saveSingleWValues(form);
                }
                else {
                    saveSingleQValues(form);
                }
            }

            return getSingleData();
        }
        else {
            Canvas member = container.getMember(0);
            if (member instanceof DoubleRangePanel) {
                DoubleRangePanel form = (DoubleRangePanel) member;

                if (isWMode()) {
                    saveRangeWValues(form);
                }
                else {
                    saveRangeQValues(form);
                }
            }

            return getRangeData();
        }
    }


    /**
     * Collects the required data for single mode and resets the data for range
     * mode.
     */
    protected Data[] getSingleData() {
        DataItem from = new DefaultDataItem("wq_from", "wq_from", "");
        DataItem to   = new DefaultDataItem("wq_to", "wq_to", "");
        DataItem step = new DefaultDataItem("wq_step", "wq_step", "");

        return new Data[] {
                getDataMode(),
                getQMode(),
                getDataSelectionMode(),
                getDataSingle(),
                new DefaultData(
                    "wq_from",
                    null,
                    null,
                    new DataItem[] {from}),
                new DefaultData(
                    "wq_to",
                    null,
                    null,
                    new DataItem[] {to}),
                new DefaultData(
                    "wq_step",
                    null,
                    null,
                    new DataItem[] {step}) };
    }


    /**
     * Collects the required data for range mode and resets the data for single
     * mode.
     */
    protected Data[] getRangeData() {
        DataItem item = new DefaultDataItem("wq_single", "wq_single", "");

        return new Data[] {
                getDataMode(),
                getQMode(),
                getDataSelectionMode(),
                getDataFrom(),
                getDataTo(),
                getDataStep(),
                new DefaultData(
                    "wq_single",
                    null,
                    null,
                    new DataItem[] {item}) };
    }


    /**
     * Returns the Data object for the 'mode' attribute.
     *
     * @return the Data object for the 'mode' attribute.
     */
    protected Data getDataMode() {
        String wqMode = modes.getValueAsString(FIELD_WQ);

        String value = null;
        if (wqMode.equals(FIELD_WQ_Q) || wqMode.equals(FIELD_WQ_Q_GAUGE)) {
            value = FIELD_WQ_Q;
        }
        else {
            value = FIELD_WQ_W;
        }

        DataItem item = new DefaultDataItem("wq_mode", "wq_mode", value);
        return new DefaultData(
            "wq_mode", null, null, new DataItem[] { item });
    }


    /**
     * Returns the Q mode. The Q mode can be "true" or "false". True means, the
     * calculation is not based on a gauge, false means the calculation should
     * be based on a gauge.
     *
     * @return the Data object for the 'wq_free' attribute.
     */
    protected Data getQMode() {
        String value = isQFree() ? "true" : "false";

        DataItem item = new DefaultDataItem("wq_free", "wq_free", value);
        return new DefaultData(
            "wq_free", null, null, new DataItem[] { item });
    }


    /**
     * Returns the Data object for the 'mode' attribute.
     *
     * @return the Data object for the 'mode' attribute.
     */
    protected Data getDataSelectionMode() {
        String wqSelection = modes.getValueAsString(FIELD_MODE);
        DataItem item = new DefaultDataItem(
            "wq_selection", "wq_selection", wqSelection);

        return new DefaultData(
            "wq_selection", null, null, new DataItem[] { item });
    }


    /**
     * Returns the data object for the 'single' attribute.
     *
     * @return the Data object for the 'single' attribute.
     */
    protected Data getDataSingle() {
        double[] values  = getFinalSingle();
        StringBuilder sb = new StringBuilder();
        for (double value: values) {
            sb.append(Double.toString(value));
            sb.append(" ");
        }

        DataItem item = new DefaultDataItem(
            "wq_single", "wq_single", sb.toString());

        return new DefaultData(
            "wq_single", null, null, new DataItem[] { item });
    }


    /**
     * Returns the Data object for the 'from' attribute.
     *
     * @return the Data object for the 'from' attribute.
     */
    protected Data getDataFrom() {
        String value  = Double.valueOf(getFinalFrom()).toString();
        DataItem item = new DefaultDataItem("wq_from", "wq_from", value);
        return new DefaultData(
            "wq_from", null, null, new DataItem[] { item });
    }


    /**
     * Returns the Data object for the 'to' attribute.
     *
     * @return the Data object for the 'to' attribute.
     */
    protected Data getDataTo() {
        String value  = Double.valueOf(getFinalTo()).toString();
        DataItem item = new DefaultDataItem("wq_to", "wq_to", value);
        return new DefaultData(
            "wq_to", null, null, new DataItem[] { item });
    }


    /**
     * Returns the Data object for the 'step' attribute.
     *
     * @return the Data object for the 'step' attribute.
     */
    protected Data getDataStep() {
        String value  = Double.valueOf(getFinalStep()).toString();
        DataItem item = new DefaultDataItem("wq_step","wq_step", value);
        return new DefaultData(
            "wq_step", null, null, new DataItem[] { item });
    }


    protected double[] getFinalSingle() {
        boolean wMode = isWMode();

        return wMode ? getSingleW() : getSingleQ();
    }


    /**
     * Returns the value of 'from' depending on the selected input mode.
     *
     * @return the value of 'from' depending on the selected input mode.
     */
    protected double getFinalFrom() {
        boolean wMode     = isWMode();
        boolean rangeMode = isRangeMode();

        if (rangeMode) {
            return wMode ? getFromW() : getFromQ();

        }
        else {
            double[] values = wMode ? getSingleW() : getSingleQ();
            double   value  = Double.MAX_VALUE;

            for (double v: values) {
                value = value < v ? value : v;
            }

            return value;
        }
    }


    /**
     * Returns the value of 'to' depending on the selected input mode.
     *
     * @return the value of 'to' depending on the selected input mode.
     */
    protected double getFinalTo() {
        boolean wMode     = isWMode();
        boolean rangeMode = isRangeMode();

        if (rangeMode) {
            return wMode ? getToW() : getToQ();

        }
        else {
            double[] values = wMode ? getSingleW() : getSingleQ();
            double   value  = Double.MIN_VALUE;

            for (double v: values) {
                value = value > v ? value : v;
            }

            return value;
        }
    }


    /**
     * Returns the value of 'step' depending on the selected input mode.
     *
     * @return the value of 'step' depending on the selected input mode.
     */
    protected double getFinalStep() {
        boolean wMode     = isWMode();
        boolean rangeMode = isRangeMode();

        if (rangeMode) {
            return wMode ? getStepW() : getStepQ();
        }
        else {
            // we have no field to enter the 'step' attribute in the
            // single mode
            return 0d;
        }
    }


    /**
     * Determines the range/single mode.
     *
     * @return true if the range mode is activated.
     */
    public boolean isRangeMode() {
        String rMode = modes.getValueAsString(FIELD_MODE);

        return rMode.equals(FIELD_MODE_RANGE);
    }


    /**
     * Determines the w/q mode.
     *
     * @return true, if the W mode is activated.
     */
    public boolean isWMode() {
        String wq = modes.getValueAsString(FIELD_WQ);
        return wq.equals(FIELD_WQ_W);
    }


    public boolean isQFree() {
        String wqMode = modes.getValueAsString(FIELD_WQ);
        return wqMode.equals(FIELD_WQ_Q);
    }


    /**
     * This method changes the lower panel with the input fields depending on
     * the combination of the two radio button panels.
     *
     * @param event The ChangeEvent.
     */
    public void onChange(ChangeEvent event) {
        DynamicForm form = event.getForm();
        FormItem    item = event.getItem();

        String wqMode    = null;
        String inputMode = null;

        if (item.getFieldName().equals(FIELD_MODE)) {
            wqMode    = form.getValueAsString(FIELD_WQ);
            inputMode = (String) event.getValue();
        }
        else {
            wqMode    = (String) event.getValue();
            inputMode = form.getValueAsString(FIELD_MODE);
        }

        if (wqMode.equals("Q")) {
            qdTable.hideIconFields();
        }
        else {
            qdTable.showIconFields();
        }

        updatePanels(wqMode, inputMode);
    }


    protected void updatePanels(String wqMode, String inputMode) {
        container.removeMembers(container.getMembers());

        if (wqMode.equals(FIELD_WQ_W)) {
            if (inputMode.equals(FIELD_MODE_SINGLE)) {
                // Single W mode
                double[] values = getSingleW();

                wArrayPanel = new DoubleArrayPanel(
                    MESSAGE.unitWSingle(), values, this);

                container.addMember(wArrayPanel);
            }
            else {
                // Range W mode
                double from = getFromW();
                double to   = getToW();
                double step = getStepW();

                wRangePanel = new DoubleRangePanel(
                    MESSAGE.unitWFrom(), MESSAGE.unitWTo(), MESSAGE.unitWStep(),
                    from, to, step,
                    250,
                    this);
                container.addMember(wRangePanel);
            }

            tabs.selectTab(0);
        }
        else {
            if (inputMode.equals(FIELD_MODE_SINGLE)) {
                // Single Q mode
                double[] values = getSingleQ();

                qArrayPanel = new DoubleArrayPanel(
                    MESSAGE.unitQSingle(), values, this);
                container.addMember(qArrayPanel);
            }
            else {
                // Range Q mode
                double from = getFromQ();
                double to   = getToQ();
                double step = getStepQ();

                qRangePanel = new DoubleRangePanel(
                    MESSAGE.unitQFrom(), MESSAGE.unitQTo(), MESSAGE.unitQStep(),
                    from, to, step,
                    250,
                    this);
                container.addMember(qRangePanel);
            }

            tabs.selectTab(1);
        }
    }

    /**
     * This method is called if the value of one of the input fields might have
     * changed. The entered values are validated and stored.
     *
     * @param event The BlurEvent.
     */
    public void onBlur(BlurEvent event) {
        DynamicForm form = event.getForm();
        FormItem    item = event.getItem();

        String wqMode    = (String) modes.getValue(FIELD_WQ);
        String inputMode = (String) modes.getValue(FIELD_MODE);

        if (wqMode.equals(FIELD_WQ_W)) {
            if (inputMode.equals(FIELD_MODE_SINGLE)) {
                DoubleArrayPanel p = (DoubleArrayPanel) form;
                saveSingleWValue(p, item);
            }
            else {
                DoubleRangePanel p = (DoubleRangePanel) form;
                saveRangeWValue(p, item);
            }
        }
        else {
            if (inputMode.equals(FIELD_MODE_SINGLE)) {
                DoubleArrayPanel p = (DoubleArrayPanel) form;
                saveSingleQValue(p, item);
            }
            else {
                DoubleRangePanel p = (DoubleRangePanel) form;
                saveRangeQValue(p, item);
            }
        }
    }


    protected void saveSingleWValues(DoubleArrayPanel p) {
        FormItem[] formItems = p.getFields();

        for (FormItem item: formItems) {
            if (item.getFieldName().equals(DoubleArrayPanel.FIELD_NAME)) {
                saveSingleWValue(p, item);
            }
        }
    }


    protected void saveSingleQValues(DoubleArrayPanel p) {
        FormItem[] formItems = p.getFields();

        for (FormItem item: formItems) {
            if (item.getFieldName().equals(DoubleArrayPanel.FIELD_NAME)) {
                saveSingleQValue(p, item);
            }
        }
    }


    protected void saveSingleWValue(DoubleArrayPanel p, FormItem item) {
        if (p.validateForm(item)) {
            setSingleW(p.getInputValues(item));
        }
    }


    protected void saveSingleQValue(DoubleArrayPanel p, FormItem item) {
        if (p.validateForm(item)) {
            setSingleQ(p.getInputValues(item));
        }
    }


    protected void saveRangeWValues(DoubleRangePanel p) {
        FormItem[] formItems = p.getFields();

        for (FormItem item: formItems) {
            saveRangeWValue(p, item);
        }
    }


    protected void saveRangeQValues(DoubleRangePanel p) {
        FormItem[] formItems = p.getFields();

        for (FormItem item: formItems) {
            saveRangeQValue(p, item);
        }
    }


    protected void saveRangeWValue(DoubleRangePanel p, FormItem item) {
        if (p.validateForm(item)) {
            setFromW(p.getFrom());
            setToW(p.getTo());
            setStepW(p.getStep());
        }
    }


    protected void saveRangeQValue(DoubleRangePanel p, FormItem item) {
        if (p.validateForm(item)) {
            setFromQ(p.getFrom());
            setToQ(p.getTo());
            setStepQ(p.getStep());
        }
    }


    protected double[] getSingleQ() {
        return valuesQ;
    }


    protected void setSingleQ(double[] values) {
        valuesQ = values;
    }


    protected double getFromQ() {
        return fromQ;
    }


    protected void setFromQ(double fromQ) {
        this.fromQ = fromQ;
    }


    protected double getToQ() {
        return toQ;
    }


    protected void setToQ(double toQ) {
        this.toQ = toQ;
    }


    protected double getStepQ() {
        return stepQ;
    }


    protected void setStepQ(double stepQ) {
        this.stepQ = stepQ;
    }


    protected double[] getSingleW() {
        return valuesW;
    }


    protected void setSingleW(double[] values) {
        valuesW = values;
    }


    protected double getFromW() {
        return fromW;
    }


    protected void setFromW(double fromW) {
        this.fromW = fromW;
    }


    protected double getToW() {
        return toW;
    }


    protected void setToW(double toW) {
        this.toW = toW;
    }


    protected double getStepW() {
        return stepW;
    }


    protected void setStepW(double stepW) {
        this.stepW = stepW;
    }


    /**
     * Determines the min and max kilometer value selected in a former state. A
     * bit silly, but we need to run over each value of the "old data" to find
     * such values because it is not available here.
     *
     * @param data The DataList which contains the whole data inserted for the
     * current artifact.
     *
     * @return a double array with [min, max].
     */
    protected double[] getMinMaxKM(DataList[] data) {
        ArtifactDescription adesc = artifact.getArtifactDescription();
        return adesc.getKMRange();
    }


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


    protected void fetchWQData() {
        Config config    = Config.getInstance();
        String url       = config.getServerUrl();
        String locale    = config.getLocale ();

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

        double[]  mm = getMinMaxKM(data);
        String river = getRiverName(data);

        wqInfoService.getWQInfo(url, locale, river, mm[0], mm[1],
            new AsyncCallback<WQInfoObject[]>() {
                public void onFailure(Throwable caught) {
                    GWT.log("Could not recieve wq informations.");
                    SC.warn(caught.getMessage());
                }

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

                    if (num == 0) {
                        return;
                    }

                    addWQInfo(wqi);

                    String wq = (String) modes.getValue(FIELD_WQ);
                    String sr = (String) modes.getValue(FIELD_MODE);
                    updatePanels(wq, sr);
                }
            }
        );
    }


    protected void addWQInfo (WQInfoObject[] wqi) {
        for(WQInfoObject wi: wqi) {
            WQInfoRecord rec = new WQInfoRecord(wi);

            if (wi.getType().equals("W")) {
                wTable.addData(rec);
            }
            else {
                qdTable.addData(rec);
            }
        }
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org