view gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DistancePanel.java @ 9064:28c50f5efceb

work on uinfo-vegetation-zones table
author gernotbelger
date Wed, 09 May 2018 16:31:12 +0200
parents 5e38e2924c07
children 8c0d1542c1d8
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.LinkedHashMap;
import java.util.List;

import org.dive4elements.river.client.client.Config;
import org.dive4elements.river.client.client.FLYSConstants;
import org.dive4elements.river.client.client.event.FilterHandler;
import org.dive4elements.river.client.client.event.RangeFilterEvent;
import org.dive4elements.river.client.client.event.StringFilterEvent;
import org.dive4elements.river.client.client.ui.range.DistanceInfoDataSource;
import org.dive4elements.river.client.client.ui.range.LocationsTable;
import org.dive4elements.river.client.client.ui.range.RangeTable;
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 com.google.gwt.core.client.GWT;
import com.google.gwt.i18n.client.NumberFormat;
import com.smartgwt.client.data.AdvancedCriteria;
import com.smartgwt.client.data.Criteria;
import com.smartgwt.client.data.Criterion;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.OperatorId;
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.SelectItem;
import com.smartgwt.client.widgets.form.fields.StaticTextItem;
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.ChangedEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.tab.Tab;
import com.smartgwt.client.widgets.tab.TabSet;
import com.smartgwt.client.widgets.tab.events.TabSelectedEvent;
import com.smartgwt.client.widgets.tab.events.TabSelectedHandler;

/** Panel to allow input of distance for calculation range. */
public class DistancePanel extends AbstractUIProvider implements BlurHandler, FilterHandler {

    private static final long serialVersionUID = -883142387908664588L;

    public static final int DEFAULT_STEP_WIDTH = 100;

    public static final String FIELD_LOWER = "ld_from";
    public static final String FIELD_UPPER = "ld_to";
    public static final String FIELD_STEP = "ld_step";

    protected FLYSConstants MSG = GWT.create(FLYSConstants.class);

    protected RangeTable distancesTable;
    protected LocationsTable locationsTable;

    protected DoubleRangePanel distancePanel;

    protected TableFilter filterDescription;
    protected RangeTableFilter filterRange;

    protected TabSet tabs;

    protected double min;
    protected double max;

    protected StaticTextItem filterResultCount;
    protected ListGrid currentFiltered;

    public DistancePanel() {
        this("right");
    }

    public DistancePanel(final String labelOrientation) {
        this.distancePanel = new DoubleRangePanel(labelFrom(), labelTo(), labelStep(), 0d, 0d, 0d, 250, this, labelOrientation);
    }

    @Override
    public Canvas create(final DataList data) {
        final VLayout layout = new VLayout();
        layout.setMembersMargin(10);

        final Label label = new Label(getLabel());

        final Canvas submit = getNextButton();

        label.setHeight(25);
        this.distancePanel.setHeight(50);

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

        initMinMaxValues(data);
        initDefaultValues(data);
        initHelperPanel();

        return layout;
    }

    @Override
    public Canvas createOld(final DataList dataList) {
        final String s = getOldSelectionString(dataList);
        final String l = dataList.getLabel();

        final Label label = new Label(l);
        final Label selected = new Label(s);

        final HLayout layout = new HLayout();

        layout.setWidth(400);
        label.setWidth(200);
        selected.setWidth(130);

        layout.addMember(label);
        layout.addMember(selected);
        layout.addMember(getBackButton(dataList.getState()));

        return layout;
    }

    protected String getOldSelectionString(final DataList dataList) {
        final List<Data> items = dataList.getAll();

        final Data dFrom = getData(items, getLowerField());
        final Data dTo = getData(items, getUpperField());
        final Data dStep = getData(items, getStepField());

        final DataItem[] from = dFrom.getItems();
        final DataItem[] to = dTo.getItems();
        final DataItem[] step = dStep.getItems();

        final StringBuilder sb = new StringBuilder();
        sb.append(from[0].getLabel());
        sb.append(" " + getUnitFrom() + " - ");
        sb.append(to[0].getLabel());
        sb.append(" " + getUnitTo() + " - ");
        sb.append(step[0].getLabel());
        sb.append(" " + getUnitStep());

        return sb.toString();
    }

    protected String getLabel() {
        return this.MSG.distance_state();
    }

    protected String labelFrom() {
        return getLabelFrom() + " [" + getUnitFrom() + "]";
    }

    protected String getLabelFrom() {
        return this.MSG.dpLabelFrom();
    }

    protected String getUnitFrom() {
        return this.MSG.dpUnitFrom();
    }

    protected String labelTo() {
        return getLabelTo() + " [" + getUnitTo() + "]";
    }

    protected String getLabelTo() {
        return this.MSG.dpLabelTo();
    }

    protected String getUnitTo() {
        return this.MSG.dpUnitTo();
    }

    protected String labelStep() {
        return getLabelStep() + " [" + getUnitStep() + "]";
    }

    protected String getLabelStep() {
        return this.MSG.dpLabelStep();
    }

    protected String getUnitStep() {
        return this.MSG.dpUnitStep();
    }

    protected String getLowerField() {
        return FIELD_LOWER;
    }

    protected String getUpperField() {
        return FIELD_UPPER;
    }

    protected String getStepField() {
        return FIELD_STEP;
    }

    @Override
    public List<String> validate() {
        final List<String> errors = new ArrayList<String>();

        if (!this.distancePanel.validateForm()) {
            errors.add(this.MSG.wrongFormat());

            return errors;
        }

        validateFrom(errors);
        validateTo(errors);

        return errors;
    }

    protected void validateFrom(final List<String> errors) {
        final double from = this.distancePanel.getFrom();

        if (from < this.min || from > this.max) {
            final NumberFormat nf = NumberFormat.getDecimalFormat();

            String tmp = this.MSG.error_validate_lower_range();
            tmp = tmp.replace("$1", nf.format(from));
            tmp = tmp.replace("$2", nf.format(this.min));

            this.distancePanel.setFrom(this.min);
            errors.add(tmp);
        }
    }

    protected void validateTo(final List<String> errors) {
        final double to = this.distancePanel.getTo();

        if (to < this.min || to > this.max) {
            final NumberFormat nf = NumberFormat.getDecimalFormat();

            String tmp = this.MSG.error_validate_upper_range();
            tmp = tmp.replace("$1", nf.format(to));
            tmp = tmp.replace("$2", nf.format(this.max));

            this.distancePanel.setTo(this.max);
            errors.add(tmp);
        }
    }

    @Override
    public Data[] getData() {
        final Data[] data = new Data[4];

        data[0] = getDataFrom();
        data[1] = getDataTo();
        data[2] = getDataStep();

        final DataItem item = new DefaultDataItem("ld_mode", "ld_mode", "distance");
        data[3] = new DefaultData("ld_mode", null, null, new DataItem[] { item });

        return data;
    }

    protected Data getDataFrom() {
        final String value = String.valueOf(this.distancePanel.getFrom());
        final String field = getLowerField();

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

    protected Data getDataTo() {
        final String value = String.valueOf(this.distancePanel.getTo());
        final String field = getUpperField();

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

    protected Data getDataStep() {
        final String value = String.valueOf(this.distancePanel.getStep());
        final String field = getStepField();

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

    @Override
    public void onBlur(final BlurEvent event) {
        this.distancePanel.validateForm();
    }

    protected void initMinMaxValues(final DataList data) {
        final Data f = getData(data.getAll(), getLowerField());
        final Data t = getData(data.getAll(), getUpperField());

        final DataItem[] fItems = f.getItems();
        final DataItem[] tItems = t.getItems();

        try {
            this.min = Double.valueOf(fItems[0].getStringValue());
            this.max = Double.valueOf(tItems[0].getStringValue());
        }
        catch (final NumberFormatException nfe) {
            this.min = -Double.MAX_VALUE;
            this.max = Double.MAX_VALUE;
        }
    }

    protected void initDefaultValues(final DataList data) {
        initDefaultFrom(data);
        initDefaultTo(data);
        initDefaultStep(data);
    }

    protected void initDefaultFrom(final DataList data) {
        final Data f = getData(data.getAll(), getLowerField());

        double from = getDefaultFrom();

        try {
            from = getDefaultValue(f);
        }
        catch (final NumberFormatException nfe) {
            // do nothing
        }

        this.distancePanel.setFrom(from);
    }

    protected double getDefaultFrom() {
        return this.min;
    }

    protected void initDefaultTo(final DataList data) {
        final Data t = getData(data.getAll(), getUpperField());

        double to = getDefaultTo();

        try {
            to = getDefaultValue(t);
        }
        catch (final NumberFormatException nfe) {
            // do nothing
        }

        this.distancePanel.setTo(to);
    }

    protected double getDefaultTo() {
        return this.max;
    }

    protected void initDefaultStep(final DataList data) {
        final Data s = getData(data.getAll(), getStepField());

        double step = getDefaultStep();

        try {
            step = getDefaultValue(s);
        }
        catch (final NumberFormatException nfe) {
            // do nothing
        }

        this.distancePanel.setStep(step);
    }

    protected double getDefaultStep() {
        return DEFAULT_STEP_WIDTH;
    }

    /** Gets the double from default in data, null if none. */
    protected double getDefaultValue(final Data data) throws NumberFormatException {
        final DataItem def = data.getDefault();
        final String defValue = def != null ? def.getStringValue() : null;

        return Double.valueOf(defValue);
    }

    protected void initHelperPanel() {
        this.distancesTable = new RangeTable();
        this.locationsTable = new LocationsTable();

        final Config config = Config.getInstance();
        final String url = config.getServerUrl();
        final String river = getRiverName();

        this.distancesTable.setAutoFetchData(true);
        this.locationsTable.setAutoFetchData(true);
        this.distancesTable.setDataSource(new DistanceInfoDataSource(url, river, "distances"));
        this.locationsTable.setDataSource(new DistanceInfoDataSource(url, river, "locations"));

        this.distancesTable.addRecordClickHandler(new RecordClickHandler() {
            @Override
            public void onRecordClick(final RecordClickEvent e) {
                final Record r = e.getRecord();

                final String from = r.getAttribute("from");
                final String to = r.getAttribute("to");

                try {
                    DistancePanel.this.distancePanel.setFrom(Double.valueOf(from));
                    DistancePanel.this.distancePanel.setTo(Double.valueOf(to));
                }
                catch (final NumberFormatException nfe) {
                    SC.warn(DistancePanel.this.MSG.wrongFormat());
                }
            }
        });

        this.locationsTable.addRecordClickHandler(new RecordClickHandler() {
            @Override
            public void onRecordClick(final RecordClickEvent e) {
                final Record r = e.getRecord();
                final int field = e.getFieldNum();

                try {
                    final String value = r.getAttribute("from");

                    switch (field) {
                    case 0:
                        DistancePanel.this.distancePanel.setFrom(Double.valueOf(value));
                        break;
                    case 1:
                        DistancePanel.this.distancePanel.setTo(Double.valueOf(value));
                        break;
                    }
                }
                catch (final NumberFormatException nfe) {
                    SC.warn(DistancePanel.this.MSG.wrongFormat());
                }
            }
        });

        this.tabs = new TabSet();
        this.tabs.setWidth100();
        this.tabs.setHeight100();

        final Tab locations = new Tab(this.MSG.locations());
        final Tab distances = new Tab(this.MSG.distance());

        locations.setPane(this.locationsTable);
        distances.setPane(this.distancesTable);

        this.tabs.addTab(locations, 0);
        this.tabs.addTab(distances, 1);

        this.filterResultCount = new StaticTextItem(this.MSG.resultCount());
        this.filterResultCount.setTitleAlign(Alignment.LEFT);
        this.filterResultCount.setTitleStyle("color: #000");

        this.filterDescription = new TableFilter();
        this.filterDescription.setHeight("30px");
        this.filterDescription.addFilterHandler(this);

        this.filterRange = new RangeTableFilter();
        this.filterRange.setHeight("30px");
        this.filterRange.addFilterHandler(this);
        this.filterRange.setVisible(false);

        final SelectItem filterCriteria = new SelectItem();
        filterCriteria.setShowTitle(false);
        filterCriteria.setWidth(100);
        filterCriteria.addChangedHandler(new ChangedHandler() {
            @Override
            public void onChanged(final ChangedEvent e) {
                if (e.getValue().toString().equals("range")) {
                    DistancePanel.this.filterRange.setVisible(true);
                    DistancePanel.this.filterDescription.setVisible(false);
                    DistancePanel.this.filterDescription.clear();
                } else {
                    DistancePanel.this.filterRange.setVisible(false);
                    DistancePanel.this.filterRange.clear();
                    DistancePanel.this.filterDescription.setVisible(true);
                }
            }
        });

        final LinkedHashMap<String, String> filterMap = new LinkedHashMap<String, String>();
        filterMap.put("description", this.MSG.description());
        filterMap.put("range", this.MSG.range());
        filterCriteria.setValueMap(filterMap);
        filterCriteria.setValue("description");

        final DynamicForm form = new DynamicForm();
        form.setFields(filterCriteria);

        final DynamicForm form2 = new DynamicForm();
        form2.setFields(this.filterResultCount);

        final HLayout filterLayout = new HLayout();
        filterLayout.addMember(form);
        filterLayout.addMember(this.filterDescription);
        filterLayout.addMember(this.filterRange);
        filterLayout.setHeight(30);
        this.tabs.addTabSelectedHandler(new TabSelectedHandler() {
            @Override
            public void onTabSelected(final TabSelectedEvent evt) {
                DistancePanel.this.filterDescription.clear();
                DistancePanel.this.filterRange.clear();
                DistancePanel.this.filterResultCount.setValue("");

                final Canvas c = evt.getTabPane();
                if (c instanceof ListGrid) {
                    DistancePanel.this.currentFiltered = (ListGrid) c;
                }
            }
        });

        this.helperContainer.addMember(this.tabs);
        this.helperContainer.addMember(filterLayout);
        this.helperContainer.addMember(form2);
    }

    @Override
    public void onFilterCriteriaChanged(final StringFilterEvent event) {
        final String search = event.getFilter();

        if (search != null && search.length() > 0) {
            final Criteria c = new Criteria("description", search);
            this.locationsTable.filterData(c);
            this.distancesTable.filterData(c);
            this.filterResultCount.setValue(this.currentFiltered.getRecords().length);
        } else {
            this.locationsTable.clearCriteria();
            this.distancesTable.clearCriteria();
            this.filterResultCount.setValue("");
        }
    }

    @Override
    public void onFilterCriteriaChanged(final RangeFilterEvent event) {
        final Float from = event.getFrom() - 0.001f;
        final Float to = event.getTo() + 0.001f;

        Criterion combinedFilter = null;
        Criterion locationFilter = null;

        if (from.equals(Float.NaN) && to.equals(Float.NaN)) {
            this.locationsTable.clearCriteria();
            this.distancesTable.clearCriteria();
            this.filterResultCount.setValue("");
            return;
        }

        if (from.equals(Float.NaN)) {
            combinedFilter = new Criterion("to", OperatorId.LESS_OR_EQUAL, to);

            locationFilter = new Criterion("from", OperatorId.LESS_OR_EQUAL, to);

            this.locationsTable.filterData(locationFilter);
            this.distancesTable.filterData(combinedFilter);
            this.filterResultCount.setValue(this.currentFiltered.getRecords().length);
            return;
        }

        if (to.equals(Float.NaN)) {
            combinedFilter = new Criterion("from", OperatorId.GREATER_OR_EQUAL, from);
        } else {
            final AdvancedCriteria c1 = new AdvancedCriteria(OperatorId.AND,
                    new Criterion[] { new Criterion("from", OperatorId.GREATER_OR_EQUAL, from), new Criterion("from", OperatorId.LESS_OR_EQUAL, to) });

            final AdvancedCriteria c2 = new AdvancedCriteria(OperatorId.AND,
                    new Criterion[] { new Criterion("to", OperatorId.GREATER_OR_EQUAL, from), new Criterion("to", OperatorId.LESS_OR_EQUAL, to) });

            final AdvancedCriteria c3 = new AdvancedCriteria(OperatorId.AND,
                    new Criterion[] { new Criterion("from", OperatorId.LESS_OR_EQUAL, to), new Criterion("to", OperatorId.GREATER_OR_EQUAL, from) });

            combinedFilter = new AdvancedCriteria(OperatorId.OR, new Criterion[] { c1, c2, c3 });
        }
        this.locationsTable.filterData(combinedFilter);
        this.distancesTable.filterData(combinedFilter);
        this.filterResultCount.setValue(this.currentFiltered.getRecords().length);

    }

    protected String getRiverName() {
        final ArtifactDescription adescr = this.artifact.getArtifactDescription();
        return adescr.getRiver();
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org