comparison flys-client/src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java @ 1436:29fc2d1dfe9b

Client side of interactive cross section diagrams. flys-client/trunk@3399 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Felix Wolfsteller <felix.wolfsteller@intevation.de>
date Tue, 13 Dec 2011 11:11:48 +0000
parents bc06a671ef60
children 432180235caf
comparison
equal deleted inserted replaced
1435:f6fbfdc813f0 1436:29fc2d1dfe9b
1 package de.intevation.flys.client.client.ui.chart; 1 package de.intevation.flys.client.client.ui.chart;
2 2
3 import java.util.HashMap;
4 import java.util.Map;
5 import java.util.LinkedHashMap;
6
3 import com.google.gwt.core.client.GWT; 7 import com.google.gwt.core.client.GWT;
4 8
9 import com.google.gwt.user.client.rpc.AsyncCallback;
10
11 import com.smartgwt.client.util.SC;
12
5 import com.smartgwt.client.types.Alignment; 13 import com.smartgwt.client.types.Alignment;
14 import com.smartgwt.client.types.ListGridFieldType;
15
6 import com.smartgwt.client.widgets.Canvas; 16 import com.smartgwt.client.widgets.Canvas;
7 import com.google.gwt.user.client.rpc.AsyncCallback;
8 import com.smartgwt.client.types.ListGridFieldType;
9 import com.smartgwt.client.widgets.grid.ListGrid; 17 import com.smartgwt.client.widgets.grid.ListGrid;
10 import com.smartgwt.client.widgets.grid.ListGridField; 18 import com.smartgwt.client.widgets.grid.ListGridField;
11 import com.smartgwt.client.widgets.grid.ListGridRecord; 19 import com.smartgwt.client.widgets.grid.ListGridRecord;
12 import com.smartgwt.client.widgets.layout.HLayout; 20 import com.smartgwt.client.widgets.layout.HLayout;
21 import com.smartgwt.client.widgets.layout.VLayout;
13 import com.smartgwt.client.widgets.form.fields.SpinnerItem; 22 import com.smartgwt.client.widgets.form.fields.SpinnerItem;
14 import com.smartgwt.client.widgets.form.DynamicForm; 23 import com.smartgwt.client.widgets.form.DynamicForm;
24
25 import com.smartgwt.client.widgets.form.fields.ComboBoxItem;
26 import com.smartgwt.client.widgets.form.fields.SelectItem;
27 import com.smartgwt.client.widgets.form.fields.events.ChangeEvent;
15 import com.smartgwt.client.widgets.form.fields.events.ChangedEvent; 28 import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
16 import com.smartgwt.client.widgets.form.fields.events.ChangedHandler; 29 import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
30 import com.smartgwt.client.widgets.form.fields.events.ChangeHandler;
17 31
18 import de.intevation.flys.client.client.Config; 32 import de.intevation.flys.client.client.Config;
19 import de.intevation.flys.client.shared.model.Artifact; 33 import de.intevation.flys.client.shared.model.Artifact;
20 import de.intevation.flys.client.shared.model.Collection; 34 import de.intevation.flys.client.shared.model.Collection;
21 import de.intevation.flys.client.shared.model.OutputMode; 35 import de.intevation.flys.client.shared.model.CollectionItem;
22
23 import de.intevation.flys.client.shared.model.Data; 36 import de.intevation.flys.client.shared.model.Data;
24 import de.intevation.flys.client.shared.model.DataItem; 37 import de.intevation.flys.client.shared.model.DataItem;
25 import de.intevation.flys.client.shared.model.DefaultArtifact; 38 import de.intevation.flys.client.shared.model.DefaultArtifact;
26 import de.intevation.flys.client.shared.model.DefaultData; 39 import de.intevation.flys.client.shared.model.DefaultData;
27 import de.intevation.flys.client.shared.model.DefaultDataItem; 40 import de.intevation.flys.client.shared.model.DefaultDataItem;
28 import de.intevation.flys.client.shared.model.FacetRecord; 41 import de.intevation.flys.client.shared.model.FacetRecord;
42 import de.intevation.flys.client.shared.model.OutputMode;
43 import de.intevation.flys.client.shared.model.Theme;
44 import de.intevation.flys.client.shared.model.ThemeList;
29 45
30 import de.intevation.flys.client.client.services.FeedServiceAsync; 46 import de.intevation.flys.client.client.services.FeedServiceAsync;
31 47 import de.intevation.flys.client.client.services.CrossSectionKMServiceAsync;
32 48
33 /** 49 /**
34 * ThemePanel much like ChartThemePanel, but shows an "Actions" column, 50 * ThemePanel much like ChartThemePanel, but shows an "Actions" column,
35 * needed for interaction in the CrossSection Charts. 51 * needed for interaction in the CrossSection Charts and a selctor to
52 * declare which cross section profile is "master".
36 */ 53 */
37 public class CrossSectionChartThemePanel 54 public class CrossSectionChartThemePanel
38 extends ChartThemePanel { 55 extends ChartThemePanel {
39 56
57 /** Service to query measurement points of cross sections. */
58 CrossSectionKMServiceAsync kmService = GWT.create(
59 de.intevation.flys.client.client.services.CrossSectionKMService.class);
60
61 /** UUID of the current "master" cross section. */
62 protected String currentMasterUUID;
63
64 /** The layout (used for visual active/inactive feedback). */
65 protected VLayout layout;
66
40 /** 67 /**
41 * Trivial constructor. 68 * Trivial constructor.
42 */ 69 */
43 public CrossSectionChartThemePanel( 70 public CrossSectionChartThemePanel(
44 Collection collection, 71 Collection collection,
45 OutputMode mode) 72 OutputMode mode)
46 { 73 {
47 super(collection, mode); 74 super(collection, mode);
75 }
76
77
78 /**
79 * Feed an artifact to let it know that it is master wrt cross-sections.
80 * @param artifact uuid of an artifact.
81 */
82 public void feedTellMaster(final String artifact) {
83 Data[] feedData = DefaultData.createSimpleStringDataArray(
84 "cross_section.master?", "1");
85
86 feedService.feed(
87 Config.getInstance().getLocale(),
88 new DefaultArtifact(artifact, "TODO:hash"),
89 feedData,
90 new AsyncCallback<Artifact>() {
91 public void onFailure(Throwable caught) {
92 GWT.log("Could not feed artifact (" + artifact
93 + ") with master marker: " + caught.getMessage());
94 SC.warn(MSG.getString(caught.getMessage()));
95 enable();
96 }
97 public void onSuccess(Artifact artifact) {
98 GWT.log("Successfully injected master mark to " + artifact);
99 setCurrentMaster(artifact.getUuid());
100 requestRedraw();
101 enable();
102 }
103 });
104 }
105
106
107 /**
108 * Create Layout, add a master selection box beneath.
109 */
110 @Override
111 protected VLayout createLayout() {
112
113 layout = super.createLayout();
114
115 // Create "set master" combobox.
116 SelectItem cbItem = new SelectItem();
117
118 cbItem.setTitle(MSG.chart_themepanel_set_master());
119 cbItem.setType("comboBox");
120 final LinkedHashMap<String, String> valueMap =
121 getThemeList().toMapArtifactUUIDDescription("cross_section");
122 cbItem.setValueMap(valueMap);
123
124 final DynamicForm form = new DynamicForm();
125 form.setWidth(200);
126 form.setFields(cbItem);
127 layout.addMember(form);
128
129 Config config = Config.getInstance();
130 final String locale = config.getLocale();
131
132 // Add Change Handler to first unset the old master and then set the
133 // new master.
134 cbItem.addChangeHandler(new ChangeHandler() {
135 public void onChange(ChangeEvent event) {
136 String selectedItem = (String) event.getValue();
137 final String artifact = selectedItem;
138
139 disable();
140
141 // Tell current master that he is not master anymore.
142 if (getCurrentMaster() != null) {
143 Data[] feedData = DefaultData.createSimpleStringDataArray(
144 "cross_section.master?", "0");
145 feedService.feed(
146 locale,
147 new DefaultArtifact(getCurrentMaster(), "TODO:hash"),
148 feedData,
149 new AsyncCallback<Artifact>() {
150 public void onFailure(Throwable caught) {
151 GWT.log("Could not un-master artifact: " +
152 caught.getMessage());
153 SC.warn(MSG.getString(caught.getMessage()));
154 enable();
155 }
156 public void onSuccess(Artifact oldMaster) {
157 GWT.log("Successfully un-mastered artifact.");
158 feedTellMaster(artifact);
159 }
160 });
161 }
162 else {
163 feedTellMaster(artifact);
164 }
165 }
166 });
167
168 return layout;
169 }
170
171
172 /** Disable the UI (becomes gray, inresponsive to user input). */
173 public void disable() {
174 this.layout.setDisabled(true);
175 }
176
177
178 /** DisDisable the UI (becomes ungray, responsive to user input). */
179 public void enable() {
180 this.layout.setDisabled(false);
181 }
182
183
184 /**
185 * Returns a double from the list that has the smallest distance to the
186 * given to value. In case of multiple values with the same difference,
187 * the last one is taken.
188 * @param in possible return values.
189 * @param to the value to be as close to as possible.
190 * @return value from in that is closest to to, -1 if none.
191 */
192 public static double closest(Double[] in, double to) {
193 if (in == null || in.length == 0) {
194 return -1;
195 }
196 if (in[0] == to) {
197 return to;
198 }
199 double minDiff = Math.abs(to - in[0]);
200 double bestMatch = in[0];
201 for (int i = 1; i < in.length; i++) {
202 if (in[i] == to) {
203 return to;
204 }
205 double diff = Math.abs(to - in[0]);
206 if (diff < minDiff) {
207 minDiff = diff;
208 bestMatch = in[i];
209 }
210 }
211 return bestMatch;
212 }
213
214
215 /** Feed a single artifact with the km of the crosssection to display. */
216 public void sendFeed(FacetRecord facetRecord, double kmD) {
217 Config config = Config.getInstance();
218 final String locale = config.getLocale();
219
220 Data[] feedData =
221 DefaultData.createSimpleStringDataArray("cross_section.km",
222 Double.valueOf(kmD).toString());
223
224 disable();
225 feedService.feed(
226 locale,
227 new DefaultArtifact(
228 facetRecord.getTheme().getArtifact(),
229 "TODO:hash"),
230 feedData,
231 new AsyncCallback<Artifact>() {
232 @Override
233 public void onFailure(Throwable caught) {
234 GWT.log("Could not feed artifact " + caught.getMessage());
235 SC.warn(MSG.getString(caught.getMessage()));
236 enable();
237 }
238 @Override
239 public void onSuccess(Artifact artifact) {
240 GWT.log("Successfully fed");
241 requestRedraw();
242 enable();
243 }
244 });
48 } 245 }
49 246
50 247
51 /** 248 /**
52 * Create the handler for ChangeEvents on the Spinner in the 249 * Create the handler for ChangeEvents on the Spinner in the
64 final String locale = config.getLocale(); 261 final String locale = config.getLocale();
65 262
66 ChangedHandler handler = new ChangedHandler() 263 ChangedHandler handler = new ChangedHandler()
67 { 264 {
68 @Override 265 @Override
69 public void onChanged(ChangedEvent ce) { 266 public void onChanged(final ChangedEvent ce) {
70 if (ce.getValue() == null) { 267 if (ce.getValue() == null) {
71 return; 268 return;
72 } 269 }
73 DefaultDataItem kmItem = new DefaultDataItem( 270
74 "cross_section.km", 271 // Now, query the value with the kmService.
75 "cross_section.km", 272 Map<Integer, Double> map = new HashMap<Integer,Double>();
76 ce.getValue().toString()); 273 final double selected_km =
77 DefaultData km = new DefaultData( 274 Double.parseDouble(ce.getValue().toString());
78 "cross_section.km", 275
79 null, 276 int _dbid = -1;
80 null, 277 try {
81 new DataItem[] {kmItem}); 278 _dbid = Integer.valueOf(facetRecord.getTheme()
82 Data[] feedData = new Data[] {km}; 279 .getCollectionItem()
83 feedService.feed( 280 .getData().get("cross_section.dbid"));
84 locale, 281 }
85 new DefaultArtifact( 282 catch (NumberFormatException nfe) {
86 facetRecord.getTheme().getArtifact(), 283 GWT.log("Could not extract cross-section db id from data.");
87 "TODO:hash"), 284 }
88 feedData, 285 final int dbid = _dbid;
89 new AsyncCallback<Artifact>() { 286
287 map.put(dbid, Double.parseDouble(ce.getValue().toString()));
288
289 disable();
290
291 kmService.getCrossSectionKMs(locale, map, 2,
292 new AsyncCallback<Map<Integer, Double[]>>() {
293 @Override
90 public void onFailure(Throwable caught) { 294 public void onFailure(Throwable caught) {
91 GWT.log("Could not feed artifact " + caught.getMessage()); 295 GWT.log("Could not get single km for "
92 // TODO SC.warn 296 + dbid + ": "+ caught.getMessage());
297 SC.warn(MSG.getString(caught.getMessage()));
298 updateCollection();
299 updateGrid();
300 enable();
93 } 301 }
94 public void onSuccess(Artifact artifact) { 302 @Override
95 GWT.log("Successfully fed"); 303 public void onSuccess(Map<Integer, Double[]> obj) {
96 // TODO: Also update content of spinnerbox 304 Double[] kms = obj.get(dbid);
97 requestRedraw(); 305 double closest =
306 CrossSectionChartThemePanel.closest(kms,
307 selected_km);
308 GWT.log("Got single km for " + dbid + ", it is "
309 + closest);
310 SpinnerItem item = (SpinnerItem) ce.getItem();
311 item.setValue(closest);
312 sendFeed(facetRecord, closest);
98 } 313 }
99 }); 314 });
100 } 315 }
101 }; 316 };
102 return handler; 317 return handler;
318 }
319
320
321 /**
322 * Get the chosen km for given cross-section.
323 */
324 final public double getKmForCrossSectionIdx(final int index) {
325 double km = 0d;
326 int collIdx = 0;
327 while (km == 0d) {
328 CollectionItem item = collection.getItem(collIdx++);
329 if (item == null) {
330 break;
331 }
332 if (item.getData() == null) continue;
333 String d = item.getData().get("cross_section" + index + ".km");
334 if (d == null) {
335 continue;
336 }
337 km = Double.valueOf(d);
338 }
339 return km;
103 } 340 }
104 341
105 342
106 /** 343 /**
107 * Create and configure the Grid to display. 344 * Create and configure the Grid to display.
132 SpinnerItem spinnerItem = new SpinnerItem(); 369 SpinnerItem spinnerItem = new SpinnerItem();
133 spinnerItem.setShowTitle(false); 370 spinnerItem.setShowTitle(false);
134 spinnerItem.setTitle("Waterlevel-Spinner"); 371 spinnerItem.setTitle("Waterlevel-Spinner");
135 spinnerItem.setWidth(45); 372 spinnerItem.setWidth(45);
136 // TODO actually get the value from artifact 373 // TODO actually get the value from artifact
137 // TODO actually get the range from artifact (or river?) 374 spinnerItem.setDefaultValue(
138 spinnerItem.setDefaultValue(0); 375 getKmForCrossSectionIdx(facetRecord.getTheme().getIndex()));
376
377 // TODO actually use crosssectionkmservive
139 spinnerItem.setMin(0); 378 spinnerItem.setMin(0);
140 spinnerItem.setMax(1000); 379 spinnerItem.setMax(1000);
141 spinnerItem.setStep(5f); 380 spinnerItem.setStep(5f);
142 spinnerItem.setChangeOnKeypress(true); 381 spinnerItem.setChangeOnKeypress(true);
143 382
175 list.setCanEdit(true); 414 list.setCanEdit(true);
176 list.setCanSort(false); 415 list.setCanSort(false);
177 list.setShowRecordComponents(true); 416 list.setShowRecordComponents(true);
178 list.setShowRecordComponentsByCell(true); 417 list.setShowRecordComponentsByCell(true);
179 list.setShowHeader(true); 418 list.setShowHeader(true);
180 //list.setShowHeaderContextMenu(false);
181 list.setWidth100(); 419 list.setWidth100();
182 list.setHeight100(); 420 list.setHeight100();
183 421
184 list.addEditCompleteHandler(this); 422 list.addEditCompleteHandler(this);
185 423
193 ListGridField actions = new ListGridField(GRID_FIELD_ACTIONS, 431 ListGridField actions = new ListGridField(GRID_FIELD_ACTIONS,
194 MSG.chart_themepanel_header_actions(), 50); 432 MSG.chart_themepanel_header_actions(), 50);
195 433
196 list.setFields(active, name, actions); 434 list.setFields(active, name, actions);
197 } 435 }
436
437
438 /** Get Current Cross-section Masters uuid. */
439 public String getCurrentMaster() {
440 return currentMasterUUID;
441 }
442
443
444 /** Set Current Cross-section Masters uuid. */
445 public void setCurrentMaster(String currentMasterUuid) {
446 this.currentMasterUUID = currentMasterUuid;
447 }
198 } 448 }
199 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : 449 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org