ref #7458 solving generic type parameter problem in FilterableAnnotationsField
[cdm-vaadin.git] / src / main / java / eu / etaxonomy / cdm / vaadin / view / name / TaxonNamePopupEditor.java
1 /**
2 * Copyright (C) 2017 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.cdm.vaadin.view.name;
10
11 import java.util.Collection;
12 import java.util.EnumSet;
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.UUID;
17
18 import org.apache.commons.lang3.BooleanUtils;
19 import org.apache.log4j.Level;
20 import org.springframework.context.annotation.Scope;
21 import org.springframework.security.core.GrantedAuthority;
22 import org.vaadin.viritin.fields.LazyComboBox;
23
24 import com.vaadin.data.Property;
25 import com.vaadin.data.Property.ValueChangeListener;
26 import com.vaadin.shared.ui.label.ContentMode;
27 import com.vaadin.spring.annotation.SpringComponent;
28 import com.vaadin.ui.AbstractField;
29 import com.vaadin.ui.Alignment;
30 import com.vaadin.ui.CheckBox;
31 import com.vaadin.ui.GridLayout;
32 import com.vaadin.ui.Label;
33 import com.vaadin.ui.ListSelect;
34 import com.vaadin.ui.TextField;
35
36 import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
37 import eu.etaxonomy.cdm.model.common.AnnotationType;
38 import eu.etaxonomy.cdm.model.common.CdmBase;
39 import eu.etaxonomy.cdm.model.common.RelationshipBase.Direction;
40 import eu.etaxonomy.cdm.model.name.NameRelationshipType;
41 import eu.etaxonomy.cdm.model.name.Rank;
42 import eu.etaxonomy.cdm.model.name.TaxonName;
43 import eu.etaxonomy.cdm.model.reference.Reference;
44 import eu.etaxonomy.cdm.vaadin.component.TextFieldNFix;
45 import eu.etaxonomy.cdm.vaadin.component.common.FilterableAnnotationsField;
46 import eu.etaxonomy.cdm.vaadin.component.common.TeamOrPersonField;
47 import eu.etaxonomy.cdm.vaadin.event.ReferenceEditorAction;
48 import eu.etaxonomy.cdm.vaadin.event.TaxonNameEditorAction;
49 import eu.etaxonomy.cdm.vaadin.model.name.NameRelationshipDTO;
50 import eu.etaxonomy.cdm.vaadin.model.name.TaxonNameDTO;
51 import eu.etaxonomy.cdm.vaadin.permission.AccessRestrictedView;
52 import eu.etaxonomy.cdm.vaadin.permission.CdmEditDeletePermissionTester;
53 import eu.etaxonomy.cdm.vaadin.util.TeamOrPersonBaseCaptionGenerator;
54 import eu.etaxonomy.cdm.vaadin.util.converter.SetToListConverter;
55 import eu.etaxonomy.vaadin.component.NameRelationField;
56 import eu.etaxonomy.vaadin.component.ReloadableLazyComboBox;
57 import eu.etaxonomy.vaadin.component.SwitchableTextField;
58 import eu.etaxonomy.vaadin.component.ToManyRelatedEntitiesComboboxSelect;
59 import eu.etaxonomy.vaadin.component.ToOneRelatedEntityCombobox;
60 import eu.etaxonomy.vaadin.event.EditorActionType;
61 import eu.etaxonomy.vaadin.mvp.AbstractCdmDTOPopupEditor;
62
63 /**
64 * @author a.kohlbecker
65 * @since May 22, 2017
66 *
67 */
68 @SpringComponent
69 @Scope("prototype")
70 public class TaxonNamePopupEditor extends AbstractCdmDTOPopupEditor<TaxonNameDTO, TaxonName, TaxonNameEditorPresenter>
71 implements TaxonNamePopupEditorView, AccessRestrictedView {
72
73 private static final long serialVersionUID = -7037436241474466359L;
74
75 private final static int GRID_COLS = 4;
76
77 private final static int GRID_ROWS = 17;
78
79 private static final boolean HAS_BASIONYM_DEFAULT = false;
80
81 private AbstractField<String> genusOrUninomialField;
82
83 private AbstractField<String> infraGenericEpithetField;
84
85 private AbstractField<String> specificEpithetField;
86
87 private AbstractField<String> infraSpecificEpithetField;
88
89 private SwitchableTextField fullTitleCacheFiled;
90
91 private SwitchableTextField protectedNameCacheField;
92
93 private ToOneRelatedEntityCombobox<Reference> nomReferenceCombobox;
94
95 private TextField nomenclaturalReferenceDetail;
96
97 private TeamOrPersonField exBasionymAuthorshipField;
98
99 private TeamOrPersonField basionymAuthorshipField;
100
101 private ToManyRelatedEntitiesComboboxSelect<TaxonName> basionymsComboboxSelect;
102
103 private ToManyRelatedEntitiesComboboxSelect<TaxonName> replacedSynonymsComboboxSelect;
104
105 private NameRelationField validationField;
106
107 private CheckBox basionymToggle;
108
109 private CheckBox replacedSynonymsToggle;
110
111 private CheckBox validationToggle;
112
113 private ListSelect rankSelect;
114
115 private TeamOrPersonField combinationAuthorshipField;
116
117 private TeamOrPersonField exCombinationAuthorshipField;
118
119 private EnumSet<TaxonNamePopupEditorMode> modesActive = EnumSet.noneOf(TaxonNamePopupEditorMode.class);
120
121 private Boolean isInferredCombinationAuthorship = null;
122
123 private Boolean isInferredBasionymAuthorship = null;
124
125 private Boolean isInferredExBasionymAuthorship = null;
126
127 private Map<AbstractField, Property.ValueChangeListener> authorshipUpdateListeners = new HashMap<>();
128
129 private Boolean isInferredExCombinationAuthorship;
130
131 private int specificEpithetFieldRow;
132
133 private ValueChangeListener updateFieldVisibilityListener = e -> updateFieldVisibility();
134
135 private FilterableAnnotationsField annotationsListField;
136
137 private AnnotationType[] editableAnotationTypes = new AnnotationType[]{AnnotationType.EDITORIAL()};
138
139
140 /**
141 * By default AnnotationType.EDITORIAL() is enabled.
142 *
143 * @return the editableAnotationTypes
144 */
145 public AnnotationType[] getEditableAnotationTypes() {
146 return editableAnotationTypes;
147 }
148
149 /**
150 * By default AnnotationType.EDITORIAL() is enabled.
151 *
152 *
153 * @param editableAnotationTypes the editableAnotationTypes to set
154 */
155 public void setEditableAnotationTypes(AnnotationType ... editableAnotationTypes) {
156 this.editableAnotationTypes = editableAnotationTypes;
157 }
158
159 /**
160 * @param layout
161 * @param dtoType
162 */
163 public TaxonNamePopupEditor() {
164 super(new GridLayout(GRID_COLS, GRID_ROWS), TaxonNameDTO.class);
165 }
166
167 /**
168 * {@inheritDoc}
169 */
170 @Override
171 public String getWindowCaption() {
172 return "Name editor";
173 }
174
175
176 /**
177 * {@inheritDoc}
178 */
179 @Override
180 public int getWindowWidth() {
181 return 800;
182 }
183
184 /**
185 * {@inheritDoc}
186 */
187 @Override
188 public void focusFirst() {
189 // titleField.focus();
190
191 }
192
193 /**
194 * {@inheritDoc}
195 */
196 @Override
197 protected String getDefaultComponentStyles() {
198 return "tiny";
199 }
200
201 /**
202 * {@inheritDoc}
203 */
204 @Override
205 protected void initContent() {
206
207 GridLayout grid = (GridLayout)getFieldLayout();
208 grid.setSizeFull();
209 grid.setHideEmptyRowsAndColumns(true);
210 grid.setSpacing(true);
211 grid.setColumnExpandRatio(0, 0.3f);
212 grid.setColumnExpandRatio(1, 0.3f);
213 grid.setColumnExpandRatio(2, 0.3f);
214 grid.setColumnExpandRatio(3, 0.0f);
215
216 /*
217 - nameType: preset, needs to be set in the presenter for new names
218 - appendedPhrase: -> TODO field
219 - nomenclaturalMicroReference: -> TODO field
220 - nomenclaturalReference -> field but disabled for REGISTRY
221 - rank -> SelectField which determines the visiblity of the other fields
222
223 - fullTitleCache + protectedFullTitleCache -> SwitchableTextField : ADVANCED_MODE
224 - nameCache + protectedNameCache -> SwitchableTextField : ADVANCED_MODE
225
226 - homotypicalGroup -> hidden
227 - typeDesignations -> hidden
228 - descriptions -> hidden
229 - taxonBases -> hidden
230 - registrations -> hidden
231
232 - relationsFromThisName-> TODO implement later
233 - relationsToThisName -> TODO implement later
234
235 - genusOrUninomial -> textField
236 - infraGenericEpithet -> textField
237 - specificEpithet -> textField
238 - infraSpecificEpithet -> textField
239
240 - authorshipCache + protectedAuthorshipCache -> SwitchableTextField : only ADVANCED_MODE and disabled for REGISTRY
241 - basionymAuthorship -> field but disabled for REGISTRY, basionym is set as nameRelationShip
242 - combinationAuthorship -> field but disabled for REGISTRY author team of the reference
243 - exCombinationAuthorship -> textField
244 - exBasionymAuthorship -> textField
245
246 - status -> TODO field
247 - monomHybrid -> TODO implement hybrids later
248 - binomHybrid -> TODO implement hybrids later
249 - trinomHybrid -> TODO implement hybrids later
250
251 - hybridParentRelations -> TODO implement hybrids later
252 - hybridChildRelations -> TODO implement hybrids later
253 - hybridFormula -> TODO implement hybrids later
254
255 ** ViralName attributes **
256 - acronym
257
258 ** BacterialName attributes **
259 - subGenusAuthorship
260 - nameApprobation
261 - breed
262 - publicationYear
263 - originalPublicationYear
264 - cultivarName
265 */
266
267 int row = 0;
268
269 rankSelect = new ListSelect("Rank");
270 rankSelect.setNullSelectionAllowed(false);
271 rankSelect.setRows(1);
272 rankSelect.setWidth(100, Unit.PERCENTAGE);
273 addField(rankSelect, "rank", 0, row, 1, row);
274 grid.setComponentAlignment(rankSelect, Alignment.TOP_RIGHT);
275
276 basionymToggle = new CheckBox("With basionym");
277 basionymToggle.setValue(HAS_BASIONYM_DEFAULT);
278
279 basionymToggle.setStyleName(getDefaultComponentStyles());
280 grid.addComponent(basionymToggle, 2, row, 3, row);
281 grid.setComponentAlignment(basionymToggle, Alignment.BOTTOM_LEFT);
282
283 row++;
284 replacedSynonymsToggle = new CheckBox("With replaced synonym");
285 grid.addComponent(replacedSynonymsToggle, 2, row, 3, row);
286 grid.setComponentAlignment(replacedSynonymsToggle, Alignment.BOTTOM_LEFT);
287
288 row++;
289 validationToggle = new CheckBox("Validation");
290
291 grid.addComponent(validationToggle, 2, row, 3, row);
292 grid.setComponentAlignment(validationToggle, Alignment.BOTTOM_LEFT);
293
294 row++;
295 // fullTitleCache
296 fullTitleCacheFiled = addSwitchableTextField("Full title cache", "fullTitleCache", "protectedFullTitleCache", 0, row, GRID_COLS-1, row);
297 fullTitleCacheFiled.setWidth(100, Unit.PERCENTAGE);
298 row++;
299 protectedNameCacheField = addSwitchableTextField("Name cache", "nameCache", "protectedNameCache", 0, row, GRID_COLS-1, row);
300 protectedNameCacheField.setWidth(100, Unit.PERCENTAGE);
301 row++;
302 if(isModeEnabled(TaxonNamePopupEditorMode.VALIDATE_AGAINST_HIGHER_NAME_PART)){
303 genusOrUninomialField = addTextField("Genus or uninomial", "genusOrUninomial", 0, row, 1, row);
304 } else {
305 genusOrUninomialField = new LazyComboBox<String>(String.class);
306 addField(genusOrUninomialField, "genusOrUninomial", 0, row, 1, row);
307 }
308 genusOrUninomialField.setWidth(200, Unit.PIXELS);
309 infraGenericEpithetField = addTextField("Infrageneric epithet", "infraGenericEpithet", 2, row, 3, row);
310 infraGenericEpithetField.setWidth(200, Unit.PIXELS);
311 row++;
312 specificEpithetFieldRow = row;
313 specificEpithetField = addTextField("Specific epithet", "specificEpithet", 0, row, 1, row);
314 specificEpithetField.setWidth(200, Unit.PIXELS);
315 infraSpecificEpithetField = addTextField("Infraspecific epithet", "infraSpecificEpithet", 2, row, 3, row);
316 infraSpecificEpithetField.setWidth(200, Unit.PIXELS);
317
318 row++;
319 grid.addComponent(new Label("Hint: <i>Edit nomenclatural authors in the nomenclatural reference.</i>", ContentMode.HTML), 0, row, 3, row);
320
321 row++;
322 combinationAuthorshipField = new TeamOrPersonField("Combination author(s)", TeamOrPersonBaseCaptionGenerator.CacheType.NOMENCLATURAL_TITLE);
323 combinationAuthorshipField.setWidth(100, Unit.PERCENTAGE);
324 addField(combinationAuthorshipField, "combinationAuthorship", 0, row, GRID_COLS-1, row);
325
326 row++;
327 nomReferenceCombobox = new ToOneRelatedEntityCombobox<Reference>("Nomenclatural reference", Reference.class);
328 nomReferenceCombobox.addClickListenerAddEntity(e -> getViewEventBus().publish(
329 this,
330 new ReferenceEditorAction(EditorActionType.ADD, null, nomReferenceCombobox, this)
331 ));
332 nomReferenceCombobox.addClickListenerEditEntity(e -> {
333 if(nomReferenceCombobox.getValue() != null){
334 getViewEventBus().publish(this,
335 new ReferenceEditorAction(
336 EditorActionType.EDIT,
337 nomReferenceCombobox.getValue().getUuid(),
338 e.getButton(),
339 nomReferenceCombobox,
340 this)
341 );
342 }
343 });
344 logger.setLevel(Level.DEBUG);
345 // nomReferenceCombobox.getSelect().addValueChangeListener(e -> logger.debug("nomReferenceCombobox value changed #1"));
346 // nomReferenceCombobox.setWidth(300, Unit.PIXELS);
347 nomReferenceCombobox.setWidth("100%");
348 addField(nomReferenceCombobox, "nomenclaturalReference", 0, row, 2, row);
349 nomenclaturalReferenceDetail = addTextField("Reference detail", "nomenclaturalMicroReference", 3, row, 3, row);
350 nomenclaturalReferenceDetail.setWidth(100, Unit.PIXELS);
351
352 // --------------- Basionyms
353 row++;
354 basionymsComboboxSelect = new ToManyRelatedEntitiesComboboxSelect<TaxonName>(TaxonName.class, "Basionym");
355 basionymsComboboxSelect.setConverter(new SetToListConverter<TaxonName>());
356 addField(basionymsComboboxSelect, "basionyms", 0, row, 3, row);
357 basionymsComboboxSelect.setWidth(100, Unit.PERCENTAGE);
358 basionymsComboboxSelect.withEditButton(true);
359 basionymsComboboxSelect.setEditPermissionTester(new CdmEditDeletePermissionTester());
360 basionymsComboboxSelect.setEditActionListener(e -> {
361
362 Object fieldValue = e.getSource().getValue();
363 UUID beanUuid = null;
364 if(fieldValue != null){
365 beanUuid = ((CdmBase)fieldValue).getUuid();
366
367 }
368 ReloadableLazyComboBox<TaxonName> lazyCombobox = (ReloadableLazyComboBox<TaxonName>) e.getSource();
369 getViewEventBus().publish(this, new TaxonNameEditorAction(e.getAction(), beanUuid, null, lazyCombobox, this));
370 });
371 grid.setComponentAlignment(basionymsComboboxSelect, Alignment.TOP_RIGHT);
372
373 row++;
374 basionymAuthorshipField = new TeamOrPersonField("Basionym author(s)", TeamOrPersonBaseCaptionGenerator.CacheType.NOMENCLATURAL_TITLE);
375 basionymAuthorshipField.setWidth(100, Unit.PERCENTAGE);
376 addField(basionymAuthorshipField, "basionymAuthorship", 0, row, GRID_COLS-1, row);
377 row++;
378 exBasionymAuthorshipField = new TeamOrPersonField("Ex-basionym author(s)", TeamOrPersonBaseCaptionGenerator.CacheType.NOMENCLATURAL_TITLE);
379 exBasionymAuthorshipField.setWidth(100, Unit.PERCENTAGE);
380 addField(exBasionymAuthorshipField, "exBasionymAuthorship", 0, row, GRID_COLS-1, row);
381
382 // --------------- ReplacedSynonyms
383 row++;
384 replacedSynonymsComboboxSelect = new ToManyRelatedEntitiesComboboxSelect<TaxonName>(TaxonName.class, "Replaced synonyms");
385 replacedSynonymsComboboxSelect.setConverter(new SetToListConverter<TaxonName>());
386 addField(replacedSynonymsComboboxSelect, "replacedSynonyms", 0, row, 3, row);
387 replacedSynonymsComboboxSelect.setWidth(100, Unit.PERCENTAGE);
388 replacedSynonymsComboboxSelect.withEditButton(true);
389 replacedSynonymsComboboxSelect.setEditPermissionTester(new CdmEditDeletePermissionTester());
390 replacedSynonymsComboboxSelect.setEditActionListener(e -> {
391
392 Object fieldValue = e.getSource().getValue();
393 UUID beanUuid = null;
394 if(fieldValue != null){
395 beanUuid = ((CdmBase)fieldValue).getUuid();
396
397 }
398 ReloadableLazyComboBox<TaxonName> lazyCombobox = (ReloadableLazyComboBox<TaxonName>) e.getSource();
399 getViewEventBus().publish(this, new TaxonNameEditorAction(e.getAction(), beanUuid, null, lazyCombobox, this));
400 });
401 grid.setComponentAlignment(replacedSynonymsComboboxSelect, Alignment.TOP_RIGHT);
402
403 // --------------- Validation
404 row++;
405 validationField = new NameRelationField("Validation", Direction.relatedTo, NameRelationshipType.VALIDATED_BY_NAME());
406 validationField.setWidth(100, Unit.PERCENTAGE);
407 ToOneRelatedEntityCombobox<TaxonName> validatedNameComboBox = validationField.getValidatedNameComboBox();
408 validatedNameComboBox.addClickListenerAddEntity(e -> getViewEventBus().publish(
409 this,
410 new TaxonNameEditorAction(EditorActionType.ADD, null, validatedNameComboBox, this)
411 ));
412 validatedNameComboBox.addClickListenerEditEntity(e -> {
413 if(validatedNameComboBox.getValue() != null){
414 getViewEventBus().publish(this,
415 new TaxonNameEditorAction(
416 EditorActionType.EDIT,
417 validatedNameComboBox.getValue().getUuid(),
418 e.getButton(),
419 validatedNameComboBox,
420 this)
421 );
422 }
423 });
424 ToOneRelatedEntityCombobox<Reference> validationCitatonComboBox = validationField.getCitatonComboBox();
425 validationCitatonComboBox.addClickListenerAddEntity(e -> getViewEventBus().publish(
426 this,
427 new ReferenceEditorAction(EditorActionType.ADD, null, validationCitatonComboBox, this)
428 ));
429 validationCitatonComboBox.addClickListenerEditEntity(e -> {
430 if(validationCitatonComboBox.getValue() != null){
431 getViewEventBus().publish(this,
432 new ReferenceEditorAction(
433 EditorActionType.EDIT,
434 validationCitatonComboBox.getValue().getUuid(),
435 e.getButton(),
436 validationCitatonComboBox,
437 this)
438 );
439 }
440 });
441 addField(validationField, "validationFor", 0, row, 3, row);
442 grid.setComponentAlignment(validationField, Alignment.TOP_RIGHT);
443
444 row++;
445 exCombinationAuthorshipField = new TeamOrPersonField("Ex-combination author(s)", TeamOrPersonBaseCaptionGenerator.CacheType.NOMENCLATURAL_TITLE);
446 exCombinationAuthorshipField.setWidth(100, Unit.PERCENTAGE);
447 addField(exCombinationAuthorshipField, "exCombinationAuthorship", 0, row, GRID_COLS-1, row);
448
449 row++;
450 annotationsListField = new FilterableAnnotationsField("Editorial notes");
451 annotationsListField.setWidth(100, Unit.PERCENTAGE);
452 annotationsListField.setAnnotationTypesVisible(editableAnotationTypes);
453 addField(annotationsListField, "annotations", 0, row, GRID_COLS-1, row);
454
455 // -----------------------------------------------------------------------------
456
457 setAdvancedModeEnabled(true);
458 registerAdvancedModeComponents(fullTitleCacheFiled, protectedNameCacheField);
459
460 registerAdvancedModeComponents(combinationAuthorshipField);
461 registerAdvancedModeComponents(basionymAuthorshipField);
462 registerAdvancedModeComponents(exBasionymAuthorshipField);
463 registerAdvancedModeComponents(exCombinationAuthorshipField);
464
465 registerAdvancedModeComponents(combinationAuthorshipField.getCachFields());
466 registerAdvancedModeComponents(exCombinationAuthorshipField.getCachFields());
467 registerAdvancedModeComponents(basionymAuthorshipField.getCachFields());
468 registerAdvancedModeComponents(exBasionymAuthorshipField.getCachFields());
469
470 setAdvancedMode(false);
471
472 }
473
474 protected TeamOrPersonBase inferBasiomynAuthors() {
475 List<TaxonName> basionyms = basionymsComboboxSelect.getValue();
476 if(!basionyms.isEmpty()){
477 TaxonName basionym = basionyms.get(0);
478 if(basionym.getCombinationAuthorship() != null){
479 return basionym.getCombinationAuthorship();
480 } else if(basionym.getNomenclaturalReference() != null){
481 return basionym.getNomenclaturalReference().getAuthorship();
482 }
483 }
484 return null;
485 }
486
487 protected TeamOrPersonBase inferExBasiomynAuthors() {
488 List<TaxonName> basionyms = basionymsComboboxSelect.getValue();
489 if(!basionyms.isEmpty()){
490 TaxonName basionym = basionyms.get(0);
491 return basionym.getExCombinationAuthorship();
492 }
493 return null;
494 }
495
496 protected TeamOrPersonBase inferCombinationAuthors() {
497 Reference nomRef = nomReferenceCombobox.getValue();
498 if(nomRef != null) {
499 return nomRef.getAuthorship();
500 }
501 return null;
502 }
503
504 protected TeamOrPersonBase inferExCombinationAuthors() {
505 NameRelationshipDTO nameRelationDTO = validationField.getValue();
506 if(nameRelationDTO != null && nameRelationDTO.getOtherName() != null){
507 TaxonName validatedName = nameRelationDTO.getOtherName();
508 if(validatedName.getCombinationAuthorship() != null) {
509 return validatedName.getCombinationAuthorship();
510 } else if(validatedName.getNomenclaturalReference() != null){
511 return validatedName.getNomenclaturalReference().getAuthorship();
512 }
513 }
514 return null;
515 }
516
517 @Override
518 protected void afterItemDataSourceSet() {
519
520
521 rankSelect.addValueChangeListener(updateFieldVisibilityListener);
522 basionymToggle.addValueChangeListener(e -> {
523 updateAuthorshipFields();
524 });
525 validationToggle.addValueChangeListener(e -> {
526 updateAuthorshipFields();
527 });
528 replacedSynonymsToggle.addValueChangeListener(e -> {
529 boolean enable = e.getProperty().getValue() != null && (Boolean)e.getProperty().getValue();
530 replacedSynonymsComboboxSelect.setVisible(enable);
531 });
532
533
534 TaxonNameDTO taxonNameDTO = getBean();
535 boolean showBasionymSection = taxonNameDTO.getBasionyms().size() > 0
536 || taxonNameDTO.getBasionymAuthorship() != null
537 || taxonNameDTO.getExBasionymAuthorship() != null;
538 basionymToggle.setValue(showBasionymSection);
539 basionymToggle.setReadOnly(showBasionymSection);
540
541 boolean showReplacedSynonyms = taxonNameDTO.getReplacedSynonyms().size() > 0;
542 replacedSynonymsToggle.setValue(showReplacedSynonyms);
543 replacedSynonymsToggle.setReadOnly(showReplacedSynonyms);
544 replacedSynonymsComboboxSelect.setVisible(showReplacedSynonyms);
545
546 boolean showValidationSection = taxonNameDTO.getValidationFor() != null || taxonNameDTO.getExCombinationAuthorship() != null;
547
548 validationToggle.setValue(showValidationSection);
549 validationToggle.setReadOnly(showValidationSection);
550 // validationField.setVisible(showValidation);
551 // exCombinationAuthorshipField.setVisible(showExAuthors);
552
553 if(isModeEnabled(TaxonNamePopupEditorMode.AUTOFILL_AUTHORSHIP_DATA)){
554 updateAuthorshipFields();
555 }
556 if(isModeEnabled(TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY) && getBean().getNomenclaturalReference() != null) {
557 nomReferenceCombobox.setCaption("Selection limited to nomenclatural reference and sections");
558 }
559 if(isModeEnabled(TaxonNamePopupEditorMode.REQUIRE_NOMENCLATURALREFERENCE)) {
560 if(combinationAuthorshipField.getValue() == null){
561 nomReferenceCombobox.setRequired(true);
562 } else {
563 combinationAuthorshipField.addValueChangeListener(e -> {
564 if(e.getProperty().getValue() == null){
565 nomReferenceCombobox.setRequired(true);
566 }
567 });
568 }
569 }
570
571 }
572
573 /**
574 * Updates all authorship fields if the an authorship field is empty this method attempts to infer the
575 * authors from the related nomenclatural reference or taxon name.
576 * <p>
577 * Finally the {@link #updateFieldVisibility()} is invoked.
578 *
579 * @param taxonName
580 */
581 @Override
582 public void updateAuthorshipFields() {
583
584 TaxonNameDTO taxonName = getBean();
585
586 // ------------- CombinationAuthors
587 isInferredCombinationAuthorship = updateAuthorshipFieldData(
588 taxonName.getCombinationAuthorship(),
589 inferCombinationAuthors(),
590 combinationAuthorshipField,
591 nomReferenceCombobox.getSelect(),
592 isInferredCombinationAuthorship);
593
594
595 // ------------- Basionym and ExBasionymAuthors
596 if(BooleanUtils.isTrue(basionymToggle.getValue())){
597
598 isInferredBasionymAuthorship = updateAuthorshipFieldData(
599 taxonName.getBasionymAuthorship(),
600 inferBasiomynAuthors(),
601 basionymAuthorshipField,
602 basionymsComboboxSelect,
603 isInferredBasionymAuthorship
604 );
605
606 isInferredExBasionymAuthorship = updateAuthorshipFieldData(
607 taxonName.getExBasionymAuthorship(),
608 inferExBasiomynAuthors(),
609 exBasionymAuthorshipField,
610 basionymsComboboxSelect,
611 isInferredExBasionymAuthorship
612 );
613
614 }
615
616 // ------------- Validation and ExCombinationAuthors
617 isInferredExCombinationAuthorship = updateAuthorshipFieldData(
618 taxonName.getExCombinationAuthorship(),
619 inferExCombinationAuthors(),
620 exCombinationAuthorshipField,
621 validationField.getValidatedNameComboBox(),
622 isInferredExCombinationAuthorship
623 );
624
625 updateFieldVisibility();
626
627 }
628
629 // /**
630 // *
631 // */
632 // protected void updateAuthorshipFieldsVisibility() {
633 // combinationAuthorshipField.setVisible(!isInferredCombinationAuthorship);
634 // if(BooleanUtils.isTrue(basionymToggle.getValue())){
635 // basionymAuthorshipField.setVisible(!isInferredBasionymAuthorship);
636 // exBasionymAuthorshipField.setVisible(!isInferredExBasionymAuthorship);
637 // }
638 // }
639
640 /**
641 *
642 * @param authorship
643 * the value of the taxonName authorship field
644 * @param inferredAuthors
645 * the value inferred from other fields which may be set as authorship to the taxon name
646 * @param authorshipField
647 * the ui element to edit the taxonName authorship field
648 * @param updateTriggerField
649 * @param lastInferredAuthorshipState
650 * @return
651 */
652 protected Boolean updateAuthorshipFieldData(TeamOrPersonBase<?> authorship, TeamOrPersonBase inferredAuthors,
653 TeamOrPersonField authorshipField, AbstractField updateTriggerField,
654 Boolean lastInferredAuthorshipState) {
655
656 if(authorship == null){
657 authorshipField.setValue(inferredAuthors);
658 lastInferredAuthorshipState = true;
659 } else {
660 boolean authorshipMatch = authorship == inferredAuthors;
661 if(lastInferredAuthorshipState == null){
662 // initialization of authorshipState, this comes only into account when the editor is just being initialized
663 lastInferredAuthorshipState = authorshipMatch;
664 }
665 if(!authorshipMatch && lastInferredAuthorshipState){
666 // update the combinationAuthorshipField to follow changes of the nomenclatural reference in case it was autofilled before
667 authorshipField.setValue(inferredAuthors);
668 lastInferredAuthorshipState = true;
669 }
670 }
671
672 if(updateTriggerField != null){
673 // IMPORTANT!
674 // this ChangeListener must be added at this very late point in the editor lifecycle so that it is called after
675 // the ToOneRelatedEntityReloader which may have been added to the updateTriggerField in the presenters handleViewEntered() method.
676 // Otherwise we risk multiple representation problems in the hibernate session
677 if(!authorshipUpdateListeners.containsKey(updateTriggerField)){
678 ValueChangeListener listener = e -> {
679 logger.debug(" value changed #2");
680 updateAuthorshipFields();
681 };
682 updateTriggerField.addValueChangeListener(listener);
683 authorshipUpdateListeners.put(updateTriggerField, listener);
684 }
685 }
686
687 return lastInferredAuthorshipState;
688 }
689
690 /**
691 * @param rank
692 * @return
693 */
694 private void updateFieldVisibility() {
695
696 // TODO use getField() instead and remove field references
697 Rank rank = (Rank) rankSelect.getValue();
698
699 boolean isSpeciesOrBelow = !rank.isHigher(Rank.SPECIES());
700 Boolean withBasionymSection = BooleanUtils.isTrue(basionymToggle.getValue());
701 Boolean withValidationSection = isSpeciesOrBelow && BooleanUtils.isTrue(validationToggle.getValue());
702
703 if(isModeEnabled(TaxonNamePopupEditorMode.VALIDATE_AGAINST_HIGHER_NAME_PART)){
704 if(rank.isInfraSpecific()) {
705 if(TextField.class.isAssignableFrom(specificEpithetField.getClass())) {
706 specificEpithetField = replaceComponent("specificEpithet", specificEpithetField, new LazyComboBox<String>(String.class), 0, specificEpithetFieldRow, 1, specificEpithetFieldRow);
707 }
708 } else {
709 if(LazyComboBox.class.isAssignableFrom(specificEpithetField.getClass())) {
710 specificEpithetField = replaceComponent("specificEpithet", specificEpithetField, new TextFieldNFix(), 0, specificEpithetFieldRow, 1, specificEpithetFieldRow);
711 }
712 }
713 }
714
715 specificEpithetField.setVisible(isSpeciesOrBelow);
716 infraSpecificEpithetField.setVisible(rank.isInfraSpecific());
717 infraGenericEpithetField.setVisible(rank.isInfraGeneric());
718
719 basionymsComboboxSelect.setVisible(withBasionymSection);
720
721 combinationAuthorshipField.setVisible(isInferredCombinationAuthorship != null && !isInferredCombinationAuthorship);
722 basionymAuthorshipField.setVisible(withBasionymSection && isInferredBasionymAuthorship != null && !isInferredBasionymAuthorship);
723 exBasionymAuthorshipField.setVisible(withBasionymSection && isInferredExBasionymAuthorship != null && !isInferredExBasionymAuthorship);
724
725 validationField.setVisible(withValidationSection);
726 exCombinationAuthorshipField.setVisible(withValidationSection && isInferredExCombinationAuthorship != null && !isInferredExCombinationAuthorship);
727
728
729 // if(taxonName != null){
730 // if(modesActive.contains(TaxonNamePopupEditorMode.AUTOFILL_AUTHORSHIP_DATA)){
731 // }
732 // }
733
734 infraSpecificEpithetField.setVisible(rank.isInfraSpecific());
735 specificEpithetField.setVisible(isSpeciesOrBelow);
736 infraGenericEpithetField.setVisible(rank.isInfraGenericButNotSpeciesGroup());
737 genusOrUninomialField.setCaption(isSpeciesOrBelow ? "Genus" : "Uninomial");
738 }
739
740
741 @Override
742 public void cancel() {
743 authorshipUpdateListeners.keySet().forEach(field -> field.removeValueChangeListener(authorshipUpdateListeners.get(field)));
744 rankSelect.removeValueChangeListener(updateFieldVisibilityListener);
745 super.cancel();
746 }
747
748 /**
749 * {@inheritDoc}
750 */
751 @Override
752 public boolean allowAnonymousAccess() {
753 return false;
754 }
755
756 /**
757 * {@inheritDoc}
758 */
759 @Override
760 public Collection<Collection<GrantedAuthority>> allowedGrantedAuthorities() {
761 return null;
762 }
763
764 /**
765 * {@inheritDoc}
766 */
767 @Override
768 public ToOneRelatedEntityCombobox<Reference> getNomReferenceCombobox() {
769 return nomReferenceCombobox;
770 }
771
772 /**
773 * {@inheritDoc}
774 */
775 @Override
776 public ToManyRelatedEntitiesComboboxSelect<TaxonName> getBasionymComboboxSelect() {
777 return basionymsComboboxSelect;
778 }
779
780 /**
781 * {@inheritDoc}
782 */
783 @Override
784 public ToManyRelatedEntitiesComboboxSelect<TaxonName> getReplacedSynonymsComboboxSelect() {
785 return replacedSynonymsComboboxSelect;
786 }
787
788 /**
789 * {@inheritDoc}
790 */
791 @Override
792 public ListSelect getRankSelect() {
793 return rankSelect;
794 }
795
796 /**
797 * {@inheritDoc}
798 */
799 @Override
800 public AbstractField<String> getGenusOrUninomialField(){
801 return genusOrUninomialField;
802 }
803
804 /**
805 * @return the exBasionymAuthorshipField
806 */
807 @Override
808 public TeamOrPersonField getExBasionymAuthorshipField() {
809 return exBasionymAuthorshipField;
810 }
811
812 /**
813 * @return the basionymAuthorshipField
814 */
815 @Override
816 public TeamOrPersonField getBasionymAuthorshipField() {
817 return basionymAuthorshipField;
818 }
819
820 /**
821 * @return the combinationAuthorshipField
822 */
823 @Override
824 public TeamOrPersonField getCombinationAuthorshipField() {
825 return combinationAuthorshipField;
826 }
827
828 /**
829 * @return the exCombinationAuthorshipField
830 */
831 @Override
832 public TeamOrPersonField getExCombinationAuthorshipField() {
833 return exCombinationAuthorshipField;
834 }
835
836 @Override
837 public NameRelationField getValidationField(){
838 return validationField;
839 }
840
841 @Override
842 public void enableMode(TaxonNamePopupEditorMode mode){
843 modesActive.add(mode);
844 }
845
846 @Override
847 public boolean isModeEnabled(TaxonNamePopupEditorMode mode){
848 return modesActive.contains(mode);
849 }
850
851 @Override
852 public void disableMode(TaxonNamePopupEditorMode mode){
853 modesActive.remove(mode);
854 }
855
856 @Override
857 public EnumSet<TaxonNamePopupEditorMode> getModesActive(){
858 return modesActive;
859 }
860
861 @Override
862 public CheckBox getBasionymToggle() {
863 return basionymToggle;
864 }
865
866 @Override
867 public FilterableAnnotationsField getAnnotationsField() {
868 return annotationsListField;
869 }
870
871 /**
872 * {@inheritDoc}
873 */
874 @Override
875 public void setReadOnly(boolean readOnly) {
876 boolean basionymToggleReadonly = basionymToggle.isReadOnly();
877 boolean validationToggleReadonly = validationToggle.isReadOnly();
878 super.setReadOnly(readOnly);
879 combinationAuthorshipField.setEditorReadOnly(readOnly);
880 exCombinationAuthorshipField.setEditorReadOnly(readOnly);
881 basionymAuthorshipField.setEditorReadOnly(readOnly);
882 exBasionymAuthorshipField.setEditorReadOnly(readOnly);
883 // preserve old readonly states if they were true
884 if(basionymToggleReadonly){
885 basionymToggle.setReadOnly(true);
886 }
887 if(validationToggleReadonly){
888 validationToggle.setReadOnly(true);
889 }
890 }
891
892
893
894 /**
895 * @return the infraGenericEpithetField
896 */
897 @Override
898 public AbstractField<String> getInfraGenericEpithetField() {
899 return infraGenericEpithetField;
900 }
901
902 /**
903 * @return the specificEpithetField
904 */
905 @Override
906 public AbstractField<String> getSpecificEpithetField() {
907 return specificEpithetField;
908 }
909
910 /**
911 * @return the infraSpecificEpithetField
912 */
913 @Override
914 public AbstractField<String> getInfraSpecificEpithetField() {
915 return infraSpecificEpithetField;
916 }
917
918
919 }