comparison gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractWQAdaptedInputPanel.java @ 9288:82c67b859aa7

bundu.bezugswst worklflow incl. service impl for mainValues to be calculated
author gernotbelger
date Tue, 24 Jul 2018 10:39:03 +0200
parents
children 6174daaf5e56
comparison
equal deleted inserted replaced
9287:6c88ad449c83 9288:82c67b859aa7
1 /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
2 * Software engineering by Intevation GmbH
3 *
4 * This file is Free Software under the GNU AGPL (>=v3)
5 * and comes with ABSOLUTELY NO WARRANTY! Check out the
6 * documentation coming with Dive4Elements River for details.
7 */
8
9 package org.dive4elements.river.client.client.ui;
10
11 import java.util.ArrayList;
12 import java.util.HashMap;
13 import java.util.List;
14 import java.util.Map;
15
16 import org.dive4elements.river.client.client.Config;
17 import org.dive4elements.river.client.client.FLYSConstants;
18 import org.dive4elements.river.client.client.ui.wq.QDTable;
19 import org.dive4elements.river.client.client.ui.wq.WTable;
20 import org.dive4elements.river.client.shared.model.ArtifactDescription;
21 import org.dive4elements.river.client.shared.model.Data;
22 import org.dive4elements.river.client.shared.model.DataItem;
23 import org.dive4elements.river.client.shared.model.DataList;
24 import org.dive4elements.river.client.shared.model.DefaultData;
25 import org.dive4elements.river.client.shared.model.DefaultDataItem;
26 import org.dive4elements.river.client.shared.model.WQDataItem;
27 import org.dive4elements.river.client.shared.model.WQInfoObject;
28 import org.dive4elements.river.client.shared.model.WQInfoRecord;
29
30 import com.google.gwt.core.client.GWT;
31 import com.google.gwt.user.client.rpc.AsyncCallback;
32 import com.smartgwt.client.data.Record;
33 import com.smartgwt.client.util.SC;
34 import com.smartgwt.client.widgets.Canvas;
35 import com.smartgwt.client.widgets.Label;
36 import com.smartgwt.client.widgets.form.DynamicForm;
37 import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
38 import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
39 import com.smartgwt.client.widgets.form.fields.events.ChangeEvent;
40 import com.smartgwt.client.widgets.form.fields.events.ChangeHandler;
41 import com.smartgwt.client.widgets.grid.events.CellClickEvent;
42 import com.smartgwt.client.widgets.grid.events.CellClickHandler;
43 import com.smartgwt.client.widgets.layout.HLayout;
44 import com.smartgwt.client.widgets.layout.VLayout;
45 import com.smartgwt.client.widgets.tab.TabSet;
46
47 /**
48 * This UIProvider creates a widget to enter W or Q data for discharge
49 * longitudinal section computations.
50 *
51 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
52 */
53 abstract public class AbstractWQAdaptedInputPanel extends AbstractUIProvider implements ChangeHandler, BlurHandler {
54 private static final long serialVersionUID = -3218827566805476423L;
55
56 /** The message class that provides i18n strings. */
57 protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
58 protected static final int ROW_HEIGHT = 20;
59
60 /** List of QDTables in inputhelper section. */
61 protected List<QDTable> qdTables;
62
63 private static final String GAUGE_SEPARATOR = ":";
64
65 private static final String GAUGE_PART_SEPARATOR = ";";
66
67 private static final String VALUE_SEPARATOR = ",";
68
69 /** Stores the input panels related to their keys. */
70 protected Map<String, DoubleArrayPanel> wqranges;
71
72 /** [startkm,endkm] per gauge in selected range. */
73 protected List<Double[]> gaugeRanges;
74
75 /** Stores the min/max values for each q range (gauge). */
76 protected Map<String, double[]> qranges;
77
78 /** The RadioGroupItem that determines the w/q input mode. */
79 protected DynamicForm modes;
80 /** List of doubleArrayPanels shown. */
81 protected final ArrayList<DoubleArrayPanel> doubleArrayPanels = new ArrayList<DoubleArrayPanel>();
82 /** List of wTables in inputhelper section. */
83 protected List<WTable> wTables;
84
85 /** Tabs in inputhelper area. */
86 protected TabSet tabs;
87
88 public AbstractWQAdaptedInputPanel() {
89 this.wqranges = new HashMap<String, DoubleArrayPanel>();
90 this.qranges = new HashMap<String, double[]>();
91 this.wTables = new ArrayList<WTable>();
92 this.qdTables = new ArrayList<QDTable>();
93 }
94
95 /** Inits the helper panel. */
96 // TODO duplicate in WQInputPanel
97 protected void initHelperPanel() {
98 this.tabs = new TabSet();
99 this.tabs.setWidth100();
100 this.tabs.setHeight100();
101
102 // For each gauge, add two tabs with helper tables.
103 createTabs();
104
105 this.helperContainer.addMember(this.tabs);
106 }
107
108 /** Create labels, canvasses, layouts. */
109 @Override
110 public Canvas create(final DataList data) {
111 beforeCreate(data);
112
113 readGaugeRanges(data);
114 initHelperPanel();
115
116 final Canvas submit = getNextButton();
117 final Canvas widget = createWidget(data);
118 final Label label = new Label(this.MSG.wqadaptedTitle());
119
120 label.setHeight(25);
121
122 final VLayout layout = new VLayout();
123 layout.setMembersMargin(10);
124 layout.setWidth(350);
125
126 layout.addMember(label);
127 layout.addMember(widget);
128 layout.addMember(submit);
129
130 fetchWQData();
131
132 initTableListeners();
133
134 afterCreate();
135
136 return layout;
137 }
138
139 protected abstract void createTabs();
140
141 protected abstract void beforeCreate(final DataList data);
142
143 protected abstract void afterCreate();
144
145 /**
146 * Initializes the listeners of the WQD tables.
147 */
148 // TODO dupe from WQInputPanel
149 protected void initTableListeners() {
150 int i = 0;
151 for (final QDTable qdTable : this.qdTables) {
152 // Register listener such that values are filled in on click.
153 final QDTable table = qdTable;
154 final int fi = i;
155 final CellClickHandler handler = new CellClickHandler() {
156 @Override
157 public void onCellClick(final CellClickEvent e) {
158 if (table.isDisabled() || table.isLocked()) {
159 return;
160 }
161
162 final Record r = e.getRecord();
163 final double val = r.getAttributeAsDouble("value");
164
165 AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(fi).setValues(new double[] { val });
166 // If a named value for first gauge is chosen,
167 // try to find and set
168 // the values to the other panels too.
169 if (fi == 0) {
170 final String valueName = r.getAttribute("name");
171 int oi = 0;
172 // TODO instead of oi use random access.
173 for (final QDTable otherQDTable : AbstractWQAdaptedInputPanel.this.qdTables) {
174 if (oi == 0) {
175 oi++;
176 continue;
177 }
178 final Double value = otherQDTable.findRecordValue(valueName);
179 if (value == null) {
180 SC.warn(AbstractWQAdaptedInputPanel.this.MSG.noMainValueAtGauge());
181 } else {
182 AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(oi).setValues(new double[] { value });
183 }
184 oi++;
185 }
186 } else {
187 // Focus next.
188 if (fi != AbstractWQAdaptedInputPanel.this.doubleArrayPanels.size() - 1) {
189 AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(fi + 1).focusInItem(1);
190 }
191 }
192 }
193 };
194
195 qdTable.addCellClickHandler(handler);
196 i++;
197 }
198
199 i = 0;
200 for (final WTable wTable : this.wTables) {
201 // Register listener such that values are filled in on click.
202 final WTable table = wTable;
203 final int fi = i;
204 final CellClickHandler handler = new CellClickHandler() {
205
206 @Override
207 public void onCellClick(final CellClickEvent e) {
208 if (table.isDisabled()) {
209 return;
210 }
211
212 final Record r = e.getRecord();
213 final double val = r.getAttributeAsDouble("value");
214
215 AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(fi).setValues(new double[] { val });
216 // If a named value for first gauge is chosen,
217 // try to find and set
218 // the values to the other panels too.
219 if (fi == 0) {
220 final String valueName = r.getAttribute("name");
221 int oi = 0;
222 // TODO instead of oi use random access.
223 for (final WTable otherWTable : AbstractWQAdaptedInputPanel.this.wTables) {
224 if (oi == 0) {
225 oi++;
226 continue;
227 }
228 final Double value = otherWTable.findRecordValue(valueName);
229 if (value == null) {
230 // TODO: afterwards it freaks out
231 SC.warn(AbstractWQAdaptedInputPanel.this.MSG.noMainValueAtGauge());
232 } else {
233 AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(oi).setValues(new double[] { value });
234 }
235 oi++;
236 }
237 } else {
238 // Focus next.
239 if (fi != AbstractWQAdaptedInputPanel.this.doubleArrayPanels.size() - 1) {
240 AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(fi + 1).focusInItem(1);
241 }
242 }
243 }
244
245 };
246
247 wTable.addCellClickHandler(handler);
248 i++;
249 }
250 }
251
252 /** Create area showing previously entered w or q data. */
253 protected final Canvas createOldWQValues(final Data wqData, final boolean isQ) {
254
255 final VLayout layout = new VLayout();
256 if (wqData != null) {
257 final DataItem item = wqData.getItems()[0];
258 final String value = item.getStringValue();
259
260 final String[] gauges = value.split(GAUGE_SEPARATOR);
261
262 final String unit = isQ ? "m³/s" : "cm";
263
264 for (final String gauge : gauges) {
265 final HLayout h = new HLayout();
266
267 final String[] parts = gauge.split(GAUGE_PART_SEPARATOR);
268 final String[] values = parts[3].split(VALUE_SEPARATOR);
269
270 final Label l = new Label(parts[2] + ": ");
271
272 final StringBuilder sb = new StringBuilder();
273 boolean first = true;
274
275 for (final String v : values) {
276 if (!first) {
277 sb.append(", ");
278 }
279
280 sb.append(v);
281 sb.append(" ");
282 sb.append(unit);
283
284 first = false;
285 }
286
287 final Label v = new Label(sb.toString());
288
289 l.setWidth(65);
290 v.setWidth(65);
291
292 h.addMember(l);
293 h.addMember(v);
294
295 layout.addMember(h);
296 }
297 }
298
299 return layout;
300 }
301
302 protected void initUserWQValues(final DataList dataList) {
303 final List<Data> allData = dataList.getAll();
304
305 final Data dDef = getData(allData, "wq_values");
306 final DataItem def = dDef != null ? dDef.getDefault() : null;
307 final String value = def != null ? def.getStringValue() : null;
308
309 if (value == null || value.length() == 0) {
310 return;
311 }
312
313 final String[] lines = value.split(GAUGE_SEPARATOR);
314
315 if (lines == null || lines.length == 0) {
316 return;
317 }
318
319 for (final String line : lines) {
320 final String[] cols = line.split(GAUGE_PART_SEPARATOR);
321 // final String title = createLineTitle(line);
322
323 if (cols == null || cols.length < 3) {
324 continue;
325 }
326
327 final String[] strValues = cols[2].split(VALUE_SEPARATOR);
328 final double[] values = new double[strValues.length];
329
330 int idx = 0;
331
332 for (final String strValue : strValues) {
333 try {
334 values[idx++] = Double.valueOf(strValue);
335 }
336 catch (final NumberFormatException nfe) {
337 // do nothing
338 }
339 }
340
341 final String key = cols[0] + GAUGE_PART_SEPARATOR + cols[1];
342 final DoubleArrayPanel dap = this.wqranges.get(key);
343
344 if (dap == null) {
345 continue;
346 }
347
348 dap.setValues(values);
349 }
350 }
351
352 /** Populate Gauge Ranges array. */
353 protected final void readGaugeRanges(final DataList dataList) {
354 final List<WQDataItem> items = getWQItems(dataList);
355 this.gaugeRanges = new ArrayList<Double[]>();
356
357 for (final DataItem item : items) {
358 if (item instanceof WQDataItem) {
359 final String[] startEndKm = item.getLabel().split(";");
360 final Double[] kvp = new Double[] { Double.parseDouble(startEndKm[0]), Double.parseDouble(startEndKm[1]) };
361 this.gaugeRanges.add(kvp);
362 }
363 }
364 }
365
366 /** Get items which are not WQ_MODE. */
367 protected List<WQDataItem> getWQItems(final DataList dataList) {
368 final List<Data> data = dataList.getAll();
369 final List<WQDataItem> results = new ArrayList<WQDataItem>();
370 for (final Data d : data) {
371 final DataItem[] items = d.getItems();
372 if (items != null) {
373 for (final Object item : items) {
374 if (item instanceof WQDataItem)
375 results.add((WQDataItem) item);
376 }
377 }
378 }
379 return results;
380 }
381
382 protected final Data getWQValues(final String dataKey) {
383 String wqvalue = null;
384
385 for (final Map.Entry<String, DoubleArrayPanel> entry : this.wqranges.entrySet()) {
386 final String key = entry.getKey();
387 final DoubleArrayPanel dap = entry.getValue();
388 final String label = dap.getItemTitle();
389
390 final double[] values = dap.getInputValues();
391 if (wqvalue == null) {
392 wqvalue = createValueString(key + ";" + label, values);
393 } else {
394 wqvalue += GAUGE_SEPARATOR + createValueString(key + ";" + label, values);
395 }
396 }
397
398 final DataItem valueItem = new DefaultDataItem(dataKey, dataKey, wqvalue);
399 final Data values = new DefaultData(dataKey, null, null, new DataItem[] { valueItem });
400
401 return values;
402 }
403
404 protected String createValueString(final String key, final double[] values) {
405 final StringBuilder sb = new StringBuilder();
406
407 boolean first = true;
408
409 for (final double value : values) {
410 if (!first) {
411 sb.append(",");
412 }
413
414 sb.append(Double.toString(value));
415
416 first = false;
417 }
418
419 return key + ";" + sb.toString();
420 }
421
422 @Override
423 public void onChange(final ChangeEvent event) {
424 // TODO IMPLEMENT ME
425 }
426
427 /** Store the currently focussed DoubleArrayPanel and focus helper tab. */
428
429 @Override
430 public final void onBlur(final BlurEvent event) {
431 final DoubleArrayPanel dap = (DoubleArrayPanel) event.getForm();
432 dap.validateForm(event.getItem());
433 }
434
435 /** Get the WQD data from service and stuck them up that tables. */
436 protected void fetchWQData() {
437 final Config config = Config.getInstance();
438 final String locale = config.getLocale();
439
440 final ArtifactDescription adescr = this.artifact.getArtifactDescription();
441 final DataList[] data = adescr.getOldData();
442
443 final String river = getRiverName(data);
444
445 int i = 0;
446
447 // Get Data for respective gauge.
448 for (final Double[] range : this.gaugeRanges) {
449 // Gauge ranges overlap, move start and end a bit closer
450 // to each other.
451 final double rDiff = (range[1] - range[0]) / 10d;
452 final int fi = i;
453
454 final AsyncCallback<WQInfoObject[]> cb = new AsyncCallback<WQInfoObject[]>() {
455 @Override
456 public void onFailure(final Throwable caught) {
457 GWT.log("Could not recieve wq informations.");
458 SC.warn(caught.getMessage());
459 }
460
461 @Override
462 public void onSuccess(final WQInfoObject[] wqi) {
463 final int num = wqi != null ? wqi.length : 0;
464 GWT.log("Received " + num + " wq informations (" + fi + ".");
465
466 if (num == 0) {
467 return;
468 }
469
470 addWQInfo(wqi, fi);
471 }
472 };
473
474 callMainValuesService(locale, river, range[0] + rDiff, range[1] - rDiff, cb);
475
476 i++;
477 }
478 }
479
480 protected abstract void callMainValuesService(String locale, String river, double start, double end, AsyncCallback<WQInfoObject[]> cb);
481
482 /** Add Info to helper table for gauge at index gaugeIdx. */
483 private void addWQInfo(final WQInfoObject[] wqi, final int gaugeIdx) {
484 for (final WQInfoObject wi : wqi) {
485 final WQInfoRecord rec = new WQInfoRecord(wi);
486
487 if (wi.getType().equals("W")) {
488 if (gaugeIdx < this.wTables.size())
489 this.wTables.get(gaugeIdx).addData(rec);
490 } else if (wi.getType().equals("Q")) {
491 if (gaugeIdx < this.qdTables.size())
492 this.qdTables.get(gaugeIdx).addData(rec);
493 }
494 }
495 }
496
497 /**
498 * Returns the name of the selected river.
499 *
500 * @param data
501 * The DataList with all data.
502 *
503 * @return the name of the current river.
504 */
505 protected String getRiverName(final DataList[] data) {
506 final ArtifactDescription adesc = this.artifact.getArtifactDescription();
507 return adesc.getRiver();
508 }
509
510 abstract protected Canvas createWidget(final DataList dataList);
511 }

http://dive4elements.wald.intevation.org