view gwt-client/src/main/java/org/dive4elements/river/client/client/ui/ParameterMatrix.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 2da486c7c05f
children
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.io.Serializable;
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.ParameterMatrix.Column.SelectionMode;
import org.dive4elements.river.client.shared.model.DataItem;
import org.dive4elements.river.client.shared.model.IntegerOptionsData;
import org.dive4elements.river.client.shared.model.MultiAttributeData;
import org.dive4elements.river.client.shared.model.MultiDataItem;
import org.dive4elements.river.client.shared.model.StringOptionsData;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.Widget;
import com.smartgwt.client.types.ListGridFieldType;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.grid.events.ChangedHandler;

/**
 * Some parameters take the form of on/off options that can also be seen
 * as a matrix.
 *
 * This class helps to survive the underlying objects and create a visual
 * representation of this matrix. Later can happen in two ways to overcome
 * shortcomings of GWT/SmartGWT combination.
 */
public class ParameterMatrix {

    protected static ListGrid listGrid = null;

    public static class Column implements Serializable {

        private static final long serialVersionUID = -3493426383086860118L;

        public static enum SelectionMode {
            single, multi
        }

        protected String name;
        protected Map<String, String> values;

        private Column() {
            this.values = new HashMap<String, String>();
        }

        public Column(final String name) {
            this();
            this.name = name;
        }

        public void addValue(final String label, final String value) {
            this.values.put(label, value);
        }

        public String getValue(final String label) {
            return this.values.get(label);
        }
    } // end of class Column

    /** The message class that provides i18n strings. */
    protected FLYSConstants MESSAGE = GWT.create(FLYSConstants.class);

    public static final int CELL_HEIGHT = 25;

    private final Map<String, Column> columns;
    private final List<String> columnNames;
    private final List<String> valueNames;
    private final Map<String, List<String>> attributes;

    /** Maps column names to list of rows' first fields. */
    private final Map<String, List<String>> selected;
    private final String itemname;
    private final SelectionMode mode;

    public ParameterMatrix(final String itemnameColTitle, final SelectionMode mode) {
        super();
        this.mode = mode;
        this.itemname = itemnameColTitle;
        this.columns = new HashMap<String, Column>();
        this.columnNames = new ArrayList<String>();
        this.valueNames = new ArrayList<String>();
        this.selected = new HashMap<String, List<String>>();
        this.attributes = new HashMap<String, List<String>>();
    }

    public void addColumn(final IntegerOptionsData group) {
        final String groupTitle = group.getLabel();

        final Column col = new Column(groupTitle);
        final DataItem[] items = group.getItems();

        if (items == null) {
            GWT.log("No items found in StringOptionsData '" + groupTitle + "'");
            return;
        }

        for (final DataItem item : items) {
            final String title = item.getLabel();

            if (this.valueNames.indexOf(title) < 0) {
                this.valueNames.add(title);
            }

            col.addValue(item.getLabel(), item.getStringValue());
        }

        this.columnNames.add(groupTitle);
        this.columns.put(groupTitle, col);
    }

    public List<String> getColumnNames() {
        return this.columnNames;
    }

    public void addColumn(final StringOptionsData options) {
        final String groupTitle = options.getLabel();

        final Column col = new Column(groupTitle);
        final DataItem[] items = options.getItems();

        if (items == null) {
            GWT.log("No items found in StringOptionsData '" + groupTitle + "'");
            return;
        }

        for (final DataItem item : items) {
            final String title = item.getLabel();

            if (this.valueNames.indexOf(title) < 0) {
                this.valueNames.add(title);
            }

            col.addValue(item.getLabel(), item.getStringValue());
        }

        this.columnNames.add(groupTitle);
        this.columns.put(groupTitle, col);
    }

    public void addColumn(final MultiAttributeData options) {
        GWT.log("Add Columns for MultiAttribute data");
        final String groupTitle = options.getLabel();

        final Column col = new Column(groupTitle);
        final DataItem[] items = options.getItems();

        if (items == null) {
            GWT.log("No items found in StringOptionsData '" + groupTitle + "'");
            return;
        }

        final MultiDataItem mItem = (MultiDataItem) items[0];
        for (final Map.Entry<String, String> entry : mItem.getValue().entrySet()) {
            if (entry.getKey().equals("art:value") || entry.getKey().equals("art:label")) {
                continue;
            }
            this.attributes.put(entry.getKey(), new ArrayList<String>());
        }
        for (final DataItem item : items) {
            GWT.log("multidataitem: " + item.getLabel());
            final String title = item.getLabel();

            if (this.valueNames.indexOf(title) < 0) {
                this.valueNames.add(title);
            }
            final MultiDataItem mi = (MultiDataItem) item;
            final Map<String, String> vs = mi.getValue();
            for (final Map.Entry<String, String> e : vs.entrySet()) {
                if (e.getKey().equals("art:value") || e.getKey().equals("art:label")) {
                    continue;
                }
                final List<String> data = this.attributes.get(e.getKey());
                data.add(e.getValue());
            }
            col.addValue(item.getLabel(), mi.getValue().get("art:value"));
        }

        this.columnNames.add(groupTitle);
        this.columns.put(groupTitle, col);
    }

