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; felix@4116: felix@4116: import com.google.gwt.core.client.GWT; felix@4116: import com.google.gwt.i18n.client.NumberFormat; felix@4116: import com.google.gwt.user.client.rpc.AsyncCallback; felix@4116: felix@4116: import com.smartgwt.client.types.TitleOrientation; felix@4116: import com.smartgwt.client.types.VerticalAlignment; felix@4116: import com.smartgwt.client.util.SC; felix@4116: import com.smartgwt.client.widgets.Canvas; felix@4116: import com.smartgwt.client.widgets.Label; christian@4184: import com.smartgwt.client.widgets.form.fields.events.BlurEvent; felix@4116: import com.smartgwt.client.widgets.form.fields.events.BlurHandler; christian@4184: import com.smartgwt.client.widgets.form.fields.events.ChangeEvent; felix@4116: import com.smartgwt.client.widgets.form.fields.events.ChangeHandler; felix@4116: import com.smartgwt.client.widgets.layout.HLayout; felix@4116: import com.smartgwt.client.widgets.layout.VLayout; christian@4184: import com.smartgwt.client.widgets.tab.Tab; felix@4116: import com.smartgwt.client.widgets.tab.TabSet; felix@4116: teichmann@5835: import org.dive4elements.river.client.client.Config; teichmann@5835: import org.dive4elements.river.client.client.FLYSConstants; teichmann@5835: import org.dive4elements.river.client.client.services.WQInfoService; teichmann@5835: import org.dive4elements.river.client.client.services.WQInfoServiceAsync; teichmann@5835: import org.dive4elements.river.client.client.ui.wq.QDTable; teichmann@5835: import org.dive4elements.river.client.client.ui.wq.WTable; teichmann@5835: import org.dive4elements.river.client.shared.model.ArtifactDescription; teichmann@5835: import org.dive4elements.river.client.shared.model.Data; teichmann@5835: import org.dive4elements.river.client.shared.model.DataItem; teichmann@5835: import org.dive4elements.river.client.shared.model.DataList; teichmann@5835: import org.dive4elements.river.client.shared.model.DefaultData; teichmann@5835: import org.dive4elements.river.client.shared.model.DefaultDataItem; teichmann@5835: import org.dive4elements.river.client.shared.model.WQDataItem; teichmann@5835: import org.dive4elements.river.client.shared.model.WQInfoObject; teichmann@5835: import org.dive4elements.river.client.shared.model.WQInfoRecord; felix@4116: christian@4184: import java.util.ArrayList; christian@4184: import java.util.HashMap; christian@4184: import java.util.List; christian@4184: import java.util.Map; felix@4116: felix@4116: felix@4116: /** felix@4116: * This UIProvider creates a widget to enter Q values per segment. felix@4116: */ felix@4116: public class QSegmentedInputPanel felix@4116: extends AbstractUIProvider felix@4116: implements ChangeHandler, BlurHandler felix@4116: { christian@4184: christian@4184: private static final long serialVersionUID = -8627825064071479905L; christian@4184: felix@4116: public static final String FIELD_WQ_MODE = "wq_isq"; felix@4116: public static final String FIELD_WQ_Q = "Q"; felix@4116: felix@4116: public static final String GAUGE_SEPARATOR = ":"; felix@4116: felix@4116: public static final String GAUGE_PART_SEPARATOR = ";"; felix@4116: felix@4116: public static final String VALUE_SEPARATOR = ","; felix@4116: felix@4116: public static final int ROW_HEIGHT = 20; felix@4116: felix@4116: /** The constant field name for choosing single values or range.*/ felix@4116: public static final String FIELD_MODE = "mode"; felix@4116: felix@4116: /** The constant field value for range input mode.*/ felix@4116: public static final String FIELD_MODE_RANGE = "range"; felix@4116: felix@4116: protected WQInfoServiceAsync wqInfoService = felix@4116: GWT.create(WQInfoService.class); felix@4116: felix@4116: /** The message class that provides i18n strings.*/ felix@4116: protected FLYSConstants MSG = GWT.create(FLYSConstants.class); felix@4116: felix@4116: /** Stores the input panels related to their keys.*/ felix@4116: protected Map wqranges; felix@4116: felix@4116: /** Stores the min/max values for each q range.*/ felix@4116: protected Map qranges; felix@4116: felix@4116: protected QDTable qdTable; felix@4116: felix@4116: protected WTable wTable; felix@4116: felix@4116: protected TabSet tabs; felix@4116: felix@4116: felix@4116: public QSegmentedInputPanel() { felix@4116: wqranges = new HashMap(); felix@4116: qranges = new HashMap(); felix@4116: qdTable = new QDTable(); felix@4116: wTable = new WTable(); felix@4116: } felix@4116: felix@4116: felix@4116: /** Create main UI Canvas. */ christian@4184: @Override felix@4116: public Canvas create(DataList data) { felix@4116: initHelperPanel(); felix@4116: felix@4116: Canvas submit = getNextButton(); felix@4116: Canvas widget = createWidget(data); felix@4116: Label label = new Label(MSG.wqadaptedTitle()); felix@4116: felix@4116: label.setHeight(25); felix@4116: felix@4116: VLayout layout = new VLayout(); felix@4116: layout.setMembersMargin(10); felix@4116: layout.setWidth(350); felix@4116: felix@4116: layout.addMember(label); felix@4116: layout.addMember(widget); felix@4116: layout.addMember(submit); felix@4116: felix@4116: return layout; felix@4116: } felix@4116: felix@4116: felix@4116: protected void initHelperPanel() { felix@4116: tabs = new TabSet(); felix@4116: tabs.setWidth100(); felix@4116: tabs.setHeight100(); felix@4116: felix@4116: // TODO i18n felix@4116: Tab qTab = new Tab("Q / D"); felix@4116: felix@4116: qTab.setPane(qdTable); felix@4116: qdTable.hideIconFields(); felix@4116: felix@4116: tabs.addTab(qTab, 1); felix@4116: felix@4116: helperContainer.addMember(tabs); felix@4116: felix@4116: // TODO Q only would suffice. felix@4116: fetchWQData(); felix@4116: } felix@4116: felix@4116: felix@4116: /** Create display for passive mode. */ christian@4184: @Override felix@4116: public Canvas createOld(DataList dataList) { felix@4116: List all = dataList.getAll(); felix@4116: Data wqData = getData(all, "ranges"); felix@4116: felix@4116: Canvas back = getBackButton(dataList.getState()); felix@4116: felix@4116: HLayout valLayout = new HLayout(); felix@4116: VLayout vlayout = new VLayout(); felix@4116: Label wqLabel = new Label(dataList.getLabel()); felix@4116: felix@4116: wqLabel.setValign(VerticalAlignment.TOP); felix@4116: felix@4116: wqLabel.setWidth(200); felix@4116: wqLabel.setHeight(25); felix@4116: felix@4116: valLayout.addMember(wqLabel); felix@4116: valLayout.addMember(createOldWQValues(wqData)); felix@4116: valLayout.addMember(back); felix@4116: felix@4116: vlayout.addMember(valLayout); felix@4116: felix@4116: return vlayout; felix@4116: } felix@4116: felix@4116: felix@4116: /** Create canvas showing previously entered values. */ felix@4116: protected Canvas createOldWQValues(Data wqData) { felix@4116: VLayout layout = new VLayout(); felix@4116: felix@4116: //TODO: Sort by first field, numerically. felix@4116: felix@4116: DataItem item = wqData.getItems()[0]; felix@4116: String value = item.getStringValue(); felix@4116: felix@4116: String[] gauges = value.split(GAUGE_SEPARATOR); felix@4116: felix@4116: for (String gauge: gauges) { felix@4116: HLayout h = new HLayout(); felix@4116: felix@4116: String[] parts = gauge.split(GAUGE_PART_SEPARATOR); rrenkert@5104: String[] values = parts[3].split(VALUE_SEPARATOR); felix@4116: felix@4116: Label l = new Label(parts[0] + " - " + parts[1] + ": "); felix@4116: felix@4116: StringBuilder sb = new StringBuilder(); felix@4116: boolean first = true; felix@4116: felix@4116: for (String v: values) { felix@4116: if (!first) { felix@4116: sb.append(", "); felix@4116: } felix@4116: felix@4116: sb.append(v); felix@4116: felix@4116: first = false; felix@4116: } felix@4116: felix@4116: Label v = new Label(sb.toString()); felix@4116: felix@4116: l.setWidth(65); felix@4116: v.setWidth(65); felix@4116: felix@4116: h.addMember(l); felix@4116: h.addMember(v); felix@4116: felix@4116: layout.addMember(h); felix@4116: } felix@4116: felix@4116: return layout; felix@4116: } felix@4116: felix@4116: felix@4116: protected Canvas createWidget(DataList dataList) { felix@4116: VLayout layout = new VLayout(); felix@4116: felix@4116: Canvas list = createList(dataList); felix@4116: felix@4116: DataItem[] items = getWQItems(dataList); felix@4116: int listHeight = ROW_HEIGHT * items.length; felix@4116: felix@4116: layout.addMember(list); felix@4116: felix@4116: layout.setHeight(25 + listHeight); felix@4116: layout.setWidth(350); felix@4116: felix@4116: return layout; felix@4116: } felix@4116: felix@4116: felix@4116: @Override felix@4116: public List validate() { felix@4116: List errors = new ArrayList(); felix@4116: NumberFormat nf = NumberFormat.getDecimalFormat(); felix@4116: teichmann@6100: for (Map.Entry entry: wqranges.entrySet()) { felix@4116: teichmann@6100: String key = entry.getKey(); teichmann@6100: DoubleArrayPanel dap = entry.getValue(); felix@4116: felix@4116: if (!dap.validateForm()) { felix@4116: errors.add(MSG.error_invalid_double_value()); felix@4116: return errors; felix@4116: } felix@4116: felix@4116: double[] mm = qranges.get(key); felix@4116: if (mm == null) { felix@4116: SC.warn(MSG.error_read_minmax_values()); felix@4116: continue; felix@4116: } felix@4116: teichmann@6100: List tmpErrors = new ArrayList(); felix@4116: double[] values = dap.getInputValues(); felix@4116: // might geht npe here if one field not filled felix@4116: double[] good = new double[values.length]; felix@4116: felix@4116: int idx = 0; felix@4116: felix@4116: for (double value: values) { felix@4116: if (value < mm[0] || value > mm[1]) { felix@4116: String tmp = MSG.error_validate_range(); felix@4116: tmp = tmp.replace("$1", nf.format(value)); felix@4116: tmp = tmp.replace("$2", nf.format(mm[0])); felix@4116: tmp = tmp.replace("$3", nf.format(mm[1])); felix@4116: tmpErrors.add(tmp); felix@4116: } felix@4116: else { felix@4116: good[idx++] = value; felix@4116: } felix@4116: } felix@4116: felix@4116: double[] justGood = new double[idx]; felix@4116: for (int i = 0; i < justGood.length; i++) { felix@4116: justGood[i] = good[i]; felix@4116: } felix@4116: felix@4116: if (!tmpErrors.isEmpty()) { felix@4116: dap.setValues(justGood); felix@4116: felix@4116: errors.addAll(tmpErrors); felix@4116: } felix@4116: } felix@4116: felix@4116: return errors; felix@4116: } felix@4116: felix@4116: felix@4116: protected Canvas createList(DataList dataList) { felix@4116: VLayout layout = new VLayout(); felix@4116: felix@4116: DataItem[] items = getWQItems(dataList); felix@4116: felix@4116: for (DataItem item: items) { felix@4116: String title = item.getLabel(); felix@4116: felix@4116: DoubleArrayPanel dap = new DoubleArrayPanel( tom@8856: createLineTitle(title), tom@8856: null, tom@8856: this, tom@8856: null, tom@8856: TitleOrientation.LEFT); felix@4116: felix@4116: wqranges.put(title, dap); felix@4116: felix@4116: if (item instanceof WQDataItem) { felix@4116: WQDataItem wq = (WQDataItem) item; felix@4116: double[] mmQ = wq.getQRange(); felix@4116: felix@4116: qranges.put(title, mmQ); felix@4116: } felix@4116: felix@4116: layout.addMember(dap); felix@4116: } felix@4116: felix@4116: layout.setHeight(items.length * ROW_HEIGHT); felix@4116: felix@4116: return layout; felix@4116: } felix@4116: felix@4116: felix@4116: protected DataItem[] getWQItems(DataList dataList) { felix@4116: List data = dataList.getAll(); felix@4116: felix@4116: for (Data d: data) { felix@4116: String name = d.getLabel(); felix@4116: felix@4116: // TODO to be gone felix@4116: if (name.equals(FIELD_WQ_MODE)) { felix@4116: continue; felix@4116: } felix@4116: felix@4116: return d.getItems(); felix@4116: } felix@4116: felix@4116: return null; felix@4116: } felix@4116: felix@4116: felix@4116: felix@4116: public String createLineTitle(String key) { felix@4116: String[] splitted = key.split(";"); felix@4116: felix@4116: return splitted[0] + " - " + splitted[1]; felix@4116: } felix@4116: felix@4116: christian@4184: @Override felix@4116: public Data[] getData() { felix@4116: Data values = getWQValues(); felix@4116: felix@4116: return new Data[] { values }; felix@4116: } felix@4116: felix@4116: felix@4116: protected Data getWQValues() { felix@4116: String wqvalue = null; felix@4116: teichmann@6100: for (Map.Entry entry: wqranges.entrySet()) { teichmann@6100: String key = entry.getKey(); teichmann@6100: DoubleArrayPanel dap = entry.getValue(); felix@4116: felix@4116: double[] values = dap.getInputValues(); felix@4116: if (wqvalue == null) { rrenkert@5104: wqvalue = createValueString(key + "; ", values); felix@4116: } felix@4116: else { tom@8856: wqvalue += GAUGE_SEPARATOR tom@8856: + createValueString(key + "; ", values); felix@4116: } felix@4116: } felix@4116: felix@4116: // TODO probably ranges felix@4116: DataItem valueItem = new DefaultDataItem( felix@4116: "ranges", "ranges", wqvalue); felix@4116: Data values = new DefaultData( felix@4116: "ranges", null, null, new DataItem[] { valueItem }); felix@4116: felix@4116: return values; felix@4116: } felix@4116: felix@4116: felix@4116: protected String createValueString(String key, double[] values) { felix@4116: StringBuilder sb = new StringBuilder(); felix@4116: felix@4116: boolean first = true; felix@4116: felix@4116: for (double value: values) { felix@4116: if (!first) { felix@4116: sb.append(","); felix@4116: } felix@4116: felix@4116: sb.append(Double.toString(value)); felix@4116: felix@4116: first = false; felix@4116: } felix@4116: felix@4116: return key + ";" + sb.toString(); felix@4116: } felix@4116: felix@4116: christian@4184: @Override felix@4116: public void onChange(ChangeEvent event) { felix@4116: // TODO IMPLEMENT ME felix@4116: } felix@4116: felix@4116: christian@4184: @Override felix@4116: public void onBlur(BlurEvent event) { felix@4116: DoubleArrayPanel dap = (DoubleArrayPanel) event.getForm(); felix@4116: dap.validateForm(event.getItem()); felix@4116: } felix@4116: felix@4116: felix@4116: protected void fetchWQData() { felix@4116: Config config = Config.getInstance(); felix@4116: String locale = config.getLocale (); felix@4116: felix@4116: ArtifactDescription adescr = artifact.getArtifactDescription(); felix@4116: DataList[] data = adescr.getOldData(); felix@4116: felix@4116: double[] mm = getMinMaxKM(data); felix@4116: String river = getRiverName(data); felix@4116: felix@4116: wqInfoService.getWQInfo(locale, river, mm[0], mm[0], felix@4116: new AsyncCallback() { christian@4184: @Override felix@4116: public void onFailure(Throwable caught) { felix@6556: GWT.log("Could not receive wq informations."); felix@4116: SC.warn(caught.getMessage()); felix@4116: } felix@4116: christian@4184: @Override felix@4116: public void onSuccess(WQInfoObject[] wqi) { felix@4116: int num = wqi != null ? wqi.length :0; felix@6556: GWT.log("Received " + num + " wq informations."); felix@4116: felix@4116: if (num == 0) { felix@4116: return; felix@4116: } felix@4116: felix@4116: addWQInfo(wqi); felix@4116: felix@4116: } felix@4116: } felix@4116: ); felix@4116: } felix@4116: felix@4116: felix@4116: protected void addWQInfo (WQInfoObject[] wqi) { felix@4116: for(WQInfoObject wi: wqi) { felix@4116: WQInfoRecord rec = new WQInfoRecord(wi); felix@4116: felix@4116: if (wi.getType().equals("W")) { felix@4116: wTable.addData(rec); felix@4116: } felix@4116: else { felix@4116: qdTable.addData(rec); felix@4116: } felix@4116: } felix@4116: } felix@4116: felix@4116: felix@4116: /** felix@4116: * Determines the min and max kilometer value selected in a former state. A felix@4116: * bit silly, but we need to run over each value of the "old data" to find felix@4116: * such values because it is not available here. felix@4116: * felix@4116: * @param data The DataList which contains the whole data inserted for the felix@4116: * current artifact. felix@4116: * felix@4116: * @return a double array with [min, max]. felix@4116: */ felix@4116: protected double[] getMinMaxKM(DataList[] data) { felix@4116: ArtifactDescription adesc = artifact.getArtifactDescription(); felix@4116: return adesc.getKMRange(); felix@4116: } felix@4116: felix@4116: felix@4116: /** felix@4116: * Returns the name of the selected river. felix@4116: * felix@4116: * @param data The DataList with all data. felix@4116: * felix@4116: * @return the name of the current river. felix@4116: */ felix@4116: protected String getRiverName(DataList[] data) { felix@4116: ArtifactDescription adesc = artifact.getArtifactDescription(); felix@4116: return adesc.getRiver(); felix@4116: } felix@4116: } felix@4116: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :