comparison gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractPairRecommendationPanel.java @ 9227:84397da33d17

Allow to control specific behaviour in TwinDatacagePanel Implemented client logic of 'intelligent datacage filtering' for SINFO
author gernotbelger
date Wed, 04 Jul 2018 18:28:08 +0200
parents 8d1df8639563
children 839b2aa84dd0
comparison
equal deleted inserted replaced
9226:83aee0942eae 9227:84397da33d17
50 * DatacagePairWidget which is put in the input-helper area. 50 * DatacagePairWidget which is put in the input-helper area.
51 */ 51 */
52 public abstract class AbstractPairRecommendationPanel 52 public abstract class AbstractPairRecommendationPanel
53 extends TextProvider { 53 extends TextProvider {
54 54
55 /** 55 /**
56 * Allows for abstraction on how to handle/serialize the recommendation and the used factories. 56 * Allows for abstraction on how to handle/serialize the recommendation and the used factories.
57 * Basically this allows to tweak the factory that is delivered from the datacage to be replaced by a specific one... 57 * Basically this allows to tweak the factory that is delivered from the datacage to be replaced by a specific one...
58 * 58 *
59 * @author Gernot Belger 59 * @author Gernot Belger
60 */ 60 */
61 public static interface IRecommendationInfo { 61 public static interface IRecommendationInfo {
62 62
63 String getFactory(String originalFactory); 63 String getFactory(String originalFactory);
64 64
65 /** 65 /**
66 * Separate factory for the 'createDataString' method, because in the case of waterlevels. See HOTFIX/FIXME there. 66 * Separate factory for the 'createDataString' method, because in the case of waterlevels. See HOTFIX/FIXME there.
67 * @param recommendation 67 * @param recommendation
68 */ 68 */
69 String getDataStringFactory(Recommendation recommendation); 69 String getDataStringFactory(Recommendation recommendation);
70 70
71 /** 71 /**
72 * Set factory of recommendation such that the correct artifacts will 72 * Set factory of recommendation such that the correct artifacts will
73 * be cloned for difference calculations. 73 * be cloned for difference calculations.
74 */ 74 */
75 void adjustRecommendation(Recommendation recommendation); 75 void adjustRecommendation(Recommendation recommendation);
76 } 76 }
77 77
78 public static interface IValidator 78 public static interface IValidator
79 { 79 {
80 List<String> validate(ListGrid differencesList, FLYSConstants msgProvider); 80 List<String> validate(ListGrid differencesList, FLYSConstants msgProvider);
81 } 81 }
82 82
83 private static final long serialVersionUID = 8906629596491827857L; 83 private static final long serialVersionUID = 8906629596491827857L;
84
85 // FIXME: why? we hide the field of the super class with exactly the same thing...
86 private static FLYSConstants MSG_PROVIDER = GWT.create(FLYSConstants.class);
87 84
88 private String dataName; 85 private String dataName;
89 86
90 private final User user; 87 private final User user;
91 88
95 /** 92 /**
96 * List to track previously selected but now removed pairs. (Needed to 93 * List to track previously selected but now removed pairs. (Needed to
97 * be able to identify artifacts that can be removed from the collection. 94 * be able to identify artifacts that can be removed from the collection.
98 */ 95 */
99 private final List<RecommendationPairRecord> removedPairs = 96 private final List<RecommendationPairRecord> removedPairs =
100 new ArrayList<RecommendationPairRecord>(); 97 new ArrayList<RecommendationPairRecord>();
101 98
102 /** Service handle to clone and add artifacts to collection. */ 99 /** Service handle to clone and add artifacts to collection. */
103 private final LoadArtifactServiceAsync loadArtifactService = GWT.create( 100 private final LoadArtifactServiceAsync loadArtifactService = GWT.create(
104 org.dive4elements.river.client.client.services.LoadArtifactService.class); 101 org.dive4elements.river.client.client.services.LoadArtifactService.class);
105 102
106 /** Service to remove artifacts from collection. */ 103 /** Service to remove artifacts from collection. */
107 private final RemoveArtifactServiceAsync removeArtifactService = GWT.create( 104 private final RemoveArtifactServiceAsync removeArtifactService = GWT.create(
108 org.dive4elements.river.client.client.services.RemoveArtifactService.class); 105 org.dive4elements.river.client.client.services.RemoveArtifactService.class);
109 106
110 private final IRecommendationInfo leftInfo; 107 private final IRecommendationInfo leftInfo;
111 108
112 private final IRecommendationInfo rightInfo; 109 private final IRecommendationInfo rightInfo;
113 110
114 private final IValidator validator; 111 private final IValidator validator;
115 112
116 /** 113 /**
117 * @param Validates the content of this form when the user clicks 'apply' 114 * @param Validates the content of this form when the user clicks 'apply'
118 * @param leftInfo Delegate for handling the left part of the recommendation-pair 115 * @param leftInfo Delegate for handling the left part of the recommendation-pair
119 * @param rightInfo Delegate for handling the right part of the recommendation-pair 116 * @param rightInfo Delegate for handling the right part of the recommendation-pair
120 */ 117 */
121 public AbstractPairRecommendationPanel(final User user, final IValidator validator, final IRecommendationInfo leftInfo, final IRecommendationInfo rightInfo ) { 118 public AbstractPairRecommendationPanel(final User user, final IValidator validator, final IRecommendationInfo leftInfo, final IRecommendationInfo rightInfo ) {
122 this.user = user; 119 this.user = user;
123 this.validator = validator; 120 this.validator = validator;
124 this.leftInfo = leftInfo; 121 this.leftInfo = leftInfo;
125 this.rightInfo = rightInfo; 122 this.rightInfo = rightInfo;
126 } 123 }
127 124
128 // FIXME: better than copy/pasting the MSG field into every sub-class but not really nice yet. 125 // FIXME: better than copy/pasting the MSG field into every sub-class but not really nice yet.
129 protected final static FLYSConstants msg() { 126 protected final static FLYSConstants msg() {
130 return MSG_PROVIDER; 127 return MSG;
131 } 128 }
132 129
133 /** 130 /**
134 * Remove first occurrence of "[" and "]" (if both do occur). 131 * Remove first occurrence of "[" and "]" (if both do occur).
135 * @param value String to be stripped of [] (might be null). 132 * @param value String to be stripped of [] (might be null).
136 * @return input string but with [ and ] removed, or input string if no 133 * @return input string but with [ and ] removed, or input string if no
153 } 150 }
154 151
155 /** 152 /**
156 * Create a recommendation from a string representation of it. 153 * Create a recommendation from a string representation of it.
157 * @param from string in format as shown above. 154 * @param from string in format as shown above.
158 * @param leftInfo2 155 * @param leftInfo2
159 * @return recommendation from input string. 156 * @return recommendation from input string.
160 */ 157 */
161 private Recommendation createRecommendationFromString(final String from, final IRecommendationInfo info) { 158 private Recommendation createRecommendationFromString(final String from, final IRecommendationInfo info) {
162 // TODO Construct "real" filter. 159 // TODO Construct "real" filter.
163 final String[] parts = unbracket(from).split(";"); 160 final String[] parts = unbracket(from).split(";");
167 parts[2]); 164 parts[2]);
168 165
169 final List<Recommendation.Facet> facets = new ArrayList<Recommendation.Facet>(); 166 final List<Recommendation.Facet> facets = new ArrayList<Recommendation.Facet>();
170 facets.add(facet); 167 facets.add(facet);
171 filter.add("longitudinal_section", facets); 168 filter.add("longitudinal_section", facets);
172 169
173 final String factory = info.getFactory( parts[1] ); 170 final String factory = info.getFactory( parts[1] );
174 171
175 final Recommendation r = new Recommendation(factory, parts[0], this.artifact.getUuid(), filter); 172 final Recommendation r = new Recommendation(factory, parts[0], this.artifact.getUuid(), filter);
176 r.setDisplayName(parts[3]); 173 r.setDisplayName(parts[3]);
177 return r; 174 return r;
186 // Create according recommendations and display strings. 183 // Create according recommendations and display strings.
187 final String[] recs = from.split("#"); 184 final String[] recs = from.split("#");
188 if (recs.length % 2 != 0) return; 185 if (recs.length % 2 != 0) return;
189 for (int i = 0; i < recs.length; i+=2) { 186 for (int i = 0; i < recs.length; i+=2) {
190 final Recommendation minuend = 187 final Recommendation minuend =
191 createRecommendationFromString(recs[i+0], this.leftInfo); 188 createRecommendationFromString(recs[i+0], this.leftInfo);
192 final Recommendation subtrahend = 189 final Recommendation subtrahend =
193 createRecommendationFromString(recs[i+1], this.rightInfo); 190 createRecommendationFromString(recs[i+1], this.rightInfo);
194 191
195 final RecommendationPairRecord pr = new RecommendationPairRecord( 192 final RecommendationPairRecord pr = new RecommendationPairRecord(
196 minuend, subtrahend); 193 minuend, subtrahend);
197 // This Recommendation Pair comes from the data string and was thus 194 // This Recommendation Pair comes from the data string and was thus
198 // already cloned. 195 // already cloned.
199 pr.setIsAlreadyLoaded(true); 196 pr.setIsAlreadyLoaded(true);
200 this.differencesList.addData(pr); 197 this.differencesList.addData(pr);
201 } 198 }
206 * @param dataList the data. 203 * @param dataList the data.
207 * @return graphical representation and interaction widgets for data. 204 * @return graphical representation and interaction widgets for data.
208 */ 205 */
209 @Override 206 @Override
210 public final Canvas create(final DataList dataList) { 207 public final Canvas create(final DataList dataList) {
211 208
212 final Canvas widget = createWidget(); 209 final Canvas widget = createWidget();
213 210
214 final Canvas canvas = createChooserWidgets(widget, dataList, this.user, this.differencesList); 211 final Canvas canvas = createChooserWidgets(widget, dataList, this.user, this.differencesList);
215 212
216 populateGrid(dataList); 213 populateGrid(dataList);
217 214
218 return canvas; 215 return canvas;
219 } 216 }
220 217
221 /** 218 /**
222 * Creates the individual parts of the input-helper area ('Eingabeunterstützung') for choosing the content of this widget. 219 * Creates the individual parts of the input-helper area ('Eingabeunterstützung') for choosing the content of this widget.
223 */ 220 */
224 protected abstract Canvas createChooserWidgets(final Canvas widget, final DataList dataList, final User auser, final ListGrid diffList); 221 protected abstract Canvas createChooserWidgets(final Canvas widget, final DataList dataList, final User auser, final ListGrid diffList);
225 222
226 private void populateGrid(final DataList dataList) { 223 private void populateGrid(final DataList dataList) {
227 final Data data = dataList.get(0); 224 final Data data = dataList.get(0);
228 this.dataName = data.getLabel(); 225 this.dataName = data.getLabel();
229 for (int i = 0; i < dataList.size(); i++) { 226 for (int i = 0; i < dataList.size(); i++) {
230 if (dataList.get(i) != null && dataList.get(i).getItems() != null) { 227 if (dataList.get(i) != null && dataList.get(i).getItems() != null) {
231 if (dataList.get(i).getItems() != null) { 228 if (dataList.get(i).getItems() != null) {
232 populateGridFromString( 229 populateGridFromString(
233 dataList.get(i).getItems()[0].getStringValue()); 230 dataList.get(i).getItems()[0].getStringValue());
234 } 231 }
235 } 232 }
236 } 233 }
237 } 234 }
238 235
239 @Override 236 @Override
240 public final List<String> validate() { 237 public final List<String> validate() {
241 return this.validator.validate(this.differencesList, MSG_PROVIDER); 238 return this.validator.validate(this.differencesList, msg());
242 } 239 }
243 240
244 /** 241 /**
245 * Creates layout with grid that displays selection inside. 242 * Creates layout with grid that displays selection inside.
246 */ 243 */
257 final ListGridField nameField = new ListGridField("first", "Minuend"); 254 final ListGridField nameField = new ListGridField("first", "Minuend");
258 final ListGridField capitalField = new ListGridField("second", "Subtrahend"); 255 final ListGridField capitalField = new ListGridField("second", "Subtrahend");
259 // Track removed rows, therefore more or less reimplement 256 // Track removed rows, therefore more or less reimplement
260 // setCanRecomeRecords. 257 // setCanRecomeRecords.
261 final ListGridField removeField = 258 final ListGridField removeField =
262 new ListGridField("_removeRecord", "Remove Record"){{ 259 new ListGridField("_removeRecord", "Remove Record"){{
263 setType(ListGridFieldType.ICON); 260 setType(ListGridFieldType.ICON);
264 setIcon(GWT.getHostPageBaseURL() + msg().removeFeature()); 261 setIcon(GWT.getHostPageBaseURL() + msg().removeFeature());
265 setCanEdit(false); 262 setCanEdit(false);
266 setCanFilter(false); 263 setCanFilter(false);
267 setCanSort(false); 264 setCanSort(false);
268 setCanGroupBy(false); 265 setCanGroupBy(false);
269 setCanFreeze(false); 266 setCanFreeze(false);
270 setWidth(25); 267 setWidth(25);
271 }}; 268 }};
272 269
273 this.differencesList.setFields(new ListGridField[] {nameField, 270 this.differencesList.setFields(new ListGridField[] {nameField,
274 capitalField, removeField}); 271 capitalField, removeField});
275 272
276 this.differencesList.addRecordClickHandler(new RecordClickHandler() { 273 this.differencesList.addRecordClickHandler(new RecordClickHandler() {
277 @Override 274 @Override
278 public void onRecordClick(final RecordClickEvent event) { 275 public void onRecordClick(final RecordClickEvent event) {
279 // Just handle remove-clicks 276 // Just handle remove-clicks
280 if(!event.getField().getName().equals(removeField.getName())) { 277 if(!event.getField().getName().equals(removeField.getName())) {
281 return; 278 return;
279 }
280 trackRemoved(event.getRecord());
281 event.getViewer().removeData(event.getRecord());
282 } 282 }
283 trackRemoved(event.getRecord()); 283 });
284 event.getViewer().removeData(event.getRecord()); 284 layout.addMember(this.differencesList);
285 } 285
286 }); 286 return layout;
287 layout.addMember(this.differencesList);
288
289 return layout;
290 } 287 }
291 288
292 289
293 /** 290 /**
294 * Add record to list of removed records. 291 * Add record to list of removed records.
320 final List<Recommendation> ar = new ArrayList<Recommendation>(); 317 final List<Recommendation> ar = new ArrayList<Recommendation>();
321 final List<Recommendation> all = new ArrayList<Recommendation>(); 318 final List<Recommendation> all = new ArrayList<Recommendation>();
322 319
323 for (final ListGridRecord record : records) { 320 for (final ListGridRecord record : records) {
324 final RecommendationPairRecord r = 321 final RecommendationPairRecord r =
325 (RecommendationPairRecord) record; 322 (RecommendationPairRecord) record;
326 // Do not add "old" recommendations. 323 // Do not add "old" recommendations.
327 if (!r.isAlreadyLoaded()) { 324 if (!r.isAlreadyLoaded()) {
328 // Check whether one of those is a dike or similar. 325 // Check whether one of those is a dike or similar.
329 // TODO differentiate and merge: new clones, new, old. 326 // TODO differentiate and merge: new clones, new, old.
330 final Recommendation firstR = r.getFirst(); 327 final Recommendation firstR = r.getFirst();
372 369
373 // Remove old artifacts, if any. Do this asychronously without much 370 // Remove old artifacts, if any. Do this asychronously without much
374 // feedback. 371 // feedback.
375 for(final String uuid: artifactIdsToRemove) { 372 for(final String uuid: artifactIdsToRemove) {
376 this.removeArtifactService.remove(this.collection, 373 this.removeArtifactService.remove(this.collection,
377 uuid, 374 uuid,
378 locale, 375 locale,
379 new AsyncCallback<Collection>() { 376 new AsyncCallback<Collection>() {
380 @Override 377 @Override
381 public void onFailure(final Throwable caught) { 378 public void onFailure(final Throwable caught) {
382 GWT.log("RemoveArtifact (" + uuid + ") failed."); 379 GWT.log("RemoveArtifact (" + uuid + ") failed.");
383 } 380 }
384 @Override 381 @Override
385 public void onSuccess(final Collection coll) { 382 public void onSuccess(final Collection coll) {
386 GWT.log("RemoveArtifact succeeded"); 383 GWT.log("RemoveArtifact succeeded");
387 } 384 }
388 }); 385 });
389 } 386 }
390 387
391 // Clone new ones (and spawn statics), go forward. 388 // Clone new ones (and spawn statics), go forward.
392 this.parameterList.lockUI(); 389 this.parameterList.lockUI();
393 this.loadArtifactService.loadMany( 390 this.loadArtifactService.loadMany(
394 this.collection, 391 this.collection,
395 toClone, 392 toClone,
396 //"staticwkms" and "waterlevel" 393 //"staticwkms" and "waterlevel"
397 null, 394 null,
398 locale, 395 locale,
399 new AsyncCallback<Artifact[]>() { 396 new AsyncCallback<Artifact[]>() {
400 @Override 397 @Override
401 public void onFailure(final Throwable caught) { 398 public void onFailure(final Throwable caught) {
402 caught.printStackTrace(); 399 caught.printStackTrace();
403 GWT.log("Failure of cloning with factories!"); 400 GWT.log("Failure of cloning with factories!");
404 AbstractPairRecommendationPanel.this.parameterList.unlockUI(); 401 AbstractPairRecommendationPanel.this.parameterList.unlockUI();
405 } 402 }
406 @Override 403 @Override
407 public void onSuccess(final Artifact[] artifacts) { 404 public void onSuccess(final Artifact[] artifacts) {
408 GWT.log("Successfully cloned " + toClone.length + 405 GWT.log("Successfully cloned " + toClone.length +
409 " with factories."); 406 " with factories.");
410 407
411 fireStepForwardEvent(new StepForwardEvent( 408 fireStepForwardEvent(new StepForwardEvent(
412 getData(toClone, artifacts, toUse))); 409 getData(toClone, artifacts, toUse)));
413 AbstractPairRecommendationPanel.this.parameterList.unlockUI(); 410 AbstractPairRecommendationPanel.this.parameterList.unlockUI();
414 } 411 }
415 }); 412 });
416 } 413 }
417 414
418 /** 415 /**
419 * Create Data and DataItem from selection (a long string with identifiers 416 * Create Data and DataItem from selection (a long string with identifiers
420 * to construct diff-pairs). 417 * to construct diff-pairs).
421 * 418 *
422 * @param newRecommendations "new" recommendations (did not survive a 419 * @param newRecommendations "new" recommendations (did not survive a
438 final Recommendation r = newRecommendations[i]; 435 final Recommendation r = newRecommendations[i];
439 final Artifact newArtifact = newArtifacts[i]; 436 final Artifact newArtifact = newArtifacts[i];
440 final String uuid = newArtifact.getUuid(); 437 final String uuid = newArtifact.getUuid();
441 r.setMasterArtifact(uuid); 438 r.setMasterArtifact(uuid);
442 439
443 if (i>0) 440 if (i>0)
444 dataItemString += "#"; 441 dataItemString += "#";
445 442
446 // REMARK: ugly, but we know that the recommandations comes in left/right pairs. 443 // REMARK: ugly, but we know that the recommandations comes in left/right pairs.
447 final IRecommendationInfo info = i % 2 == 0 ? this.leftInfo : this.rightInfo; 444 final IRecommendationInfo info = i % 2 == 0 ? this.leftInfo : this.rightInfo;
448 445
449 dataItemString += createDataString(uuid, r, info); 446 dataItemString += createDataString(uuid, r, info);
450 } 447 }
451 448
452 for (int i = 0; i < oldRecommendations.length; i++) { 449 for (int i = 0; i < oldRecommendations.length; i++) {
453 final Recommendation r = oldRecommendations[i]; 450 final Recommendation r = oldRecommendations[i];
454 final String uuid = r.getIDs(); 451 final String uuid = r.getIDs();
455 452
456 if (dataItemString.length() > 0) 453 if (dataItemString.length() > 0)
457 dataItemString += "#"; 454 dataItemString += "#";
458 455
459 // REMARK: ugly, but we know that the recommandations comes in left/right pairs. 456 // REMARK: ugly, but we know that the recommandations comes in left/right pairs.
460 final IRecommendationInfo info = i % 2 == 0 ? this.leftInfo : this.rightInfo; 457 final IRecommendationInfo info = i % 2 == 0 ? this.leftInfo : this.rightInfo;
461 458
462 dataItemString += createDataString(uuid, r, info); 459 dataItemString += createDataString(uuid, r, info);
464 461
465 // TODO some hassle could be resolved by using multiple DataItems 462 // TODO some hassle could be resolved by using multiple DataItems
466 // (e.g. one per pair). 463 // (e.g. one per pair).
467 final DataItem item = new DefaultDataItem(this.dataName, this.dataName, dataItemString); 464 final DataItem item = new DefaultDataItem(this.dataName, this.dataName, dataItemString);
468 return new Data[] { new DefaultData( 465 return new Data[] { new DefaultData(
469 this.dataName, null, null, new DataItem[] {item}) }; 466 this.dataName, null, null, new DataItem[] {item}) };
470 } 467 }
471 468
472 /** 469 /**
473 * Creates part of the String that encodes minuend or subtrahend. 470 * Creates part of the String that encodes minuend or subtrahend.
474 * @param recommendation Recommendation to wrap in string. 471 * @param recommendation Recommendation to wrap in string.
475 * @param info Provides the factory to encode. 472 * @param info Provides the factory to encode.
476 */ 473 */
477 protected static final String createDataString(final String artifactUuid, final Recommendation recommendation, final IRecommendationInfo info) { 474 protected static final String createDataString(final String artifactUuid, final Recommendation recommendation, final IRecommendationInfo info) {
478 final String factory = info.getDataStringFactory( recommendation ); 475 final String factory = info.getDataStringFactory( recommendation );
479 476
480 final Filter filter = recommendation.getFilter(); 477 final Filter filter = recommendation.getFilter();
481 Facet f = null; 478 Facet f = null;
482 479
483 if(filter != null) { 480 if(filter != null) {
484 final Map<String, List<Facet>> outs = filter.getOuts(); 481 final Map<String, List<Facet>> outs = filter.getOuts();
485 final Set<Map.Entry<String, List<Facet>>> entries = outs.entrySet(); 482 final Set<Map.Entry<String, List<Facet>>> entries = outs.entrySet();
486 483
487 for (final Map.Entry<String, List<Facet>> entry: entries) { 484 for (final Map.Entry<String, List<Facet>> entry: entries) {
488 final List<Facet> fs = entry.getValue(); 485 final List<Facet> fs = entry.getValue();
489 486
490 f = fs.get(0); 487 f = fs.get(0);
491 if (f != null) { 488 if (f != null) {
492 break; 489 break;
493 } 490 }
494 } 491 }
495 492
496 return "[" + artifactUuid + ";" 493 return "[" + artifactUuid + ";"
497 + f.getName() 494 + f.getName()
498 + ";" 495 + ";"
499 + f.getIndex() 496 + f.getIndex()
500 + ";" 497 + ";"
501 + recommendation.getDisplayName() + "]"; 498 + recommendation.getDisplayName() + "]";
502 } 499 }
503 500
504 return "[" 501 return "["
505 + artifactUuid 502 + artifactUuid
506 + ";" + factory + ";0;" 503 + ";" + factory + ";0;"
507 + recommendation.getDisplayName() + "]"; 504 + recommendation.getDisplayName() + "]";
508 } 505 }
509 } 506 }

http://dive4elements.wald.intevation.org