    public Widget createParameterGrid() {
        this.listGrid = new ListGrid();
        this.listGrid.setShowAllRecords(true);
        this.listGrid.setWrapCells(true);
        this.listGrid.setShowHeaderContextMenu(false);
        this.listGrid.setCanReorderFields(false);
        // listGrid.setCanSort(false);
        // listGrid.setAutoFitData(Autofit.VERTICAL);
        this.listGrid.setFixedRecordHeights(false);
        // TODO: Then also need "autofit" (when wrapping)

        final ListGridField itemNameField = new ListGridField("itemname", this.itemname);
        final ArrayList<ListGridField> fields = new ArrayList<ListGridField>();
        fields.add(itemNameField);

        for (final Map.Entry<String, List<String>> entry : this.attributes.entrySet()) {
            final ListGridField attrField = new ListGridField(entry.getKey(), this.MESSAGE.getString(entry.getKey()));
            fields.add(attrField);
        }

        for (int i = 0, n = this.columnNames.size(); i < n; i++) {
            final ListGridField field = new ListGridField(this.columnNames.get(i), this.MESSAGE.getString(this.columnNames.get(i)));
            field.setType(ListGridFieldType.BOOLEAN);
            field.setCanEdit(true);
            if (this.mode == SelectionMode.single) {
                field.addChangedHandler(new ChangedHandler() {
                    @Override
                    public void onChanged(final com.smartgwt.client.widgets.grid.events.ChangedEvent event) {
                        final int rowNumber = event.getRowNum();
                        final Boolean value = (Boolean) event.getValue();
                        final int colNr = event.getColNum();
                        final String attr = ParameterMatrix.listGrid.getFieldName(colNr);
                        if (value) {
                            final ListGridRecord[] records = ParameterMatrix.listGrid.getRecords();
                            for (int i = 0; i < records.length; i++) {
                                final ListGridRecord r = records[i];
                                if (i != rowNumber) {
                                    if (r.getAttributeAsBoolean(attr))
                                        r.setAttribute(attr, false);
                                }
                            }
                        }
                    }
                });
            }
            fields.add(field);
            this.selected.put(this.columnNames.get(i), new ArrayList<String>());
        }

        final ListGridField[] fieldsArray = fields.toArray(new ListGridField[fields.size()]);
        this.listGrid.setFields(fieldsArray);

        final int nVals = this.valueNames.size();

        final ArrayList<ListGridRecord> records = new ArrayList<ListGridRecord>();
        for (int j = 0; j < nVals; j++) {
            final String valueName = this.valueNames.get(j);
            final ListGridRecord record = new ListGridRecord();
            record.setAttribute("itemname", valueName);
            for (int i = 0, n = this.columnNames.size(); i < n; i++) {
                final String columnName = this.columnNames.get(i);
                final Column col = this.columns.get(columnName);
                final String value = col.getValue(valueName);
                record.setAttribute(columnName, false);
                record.setAttribute(columnName + "-value", value);
            }
            for (final Map.Entry<String, List<String>> entry : this.attributes.entrySet()) {
                record.setAttribute(entry.getKey(), entry.getValue().get(j));
            }
            records.add(record);
        }

        this.listGrid.setData(records.toArray(new ListGridRecord[records.size()]));

        return this.listGrid;

    }

    /**
     * Returns a widget with matrix of checkboxes and labels.
     *
     * @param asListGrid
     *            if true, use a ListGrid (for inclusion in SmartGWT
     *            containers, avoiding scrollbar-issues.
     */
    public Widget create(final boolean asListGrid) {
        if (asListGrid) {
            return createParameterGrid();
        }
        final Grid grid = new Grid(this.valueNames.size() + 1, this.columnNames.size() + 1);

        for (int i = 0, n = this.columnNames.size(); i < n; i++) {
            final String columnName = this.columnNames.get(i);
            final Column col = this.columns.get(columnName);

            this.selected.put(columnName, new ArrayList<String>());

            grid.setWidget(0, i + 1, createLabel(this.MESSAGE.getString(columnName)));

            for (int j = 0, o = this.valueNames.size(); j < o; j++) {
                final String valueName = this.valueNames.get(j);
                final String value = col.getValue(valueName);

                if (i == 0) {
                    grid.setWidget(j + 1, 0, createLabel(valueName));
                }

                if (value != null && value.length() > 0) {
                    grid.setWidget(j + 1, i + 1, createCheckBox(columnName, value));
                }
            }
        }

        return grid;
    }

    /** Creates label with given text. */
    protected Label createLabel(final String text) {
        final Label label = new Label(text);
        label.setHeight(CELL_HEIGHT);

        return label;
    }

    /** Create Checkbox for column/value. */
    protected Canvas createCheckBox(final String colName, final String value) {
        final CheckBox box = new CheckBox();
        box.addClickHandler(new ClickHandler() {

            @Override
            public void onClick(final ClickEvent event) {
                final Map<String, List<String>> selection = getSelection();

                final List<String> values = selection.get(colName);
                if (values.indexOf(value) >= 0) {
                    values.remove(value);
                } else {
                    values.add(value);
                }
            }
        });

        final Canvas c = new Canvas();
        c.addChild(box);
        return c;
    }

    public Map<String, List<String>> getSelection() {
        if (this.listGrid == null) {
            return this.selected;
        }

        final ListGridRecord[] records = this.listGrid.getRecords();
        final Map<String, List<String>> result = new HashMap<String, List<String>>();
        for (final ListGridRecord record : records) {
            for (int i = 0, n = this.columnNames.size(); i < n; i++) {
                final String columnName = this.columnNames.get(i);
                if (Boolean.valueOf(record.getAttribute(columnName)) == true) {
                    if (result.containsKey(columnName)) {
                        result.get(columnName).add(record.getAttribute(columnName + "-value"));
                    } else {
                        final List<String> items = new ArrayList<String>();
                        items.add(record.getAttribute(columnName + "-value"));
                        result.put(columnName, items);
                    }
                }
            }
        }
        return result;
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org