comparison gwt-client/src/main/java/org/dive4elements/river/client/client/ui/chart/ManualPointsEditor.java @ 5838:5aa05a7a34b7

Rename modules to more fitting names.
author Sascha L. Teichmann <teichmann@intevation.de>
date Thu, 25 Apr 2013 15:23:37 +0200
parents flys-client/src/main/java/org/dive4elements/river/client/client/ui/chart/ManualPointsEditor.java@821a02bbfb4e
children 172338b1407f
comparison
equal deleted inserted replaced
5837:d9901a08d0a6 5838:5aa05a7a34b7
1 package org.dive4elements.river.client.client.ui.chart;
2
3 import com.google.gwt.core.client.GWT;
4 import com.google.gwt.i18n.client.DateTimeFormat;
5 import com.google.gwt.i18n.client.NumberFormat;
6 import com.google.gwt.json.client.JSONArray;
7 import com.google.gwt.json.client.JSONBoolean;
8 import com.google.gwt.json.client.JSONNumber;
9 import com.google.gwt.json.client.JSONParser;
10 import com.google.gwt.json.client.JSONString;
11 import com.google.gwt.user.client.rpc.AsyncCallback;
12
13 import com.smartgwt.client.types.Alignment;
14 import com.smartgwt.client.types.ListGridFieldType;
15 import com.smartgwt.client.util.SC;
16 import com.smartgwt.client.widgets.Button;
17 import com.smartgwt.client.widgets.IButton;
18 import com.smartgwt.client.widgets.Label;
19 import com.smartgwt.client.widgets.Window;
20 import com.smartgwt.client.widgets.events.ClickEvent;
21 import com.smartgwt.client.widgets.events.ClickHandler;
22 import com.smartgwt.client.widgets.grid.CellEditValueFormatter;
23 import com.smartgwt.client.widgets.grid.CellEditValueParser;
24 import com.smartgwt.client.widgets.grid.CellFormatter;
25 import com.smartgwt.client.widgets.grid.ListGrid;
26 import com.smartgwt.client.widgets.grid.ListGridField;
27 import com.smartgwt.client.widgets.grid.ListGridRecord;
28 import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
29 import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
30 import com.smartgwt.client.widgets.layout.HLayout;
31 import com.smartgwt.client.widgets.layout.VLayout;
32
33 import org.dive4elements.river.client.client.Config;
34 import org.dive4elements.river.client.client.FLYSConstants;
35 import org.dive4elements.river.client.client.event.RedrawRequestEvent;
36 import org.dive4elements.river.client.client.event.RedrawRequestHandler;
37 import org.dive4elements.river.client.client.services.FeedServiceAsync;
38 import org.dive4elements.river.client.client.services.LoadArtifactServiceAsync;
39 import org.dive4elements.river.client.shared.model.Artifact;
40 import org.dive4elements.river.client.shared.model.Collection;
41 import org.dive4elements.river.client.shared.model.CollectionItem;
42 import org.dive4elements.river.client.shared.model.Data;
43 import org.dive4elements.river.client.shared.model.DefaultArtifact;
44 import org.dive4elements.river.client.shared.model.DefaultData;
45 import org.dive4elements.river.client.shared.model.Property;
46 import org.dive4elements.river.client.shared.model.PropertyGroup;
47 import org.dive4elements.river.client.shared.model.Recommendation;
48 import org.dive4elements.river.client.shared.model.Settings;
49 import org.dive4elements.river.client.shared.model.StringProperty;
50
51 import java.util.Date;
52 import java.util.List;
53
54
55 /**
56 * UI to enter point data and save it to an PointArtifact.
57 */
58 public class ManualPointsEditor
59 extends Window
60 implements ClickHandler
61 {
62 /** The interface that provides i18n messages. */
63 protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
64
65 /** Part of name of the main data item to be fed. */
66 public static final String POINT_DATA = "manualpoints.data";
67
68 /** When we chaged something, we need a RedrawRequest(Handler). */
69 protected RedrawRequestHandler redrawRequestHandler;
70
71 /** The collection */
72 protected Collection collection;
73
74 /** The listGrid showing point entries. */
75 protected ListGrid listGrid;
76
77 protected ListGridFieldType fieldTypeX = ListGridFieldType.FLOAT;
78
79 /** Service handle to clone and add artifacts to collection. */
80 LoadArtifactServiceAsync loadArtifactService = GWT.create(
81 org.dive4elements.river.client.client.services.LoadArtifactService.class);
82
83 /** Service to feed the artifact with new point-data. */
84 FeedServiceAsync feedService = GWT.create(
85 org.dive4elements.river.client.client.services.FeedService.class);
86
87 /** UUID of artifact to feed. */
88 protected String uuid;
89
90 /** Name of the outputmode, important when feeding data. */
91 protected String outputModeName;
92
93 /** Name of the point data item. */
94 protected String pointDataItemName;
95
96
97 /**
98 * Setup editor dialog.
99 * @param collection The collection to use.
100 */
101 public ManualPointsEditor(Collection collection,
102 RedrawRequestHandler handler, String outputModeName
103 ) {
104 this.collection = collection;
105 this.redrawRequestHandler = handler;
106 this.outputModeName = outputModeName;
107 this.pointDataItemName = outputModeName + "." + POINT_DATA;
108 init();
109 }
110
111
112 /** Searches collection for first artifact to serve (manual) point data. */
113 public String findManualPointsUUID() {
114 // TODO Need to be more picky (different points in different diagrams)
115 int size = collection.getItemLength();
116
117 for (int i = 0; i < size; i++) {
118 CollectionItem item = collection.getItem(i);
119 String dataValue = item.getData().get(pointDataItemName);
120 if (dataValue != null) {
121 // Found it.
122 uuid = item.identifier();
123 return uuid;
124 }
125 }
126
127 return null;
128 }
129
130
131 /**
132 * Initialize the editor window and its components.
133 */
134 protected void init() {
135 setTitle(MSG.addpoints());
136 setCanDragReposition(true);
137 setCanDragResize(true);
138
139 // If no manualpoints artifact found, create it now.
140 if(findManualPointsUUID() == null) {
141 addArtifactCreateUI();
142 }
143 else {
144 createUI();
145 }
146 }
147
148
149 /** Create and setup/add the ui. */
150 public void createUI() {
151 Button accept = new Button(MSG.label_ok());
152 Button cancel = new Button(MSG.label_cancel());
153 cancel.addClickHandler(this);
154
155 accept.addClickHandler(new ClickHandler() {
156 @Override
157 public void onClick(ClickEvent e) {
158 okClicked();
159 }
160 });
161
162 HLayout buttons = new HLayout();
163 buttons.addMember(accept);
164 buttons.addMember(cancel);
165 buttons.setAlign(Alignment.CENTER);
166 buttons.setHeight(30);
167
168 VLayout layout = new VLayout();
169 listGrid = new ListGrid();
170 listGrid.setWidth100();
171 listGrid.setHeight("*");
172 listGrid.setCanSort(false);
173 listGrid.setCanEdit(true);
174 listGrid.setShowHeaderContextMenu(false);
175
176 // Use X and Y as default fallback.
177 String xAxis = "X";
178 String yAxis = "Y";
179
180 // Get header text from collection settings
181 Settings settings = this.collection.getSettings(outputModeName);
182 List<Property> axes = settings.getSettings("axes");
183 if(axes != null) {
184 for (Property p: axes) {
185 PropertyGroup pg = (PropertyGroup)p;
186 GWT.log(pg.toString());
187 StringProperty id =
188 (StringProperty)pg.getPropertyByName("id");
189 if(id.getValue().equals("X")) {
190 StringProperty name =
191 (StringProperty)pg.getPropertyByName("label");
192 xAxis = name.getValue();
193 }
194 else if (yAxis.equals("Y")) {
195 StringProperty name =
196 (StringProperty)pg.getPropertyByName("label");
197 yAxis = name.getValue();
198 }
199 }
200 }
201
202 CellFormatter format = createCellFormatter();
203 CellEditValueParser cevp = createCellEditValueParser();
204 CellEditValueFormatter cevf = createCellEditValueFormatter();
205
206 ListGridField xField =
207 new ListGridField(PointRecord.ATTRIBUTE_X, xAxis);
208 if(xAxis.equalsIgnoreCase("date") || xAxis.equalsIgnoreCase("Datum")) {
209 // FIXME: This is a hack for Timeseries charts with Date types on the x axis
210 xField.setType(ListGridFieldType.DATE);
211 this.fieldTypeX = ListGridFieldType.DATE;
212 }
213 else {
214 xField.setType(ListGridFieldType.FLOAT);
215 xField.setCellFormatter(format);
216 xField.setEditValueParser(cevp);
217 xField.setEditValueFormatter(cevf);
218 }
219
220 ListGridField yField =
221 new ListGridField(PointRecord.ATTRIBUTE_Y, yAxis);
222 yField.setType(ListGridFieldType.FLOAT);
223 yField.setCellFormatter(format);
224 yField.setEditValueParser(cevp);
225 yField.setEditValueFormatter(cevf);
226
227 ListGridField nameField = new ListGridField(PointRecord.ATTRIBUTE_NAME,
228 MSG.pointname());
229 final ListGridField removeField =
230 new ListGridField("_removeRecord", MSG.removepoint()){{
231 setType(ListGridFieldType.ICON);
232 setIcon(GWT.getHostPageBaseURL() + MSG.removeFeature());
233 setCanEdit(false);
234 setCanFilter(false);
235 setCanSort(false);
236 setCanGroupBy(false);
237 setCanFreeze(false);
238 setWidth(25);
239 }};
240
241 ListGridField activeField = new ListGridField(
242 PointRecord.ATTRIBUTE_ACTIVE, MSG.selection());
243 activeField.setType(ListGridFieldType.BOOLEAN);
244 activeField.setDefaultValue(true);
245
246 listGrid.setFields(new ListGridField[] {activeField, xField, yField,
247 nameField, removeField});
248
249 listGrid.addRecordClickHandler(new RecordClickHandler() {
250 @Override
251 public void onRecordClick(final RecordClickEvent event) {
252 // Just handle remove-clicks
253 if(!event.getField().getName().equals(removeField.getName())) {
254 return;
255 }
256 event.getViewer().removeData(event.getRecord());
257 }
258 });
259
260 // Find the artifacts uuid
261 findManualPointsUUID();
262 CollectionItem item = collection.getItem(uuid);
263
264 // Add points to grid
265 if (item != null) {
266 // TODO store this from findPointUUID instead (we touched these).
267 String jsonData = item.getData().get(pointDataItemName);
268 JSONArray jsonArray = (JSONArray) JSONParser.parse(jsonData);
269 for (int i = 0; i < jsonArray.size(); i++) {
270 JSONArray point = (JSONArray) jsonArray.get(i);
271 listGrid.addData(PointRecord.fromJSON(point));
272 }
273 }
274 else {
275 GWT.log("ManualPointsEditor: No item found for " + uuid);
276 }
277
278 IButton button = new IButton(MSG.newpoint());
279 button.setTop(250);
280 button.addClickHandler(new ClickHandler() {
281 @Override
282 public void onClick(ClickEvent event) {
283 listGrid.startEditingNew();
284 }
285 });
286
287 layout.addMember(listGrid);
288 layout.addMember(button);
289
290 addItem(layout);
291
292 addItem(buttons);
293 setWidth(380);
294 setHeight(470);
295 centerInPage();
296 }
297
298
299 protected CellFormatter createCellFormatter() {
300 return new CellFormatter() {
301 @Override
302 public String format(Object value, ListGridRecord record, int rowNum, int colNum) {
303 if(value != null) {
304 NumberFormat nf = NumberFormat.getDecimalFormat();
305 try {
306 double d = Double.valueOf(value.toString()).doubleValue();
307 return nf.format(d);
308 } catch (Exception e) {
309 return value.toString();
310 }
311 } else {
312 return null;
313 }
314 }};
315 }
316
317
318 protected CellEditValueParser createCellEditValueParser() {
319 return new CellEditValueParser() {
320 @Override
321 public Object parse(Object value, ListGridRecord record, int rowNum, int colNum) {
322 if (value == null)
323 return null;
324 try {
325 NumberFormat nf = NumberFormat.getDecimalFormat();
326 double d = nf.parse(value.toString());
327 return (new Double(d)).toString();
328 }
329 catch(NumberFormatException nfe) {
330 return value;
331 }
332 }
333 };
334 }
335
336
337 protected CellEditValueFormatter createCellEditValueFormatter() {
338 return new CellEditValueFormatter() {
339 @Override
340 public Object format(Object value, ListGridRecord record, int rowNum, int colNum) {
341 if (value == null) {
342 return "";
343 }
344 NumberFormat nf = NumberFormat.getDecimalFormat();
345 try {
346 double d = Double.valueOf(value.toString()).doubleValue();
347 return nf.format(d);
348 }
349 catch(NumberFormatException nfe) {
350 return value;
351 }
352 }
353 };
354 }
355
356 protected String getLocaleDateFormat() {
357 String loc = Config.getInstance().getLocale();
358 if ("de".equals(loc)) {
359 return "yy.MM.yyyy";
360 }
361 else {
362 return "MM/dd/yyyy";
363 }
364 }
365
366 protected String formatDate(Date date) {
367 DateTimeFormat dtf = DateTimeFormat.getFormat(getLocaleDateFormat());
368 return dtf.format(date);
369 }
370
371 /** Create JSON representation of the points present in the list grid. */
372 protected JSONArray jsonArrayFromListGrid() {
373 JSONArray list = new JSONArray();
374 int idx = 0;
375
376 for(ListGridRecord record : listGrid.getRecords()) {
377 if (record instanceof PointRecord) {
378 JSONArray data = new JSONArray();
379
380 PointRecord point = (PointRecord) record;
381 if(point.isTimeseriesPoint()) {
382 data.set(0, new JSONString(point.getXAsDate()));
383 GWT.log("Date: " + point.getXAsDate());
384 }
385 else {
386 data.set(0, new JSONNumber(point.getX()));
387 }
388 data.set(1, new JSONNumber(point.getY()));
389 data.set(2, new JSONString(point.getName()));
390 data.set(3, JSONBoolean.getInstance(point.isActive()));
391
392 list.set(idx, data);
393 idx++;
394 }
395 else {
396 JSONArray data = new JSONArray();
397
398 String nameString = record.getAttributeAsString(PointRecord.ATTRIBUTE_NAME);
399 // Apply default name if none set.
400 if (nameString == null || nameString.equals("")) {
401 String xString = record.getAttributeAsString(
402 PointRecord.ATTRIBUTE_X);
403 String yString = record.getAttributeAsString(
404 PointRecord.ATTRIBUTE_Y);
405 nameString = xString + "/" + yString;
406 }
407
408 if(fieldTypeX.equals(ListGridFieldType.DATE)) {
409 Date date = record.getAttributeAsDate(PointRecord.ATTRIBUTE_X);
410 data.set(0, new JSONString(formatDate(date)));
411 GWT.log("Date: " + formatDate(date));
412 }
413 else {
414 data.set(0, new JSONNumber(record.
415 getAttributeAsDouble(PointRecord.ATTRIBUTE_X)));
416 }
417 data.set(1, new JSONNumber(record.
418 getAttributeAsDouble(PointRecord.ATTRIBUTE_Y)));
419 data.set(2, new JSONString(nameString));
420 data.set(3, JSONBoolean.getInstance(record.getAttributeAsBoolean(
421 PointRecord.ATTRIBUTE_ACTIVE)));
422
423 list.set(idx, data);
424 idx++;
425 }
426 }
427 return list;
428 }
429
430
431 /**
432 * Called when OK Button was clicked. Then, if entered values are valid,
433 * fire a RedrawRequest and destroy.
434 */
435 protected void okClicked() {
436 if(isDialogValid()) {
437 // Feed JSON-encoded content of listgrid.
438 JSONArray list = jsonArrayFromListGrid();
439
440 Data[] feedData = new Data[] {
441 DefaultData.createSimpleStringData(pointDataItemName,
442 list.toString())
443 };
444
445 feedService.feed(
446 Config.getInstance().getLocale(),
447 new DefaultArtifact(uuid, "TODO:hash"),
448 feedData,
449 new AsyncCallback<Artifact>() {
450 @Override
451 public void onFailure(Throwable caught) {
452 GWT.log("Could not feed artifact with points.");
453 SC.warn(MSG.getString(caught.getMessage()));
454 enable();
455 }
456 @Override
457 public void onSuccess(Artifact fartifact) {
458 GWT.log("Successfully set points");
459 redrawRequestHandler.onRedrawRequest(
460 new RedrawRequestEvent());
461 destroy();
462 }
463 });
464 }
465 else {
466 GWT.log("Dialog not valid");
467 SC.warn(MSG.error_dialog_not_valid());
468 }
469 }
470
471
472 /** Add a ManualPointArtifact to Collection. */
473 public void addArtifactCreateUI() {
474 final Label standByLabel = new Label(MSG.standby());
475 addItem(standByLabel);
476
477 setWidth(380);
478 setHeight(470);
479 centerInPage();
480
481 Config config = Config.getInstance();
482 String locale = config.getLocale();
483
484 loadArtifactService.load(
485 this.collection,
486 new Recommendation("manualpoints", ""),
487 "manualpoints",
488 locale,
489 new AsyncCallback<Artifact>() {
490 @Override
491 public void onFailure(Throwable caught) {
492 GWT.log("Creating manualpoint artifact failed!");
493 }
494 @Override
495 public void onSuccess(Artifact artifact) {
496 GWT.log("Successfully created artifact.");
497 removeItem(standByLabel);
498 uuid = artifact.getUuid();
499 createUI();
500 }
501 });
502 }
503
504
505 /**
506 * This method is called when the user aborts point editing.
507 * @param event The event.
508 */
509 @Override
510 public void onClick(ClickEvent event) {
511 this.destroy();
512 }
513
514
515 /** Return false if x or y attribute is missing. */
516 protected boolean isDialogValid() {
517 boolean valid = true;
518 for (ListGridRecord record : listGrid.getRecords()) {
519 try {
520 if (record.getAttribute(PointRecord.ATTRIBUTE_X) == null
521 || record.getAttribute(PointRecord.ATTRIBUTE_Y) == null) {
522 return false;
523 }
524 }
525 catch(IllegalArgumentException ex) {
526
527 }
528 }
529 if (listGrid.hasErrors()) {
530 valid = false;
531 }
532 return valid;
533 }
534 }
535 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org