teichmann@5861: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5861: * Software engineering by Intevation GmbH teichmann@5861: * teichmann@5861: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5861: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5861: * documentation coming with Dive4Elements River for details. teichmann@5861: */ teichmann@5861: teichmann@5835: package org.dive4elements.river.client.client.ui; felix@1612: felix@1612: import com.google.gwt.core.client.GWT; felix@1612: import com.google.gwt.i18n.client.NumberFormat; felix@1612: christian@4184: import com.smartgwt.client.data.Record; felix@1612: import com.smartgwt.client.util.SC; felix@1612: import com.smartgwt.client.widgets.Canvas; felix@1612: import com.smartgwt.client.widgets.Label; christian@4184: import com.smartgwt.client.widgets.form.fields.events.BlurEvent; felix@1612: import com.smartgwt.client.widgets.form.fields.events.BlurHandler; rrenkert@4221: import com.smartgwt.client.widgets.grid.events.CellClickEvent; rrenkert@4221: import com.smartgwt.client.widgets.grid.events.CellClickHandler; felix@1612: import com.smartgwt.client.widgets.layout.HLayout; felix@1612: import com.smartgwt.client.widgets.layout.VLayout; felix@1612: teichmann@5835: import org.dive4elements.river.client.client.Config; teichmann@5835: import org.dive4elements.river.client.client.services.DistanceInfoService; teichmann@5835: import org.dive4elements.river.client.client.services.DistanceInfoServiceAsync; teichmann@5835: import org.dive4elements.river.client.client.ui.range.DistanceInfoDataSource; teichmann@5835: import org.dive4elements.river.client.shared.DoubleUtils; 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.DistanceInfoObject; teichmann@5835: import org.dive4elements.river.client.shared.model.RangeData; felix@1612: christian@4184: import java.util.ArrayList; christian@4184: import java.util.List; felix@1612: felix@1612: felix@1612: /** felix@1612: * This UIProvider creates a widget to enter a single location (km). felix@1612: * felix@1612: * @author Raimund Renkert felix@1612: */ felix@1612: public class MultipleLocationPanel felix@1612: extends LocationPanel rrenkert@4221: implements CellClickHandler felix@1612: { christian@4184: private static final long serialVersionUID = -3359966826794082718L; christian@4184: felix@1612: /** The DistanceInfoService used to retrieve locations about rivers. */ felix@1612: protected DistanceInfoServiceAsync distanceInfoService = felix@1612: GWT.create(DistanceInfoService.class); felix@1612: felix@1612: /** The table data. */ felix@1612: protected DistanceInfoObject[] tableData; felix@1612: felix@1612: /** The input helper (usually right side, table to click on, values are felix@1612: * then entered in the texfield. */ felix@1612: protected LocationPicker picker; felix@1612: felix@1615: felix@1612: /** felix@1612: * Creates a new LocationDistancePanel instance. felix@1612: */ felix@1612: public MultipleLocationPanel() { felix@1612: picker = new LocationPicker(this); felix@1612: } felix@1612: felix@1612: felix@1612: /** felix@1612: * This method creates a widget that contains a label, a panel with felix@1612: * checkboxes to switch the input mode between location and distance input, felix@1612: * and a mode specific panel. felix@1612: * felix@1612: * @param data The data that might be inserted. felix@1612: * felix@1612: * @return a panel. felix@1612: */ felix@1612: @Override felix@1612: public Canvas create(DataList data) { felix@1612: findDataItemName(data); felix@1612: felix@1612: VLayout layout = new VLayout(); felix@1612: layout.setMembersMargin(10); felix@1612: felix@1615: // Take translated data item name as label, if translation available. felix@1615: String labelString; felix@1615: try { felix@1615: labelString = MSG.getString(getDataItemName()); felix@1615: } felix@1615: catch(java.util.MissingResourceException mre) { felix@1615: GWT.log("Cannot find translation for data item name : " + getDataItemName()); raimund@3493: labelString = getLabelString(); felix@1615: } felix@1615: Label label = new Label(labelString); felix@1612: Canvas widget = createWidget(data); felix@1612: Canvas submit = getNextButton(); felix@1612: felix@1612: initDefaults(data); felix@1612: felix@1612: picker.createLocationTable(); felix@1612: felix@1612: widget.setHeight(50); felix@1612: label.setHeight(25); felix@1612: felix@1612: layout.addMember(label); felix@1612: layout.addMember(widget); felix@1612: layout.addMember(submit); felix@1612: felix@1612: return layout; felix@1612: } felix@1612: felix@1612: felix@1612: /** felix@1612: * This method reads the default values defined in the DataItems of the Data felix@1612: * objects in list. felix@1612: * felix@1612: * @param list The DataList container that stores the Data objects. felix@1612: */ christian@4184: @Override felix@1612: protected void initDefaults(DataList list) { felix@1612: Data data = list.get(0); felix@1612: felix@1612: // Compatibility with MinMax- DataItems: felix@1612: RangeData rangeData = null; felix@1612: felix@1612: for (int i = 0, n = list.size(); i < n; i++) { felix@1612: Data tmp = list.get(i); felix@1612: felix@1612: if (tmp instanceof RangeData) { felix@1612: rangeData = (RangeData) tmp; felix@1612: } felix@1612: } felix@1612: felix@1612: if (rangeData != null) { felix@1612: min = Double.parseDouble(rangeData.getDefaultLower().toString()); felix@1612: max = Double.parseDouble(rangeData.getDefaultUpper().toString()); felix@1612: // catch ..? felix@1612: } felix@1612: else { felix@1612: DataItem[] items = data.getItems(); felix@1612: DataItem iMin = getDataItem(items, "min"); felix@1612: DataItem iMax = getDataItem(items, "max"); sascha@2905: felix@1612: try { felix@1612: min = Double.parseDouble(iMin.getStringValue()); felix@1612: max = Double.parseDouble(iMax.getStringValue()); felix@1612: } felix@1612: catch (NumberFormatException nfe) { felix@1612: SC.warn(MSG.error_read_minmax_values()); felix@1612: min = -Double.MAX_VALUE; felix@1612: max = Double.MAX_VALUE; felix@1612: } felix@1612: } felix@1612: felix@1612: DataItem def = data.getDefault(); felix@1612: if (def != null) { felix@1612: String value = def.getStringValue(); felix@1612: felix@1612: try { felix@1612: double d = Double.parseDouble(value); felix@1612: setLocationValues(new double[] { d } ); felix@1612: } felix@1612: catch (NumberFormatException nfe) { felix@1612: // could not parse, dont know what to do else felix@1612: } felix@1612: } felix@1612: } felix@1612: felix@1612: christian@4184: @Override felix@1612: protected Canvas createWidget(DataList data) { felix@1612: VLayout layout = new VLayout(); felix@1612: inputLayout = new HLayout(); felix@1612: felix@1612: // The initial view will display the location input mode. felix@1612: locationPanel = new DoubleArrayPanel( felix@1612: MSG.unitLocation(), felix@1612: getLocationValues(), christian@4184: new BlurHandler(){@Override christian@4184: public void onBlur(BlurEvent be) {validate();}}); felix@1612: felix@1612: picker.getLocationTable().setAutoFetchData(true); felix@1612: felix@1612: inputLayout.addMember(locationPanel); felix@1612: felix@1612: layout.addMember(inputLayout); felix@1612: felix@1612: inputLayout.setMembersMargin(30); felix@1612: felix@1612: picker.prepareFilter(); felix@1612: felix@1612: helperContainer.addMember(picker.getLocationTable()); felix@1612: helperContainer.addMember(picker.getFilterLayout()); felix@1612: helperContainer.addMember(picker.getResultCountForm()); felix@1612: setPickerDataSource(); felix@1612: return layout; felix@1612: } felix@1612: felix@1612: felix@1612: /** Overridden to restrict to one entered value. */ felix@1612: @Override felix@1612: public List validate() { felix@1612: List errors = new ArrayList(); felix@1612: NumberFormat nf = NumberFormat.getDecimalFormat(); felix@1612: raimund@3539: DataList[] ref = artifact.getArtifactDescription().getOldData(); raimund@3539: String mode = ref[1].get(0).getStringValue(); raimund@3539: felix@1612: saveLocationValues(locationPanel); felix@1612: felix@1612: if (!locationPanel.validateForm()) { felix@1612: errors.add(MSG.wrongFormat()); felix@1612: return errors; felix@1612: } felix@1612: felix@1618: double[] lValues = getLocationValues(); felix@1618: double[] good = new double[lValues.length]; felix@1612: int idx = 0; felix@1612: raimund@3539: double reference = raimund@3539: Double.valueOf(ref[2].get(0).getStringValue()).doubleValue(); felix@1618: for (double value: lValues) { raimund@3539: if (mode.equals("calc.reference.curve") && raimund@3539: value == reference) { raimund@3539: errors.add(MSG.error_contains_same_location()); raimund@3539: return errors; raimund@3539: } felix@1612: if (value < min || value > max) { felix@1612: String tmp = MSG.error_validate_range(); felix@1612: tmp = tmp.replace("$1", nf.format(value)); felix@1612: tmp = tmp.replace("$2", nf.format(min)); felix@1612: tmp = tmp.replace("$3", nf.format(max)); felix@1612: errors.add(tmp); felix@1612: } felix@1612: else { felix@1612: good[idx++] = value; felix@1612: } felix@1612: } felix@1612: felix@1612: double[] justGood = new double[idx]; felix@1612: for (int i = 0; i < justGood.length; i++) { felix@1612: justGood[i] = good[i]; felix@1612: } felix@1612: felix@1612: if (!errors.isEmpty()) { felix@1612: locationPanel.setValues(justGood); felix@1612: } felix@1612: felix@1612: return errors; felix@1612: } felix@1612: felix@1612: felix@1612: /** felix@1615: * This method returns the selected data (to feed). felix@1612: * felix@1615: * @return the selected/inserted data in feedable form. felix@1612: */ christian@4184: @Override felix@1612: public Data[] getData() { felix@1612: saveLocationValues(locationPanel); felix@1618: double[] lValues = getLocationValues(); felix@1612: Data[] data = new Data[2]; felix@1612: boolean first = true; felix@1612: String valueString = ""; felix@1612: felix@1618: for (int i = 0; i < lValues.length; i++) { felix@1612: if (!first) valueString += " "; felix@1612: else first = false; felix@1618: valueString += Double.valueOf(lValues[i]).toString(); felix@1612: } felix@1612: felix@1612: data[0] = createDataArray(getDataItemName(), valueString); felix@1612: felix@1612: data[1] = createDataArray("ld_mode", "locations"); felix@1612: felix@1612: return data; felix@1612: } felix@1612: felix@1612: felix@1612: /** Hook service to the listgrid with possible input values. */ felix@1612: protected void setPickerDataSource() { felix@1612: Config config = Config.getInstance(); felix@1612: String url = config.getServerUrl(); felix@1612: String river = ""; felix@1612: felix@1612: ArtifactDescription adescr = artifact.getArtifactDescription(); felix@1612: DataList[] data = adescr.getOldData(); felix@1612: felix@1612: // Try to find a "river" data item to set the source for the felix@1612: // list grid. raimund@2898: String dataFilter = "locations"; felix@1612: if (data != null && data.length > 0) { felix@1612: for (int i = 0; i < data.length; i++) { felix@1612: DataList dl = data[i]; raimund@2898: if (dl.getState().equals("state.minfo.river")) { raimund@2898: dataFilter = "measuringpoint"; raimund@2898: } felix@1612: if (dl.getState().equals("state.winfo.river") || raimund@2898: dl.getState().equals("state.chart.river") || raimund@2898: dl.getState().equals("state.minfo.river")) { felix@1612: for (int j = 0; j < dl.size(); j++) { felix@1612: Data d = dl.get(j); felix@1612: DataItem[] di = d.getItems(); felix@1612: if (di != null && di.length == 1) { felix@1612: river = d.getItems()[0].getStringValue(); felix@1612: break; felix@1612: } felix@1612: } felix@1612: } felix@1612: } felix@1612: } felix@1612: felix@1612: picker.getLocationTable().setDataSource(new DistanceInfoDataSource( raimund@2898: url, river, dataFilter)); felix@1612: } felix@1612: felix@1615: felix@1612: // TODO allow multiple selections here or in LocationPanel felix@1612: /** felix@1612: * Callback when an item from the input helper was clicked. felix@1612: * Set the respective km-value in the location value field. felix@1612: * @param e event passed. felix@1612: */ christian@4184: @Override rrenkert@4221: public void onCellClick (CellClickEvent e) { felix@1617: Record record = e.getRecord(); felix@1617: double[] old = getLocationValues(); felix@1617: double[] selected = DoubleUtils.copyOf(old, old.length + 1); felix@1612: try { felix@1617: selected[old.length] = felix@1612: Double.parseDouble(record.getAttribute("from")); felix@1612: } felix@1612: catch(NumberFormatException nfe) { felix@1612: // Is there anything else to do here? christian@4184: GWT.log(nfe.getMessage()); felix@1612: } raimund@3539: raimund@3539: // compare reference location and target location. raimund@3539: DataList[] ref = artifact.getArtifactDescription().getOldData(); raimund@3539: String mode = ref[1].get(0).getStringValue(); raimund@3539: if (mode.equals("calc.reference.curve") && raimund@3539: ref[2].get(0).getStringValue().equals(record.getAttribute("from"))) raimund@3539: { raimund@3539: SC.warn(MSG.error_same_location()); raimund@3539: return; raimund@3539: } raimund@3539: felix@1612: setLocationValues(selected); felix@1612: } raimund@3493: felix@4980: raimund@3493: /** raimund@3493: * Returns the label string for the input panel. raimund@3493: */ raimund@3493: protected String getLabelString() { raimund@3493: return MSG.location(); raimund@3493: } felix@1612: } felix@1612: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :