1 package fr.ifremer.tutti.ui.swing.content.operation.catches;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 import com.google.common.base.Function;
28 import com.google.common.collect.HashMultimap;
29 import com.google.common.collect.ImmutableSet;
30 import com.google.common.collect.Multimap;
31 import com.google.common.collect.Sets;
32 import fr.ifremer.tutti.TuttiConfiguration;
33 import fr.ifremer.tutti.persistence.entities.data.CatchBatch;
34 import fr.ifremer.tutti.persistence.entities.data.FishingOperation;
35 import fr.ifremer.tutti.type.WeightUnit;
36 import fr.ifremer.tutti.ui.swing.TuttiUIContext;
37 import fr.ifremer.tutti.ui.swing.util.TuttiUIUtil;
38 import fr.ifremer.tutti.ui.swing.util.catches.EnterWeightUI;
39 import fr.ifremer.tutti.ui.swing.util.computable.ComputableData;
40 import fr.ifremer.tutti.util.Numbers;
41 import jaxx.runtime.JAXXUtil;
42 import org.apache.batik.bridge.UpdateManager;
43 import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
44 import org.apache.batik.dom.svg.SVGOMRectElement;
45 import org.apache.batik.dom.svg.SVGOMTextElement;
46 import org.apache.batik.swing.JSVGCanvas;
47 import org.apache.batik.swing.gvt.GVTTreeRendererAdapter;
48 import org.apache.batik.swing.gvt.GVTTreeRendererEvent;
49 import org.apache.batik.swing.svg.SVGUserAgentAdapter;
50 import org.apache.batik.util.XMLResourceDescriptor;
51 import org.apache.commons.beanutils.BeanUtils;
52 import org.apache.commons.logging.Log;
53 import org.apache.commons.logging.LogFactory;
54 import org.nuiton.jaxx.application.bean.JavaBeanObjectUtil;
55 import org.nuiton.util.Resource;
56 import org.w3c.dom.Document;
57 import org.w3c.dom.Element;
58 import org.w3c.dom.css.CSSStyleDeclaration;
59 import org.w3c.dom.events.EventListener;
60 import org.w3c.dom.events.EventTarget;
61 import org.w3c.dom.svg.SVGRect;
62 import org.w3c.dom.svg.SVGStylable;
63
64 import java.awt.BorderLayout;
65 import java.awt.Color;
66 import java.awt.Dimension;
67 import java.beans.PropertyChangeEvent;
68 import java.beans.PropertyChangeListener;
69 import java.io.IOException;
70 import java.net.URL;
71 import java.util.Objects;
72 import java.util.Set;
73
74 import static org.nuiton.i18n.I18n.n;
75 import static org.nuiton.i18n.I18n.t;
76
77
78
79
80
81
82
83 public class EditCatchesSvgHandler {
84
85
86 private static final Log log = LogFactory.getLog(EditCatchesSvgHandler.class);
87
88 protected Multimap<String, PropertyChangeListener> svgRelatedPropertyChangeListeners = HashMultimap.create();
89
90 protected JSVGCanvas canvas;
91
92 protected Document svgDocument;
93
94 protected final TuttiUIContext context;
95
96 protected final EditCatchesUI ui;
97
98 protected final EditCatchesUIModel model;
99
100 protected final SVGUserAgentAdapter ua = new SVGUserAgentAdapter() {
101 @Override
102 public void displayError(String message) {
103 if (log.isErrorEnabled()) {
104 log.error("Canvas error: " + message);
105 }
106 }
107
108 @Override
109 public void displayError(Exception ex) {
110 if (log.isErrorEnabled()) {
111 log.error("Canvas error", ex);
112 }
113 }
114 };
115
116 public EditCatchesSvgHandler(TuttiUIContext context, EditCatchesUI ui, EditCatchesUIModel model) {
117 this.context = context;
118 this.ui = ui;
119 this.model = model;
120 }
121
122
123 public void initResumeSvg() {
124
125 ui.getSvgCanvasPanel().removeAll();
126
127 try {
128 String parser = XMLResourceDescriptor.getXMLParserClassName();
129 SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
130 URL url = Resource.getURL("EcranResume.svg");
131 svgDocument = f.createDocument(url.toString());
132
133
134 canvas = new JSVGCanvas(ua, true, true);
135 canvas.setBackground(Color.decode("#d6d9df"));
136 canvas.setSize(new Dimension(1, 1));
137 canvas.setMySize(new Dimension(1, 1));
138
139 canvas.setRecenterOnResize(true);
140
141 final TuttiConfiguration config = context.getConfig();
142
143 final Color catchColor = config.getColorCatch();
144 final Color speciesColor = config.getColorSpecies();
145 final Color benthosColor = config.getColorBenthos();
146 final Color speciesOrBenthosUnsortedComputedWeightInWarningColor = config.getColorSpeciesOrBenthosUnsortedComputedWeightInWarning();
147 final Color marineLitterColor = config.getColorMarineLitter();
148
149 canvas.addGVTTreeRendererListener(new GVTTreeRendererAdapter() {
150 @Override
151 public void gvtRenderingCompleted(GVTTreeRendererEvent gvtTreeRendererEvent) {
152 if (log.isDebugEnabled()) {
153 log.debug("gvtRenderingCompleted");
154 }
155 WeightUnit catchWeightUnit = model.getCatchWeightUnit();
156 WeightUnit speciesWeightUnit = config.getSpeciesWeightUnit();
157 WeightUnit benthosWeightUnit = config.getBenthosWeightUnit();
158 WeightUnit marineLitterWeightUnit = config.getMarineLitterWeightUnit();
159
160 initSvgField(n("tutti.editCatchBatch.field.catchTotalWeight"),
161 CatchBatch.PROPERTY_CATCH_TOTAL_WEIGHT,
162 CatchBatch.PROPERTY_CATCH_TOTAL_COMPUTED_WEIGHT,
163 model.getCatchTotalComputedOrNotWeight(),
164 catchWeightUnit,
165 catchColor);
166
167 initSvgField(n("tutti.editCatchBatch.field.catchTotalSortedComputedWeight"),
168 CatchBatch.PROPERTY_CATCH_TOTAL_SORTED_COMPUTED_WEIGHT, catchWeightUnit, catchColor);
169
170 initSvgField(n("tutti.editCatchBatch.field.catchTotalRejectedWeight"),
171 CatchBatch.PROPERTY_CATCH_TOTAL_REJECTED_WEIGHT,
172 CatchBatch.PROPERTY_CATCH_TOTAL_REJECTED_COMPUTED_WEIGHT,
173 model.getCatchTotalRejectedComputedOrNotWeight(),
174 catchWeightUnit,
175 catchColor);
176 initSvgField(n("tutti.editCatchBatch.field.catchTotalSortedSortedComputedWeight"),
177 CatchBatch.PROPERTY_CATCH_TOTAL_SORTED_SORTED_COMPUTED_WEIGHT, catchWeightUnit, catchColor);
178
179 initSvgField(n("tutti.editCatchBatch.field.speciesTotalSortedWeight"),
180 CatchBatch.PROPERTY_SPECIES_TOTAL_SORTED_WEIGHT,
181 CatchBatch.PROPERTY_SPECIES_TOTAL_SORTED_COMPUTED_WEIGHT,
182 model.getSpeciesTotalSortedComputedOrNotWeight(),
183 speciesWeightUnit,
184 speciesColor);
185 initSvgField(n("tutti.editCatchBatch.field.speciesTotalSampleSortedComputedWeight"),
186 CatchBatch.PROPERTY_SPECIES_TOTAL_SAMPLE_SORTED_COMPUTED_WEIGHT, speciesWeightUnit, speciesColor);
187
188 initSvgField(n("tutti.editCatchBatch.field.speciesTotalInertWeight"),
189 CatchBatch.PROPERTY_SPECIES_TOTAL_INERT_WEIGHT,
190 CatchBatch.PROPERTY_SPECIES_TOTAL_INERT_COMPUTED_WEIGHT,
191 model.getSpeciesTotalInertComputedOrNotWeight(),
192 speciesWeightUnit,
193 null);
194 initSvgField(n("tutti.editCatchBatch.field.speciesTotalLivingNotItemizedWeight"),
195 CatchBatch.PROPERTY_SPECIES_TOTAL_LIVING_NOT_ITEMIZED_WEIGHT,
196 CatchBatch.PROPERTY_SPECIES_TOTAL_LIVING_NOT_ITEMIZED_COMPUTED_WEIGHT,
197 model.getSpeciesTotalLivingNotItemizedComputedOrNotWeight(),
198 speciesWeightUnit,
199 null);
200
201 initSvgField(n("tutti.editCatchBatch.field.benthosTotalSortedWeight"),
202 CatchBatch.PROPERTY_BENTHOS_TOTAL_SORTED_WEIGHT,
203 CatchBatch.PROPERTY_BENTHOS_TOTAL_SORTED_COMPUTED_WEIGHT,
204 model.getBenthosTotalSortedComputedOrNotWeight(),
205 benthosWeightUnit,
206 benthosColor);
207
208 initSvgField(n("tutti.editCatchBatch.field.benthosTotalSampleSortedComputedWeight"),
209 CatchBatch.PROPERTY_BENTHOS_TOTAL_SAMPLE_SORTED_COMPUTED_WEIGHT, benthosWeightUnit, benthosColor);
210
211 initSvgField(n("tutti.editCatchBatch.field.benthosTotalInertWeight"),
212 CatchBatch.PROPERTY_BENTHOS_TOTAL_INERT_WEIGHT,
213 CatchBatch.PROPERTY_BENTHOS_TOTAL_INERT_COMPUTED_WEIGHT,
214 model.getBenthosTotalInertComputedOrNotWeight(),
215 benthosWeightUnit,
216 null);
217
218 initSvgField(n("tutti.editCatchBatch.field.benthosTotalLivingNotItemizedWeight"),
219 CatchBatch.PROPERTY_BENTHOS_TOTAL_LIVING_NOT_ITEMIZED_WEIGHT,
220 CatchBatch.PROPERTY_BENTHOS_TOTAL_LIVING_NOT_ITEMIZED_COMPUTED_WEIGHT,
221 model.getBenthosTotalLivingNotItemizedComputedOrNotWeight(),
222 benthosWeightUnit,
223 null);
224
225 initSvgField(n("tutti.editCatchBatch.field.catchTotalUnsortedComputedWeight"),
226 CatchBatch.PROPERTY_CATCH_TOTAL_UNSORTED_COMPUTED_WEIGHT, catchWeightUnit, catchColor);
227 initSvgField(n("tutti.editCatchBatch.field.speciesTotalUnsortedComputedWeight"),
228 CatchBatch.PROPERTY_SPECIES_TOTAL_UNSORTED_COMPUTED_WEIGHT, speciesWeightUnit, speciesColor);
229 initSvgField(n("tutti.editCatchBatch.field.benthosTotalUnsortedComputedWeight"),
230 CatchBatch.PROPERTY_BENTHOS_TOTAL_UNSORTED_COMPUTED_WEIGHT, benthosWeightUnit, benthosColor);
231
232 addSvgRelatedPropertyChangeListener(null, new ChangeElementBackgroundColorPropertyChangeListener(
233 CatchBatch.PROPERTY_SPECIES_TOTAL_UNSORTED_COMPUTED_WEIGHT,
234 Sets.newHashSet(CatchBatch.PROPERTY_CATCH_TOTAL_REJECTED_WEIGHT,
235 CatchBatch.PROPERTY_CATCH_TOTAL_REJECTED_COMPUTED_WEIGHT,
236 CatchBatch.PROPERTY_SPECIES_TOTAL_SORTED_WEIGHT,
237 CatchBatch.PROPERTY_SPECIES_TOTAL_SORTED_COMPUTED_WEIGHT,
238 CatchBatch.PROPERTY_SPECIES_TOTAL_SAMPLE_SORTED_COMPUTED_WEIGHT),
239 model1 -> {
240 boolean warning = model1.isSpeciesTotalUnsortedComputedWeightInWarning();
241 return warning ? speciesOrBenthosUnsortedComputedWeightInWarningColor : speciesColor;
242 }));
243
244 addSvgRelatedPropertyChangeListener(null, new ChangeElementBackgroundColorPropertyChangeListener(
245 CatchBatch.PROPERTY_BENTHOS_TOTAL_UNSORTED_COMPUTED_WEIGHT,
246 Sets.newHashSet(CatchBatch.PROPERTY_CATCH_TOTAL_REJECTED_WEIGHT,
247 CatchBatch.PROPERTY_CATCH_TOTAL_REJECTED_COMPUTED_WEIGHT,
248 CatchBatch.PROPERTY_BENTHOS_TOTAL_SORTED_WEIGHT,
249 CatchBatch.PROPERTY_BENTHOS_TOTAL_SORTED_COMPUTED_WEIGHT,
250 CatchBatch.PROPERTY_BENTHOS_TOTAL_SAMPLE_SORTED_COMPUTED_WEIGHT),
251 model1 -> {
252 boolean warning = model1.isBenthosTotalUnsortedComputedWeightInWarning();
253 return warning ? speciesOrBenthosUnsortedComputedWeightInWarningColor : benthosColor;
254 }));
255
256 initSvgField(n("tutti.editCatchBatch.field.speciesTotalComputedWeight"),
257 CatchBatch.PROPERTY_SPECIES_TOTAL_COMPUTED_WEIGHT,
258 speciesWeightUnit,
259 speciesColor,
260 CatchBatch.PROPERTY_BENTHOS_TOTAL_COMPUTED_WEIGHT,
261 CatchBatch.PROPERTY_MARINE_LITTER_TOTAL_WEIGHT);
262 initSvgField(n("tutti.editCatchBatch.field.benthosTotalComputedWeight"),
263 CatchBatch.PROPERTY_BENTHOS_TOTAL_COMPUTED_WEIGHT,
264 benthosWeightUnit,
265 benthosColor,
266 CatchBatch.PROPERTY_SPECIES_TOTAL_COMPUTED_WEIGHT,
267 CatchBatch.PROPERTY_MARINE_LITTER_TOTAL_WEIGHT);
268 initSvgField(n("tutti.editCatchBatch.field.marineLitterTotalWeight"),
269 CatchBatch.PROPERTY_MARINE_LITTER_TOTAL_WEIGHT,
270 CatchBatch.PROPERTY_MARINE_LITTER_TOTAL_COMPUTED_WEIGHT,
271 model.getMarineLitterTotalComputedOrNotWeight(),
272 marineLitterWeightUnit,
273 marineLitterColor,
274 CatchBatch.PROPERTY_SPECIES_TOTAL_COMPUTED_WEIGHT,
275 CatchBatch.PROPERTY_BENTHOS_TOTAL_COMPUTED_WEIGHT);
276
277 addSvgRelatedPropertyChangeListener(null, new RatioPropertyChangeListener("ratioSpeciesSampleSortedOverSpeciesSortedWeightLabel",
278 CatchBatch.PROPERTY_SPECIES_TOTAL_SAMPLE_SORTED_COMPUTED_WEIGHT,
279 CatchBatch.PROPERTY_SPECIES_TOTAL_SORTED_WEIGHT,
280 CatchBatch.PROPERTY_SPECIES_TOTAL_SORTED_COMPUTED_WEIGHT));
281 addSvgRelatedPropertyChangeListener(null, new RatioPropertyChangeListener("ratioBenthosSampleSortedOverBenthosSortedWeightLabel",
282 CatchBatch.PROPERTY_BENTHOS_TOTAL_SAMPLE_SORTED_COMPUTED_WEIGHT,
283 CatchBatch.PROPERTY_BENTHOS_TOTAL_SORTED_WEIGHT,
284 CatchBatch.PROPERTY_BENTHOS_TOTAL_SORTED_COMPUTED_WEIGHT));
285 addSvgRelatedPropertyChangeListener(null, new RatioPropertyChangeListener("ratioSortedSortedOverSortedWeightLabel",
286 CatchBatch.PROPERTY_CATCH_TOTAL_SORTED_SORTED_COMPUTED_WEIGHT,
287 CatchBatch.PROPERTY_CATCH_TOTAL_SORTED_COMPUTED_WEIGHT,
288 CatchBatch.PROPERTY_CATCH_TOTAL_SORTED_COMPUTED_WEIGHT));
289
290 initSpeciesCount(n("tutti.editCatchBatch.field.speciesDistinctSortedSpeciesCount"),
291 CatchBatch.PROPERTY_SPECIES_DISTINCT_SORTED_SPECIES_COUNT);
292 initSpeciesCount(n("tutti.editCatchBatch.field.benthosDistinctSortedSpeciesCount"),
293 CatchBatch.PROPERTY_BENTHOS_DISTINCT_SORTED_SPECIES_COUNT);
294
295 initSpeciesCount(n("tutti.editCatchBatch.field.speciesDistinctUnsortedSpeciesCount"),
296 CatchBatch.PROPERTY_SPECIES_DISTINCT_UNSORTED_SPECIES_COUNT);
297 initSpeciesCount(n("tutti.editCatchBatch.field.benthosDistinctUnsortedSpeciesCount"),
298 CatchBatch.PROPERTY_BENTHOS_DISTINCT_UNSORTED_SPECIES_COUNT);
299
300 initTremieCarrouselField(n("tutti.editCatchBatch.field.catchTotalSortedCarousselWeight"),
301 CatchBatch.PROPERTY_CATCH_TOTAL_SORTED_CAROUSSEL_WEIGHT, catchWeightUnit);
302 initTremieCarrouselField(n("tutti.editCatchBatch.field.catchTotalSortedTremisWeight"),
303 CatchBatch.PROPERTY_CATCH_TOTAL_SORTED_TREMIS_WEIGHT, catchWeightUnit);
304
305 ui.getSvgCanvasPanel().add(canvas, BorderLayout.CENTER);
306 }
307 });
308
309 canvas.setDocumentState(JSVGCanvas.ALWAYS_DYNAMIC);
310 canvas.setDocument(svgDocument);
311
312 } catch (IOException err) {
313 if (log.isErrorEnabled()) {
314 log.error("error while initializing the resume background", err);
315 }
316 context.getErrorHelper().showErrorDialog(t("tutti.editCatchBatch.svgLoading.error"), err);
317 }
318 }
319
320 public void clearSVG() {
321
322 for (String property : svgRelatedPropertyChangeListeners.keySet()) {
323 for (PropertyChangeListener listener : svgRelatedPropertyChangeListeners.get(property)) {
324 if (property != null) {
325 model.removePropertyChangeListener(property, listener);
326 } else {
327 model.removePropertyChangeListener(listener);
328 }
329 }
330 }
331 svgRelatedPropertyChangeListeners.clear();
332
333 if (canvas != null) {
334 UpdateManager updateManager = canvas.getUpdateManager();
335 if (updateManager != null ) {
336 try {
337 updateManager.suspend();
338 } catch (Exception e) {
339
340 }
341 }
342 try {
343 canvas.dispose();
344 } catch (Exception e) {
345
346 }
347 ui.getSvgCanvasPanel().remove(canvas);
348 }
349 }
350
351 protected void initSvgField(String label, String computedProperty, WeightUnit weightUnit, Color bgColor, String... idsInGroup) {
352 initSvgField(label, null, computedProperty, null, weightUnit, bgColor, idsInGroup);
353 }
354
355 protected void initSvgField(final String label,
356 String property,
357 String computedProperty,
358 final ComputableData<Float> computableData,
359 final WeightUnit weightUnit,
360 final Color bgColor,
361 final String... idsInGroup) {
362
363 if (log.isDebugEnabled()) {
364 log.debug("init " + property + " field");
365 }
366
367 final String notNullProperty = property != null ? property : computedProperty;
368
369 OnDataOrComputedDataValueChangedListener listener = new OnDataOrComputedDataValueChangedListener(notNullProperty, computableData, weightUnit, idsInGroup);
370 if (property != null) {
371 addSvgRelatedPropertyChangeListener(property, listener);
372 }
373 if (computedProperty != null) {
374 addSvgRelatedPropertyChangeListener(computedProperty, listener);
375 }
376
377 if (computableData != null) {
378
379 Element element = svgDocument.getElementById(property);
380 EventTarget target = (EventTarget) element;
381 target.addEventListener("click", new OnValueClickListener(computableData, property, weightUnit), false);
382 }
383
384 updateOnCanvas(() -> {
385
386 SVGOMRectElement rectElement = (SVGOMRectElement) svgDocument.getElementById(notNullProperty + "Rect");
387 SVGRect bbox = rectElement.getBBox();
388 Float x = bbox.getX();
389
390 SVGOMTextElement labelElement = (SVGOMTextElement) svgDocument.getElementById(notNullProperty + "Label");
391 CSSStyleDeclaration style = labelElement.getStyle();
392 if (computableData == null) {
393 style.setProperty("font-style", "italic", null);
394 }
395
396 if (bgColor != null) {
397 int colorBrightness = TuttiUIUtil.getColorBrightness(bgColor);
398 String textColor = colorBrightness > 150 ? "#000000" : "#FFFFFF";
399 style.setProperty("fill", textColor, null);
400 }
401
402 labelElement.setTextContent(weightUnit.decorateLabel(t(label)));
403 bbox = labelElement.getBBox();
404 float labelX = bbox.getX();
405 float width = Math.abs(x - labelX) + 10;
406
407 SVGOMRectElement labelRectElement = (SVGOMRectElement) svgDocument.getElementById(notNullProperty + "LabelRect");
408 if (labelRectElement != null) {
409 float actualWidth = Math.abs(labelRectElement.getBBox().getX() - labelX) + 10;
410
411 if (actualWidth < width) {
412 labelRectElement.setAttribute("width", Float.toString(width));
413 labelRectElement.setAttribute("x", String.valueOf(labelX - 10));
414
415 for (String id : idsInGroup) {
416 Element el = svgDocument.getElementById(id + "LabelRect");
417 el.setAttribute("width", Float.toString(width));
418 el.setAttribute("x", String.valueOf(labelX - 10));
419 }
420 }
421
422 style = labelRectElement.getStyle();
423 String hexaColor = "#" + Integer.toHexString(bgColor.getRGB()).substring(2);
424 style.setProperty("fill", hexaColor, null);
425 }
426
427 Float value;
428 boolean computed;
429 if (computableData == null) {
430 computed = true;
431 value = getModelPropertyValue(notNullProperty);
432
433 } else if (computableData.getData() == null) {
434 computed = true;
435 value = computableData.getComputedData();
436
437 } else {
438 computed = false;
439 value = computableData.getData();
440 }
441
442 updateValue(notNullProperty, value, weightUnit, computed, idsInGroup);
443 });
444
445 }
446
447 protected void updateOnCanvas(Runnable runnable) {
448 try {
449 canvas.getUpdateManager().getUpdateRunnableQueue().invokeLater(runnable);
450 } catch (IllegalStateException e) {
451 if (log.isErrorEnabled()) {
452 log.error("error while updating canvas, reload it");
453 }
454 clearSVG();
455 initResumeSvg();
456 }
457 }
458
459 protected void addSvgRelatedPropertyChangeListener(String property, PropertyChangeListener listener) {
460 svgRelatedPropertyChangeListeners.put(property, listener);
461 if (property != null) {
462 model.addPropertyChangeListener(property, listener);
463 } else {
464 model.addPropertyChangeListener(listener);
465 }
466 }
467
468 protected void updateValue(final String property,
469 final Float value,
470 final WeightUnit weightUnit,
471 final boolean computed,
472 final String... idsInGroup) {
473
474 updateOnCanvas(() -> {
475 if (log.isDebugEnabled()) {
476 log.debug("update " + property + " field");
477 }
478
479 SVGOMTextElement valueElement = (SVGOMTextElement) svgDocument.getElementById(property + "Value");
480 if (valueElement == null) {
481 return;
482 }
483
484
485 String textContent;
486 if (value != null) {
487 textContent = weightUnit.renderWeight(value) + " " + weightUnit.getShortLabel();
488 } else {
489 textContent = null;
490 }
491 valueElement.setTextContent(textContent);
492
493 CSSStyleDeclaration style = valueElement.getStyle();
494
495 Color colorComputedWeights = context.getConfig().getColorComputedWeights();
496 String computedColor = "#" + Integer.toHexString(colorComputedWeights.getRGB()).substring(2);
497 style.setProperty("fill", computed ? computedColor : "#000000", null);
498 style.setProperty("font-style", computed ? "italic" : "normal", null);
499
500 SVGRect bbox = valueElement.getBBox();
501 SVGOMRectElement rectElement = (SVGOMRectElement) svgDocument.getElementById(property + "Rect");
502 if (bbox != null && rectElement != null) {
503 float width = bbox.getWidth() + 15;
504 float actualWidth = rectElement.getBBox().getWidth();
505 if (actualWidth < width) {
506 rectElement.setAttribute("width", Float.toString(width));
507 for (String id : idsInGroup) {
508 Element el = svgDocument.getElementById(id + "Rect");
509 el.setAttribute("width", Float.toString(width));
510 }
511 }
512 }
513 });
514
515 }
516
517 protected Float getModelPropertyValue(String property) {
518 Float value;
519 try {
520 String sValue = BeanUtils.getProperty(model, property);
521 if (sValue != null) {
522 value = Float.parseFloat(sValue);
523 } else {
524 value = null;
525 }
526
527 } catch (ReflectiveOperationException e) {
528 if (log.isErrorEnabled()) {
529 log.error("error on reading model's property " + property, e);
530 }
531 value = null;
532 }
533 return value;
534 }
535
536 protected void initSpeciesCount(final String label, final String property) {
537
538 if (log.isDebugEnabled()) {
539 log.debug("init " + property + " field");
540 }
541
542 updateOnCanvas(() -> {
543 Element labelElement = svgDocument.getElementById(property + "Label");
544 labelElement.setTextContent(t(label));
545
546 Element valueElement = svgDocument.getElementById(property + "Value");
547 Integer value;
548 try {
549 String sValue = BeanUtils.getProperty(model, property);
550 if (sValue != null) {
551 value = Integer.parseInt(sValue);
552 } else {
553 value = null;
554 }
555
556 } catch (ReflectiveOperationException e) {
557 if (log.isErrorEnabled()) {
558 log.error("error on reading model's property " + property, e);
559 }
560 value = null;
561 }
562 valueElement.setTextContent(JAXXUtil.getStringValue(value));
563 });
564
565 addSvgRelatedPropertyChangeListener(property, evt -> {
566 final Integer value = (Integer) evt.getNewValue();
567 updateOnCanvas(() -> {
568 Element labelElement = svgDocument.getElementById(property + "Value");
569 labelElement.setTextContent(JAXXUtil.getStringValue(value));
570 });
571 });
572 }
573
574 protected void initTremieCarrouselField(final String label, final String property, final WeightUnit weightUnit) {
575 if (log.isDebugEnabled()) {
576 log.debug("init " + property + " field");
577 }
578
579 updateOnCanvas(() -> {
580 Element labelElement = svgDocument.getElementById(property + "Label");
581 labelElement.setTextContent(weightUnit.decorateLabel(t(label)));
582 });
583
584 addSvgRelatedPropertyChangeListener(property, evt -> {
585 Float value = (Float) evt.getNewValue();
586 updateValue(property, value, weightUnit, true);
587 });
588
589 Float value = getModelPropertyValue(property);
590 updateValue(property, value, weightUnit, true);
591
592 addSvgRelatedPropertyChangeListener(EditCatchesUIModel.PROPERTY_FISHING_OPERATION, evt -> updateTremieCarrouselVisibility(property));
593 updateTremieCarrouselVisibility(property);
594 }
595
596
597 protected void updateTremieCarrouselVisibility(final String property) {
598 FishingOperation fishingOperation = model.getFishingOperation();
599 if (fishingOperation != null) {
600 final boolean tremieCarrouselFieldsVisisble = fishingOperation.getVessel() != null
601 && fishingOperation.getVessel().getId().equals(context.getConfig().getTremieCarousselVesselId());
602
603 updateOnCanvas(() -> {
604 Element labelElement = svgDocument.getElementById(property + "Label");
605 labelElement.setAttribute("visibility", tremieCarrouselFieldsVisisble ? "visible" : "hidden");
606
607 Element valueElement = svgDocument.getElementById(property + "Value");
608 valueElement.setAttribute("visibility", tremieCarrouselFieldsVisisble ? "visible" : "hidden");
609 });
610 }
611 }
612
613 private class OnValueClickListener implements EventListener {
614
615 private final ComputableData<Float> computableData;
616
617 private final String property;
618
619 private final WeightUnit weightUnit;
620
621 public OnValueClickListener(ComputableData<Float> computableData, String property, WeightUnit weightUnit) {
622 this.computableData = computableData;
623 this.property = property;
624 this.weightUnit = weightUnit;
625 }
626
627 public void handleEvent(org.w3c.dom.events.Event evt) {
628 log.info("element clicked");
629 EnterWeightUI dialog = new EnterWeightUI(context);
630 Float originalWeight = computableData.getData();
631 Float weight = dialog.openAndGetWeightValue(t("tutti.editCatchBatch.field." + property),
632 originalWeight,
633 weightUnit);
634
635 if (!Objects.equals(originalWeight, weight)) {
636
637 computableData.setData(weight);
638 }
639 }
640 }
641
642 private class OnDataOrComputedDataValueChangedListener implements PropertyChangeListener {
643
644 private final String property;
645
646 private final ComputableData<Float> computableData;
647
648 private final WeightUnit weightUnit;
649
650 private final String[] idsInGroup;
651
652 public OnDataOrComputedDataValueChangedListener(String property,
653 ComputableData<Float> computableData,
654 WeightUnit weightUnit,
655 String... idsInGroup) {
656 this.property = property;
657 this.computableData = computableData;
658 this.weightUnit = weightUnit;
659 this.idsInGroup = idsInGroup;
660 }
661
662 @Override
663 public void propertyChange(PropertyChangeEvent evt) {
664 boolean computedData;
665 Float newValue;
666
667 if (computableData == null) {
668 computedData = true;
669 newValue = (Float) evt.getNewValue();
670
671 } else {
672 if (computableData.getData() == null) {
673 computedData = true;
674 newValue = computableData.getComputedData();
675
676 } else {
677 computedData = false;
678 newValue = computableData.getData();
679 }
680 }
681 updateValue(property, newValue, weightUnit, computedData, idsInGroup);
682 }
683
684 }
685
686 private class ChangeElementBackgroundColorPropertyChangeListener implements PropertyChangeListener {
687
688 private final String elementId;
689
690 private Set<String> propertiesToListen;
691
692 private Function<EditCatchesUIModel, Color> colorFunction;
693
694 public ChangeElementBackgroundColorPropertyChangeListener(String elementId,
695 Set<String> propertiesToListen,
696 Function<EditCatchesUIModel, Color> colorFunction) {
697 this.elementId = elementId;
698 this.propertiesToListen = propertiesToListen;
699 this.colorFunction = colorFunction;
700
701 updateColor();
702 }
703
704 @Override
705 public void propertyChange(PropertyChangeEvent evt) {
706 if (propertiesToListen.contains(evt.getPropertyName())) {
707 updateColor();
708 }
709 }
710
711 protected void updateColor() {
712 updateOnCanvas(() -> {
713 if (log.isDebugEnabled()) {
714 log.debug("update " + elementId + " field");
715 }
716
717 Element rectElement = svgDocument.getElementById(elementId + "LabelRect");
718 SVGStylable field = (SVGStylable) rectElement;
719 CSSStyleDeclaration style = field.getStyle();
720
721 Color background = colorFunction.apply(model);
722 String color = "#" + Integer.toHexString(background.getRGB()).substring(2);
723 style.setProperty("fill", color, null);
724
725 SVGOMTextElement labelElement = (SVGOMTextElement) svgDocument.getElementById(elementId + "Label");
726 CSSStyleDeclaration labelStyle = labelElement.getStyle();
727
728 int colorBrightness = TuttiUIUtil.getColorBrightness(background);
729 String textColor = colorBrightness > 150 ? "#000000" : "#FFFFFF";
730 labelStyle.setProperty("fill", textColor, null);
731 });
732 }
733 }
734
735 private class RatioPropertyChangeListener implements PropertyChangeListener {
736
737 private final String elementId;
738
739 private final String numeratorProperty;
740
741 private final String denominatorProperty;
742
743 private final String denominatorComputedProperty;
744
745 private Integer ratio = null;
746
747 private final Set<String> propertyNames;
748
749 public RatioPropertyChangeListener(String elementId,
750 String numeratorProperty,
751 String denominatorProperty,
752 String denominatorComputedProperty) {
753 this.elementId = elementId;
754 this.numeratorProperty = numeratorProperty;
755 this.denominatorProperty = denominatorProperty;
756 this.denominatorComputedProperty = denominatorComputedProperty;
757 this.propertyNames = ImmutableSet.of(numeratorProperty, denominatorProperty, denominatorComputedProperty);
758 updateRatioText();
759 }
760
761 @Override
762 public void propertyChange(PropertyChangeEvent evt) {
763 String propertyName = evt.getPropertyName();
764
765 if (propertyNames.contains(propertyName)) {
766 updateRatioText();
767 }
768 }
769
770 protected void updateRatioText() {
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795 Float numerator = (Float) JavaBeanObjectUtil.getProperty(model, numeratorProperty);
796 Float denominator = (Float) JavaBeanObjectUtil.getProperty(model, denominatorProperty);
797 if (denominator == null) {
798 denominator = (Float) JavaBeanObjectUtil.getProperty(model, denominatorComputedProperty);
799 }
800 if (numerator == null || WeightUnit.KG.isNullOrZero(denominator)) {
801 ratio = null;
802 } else {
803 ratio = Numbers.roundToInt(100f * numerator / denominator);
804 }
805
806 updateOnCanvas(() -> {
807 if (log.isDebugEnabled()) {
808 log.debug("update " + elementId + " field");
809 }
810
811 Element ratioElement = svgDocument.getElementById(elementId);
812 String textContent;
813 if (ratio != null) {
814 textContent = ratio + "%";
815 } else {
816 textContent = null;
817 }
818 ratioElement.setTextContent(textContent);
819 });
820 }
821 }
822
823 }