teichmann@5861: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
teichmann@5861: * Software engineering by Intevation GmbH
teichmann@5861: *
teichmann@5993: * This file is Free Software under the GNU AGPL (>=v3)
teichmann@5861: * and comes with ABSOLUTELY NO WARRANTY! Check out the
teichmann@5993: * documentation coming with Dive4Elements River for details.
teichmann@5861: */
teichmann@5861:
teichmann@5835: package org.dive4elements.river.client.client.ui;
ingo@243:
gernotbelger@9278: import java.util.ArrayList;
gernotbelger@9278: import java.util.HashMap;
gernotbelger@9278: import java.util.LinkedHashMap;
gernotbelger@9278: import java.util.List;
gernotbelger@9278: import java.util.Map;
gernotbelger@9278:
gernotbelger@9404: import org.dive4elements.river.client.client.Config;
gernotbelger@9278: import org.dive4elements.river.client.client.services.WQInfoService;
gernotbelger@9278: import org.dive4elements.river.client.client.services.WQInfoServiceAsync;
gernotbelger@9278: import org.dive4elements.river.client.client.ui.wq.QDTable;
gernotbelger@9278: import org.dive4elements.river.client.client.ui.wq.WTable;
gernotbelger@9404: import org.dive4elements.river.client.shared.model.ArtifactDescription;
gernotbelger@9278: import org.dive4elements.river.client.shared.model.Data;
gernotbelger@9278: import org.dive4elements.river.client.shared.model.DataItem;
gernotbelger@9278: import org.dive4elements.river.client.shared.model.DataList;
gernotbelger@9278: import org.dive4elements.river.client.shared.model.DefaultData;
gernotbelger@9278: import org.dive4elements.river.client.shared.model.DefaultDataItem;
gernotbelger@9278: import org.dive4elements.river.client.shared.model.WQDataItem;
gernotbelger@9278: import org.dive4elements.river.client.shared.model.WQInfoObject;
gernotbelger@9278:
ingo@243: import com.google.gwt.core.client.GWT;
ingo@565: import com.google.gwt.i18n.client.NumberFormat;
raimund@2456: import com.google.gwt.user.client.rpc.AsyncCallback;
ingo@246: import com.smartgwt.client.types.TitleOrientation;
ingo@247: import com.smartgwt.client.types.VerticalAlignment;
ingo@602: import com.smartgwt.client.util.SC;
ingo@243: import com.smartgwt.client.widgets.Canvas;
ingo@243: import com.smartgwt.client.widgets.Label;
ingo@255: import com.smartgwt.client.widgets.form.DynamicForm;
ingo@255: import com.smartgwt.client.widgets.form.fields.RadioGroupItem;
christian@4568: import com.smartgwt.client.widgets.form.fields.events.ChangeEvent;
ingo@243: import com.smartgwt.client.widgets.form.fields.events.ChangeHandler;
felix@5195: import com.smartgwt.client.widgets.form.fields.events.FocusEvent;
felix@5195: import com.smartgwt.client.widgets.form.fields.events.FocusHandler;
ingo@247: import com.smartgwt.client.widgets.layout.HLayout;
ingo@243: import com.smartgwt.client.widgets.layout.VLayout;
christian@4568: import com.smartgwt.client.widgets.tab.Tab;
ingo@243:
ingo@243: /**
ingo@243: * This UIProvider creates a widget to enter W or Q data for discharge
ingo@243: * longitudinal section computations.
ingo@243: *
ingo@243: * @author Ingo Weinzierl
ingo@243: */
gernotbelger@9288: public class WQAdaptedInputPanel extends AbstractWQAdaptedInputPanel implements FocusHandler {
christian@4568: private static final long serialVersionUID = -3218827566805476423L;
gernotbelger@9288: private static final String FIELD_WQ_MODE = "wq_isq";
gernotbelger@9288: private static final String FIELD_WQ_W = "W";
gernotbelger@9288: private static final String FIELD_WQ_Q = "Q";
ingo@565:
felix@5773: /** Stores the min/max values for each w range (gauge). */
gernotbelger@9288: private final Map wranges = new HashMap();
ingo@255:
gernotbelger@9288: /** Service to fetch W/Q MainValues. */
gernotbelger@9288: private final WQInfoServiceAsync wqInfoService = GWT.create(WQInfoService.class);
ingo@246:
felix@5195: /** The currently focussed Input element. */
gernotbelger@9288: private DoubleArrayPanel itemWithFocus;
felix@5195:
gernotbelger@9288: private void enableWTabs() {
gernotbelger@9288: for (int i = 0; i < this.doubleArrayPanels.size(); i++) {
gernotbelger@9288: this.tabs.disableTab(2 * i);
gernotbelger@9288: this.tabs.enableTab(2 * i + 1);
gernotbelger@9288: }
ingo@243: }
ingo@243:
gernotbelger@9288: private void enableQTabs() {
gernotbelger@9288: for (int i = 0; i < this.doubleArrayPanels.size(); i++) {
gernotbelger@9288: this.tabs.enableTab(2 * i);
gernotbelger@9288: this.tabs.disableTab(2 * i + 1);
gernotbelger@9288: }
gernotbelger@9288: }
ingo@243:
gernotbelger@9288: /**
gernotbelger@9288: * Create radio button for switching w and q input.
gernotbelger@9288: * Radiobutton-change also triggers helper panel tab selection.
gernotbelger@9288: */
ingo@243:
gernotbelger@9288: private final Canvas createMode(final DataList dataList) {
gernotbelger@9288: final RadioGroupItem wq = new RadioGroupItem(FIELD_WQ_MODE);
gernotbelger@9288: wq.setShowTitle(false);
gernotbelger@9288: wq.setVertical(false);
gernotbelger@9288: wq.setWidth(200);
ingo@243:
gernotbelger@9288: final LinkedHashMap wqValues = new LinkedHashMap();
gernotbelger@9288: wqValues.put(FIELD_WQ_W, this.MSG.wqW());
gernotbelger@9288: wqValues.put(WQAdaptedInputPanel.FIELD_WQ_Q, this.MSG.wqQatGauge());
felix@5773:
gernotbelger@9288: wq.setValueMap(wqValues);
felix@5773:
gernotbelger@9288: this.modes = new DynamicForm();
gernotbelger@9288: this.modes.setFields(wq);
gernotbelger@9288: this.modes.setWidth(200);
gernotbelger@9288: wq.addChangeHandler(new ChangeHandler() {
gernotbelger@9288: @Override
gernotbelger@9288: public void onChange(final ChangeEvent e) {
gernotbelger@9288: final DynamicForm form = e.getForm();
gernotbelger@9288:
gernotbelger@9288: if (form.getValueAsString(FIELD_WQ_MODE).contains("Q")) {
gernotbelger@9288: WQAdaptedInputPanel.this.tabs.selectTab(0);
gernotbelger@9288: enableQTabs();
gernotbelger@9288: } else {
gernotbelger@9288: WQAdaptedInputPanel.this.tabs.selectTab(1);
gernotbelger@9288: enableWTabs();
gernotbelger@9288: }
gernotbelger@9288: }
gernotbelger@9288: });
gernotbelger@9288:
gernotbelger@9288: final LinkedHashMap initial = new LinkedHashMap();
gernotbelger@9288: initial.put(FIELD_WQ_MODE, this.FIELD_WQ_Q);
gernotbelger@9288: this.modes.setValues(initial);
gernotbelger@9288: this.tabs.selectTab(1);
gernotbelger@9288: return this.modes;
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: @Override
gernotbelger@9288: protected void createTabs() {
gernotbelger@9288: for (int i = 0; i < this.gaugeRanges.size(); i++) {
gernotbelger@9288: // Later the tabs title will get adjusted to include gauges name.
gernotbelger@9288: // TODO the tabs title becomes rather long through that (i18n).
gernotbelger@9288:
gernotbelger@9288: final Tab wTab = new Tab(this.MSG.wq_table_w());
gernotbelger@9288: final WTable wTable = new WTable();
gernotbelger@9288: this.wTables.add(wTable);
gernotbelger@9288: wTable.showSelect();
gernotbelger@9288: wTab.setPane(wTable);
gernotbelger@9288:
gernotbelger@9288: final Tab qTab = new Tab(this.MSG.wq_table_q());
gernotbelger@9288: final QDTable qdTable = new QDTable();
gernotbelger@9288: this.qdTables.add(qdTable);
gernotbelger@9288: qTab.setPane(qdTable);
gernotbelger@9288: qdTable.showSelect();
gernotbelger@9288:
gernotbelger@9288: this.tabs.addTab(wTab, i * 2 + 0);
gernotbelger@9288: this.tabs.addTab(qTab, i * 2 + 1);
gernotbelger@9288:
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: // Defaults at "Q", first input field.
gernotbelger@9288: this.tabs.selectTab(0);
gernotbelger@9288: enableQTabs();
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: @Override
gernotbelger@9288: protected void beforeCreate(final DataList data) {
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: @Override
gernotbelger@9288: protected void afterCreate() {
felix@6413: // We actually want the first Q tab to be selected and all
felix@6413: // Q tabs to be enabled. I sense a bug in TabSet here, as
felix@6413: // the code in the W/Q radiogroup-changehandler behaves
felix@6413: // exactly vice versa (enabling Q, selecting tab 0).
felix@6413: enableWTabs();
gernotbelger@9278: this.tabs.selectTab(1);
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: @Override
gernotbelger@9288: protected Canvas createWidget(final DataList dataList) {
gernotbelger@9288: final VLayout layout = new VLayout();
gernotbelger@9288: final Canvas mode = createMode(dataList);
gernotbelger@9288: final Canvas list = createList(dataList);
gernotbelger@9288:
gernotbelger@9288: final List items = getWQItems(dataList);
gernotbelger@9288: final int listHeight = ROW_HEIGHT * items.size();
gernotbelger@9288:
gernotbelger@9288: mode.setHeight(25);
gernotbelger@9288: mode.setWidth(200);
gernotbelger@9288:
gernotbelger@9288: layout.addMember(mode);
gernotbelger@9288: layout.addMember(list);
gernotbelger@9288:
gernotbelger@9288: layout.setHeight(25 + listHeight);
gernotbelger@9288: layout.setWidth(350);
gernotbelger@9288:
gernotbelger@9288: initUserDefaults(dataList);
felix@6413:
ingo@243: return layout;
ingo@243: }
ingo@243:
gernotbelger@9288: private void initUserDefaults(final DataList dataList) {
gernotbelger@9288: initUserWQValues(dataList);
gernotbelger@9288: initUserWQMode(dataList);
raimund@2456: }
raimund@2456:
gernotbelger@9288: private void initUserWQMode(final DataList dataList) {
gernotbelger@9288: final List allData = dataList.getAll();
felix@5195:
gernotbelger@9288: final Data dDef = getData(allData, "wq_mode");
gernotbelger@9288: final DataItem def = dDef != null ? dDef.getDefault() : null;
gernotbelger@9288: final String value = def != null ? def.getStringValue() : null;
felix@6666:
gernotbelger@9288: if (value != null && value.equals(FIELD_WQ_W)) {
gernotbelger@9288: this.modes.setValue(FIELD_WQ_MODE, FIELD_WQ_W);
gernotbelger@9288: } else {
gernotbelger@9288: this.modes.setValue(FIELD_WQ_MODE, FIELD_WQ_Q);
felix@6666: }
felix@5195: }
felix@5195:
gernotbelger@9288: private Canvas createList(final DataList dataList) {
gernotbelger@9288: final VLayout layout = new VLayout();
gernotbelger@9288:
gernotbelger@9288: final List items = getWQItems(dataList);
gernotbelger@9288:
gernotbelger@9288: int i = 0;
gernotbelger@9288:
gernotbelger@9288: for (final DataItem item : items) {
gernotbelger@9288: if (item instanceof WQDataItem) {
gernotbelger@9288: final String title = item.getLabel(); // of form: 70.5;112.0
gernotbelger@9288: final String label = item.getStringValue();
gernotbelger@9288:
gernotbelger@9288: // Rename W and Q tab to include gauges name.
gernotbelger@9288: this.tabs.getTab(i * 2).setTitle(this.tabs.getTab(i * 2).getTitle() + " (" + label + ")");
gernotbelger@9288: this.tabs.getTab(i * 2 + 1).setTitle(this.tabs.getTab(i * 2 + 1).getTitle() + " (" + label + ")");
gernotbelger@9288:
gernotbelger@9288: final DoubleArrayPanel dap = new DoubleArrayPanel(label, null, this, this, TitleOrientation.LEFT);
gernotbelger@9288:
gernotbelger@9288: this.wqranges.put(title, dap);
gernotbelger@9288: this.doubleArrayPanels.add(dap);
gernotbelger@9288:
gernotbelger@9288: if (item instanceof WQDataItem) {
gernotbelger@9288: final WQDataItem wq = (WQDataItem) item;
gernotbelger@9288: final double[] mmQ = wq.getQRange();
gernotbelger@9288: final double[] mmW = wq.getWRange();
gernotbelger@9288:
gernotbelger@9288: this.qranges.put(title, mmQ);
gernotbelger@9288: this.wranges.put(title, mmW);
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: layout.addMember(dap);
gernotbelger@9288: i++;
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: layout.setHeight(items.size() * ROW_HEIGHT);
gernotbelger@9288:
gernotbelger@9288: return layout;
gernotbelger@9288: }
gernotbelger@9288:
christian@4568: @Override
gernotbelger@9288: public Canvas createOld(final DataList dataList) { // TODO: OVERRIDE
gernotbelger@9278: final List all = dataList.getAll();
gernotbelger@9278: final Data wqData = getData(all, "wq_values");
gernotbelger@9278: final Data wqMode = getData(all, "wq_isq");
gernotbelger@9278: final boolean isQ = wqMode.getItems()[0].getStringValue().equals("true");
gernotbelger@9278: final Canvas back = getBackButton(dataList.getState());
ingo@247:
gernotbelger@9278: final HLayout valLayout = new HLayout();
gernotbelger@9278: final HLayout modeLayout = new HLayout();
gernotbelger@9278: final VLayout vlayout = new VLayout();
ingo@247:
gernotbelger@9278: final Label wqLabel = new Label(dataList.getLabel());
gernotbelger@9278: final Label modeLabel = new Label("");
ingo@247:
ingo@247: wqLabel.setValign(VerticalAlignment.TOP);
ingo@247:
ingo@247: wqLabel.setWidth(200);
ingo@247: wqLabel.setHeight(25);
ingo@247: modeLabel.setHeight(25);
ingo@247: modeLabel.setWidth(200);
ingo@247:
ingo@247: valLayout.addMember(wqLabel);
felix@5154: valLayout.addMember(createOldWQValues(wqData, isQ));
felix@5154:
ingo@247: valLayout.addMember(back);
ingo@247: modeLayout.addMember(modeLabel);
ingo@247:
ingo@247: vlayout.addMember(valLayout);
ingo@247: vlayout.addMember(modeLayout);
ingo@247:
ingo@247: return vlayout;
ingo@247: }
ingo@247:
ingo@565: @Override
ingo@565: public List validate() {
ingo@565: if (isWMode()) {
ingo@565: return validateW();
gernotbelger@9278: } else {
ingo@565: return validateQ();
ingo@565: }
ingo@565: }
ingo@565:
gernotbelger@9288: private boolean isWMode() {
gernotbelger@9288: final String mode = (String) this.modes.getValue(FIELD_WQ_MODE);
gernotbelger@9288:
gernotbelger@9288: return FIELD_WQ_W.equals(mode);
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9278: protected List validateRange(final Map ranges) {
gernotbelger@9278: final List errors = new ArrayList();
gernotbelger@9278: final NumberFormat nf = NumberFormat.getDecimalFormat();
felix@5527:
gernotbelger@9278: for (final Map.Entry entry : this.wqranges.entrySet()) {
ingo@565:
gernotbelger@9278: final String key = entry.getKey();
gernotbelger@9278: final DoubleArrayPanel dap = entry.getValue();
ingo@602:
ingo@602: if (!dap.validateForm()) {
gernotbelger@9278: errors.add(this.MSG.error_invalid_double_value());
ingo@602: return errors;
ingo@602: }
ingo@602:
gernotbelger@9278: final double[] mm = ranges.get(key);
ingo@602: if (mm == null) {
gernotbelger@9278: SC.warn(this.MSG.error_read_minmax_values());
ingo@602: continue;
ingo@602: }
ingo@565:
gernotbelger@9278: final double[] values = dap.getInputValues();
gernotbelger@9278: final double[] good = new double[values.length];
ingo@565:
ingo@565: int idx = 0;
ingo@565:
gernotbelger@9278: final List tmpErrors = new ArrayList();
gernotbelger@9278: for (final double value : values) {
ingo@565: if (value < mm[0] || value > mm[1]) {
gernotbelger@9278: String tmp = this.MSG.error_validate_range();
ingo@565: tmp = tmp.replace("$1", nf.format(value));
ingo@565: tmp = tmp.replace("$2", nf.format(mm[0]));
ingo@565: tmp = tmp.replace("$3", nf.format(mm[1]));
ingo@565: tmpErrors.add(tmp);
gernotbelger@9278: } else {
ingo@565: good[idx++] = value;
ingo@565: }
ingo@565: }
ingo@565:
gernotbelger@9278: final double[] justGood = new double[idx];
ingo@565: for (int i = 0; i < justGood.length; i++) {
ingo@565: justGood[i] = good[i];
ingo@565: }
ingo@565:
ingo@565: if (!tmpErrors.isEmpty()) {
ingo@565: dap.setValues(justGood);
ingo@565:
ingo@565: errors.addAll(tmpErrors);
ingo@565: }
ingo@565: }
ingo@565:
ingo@565: return errors;
ingo@565: }
ingo@565:
gernotbelger@9288: private Data getWQMode() {
gernotbelger@9278: final String wqMode = this.modes.getValueAsString(FIELD_WQ_MODE);
ingo@2392: String value = "false";
ingo@2392: if (wqMode.equals("Q")) {
ingo@2392: value = "true";
ingo@2392: }
gernotbelger@9278: final DataItem item = new DefaultDataItem("wq_isq", "wq_isq", value);
gernotbelger@9278: final Data mode = new DefaultData("wq_isq", null, null, new DataItem[] { item });
ingo@243:
ingo@246: return mode;
ingo@246: }
ingo@246:
gernotbelger@9288: @Override
gernotbelger@9288: public Data[] getData() {
gernotbelger@9288: final Data mode = getWQMode();
gernotbelger@9288: final Data values = getWQValues("wq_values");
ingo@246:
gernotbelger@9288: return new Data[] { mode, values };
ingo@246: }
ingo@246:
gernotbelger@9288: private List validateW() {
gernotbelger@9288: return validateRange(this.wranges);
ingo@243: }
ingo@243:
gernotbelger@9288: private List validateQ() {
gernotbelger@9288: return validateRange(this.qranges);
ingo@243: }
ingo@243:
felix@5195: @Override
gernotbelger@9278: public void onFocus(final FocusEvent event) {
gernotbelger@9278: this.itemWithFocus = (DoubleArrayPanel) event.getForm();
felix@5773: // Switch to respective tab.
felix@5773: // TODO which makes a focus loss
gernotbelger@9278: final int inputIndex = this.doubleArrayPanels.indexOf(this.itemWithFocus);
gernotbelger@9278: this.tabs.selectTab(inputIndex * 2 + (isWMode() ? 0 : 1));
felix@5195: }
felix@5195:
gernotbelger@9288: protected void callMainValuesService(final String locale, final String river, final double start, final double end,
gernotbelger@9288: final AsyncCallback cb) {
gernotbelger@9288: this.wqInfoService.getWQInfo(locale, river, start, end, cb);
ingo@243: }
gernotbelger@9404:
gernotbelger@9404: @Override
gernotbelger@9404: protected void fetchWQData() {
gernotbelger@9404: {
gernotbelger@9404: final Config config = Config.getInstance();
gernotbelger@9404: final String locale = config.getLocale();
gernotbelger@9404:
gernotbelger@9404: final ArtifactDescription adescr = this.artifact.getArtifactDescription();
gernotbelger@9404: final DataList[] data = adescr.getOldData();
gernotbelger@9404:
gernotbelger@9404: final String river = getRiverName(data);
gernotbelger@9404:
gernotbelger@9404: int i = 0;
gernotbelger@9404:
gernotbelger@9404: // Get Data for respective gauge.
gernotbelger@9404: for (final Double[] range : this.gaugeRanges) {
gernotbelger@9404: // Gauge ranges overlap, move start and end a bit closer
gernotbelger@9404: // to each other.
gernotbelger@9404: final double rDiff = (range[1] - range[0]) / 10d;
gernotbelger@9404: final int fi = i;
gernotbelger@9404: // TODO: HIER MÜSSTE EIN SERVICE HIN, der den größten gemeinsamen zeitlichen Bereich der daily_discharge_values aller
gernotbelger@9404: // Pegel ermittelt
gernotbelger@9404:
gernotbelger@9404: final AsyncCallback cb = new AsyncCallback() {
gernotbelger@9404: @Override
gernotbelger@9404: public void onFailure(final Throwable caught) {
gernotbelger@9404: GWT.log("Could not recieve wq informations.");
gernotbelger@9404: SC.warn(caught.getMessage());
gernotbelger@9404: }
gernotbelger@9404:
gernotbelger@9404: @Override
gernotbelger@9404: public void onSuccess(final WQInfoObject[] wqi) {
gernotbelger@9404: final int num = wqi != null ? wqi.length : 0;
gernotbelger@9404: GWT.log("Received " + num + " wq informations (" + fi + ".");
gernotbelger@9404:
gernotbelger@9404: if (num == 0) {
gernotbelger@9404: return;
gernotbelger@9404: }
gernotbelger@9404:
gernotbelger@9404: addWQInfo(wqi, fi, null);
gernotbelger@9404: }
gernotbelger@9404: };
gernotbelger@9404:
gernotbelger@9404: callMainValuesService(locale, river, range[0] + rDiff, range[1] - rDiff, cb);
gernotbelger@9404:
gernotbelger@9404: i++;
gernotbelger@9404: }
gernotbelger@9404: }
gernotbelger@9404:
gernotbelger@9404: }
gernotbelger@9288: }