cleanup
[cdm-vaadin.git] / src / main / java / eu / etaxonomy / cdm / vaadin / view / name / TaxonNameEditorPresenter.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.Arrays;
12 import java.util.EnumSet;
13 import java.util.HashMap;
14 import java.util.HashSet;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Optional;
18 import java.util.Set;
19 import java.util.UUID;
20
21 import org.apache.commons.lang3.StringUtils;
22 import org.hibernate.criterion.Restrictions;
23 import org.springframework.context.annotation.Scope;
24 import org.vaadin.spring.events.annotation.EventBusListenerMethod;
25 import org.vaadin.viritin.fields.AbstractElementCollection;
26
27 import com.vaadin.data.Container.Filter;
28 import com.vaadin.data.Item;
29 import com.vaadin.data.Property;
30 import com.vaadin.data.util.BeanItemContainer;
31 import com.vaadin.spring.annotation.SpringComponent;
32 import com.vaadin.ui.AbstractField;
33 import com.vaadin.ui.AbstractSelect.ItemCaptionMode;
34 import com.vaadin.ui.Field;
35
36 import eu.etaxonomy.cdm.api.service.INameService;
37 import eu.etaxonomy.cdm.format.reference.ReferenceEllypsisFormatter;
38 import eu.etaxonomy.cdm.format.reference.ReferenceEllypsisFormatter.LabelType;
39 import eu.etaxonomy.cdm.model.agent.AgentBase;
40 import eu.etaxonomy.cdm.model.agent.Person;
41 import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
42 import eu.etaxonomy.cdm.model.common.AnnotationType;
43 import eu.etaxonomy.cdm.model.common.CdmBase;
44 import eu.etaxonomy.cdm.model.common.Language;
45 import eu.etaxonomy.cdm.model.name.NomenclaturalCodeEdition;
46 import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
47 import eu.etaxonomy.cdm.model.name.Rank;
48 import eu.etaxonomy.cdm.model.name.TaxonName;
49 import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
50 import eu.etaxonomy.cdm.model.permission.CRUD;
51 import eu.etaxonomy.cdm.model.reference.Reference;
52 import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
53 import eu.etaxonomy.cdm.model.reference.ReferenceType;
54 import eu.etaxonomy.cdm.model.term.DefinedTermBase;
55 import eu.etaxonomy.cdm.model.term.TermType;
56 import eu.etaxonomy.cdm.persistence.dao.common.Restriction;
57 import eu.etaxonomy.cdm.persistence.dao.common.Restriction.Operator;
58 import eu.etaxonomy.cdm.persistence.dao.initializer.EntityInitStrategy;
59 import eu.etaxonomy.cdm.service.CdmFilterablePagingProvider;
60 import eu.etaxonomy.cdm.service.TaxonNameStringFilterablePagingProvider;
61 import eu.etaxonomy.cdm.service.UserHelperAccess;
62 import eu.etaxonomy.cdm.service.initstrategies.AgentBaseInit;
63 import eu.etaxonomy.cdm.vaadin.event.EditorActionTypeFilter;
64 import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
65 import eu.etaxonomy.cdm.vaadin.event.ReferenceEditorAction;
66 import eu.etaxonomy.cdm.vaadin.event.TaxonNameEditorAction;
67 import eu.etaxonomy.cdm.vaadin.event.TaxonNameEditorActionStrRep;
68 import eu.etaxonomy.cdm.vaadin.event.ToOneRelatedEntityButtonUpdater;
69 import eu.etaxonomy.cdm.vaadin.event.ToOneRelatedEntityReloader;
70 import eu.etaxonomy.cdm.vaadin.model.name.NomenclaturalStatusDTO;
71 import eu.etaxonomy.cdm.vaadin.model.name.TaxonNameDTO;
72 import eu.etaxonomy.cdm.vaadin.model.registration.RegistrationTermLists;
73 import eu.etaxonomy.cdm.vaadin.ui.RegistrationUIDefaults;
74 import eu.etaxonomy.cdm.vaadin.util.CdmTitleCacheCaptionGenerator;
75 import eu.etaxonomy.cdm.vaadin.util.ReferenceEllypsisCaptionGenerator;
76 import eu.etaxonomy.cdm.vaadin.view.reference.ReferencePopupEditor;
77 import eu.etaxonomy.cdm.vaadin.view.reference.RegistrationUiReferenceEditorFormConfigurator;
78 import eu.etaxonomy.vaadin.component.CompositeCustomField;
79 import eu.etaxonomy.vaadin.component.ReloadableLazyComboBox;
80 import eu.etaxonomy.vaadin.component.ToOneRelatedEntityCombobox;
81 import eu.etaxonomy.vaadin.component.WeaklyRelatedEntityCombobox;
82 import eu.etaxonomy.vaadin.component.WeaklyRelatedEntityField;
83 import eu.etaxonomy.vaadin.event.FieldReplaceEvent;
84 import eu.etaxonomy.vaadin.mvp.AbstractCdmDTOEditorPresenter;
85 import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
86 import eu.etaxonomy.vaadin.mvp.BeanInstantiator;
87 import eu.etaxonomy.vaadin.mvp.BoundField;
88 import eu.etaxonomy.vaadin.ui.view.PopupView;
89 import eu.etaxonomy.vaadin.util.PropertyIdPath;
90
91 /**
92 * @author a.kohlbecker
93 * @since May 22, 2017
94 */
95 @SpringComponent
96 @Scope("prototype")
97 public class TaxonNameEditorPresenter
98 extends AbstractCdmDTOEditorPresenter<TaxonNameDTO, TaxonName, TaxonNameEditorPresenter, TaxonNamePopupEditorView> {
99
100 private static final long serialVersionUID = -3538980627079389221L;
101
102 private static final EnumSet<CRUD> SUB_EDITOR_CRUD = EnumSet.of(CRUD.UPDATE, CRUD.DELETE);
103
104 private static final List<String> RELATED_NAME_INIT_STRATEGY = Arrays.asList("$", "nomenclaturalSource.annotations",
105 "relationsFromThisName", "relationsToThisName.type", "homotypicalGroup.typifiedNames");
106
107 public static List<String> REFERENCE_INIT_STRATEGY = ReferenceEllypsisFormatter.INIT_STRATEGY;
108
109 private CdmFilterablePagingProvider<Reference, Reference> nomReferencePagingProvider;
110
111 private Reference publishedUnit;
112
113 private BeanInstantiator<Reference> newReferenceInstantiator;
114
115 private Map<ReferencePopupEditor, NomenclaturalStatusRow> statusTypeReferencePopupEditorsRowMap = new HashMap<>();
116
117 private TaxonNameStringFilterablePagingProvider genusOrUninomialPartPagingProvider;
118
119 private TaxonNameStringFilterablePagingProvider specificEpithetPartPagingProvider;
120
121 private Property.ValueChangeListener refreshSpecificEpithetComboBoxListener;
122
123 private CdmFilterablePagingProvider<TaxonName, TaxonName> relatedNamePagingProvider;
124
125 private CdmFilterablePagingProvider<TaxonName, TaxonName> orthographicVariantNamePagingProvider;
126
127 private Restriction<Reference> orthographicCorrectionRestriction;
128
129 private Integer taxonNameId;
130
131 private BeanItemContainer<DefinedTermBase> rankTermItemContainer;
132
133 private Filter rankListFilter;
134
135 /**
136 * the taxon names rank as loaded from the persistence layer
137 */
138 private Rank initialRank;
139
140
141 @SuppressWarnings("serial")
142 @Override
143 public void handleViewEntered() {
144
145 super.handleViewEntered();
146
147 List<NomenclaturalCodeEdition> nomCodes = NomenclaturalCodeEdition
148 .forCode(RegistrationUIDefaults.NOMENCLATURAL_CODE);
149 BeanItemContainer<NomenclaturalCodeEdition> codeEditionItemContainer = cdmBeanItemContainerFactory
150 .buildEnumTermItemContainer(NomenclaturalCodeEdition.class,
151 nomCodes.toArray(new NomenclaturalCodeEdition[nomCodes.size()]));
152
153 rankTermItemContainer = cdmBeanItemContainerFactory.buildTermItemContainer(TermType.Rank);
154 rankListFilter = new Filter() {
155 @Override
156 public boolean passesFilter(Object itemId, Item item) throws UnsupportedOperationException {
157 return getView().isRanksFullList() || RegistrationUIDefaults.RANK_SET_COMPACT.contains(itemId) || itemId.equals(initialRank);
158 }
159 @Override
160 public boolean appliesToProperty(Object propertyId) {
161 return false;
162 }};
163 rankTermItemContainer.addContainerFilter(rankListFilter);
164 getView().getRankSelect()
165 .setContainerDataSource(rankTermItemContainer);
166 getView().getRankSelect().setItemCaptionPropertyId("label");
167 getView().getRankSelectFullListToggle().addClickListener(e -> {
168 updateRankTermItemContainer();
169 });
170
171 CdmFilterablePagingProvider<AgentBase, TeamOrPersonBase> termOrPersonPagingProvider = pagingProviderFactory
172 .teamOrPersonPagingProvider();
173 termOrPersonPagingProvider.setInitStrategy(AgentBaseInit.TEAM_OR_PERSON_INIT_STRATEGY);
174 CdmFilterablePagingProvider<AgentBase, Person> personPagingProvider = pagingProviderFactory
175 .personPagingProvider();
176
177 getView().getCombinationAuthorshipField().setFilterableTeamPagingProvider(termOrPersonPagingProvider, this);
178 getView().getCombinationAuthorshipField().setFilterablePersonPagingProvider(personPagingProvider, this);
179
180 getView().getExCombinationAuthorshipField().setFilterableTeamPagingProvider(termOrPersonPagingProvider, this);
181 getView().getExCombinationAuthorshipField().setFilterablePersonPagingProvider(personPagingProvider, this);
182
183 getView().getBasionymAuthorshipField().setFilterableTeamPagingProvider(termOrPersonPagingProvider, this);
184 getView().getBasionymAuthorshipField().setFilterablePersonPagingProvider(personPagingProvider, this);
185
186 getView().getExBasionymAuthorshipField().setFilterableTeamPagingProvider(termOrPersonPagingProvider, this);
187 getView().getExBasionymAuthorshipField().setFilterablePersonPagingProvider(personPagingProvider, this);
188
189 nomReferencePagingProvider = pagingProviderFactory.referencePagingProvider();
190 nomReferencePagingProvider.setInitStrategy(REFERENCE_INIT_STRATEGY);
191 getView().getNomReferenceCombobox().loadFrom(nomReferencePagingProvider, nomReferencePagingProvider,
192 nomReferencePagingProvider.getPageSize());
193 getView().getNomReferenceCombobox().setNestedButtonStateUpdater(
194 new ToOneRelatedEntityButtonUpdater<Reference>(getView().getNomReferenceCombobox()));
195 getView().getNomReferenceCombobox().getSelect().setCaptionGenerator(new ReferenceEllypsisCaptionGenerator(
196 LabelType.NOMENCLATURAL, getView().getNomReferenceCombobox().getSelect()));
197 getView().getNomReferenceCombobox().getSelect()
198 .addValueChangeListener(new ToOneRelatedEntityReloader<>(getView().getNomReferenceCombobox(), this));
199 getView().getNomReferenceCombobox().getSelect()
200 .addValueChangeListener(e -> updateOrthographicCorrectionRestriction());
201
202 CdmFilterablePagingProvider<Reference, Reference> icbnCodesPagingProvider = pagingProviderFactory
203 .referencePagingProvider();
204 // @formatter:off
205 // TODO use markers on references instead of isbn. The marker type
206 // MarkerType.NOMENCLATURAL_RELEVANT() has already prepared (#7466)
207 icbnCodesPagingProvider.getCriteria().add(Restrictions.in("isbn", new String[] {
208 "3-904144-22-7", // Saint Louis Code
209 "3-906166-48-1", // Vienna Code
210 "978-3-87429-425-6", // Melbourne Code
211 "978-3-946583-16-5", // Shenzhen Code
212 "0-85301-006-4" // ICZN 1999
213 // ICNP
214 }));
215 // @formatter:on
216
217 statusTypeReferencePopupEditorsRowMap.clear();
218 getView().getNomStatusCollectionField().addElementAddedListener(e -> addNomenclaturalStatus(e.getElement()));
219 getView().getNomStatusCollectionField()
220 .setEditorInstantiator(new AbstractElementCollection.Instantiator<NomenclaturalStatusRow>() {
221
222 @Override
223 public NomenclaturalStatusRow create() {
224 NomenclaturalStatusRow row = new NomenclaturalStatusRow();
225
226 //type
227 BeanItemContainer<DefinedTermBase> statusTypeItemContainer = cdmBeanItemContainerFactory.buildTermItemContainer(
228 RegistrationTermLists.NOMENCLATURAL_STATUS_TYPE_UUIDS()
229 );
230 row.type.setContainerDataSource(statusTypeItemContainer);
231 row.type.setItemCaptionMode(ItemCaptionMode.EXPLICIT);
232 for (DefinedTermBase<?> term : statusTypeItemContainer.getItemIds()) {
233 row.type.setItemCaption(term,
234 term.getPreferredRepresentation(Language.DEFAULT()).getAbbreviatedLabel());
235 }
236 row.type.setNullSelectionAllowed(false);
237
238 row.citation.loadFrom(icbnCodesPagingProvider, icbnCodesPagingProvider,
239 icbnCodesPagingProvider.getPageSize());
240 row.citation.getSelect().setCaptionGenerator(new ReferenceEllypsisCaptionGenerator(
241 LabelType.NOMENCLATURAL, row.citation.getSelect()));
242 row.citation.getSelect().addValueChangeListener(new ToOneRelatedEntityReloader<Reference>(
243 row.citation.getSelect(), TaxonNameEditorPresenter.this));
244 row.citation.addClickListenerAddEntity(e -> doReferenceEditorAdd(row));
245 row.citation.addClickListenerEditEntity(e -> {
246 if (row.citation.getValue() != null) {
247 doReferenceEditorEdit(row);
248 }
249 });
250 row.codeEdition.setContainerDataSource(codeEditionItemContainer);
251
252 getView().applyDefaultComponentStyle(row.components());
253
254 return row;
255 }
256 });
257
258 relatedNamePagingProvider = pagingProviderFactory.taxonNamesWithoutOrthophicIncorrect();
259 relatedNamePagingProvider.setInitStrategy(RELATED_NAME_INIT_STRATEGY);
260 getView().getBasionymComboboxSelect().setCaptionGenerator(new CdmTitleCacheCaptionGenerator<TaxonName>());
261 getView().getBasionymComboboxSelect().setPagingProviders(relatedNamePagingProvider, relatedNamePagingProvider,
262 relatedNamePagingProvider.getPageSize(), this);
263
264 getView().getReplacedSynonymsComboboxSelect()
265 .setCaptionGenerator(new CdmTitleCacheCaptionGenerator<TaxonName>());
266 getView().getReplacedSynonymsComboboxSelect().setPagingProviders(relatedNamePagingProvider,
267 relatedNamePagingProvider, relatedNamePagingProvider.getPageSize(), this);
268
269 getView().getValidationField().getRelatedNameComboBox().getSelect()
270 .setCaptionGenerator(new CdmTitleCacheCaptionGenerator<TaxonName>());
271 getView().getValidationField().getRelatedNameComboBox().loadFrom(relatedNamePagingProvider,
272 relatedNamePagingProvider, relatedNamePagingProvider.getPageSize());
273 getView().getValidationField().getRelatedNameComboBox().getSelect().addValueChangeListener(
274 new ToOneRelatedEntityReloader<>(getView().getValidationField().getRelatedNameComboBox(), this));
275 getView().getValidationField().getCitatonComboBox().getSelect()
276 .setCaptionGenerator(new ReferenceEllypsisCaptionGenerator(LabelType.BIBLIOGRAPHIC,
277 getView().getValidationField().getCitatonComboBox().getSelect()));
278 getView().getValidationField().getCitatonComboBox().loadFrom(icbnCodesPagingProvider, icbnCodesPagingProvider,
279 icbnCodesPagingProvider.getPageSize());
280 getView().getValidationField().getCitatonComboBox().getSelect().addValueChangeListener(
281 new ToOneRelatedEntityReloader<>(getView().getValidationField().getCitatonComboBox(), this));
282 getView().getValidationField().getCodeEditionSelect().setContainerDataSource(codeEditionItemContainer);
283
284 getView().getOrthographicVariantField().getRelatedNameComboBox().getSelect()
285 .setCaptionGenerator(new CdmTitleCacheCaptionGenerator<TaxonName>());
286 getView().getOrthographicVariantField().getRelatedNameComboBox().getSelect().addValueChangeListener(
287 new ToOneRelatedEntityReloader<>(getView().getOrthographicVariantField().getRelatedNameComboBox(),
288 this));
289 getView().getOrthographicVariantField().getRelatedNameComboBox().loadFrom(relatedNamePagingProvider,
290 relatedNamePagingProvider, relatedNamePagingProvider.getPageSize());
291 // The Mode TaxonNamePopupEditorMode.ORTHOGRAPHIC_CORRECTION will be
292 // handled in the updateOrthographicCorrectionRestriction() method
293 getView().getOrthographicVariantField().getCitatonComboBox().getSelect()
294 .setCaptionGenerator(new ReferenceEllypsisCaptionGenerator(LabelType.BIBLIOGRAPHIC,
295 getView().getOrthographicVariantField().getCitatonComboBox().getSelect()));
296 getView().getOrthographicVariantField().getCitatonComboBox().loadFrom(icbnCodesPagingProvider,
297 icbnCodesPagingProvider, icbnCodesPagingProvider.getPageSize());
298 getView().getOrthographicVariantField().getCitatonComboBox().getSelect().addValueChangeListener(
299 new ToOneRelatedEntityReloader<>(getView().getOrthographicVariantField().getCitatonComboBox(), this));
300 getView().getOrthographicVariantField().getCodeEditionSelect().setContainerDataSource(codeEditionItemContainer);
301
302 getView().getAnnotationsField().setAnnotationTypeItemContainer(cdmBeanItemContainerFactory
303 .buildVocabularyTermsItemContainer(AnnotationType.EDITORIAL().getVocabulary().getUuid()));
304 }
305
306 public void updateRankTermItemContainer() {
307 // add and remove the filter to update the list of rank terms
308 // the filter itself will behave accordingly to the isRanksFullList in the view
309 rankTermItemContainer.removeContainerFilter(rankListFilter);
310 rankTermItemContainer.addContainerFilter(rankListFilter);
311 }
312
313 @Deprecated
314 private void addNomenclaturalStatus(NomenclaturalStatusDTO element) {
315 // Nothing to do
316 }
317
318 @Override
319 protected void adaptDataProviders() {
320 updateOrthographicCorrectionRestriction();
321 updateRankTermItemContainer();
322 }
323
324 private void updateOrthographicCorrectionRestriction() {
325
326 if (getView().isModeEnabled(TaxonNamePopupEditorMode.ORTHOGRAPHIC_CORRECTION)) {
327 if (orthographicVariantNamePagingProvider == null) {
328 orthographicVariantNamePagingProvider = new CdmFilterablePagingProvider<TaxonName, TaxonName>(
329 getRepo().getNameService());
330 orthographicVariantNamePagingProvider.setInitStrategy(RELATED_NAME_INIT_STRATEGY);
331 orthographicVariantNamePagingProvider
332 .addRestriction(new Restriction<>("id", Operator.AND_NOT, null, taxonNameId));
333 getView().getOrthographicVariantField().getRelatedNameComboBox().loadFrom(
334 orthographicVariantNamePagingProvider, orthographicVariantNamePagingProvider,
335 orthographicVariantNamePagingProvider.getPageSize());
336 }
337 Reference nomReference = getView().getNomReferenceCombobox().getValue();
338 if (nomReference == null && orthographicCorrectionRestriction != null) {
339 orthographicVariantNamePagingProvider.getRestrictions().remove(orthographicCorrectionRestriction);
340 } else {
341 if (orthographicCorrectionRestriction == null) {
342 orthographicCorrectionRestriction = new Restriction<>("nomenclaturalSource.citation", Operator.AND,
343 null, nomReference);
344 orthographicVariantNamePagingProvider.addRestriction(orthographicCorrectionRestriction);
345 } else {
346 orthographicCorrectionRestriction.setValues(Arrays.asList(nomReference));
347 }
348 }
349 getView().getOrthographicVariantField().getRelatedNameComboBox().getSelect().refresh();
350 }
351 }
352
353 @Override
354 protected TaxonName loadCdmEntity(UUID identifier) {
355
356 EntityInitStrategy initStrategy = new EntityInitStrategy(
357 Arrays.asList(
358 "$",
359 "annotations.type",
360 "annotations.*", // needed as log as we are using a table in FilterableAnnotationsField
361 "rank.vocabulary", // needed for comparing ranks
362
363 "nomenclaturalSource.citation",
364 "nomenclaturalSource.annotations", // needed to allow access in AnnotatableEntity.checkEmpty()
365 "nomenclaturalSource.markers", // needed to allow access in AnnotatableEntity.checkEmpty()
366 "nomenclaturalSource.links", // needed to allow access in OriginalSourceBase.checkEmpty()
367
368 "status.type",
369 "status.source.citation",
370 "status.source.annotations", // needed to allow access in AnnotatableEntity.checkEmpty()
371 "status.source.markers", // needed to allow access in AnnotatableEntity.checkEmpty()
372 "status.source.links", // needed to allow access in AnnotatableEntity.checkEmpty()
373
374 "combinationAuthorship",
375 "exCombinationAuthorship",
376 "basionymAuthorship",
377 "exBasionymAuthorship",
378
379 // basionyms: relationsToThisName.fromName
380 "relationsToThisName.type",
381 "relationsToThisName.fromName.rank",
382 "relationsToThisName.fromName.combinationAuthorship",
383 "relationsToThisName.fromName.exCombinationAuthorship",
384 "relationsToThisName.fromName.nomenclaturalSource.citation.authorship",
385 "relationsToThisName.fromName.nomenclaturalSource.citation.inReference.authorship",
386 "relationsToThisName.fromName.nomenclaturalSource.citation.inReference.inReference.inReference.authorship",
387 "relationsToThisName.fromName.nomenclaturalSource.annotations", // needed to allow access in OriginalSourceBase.checkEmpty()
388 "relationsToThisName.fromName.nomenclaturalSource.markers", // needed to allow access in OriginalSourceBase.checkEmpty()
389 "relationsToThisName.fromName.nomenclaturalSource.links", // needed to allow access in OriginalSourceBase.checkEmpty()
390 "relationsToThisName.fromName.relationsToThisName",
391 "relationsToThisName.fromName.relationsFromThisName",
392 "relationsToThisName.source.citation",
393 "relationsToThisName.source.annotations", // needed to allow access in OriginalSourceBase.checkEmpty()
394 "relationsToThisName.source.markers", // needed to allow access in OriginalSourceBase.checkEmpty()
395 "relationsToThisName.source.links", // needed to allow access in OriginalSourceBase.checkEmpty()
396 "relationsFromThisName",
397 "homotypicalGroup.typifiedNames"
398 )
399 );
400 initStrategy.extend("nomenclaturalSource.citation", ReferenceEllypsisFormatter.INIT_STRATEGY, false);
401 initStrategy.extend("status.citation", ReferenceEllypsisFormatter.INIT_STRATEGY, false);
402 initStrategy.extend("relationsToThisName.citation", ReferenceEllypsisFormatter.INIT_STRATEGY, false);
403
404 TaxonName taxonName;
405 if (identifier != null) {
406 taxonName = getRepo().getNameService().load(identifier, initStrategy.getPropertyPaths());
407 } else {
408 taxonName = createCdmEntity();
409 }
410
411 if (getView().isModeEnabled(TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY)) {
412 Reference nomRef = taxonName.getNomenclaturalReference();
413
414 // getView().getNomReferenceCombobox().setEnabled(nomRef.isOfType(ReferenceType.Section));
415 publishedUnit = nomRef;
416 if (publishedUnit != null) {
417 while (publishedUnit.isOfType(ReferenceType.Section) && publishedUnit.getInReference() != null) {
418 publishedUnit = nomRef.getInReference();
419 }
420 // reduce available references to those which are sections of
421 // the publishedUnit and the publishedUnit itself
422 // nomReferencePagingProvider
423 nomReferencePagingProvider.getCriteria()
424 .add(Restrictions.or(
425 Restrictions.and(Restrictions.eq("inReference", publishedUnit),
426 Restrictions.eq("type", ReferenceType.Section)),
427 Restrictions.idEq(publishedUnit.getId())));
428 }
429 // and remove the empty option
430 getView().getNomReferenceCombobox().getSelect().setNullSelectionAllowed(false);
431
432 // new Reference only a sub sections of the publishedUnit
433 newReferenceInstantiator = new BeanInstantiator<Reference>() {
434 @Override
435 public Reference createNewBean() {
436 Reference newRef = ReferenceFactory.newSection();
437 newRef.setInReference(publishedUnit);
438 return newRef;
439 }
440 };
441
442 }
443
444 taxonNameId = Integer.valueOf(taxonName.getId());
445 initialRank = taxonName.getRank();
446 relatedNamePagingProvider.addRestriction(new Restriction<>("id", Operator.AND_NOT, null, taxonNameId));
447
448 return taxonName;
449 }
450
451 @Override
452 protected TaxonNameDTO preSaveBean(TaxonNameDTO bean) {
453 // ---- sync the name.nomenclaturalStatus set with the modifications
454 Set<NomenclaturalStatus> removeCandidates = new HashSet<>(bean.cdmEntity().getStatus());
455 for (NomenclaturalStatusDTO statusDTO : bean.getStatus()) {
456 if (statusDTO.getId() > 0) {
457 Optional<NomenclaturalStatus> originalEntity = bean.cdmEntity().getStatus().stream()
458 .filter(s -> s.getId() == statusDTO.getId()).findFirst();
459 if (originalEntity.isPresent()) {
460 statusDTO.update(originalEntity.get());
461 removeCandidates.remove(originalEntity.get());
462 } else {
463 throw new RuntimeException("No original NomenclaturalStatus found for DTO with id="
464 + statusDTO.getId() + ". Was the TaxonName modified otherwise when opened in the editor?");
465 }
466 } else {
467 // all new status with id = 0
468 bean.cdmEntity().addStatus(statusDTO.update(null));
469 }
470 }
471 for(NomenclaturalStatus toBeRemoved : removeCandidates) {
472 bean.cdmEntity().removeStatus(toBeRemoved);
473 }
474 return super.preSaveBean(bean);
475 }
476
477 @Override
478 protected void guaranteePerEntityCRUDPermissions(UUID identifier) {
479 if (crud != null) {
480 newAuthorityCreated = UserHelperAccess.userHelper().createAuthorityForCurrentUser(TaxonName.class,
481 identifier, crud, null);
482 }
483 }
484
485 @Override
486 protected void guaranteePerEntityCRUDPermissions(TaxonName bean) {
487 if (crud != null) {
488 newAuthorityCreated = UserHelperAccess.userHelper().createAuthorityForCurrentUser(bean, crud, null);
489 }
490 }
491
492 @Override
493 protected INameService getService() {
494 return getRepo().getNameService();
495 }
496
497 public void doReferenceEditorAdd(NomenclaturalStatusRow row) {
498
499 ReferencePopupEditor referencePopupEditor = openPopupEditor(ReferencePopupEditor.class, null);
500
501 referencePopupEditor.withReferenceTypes(RegistrationUIDefaults.MEDIA_REFERENCE_TYPES);
502 referencePopupEditor.grantToCurrentUser(SUB_EDITOR_CRUD);
503 referencePopupEditor.withDeleteButton(true);
504 referencePopupEditor.loadInEditor(null);
505
506 statusTypeReferencePopupEditorsRowMap.put(referencePopupEditor, row);
507 }
508
509 public void doReferenceEditorEdit(NomenclaturalStatusRow row) {
510
511 ReferencePopupEditor referencePopupEditor = openPopupEditor(ReferencePopupEditor.class, null);
512 referencePopupEditor.withReferenceTypes(RegistrationUIDefaults.MEDIA_REFERENCE_TYPES);
513 referencePopupEditor.grantToCurrentUser(SUB_EDITOR_CRUD);
514 referencePopupEditor.withDeleteButton(true);
515 referencePopupEditor.loadInEditor(row.citation.getValue().getUuid());
516
517 statusTypeReferencePopupEditorsRowMap.put(referencePopupEditor, row);
518 }
519
520 private void configureReferencePopupEditor(ReferencePopupEditor referenceEditorPopup, UUID referenceUUID) {
521
522 boolean nomRefSectionEditingOnly = getView()
523 .isModeEnabled(TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY);
524
525 // TODO this should be configurable per UI -
526 // RegistrationUiReferenceEditorFormConfigurator as spring bean,
527 // different spring profiles
528 boolean limitToSectionEditing = nomRefSectionEditingOnly && newReferenceInstantiator != null;
529 RegistrationUiReferenceEditorFormConfigurator
530 .create(limitToSectionEditing).configure(referenceEditorPopup, nomRefSectionEditingOnly ? newReferenceInstantiator : null);
531
532 referenceEditorPopup.loadInEditor(referenceUUID);
533 if (!nomRefSectionEditingOnly) {
534 referenceEditorPopup.getTypeSelect().setValue(ReferenceType.Article);
535 }
536 }
537
538 @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
539 public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
540
541 if (getView() == null || event.getSourceView() != getView()) {
542 return;
543 }
544
545 ReferencePopupEditor referenceEditorPopup = openPopupEditor(ReferencePopupEditor.class, event);
546
547 referenceEditorPopup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
548 referenceEditorPopup.withDeleteButton(true);
549 configureReferencePopupEditor(referenceEditorPopup, null);
550 }
551
552 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
553 public void onReferenceEditorActionEdit(ReferenceEditorAction event) {
554
555 if (!isFromOwnView(event)) {
556 return;
557 }
558 ReferencePopupEditor referenceEditorPopup = openPopupEditor(ReferencePopupEditor.class, event);
559
560 referenceEditorPopup.withDeleteButton(true);
561 configureReferencePopupEditor(referenceEditorPopup, event.getEntityUuid());
562 }
563
564 @EventBusListenerMethod
565 public void onFieldReplaceEvent(FieldReplaceEvent<String> event) {
566
567 PropertyIdPath boundPropertyIdPath = boundPropertyIdPath(event.getNewField());
568 if (boundPropertyIdPath != null) {
569 TaxonNameDTO taxonNamedto = ((AbstractPopupEditor<TaxonNameDTO, TaxonNameEditorPresenter,TaxonNamePopupEditorView>) getView())
570 .getBean();
571 if (boundPropertyIdPath.matches("specificEpithet")) {
572 AbstractField<String> genusOrUninomialField = getView().getGenusOrUninomialField();
573 if (event.getNewField() instanceof CompositeCustomField) {
574 if (specificEpithetPartPagingProvider == null) {
575 specificEpithetPartPagingProvider = new TaxonNameStringFilterablePagingProvider(
576 getRepo().getNameService(), Rank.SPECIES());
577 }
578 specificEpithetPartPagingProvider.listenToFields(genusOrUninomialField, null, null, null);
579 specificEpithetPartPagingProvider.excludeNames(taxonNamedto.cdmEntity());
580 specificEpithetPartPagingProvider.updateFromFields();
581 WeaklyRelatedEntityCombobox<TaxonName> specificEpithetField = (WeaklyRelatedEntityCombobox<TaxonName>) event
582 .getNewField();
583 refreshSpecificEpithetComboBoxListener = e -> {
584 specificEpithetField.getSelect().refresh();
585 specificEpithetField.setValue(null);
586 };
587 specificEpithetField.loadFrom(specificEpithetPartPagingProvider, specificEpithetPartPagingProvider,
588 specificEpithetPartPagingProvider.getPageSize());
589 specificEpithetField.setValue(event.getOldField().getValue());
590 specificEpithetField.reload();
591 genusOrUninomialField.addValueChangeListener(refreshSpecificEpithetComboBoxListener);
592 } else {
593 if (specificEpithetPartPagingProvider != null) {
594 specificEpithetPartPagingProvider.unlistenAllFields();
595 }
596 if (refreshSpecificEpithetComboBoxListener != null) {
597 genusOrUninomialField.removeValueChangeListener(refreshSpecificEpithetComboBoxListener);
598 refreshSpecificEpithetComboBoxListener = null;
599 }
600 }
601 } else if (boundPropertyIdPath.matches("genusOrUninomial")) {
602 if (event.getNewField() instanceof CompositeCustomField) {
603 if (genusOrUninomialPartPagingProvider == null) {
604 genusOrUninomialPartPagingProvider = new TaxonNameStringFilterablePagingProvider(
605 getRepo().getNameService());
606 }
607 genusOrUninomialPartPagingProvider.listenToFields(null, getView().getInfraGenericEpithetField(),
608 getView().getSpecificEpithetField(), getView().getInfraSpecificEpithetField());
609 genusOrUninomialPartPagingProvider.excludeNames(taxonNamedto.cdmEntity());
610 WeaklyRelatedEntityCombobox<TaxonName> genusOrUninomialField = (WeaklyRelatedEntityCombobox<TaxonName>) event
611 .getNewField();
612 genusOrUninomialField.loadFrom(genusOrUninomialPartPagingProvider,
613 genusOrUninomialPartPagingProvider, genusOrUninomialPartPagingProvider.getPageSize());
614 genusOrUninomialField.setValue(event.getOldField().getValue());
615 genusOrUninomialField.reload();
616 } else {
617 if (genusOrUninomialPartPagingProvider != null) {
618 genusOrUninomialPartPagingProvider.unlistenAllFields();
619 }
620 }
621
622 }
623 }
624
625 }
626
627 @EventBusListenerMethod
628 public void onEntityChangeEvent(EntityChangeEvent<?> event) {
629
630 if (event.getSourceView() instanceof AbstractPopupEditor) {
631
632 BoundField boundTargetField = boundTargetField((PopupView) event.getSourceView());
633
634 if (boundTargetField != null) {
635 if (boundTargetField.matchesPropertyIdPath("genusOrUninomial")) {
636 if (event.isCreateOrModifiedType()) {
637 getCache().load(event.getEntity());
638 if (getView().getGenusOrUninomialField() instanceof WeaklyRelatedEntityCombobox) {
639 WeaklyRelatedEntityCombobox<TaxonName> weaklyRelatedEntityCombobox = (WeaklyRelatedEntityCombobox<TaxonName>) getView()
640 .getGenusOrUninomialField();
641 weaklyRelatedEntityCombobox.setValue(((TaxonName) event.getEntity()).getGenusOrUninomial());
642 // NOTE: in contrast to the ToOneRelatedEntityCombobox the .discard() does not
643 // work here since no datasource is bound to the field, see weaklyRelatedEntityCombobox.reload()
644 weaklyRelatedEntityCombobox.updateButtons();
645 }
646 }
647 } else if (boundTargetField.matchesPropertyIdPath("specificEpithet")) {
648 if (event.isCreateOrModifiedType()) {
649 getCache().load(event.getEntity());
650 if (getView().getSpecificEpithetField() instanceof WeaklyRelatedEntityCombobox) {
651 WeaklyRelatedEntityCombobox<TaxonName> weaklyRelatedEntityCombobox = (WeaklyRelatedEntityCombobox<TaxonName>) getView()
652 .getSpecificEpithetField();
653 getView().getSpecificEpithetField()
654 .setValue(((TaxonName) event.getEntity()).getSpecificEpithet());
655 weaklyRelatedEntityCombobox.reload();
656 // NOTE: in contrast to the ToOneRelatedEntityCombobox the .discard() does not
657 // work here since no datasource is bound to the field, see weaklyRelatedEntityCombobox.reload()
658 weaklyRelatedEntityCombobox.updateButtons();
659 }
660 }
661 } else if (boundTargetField.matchesPropertyIdPath("nomenclaturalReference")) {
662 if (event.isCreateOrModifiedType()) {
663 getCache().load(event.getEntity());
664 if (event.isCreatedType()) {
665 getView().getNomReferenceCombobox().setValue((Reference) event.getEntity());
666 } else {
667 getView().getNomReferenceCombobox().reload(); // refreshSelectedValue(modifiedReference);
668 }
669 getView().getCombinationAuthorshipField().discard(); //refresh from the datasource
670 getView().updateAuthorshipFields();
671 }
672 } else if (boundTargetField.matchesPropertyIdPath("validationFor.otherName")
673 || boundTargetField.matchesPropertyIdPath("orthographicVariant.otherName")) {
674 ReloadableLazyComboBox<TaxonName> otherNameField = asReloadableLazyComboBox(
675 boundTargetField.getField(TaxonName.class));
676 TaxonName otherName = (TaxonName) event.getEntity();
677 if (event.isCreateOrModifiedType()) {
678 getCache().load(otherName);
679 if (event.isCreatedType()) {
680 // TODO use reloadWith((TaxonName)
681 // event.getEntity()); also in this case?
682 otherNameField.setValue(otherName);
683 } else {
684 otherNameField.reloadWith(otherName);
685 }
686
687 } else if (event.isRemovedType()) {
688 otherNameField.setValue(null);
689 }
690 } else if (boundTargetField.matchesPropertyIdPath("basionyms")) {
691 ReloadableLazyComboBox<TaxonName> basionymSourceField = asReloadableLazyComboBox(
692 boundTargetField.getField(TaxonName.class));
693 if (event.isCreateOrModifiedType()) {
694 getCache().load(event.getEntity());
695 if (event.isCreatedType()) {
696 // TODO use reloadWith((TaxonName)
697 // event.getEntity()); also in this case?
698 basionymSourceField.setValue((TaxonName) event.getEntity());
699 } else {
700 basionymSourceField.reloadWith((TaxonName) event.getEntity());
701 }
702 getView().getBasionymAuthorshipField().discard(); //refresh from the datasource
703 getView().getExBasionymAuthorshipField().discard(); //refresh from the datasource
704 getView().updateAuthorshipFields();
705 } else if (event.isRemovedType()) {
706 basionymSourceField.setValue(null);
707 getView().updateAuthorshipFields();
708 }
709 } else if (boundTargetField.matchesPropertyIdPath("replacedSynonyms")) {
710 ReloadableLazyComboBox<TaxonName> replacedSynonyms = asReloadableLazyComboBox(
711 boundTargetField.getField(TaxonName.class));
712 if (event.isCreateOrModifiedType()) {
713 getCache().load(event.getEntity());
714 if (event.isCreatedType()) {
715 // TODO use reloadWith((TaxonName)
716 // event.getEntity()); also in this case?
717 replacedSynonyms.setValue((TaxonName) event.getEntity());
718 } else {
719 replacedSynonyms.reloadWith((TaxonName) event.getEntity());
720 }
721 getView().getExCombinationAuthorshipField().discard(); //refresh from the datasource
722 getView().updateAuthorshipFields();
723 } else if (event.isRemovedType()) {
724 replacedSynonyms.setValue(null);
725 getView().updateAuthorshipFields();
726 }
727 }
728
729 }
730 }
731 }
732
733 protected <CDM extends CdmBase> ReloadableLazyComboBox<CDM> asReloadableLazyComboBox(Field<CDM> field) {
734
735 if (field instanceof ToOneRelatedEntityCombobox) {
736 field = ((ToOneRelatedEntityCombobox<CDM>) field).getSelect();
737 }
738 return (ReloadableLazyComboBox<CDM>) field;
739 }
740
741 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
742 public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
743
744 if (getView() == null || event.getSourceView() != getView()) {
745 return;
746 }
747
748 PropertyIdPath boundPropertyId = boundPropertyIdPath(event.getTarget());
749
750 if (boundPropertyId != null) {
751 if (boundPropertyId.matches("validationFor.otherName") || boundPropertyId.matches("basionyms")
752 || boundPropertyId.matches("replacedSynonyms")
753 || boundPropertyId.matches("orthographicVariant.otherName")) {
754 TaxonNamePopupEditor namePopup = openPopupEditor(TaxonNamePopupEditor.class, event);
755 namePopup.withDeleteButton(true);
756 getView().getModesActive().stream()
757 .filter(m -> !TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY.equals(m))
758 .forEach(m -> namePopup.enableMode(m));
759 if (boundPropertyId.matches("orthographicVariant.otherName")
760 && getView().isModeEnabled(TaxonNamePopupEditorMode.ORTHOGRAPHIC_CORRECTION)) {
761 namePopup.enableMode(TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY);
762 namePopup.disableMode(TaxonNamePopupEditorMode.VALIDATE_AGAINST_HIGHER_NAME_PART);
763 namePopup.getOrthographicVariantToggle().setVisible(false);
764 }
765 namePopup.loadInEditor(event.getEntityUuid());
766 }
767 }
768 }
769
770 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
771 public void onTaxonNameEditorActionStrRepEdit(TaxonNameEditorActionStrRep event) {
772
773 if (getView() == null || event.getSourceView() != getView()) {
774 return;
775 }
776
777 PropertyIdPath boundPropertyId = boundPropertyIdPath(event.getTarget());
778
779 if (boundPropertyId != null) {
780 if (boundPropertyId.matches("genusOrUninomial") || boundPropertyId.matches("specificEpithet")) {
781 TaxonNamePopupEditor namePopup = openPopupEditor(TaxonNamePopupEditor.class, event);
782 namePopup.withDeleteButton(true);
783 getView().getModesActive().stream()
784 .filter(m -> !TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY.equals(m))
785 .forEach(m -> namePopup.enableMode(m));
786 namePopup.loadInEditor(event.getEntityUuid());
787 }
788 }
789 }
790
791 @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
792 public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
793
794 if (getView() == null || event.getSourceView() != getView()) {
795 return;
796 }
797
798 PropertyIdPath boundPropertyId = boundPropertyIdPath(event.getTarget());
799
800 if (boundPropertyId != null) {
801 if (boundPropertyId.matches("validationFor.otherName") || boundPropertyId.matches("basionyms")
802 || boundPropertyId.matches("replacedSynonyms")
803 || boundPropertyId.matches("orthographicVariant.otherName")) {
804 TaxonNamePopupEditor namePopup = openPopupEditor(TaxonNamePopupEditor.class, event);
805 namePopup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
806 namePopup.withDeleteButton(true);
807 getView().getModesActive().stream()
808 .filter(m -> !TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY.equals(m))
809 .forEach(m -> namePopup.enableMode(m));
810 if (boundPropertyId.matches("orthographicVariant.otherName")
811 && getView().isModeEnabled(TaxonNamePopupEditorMode.ORTHOGRAPHIC_CORRECTION)) {
812 namePopup.enableMode(TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY);
813 namePopup.disableMode(TaxonNamePopupEditorMode.VALIDATE_AGAINST_HIGHER_NAME_PART);
814 Reference nomrefPreset = (Reference) ((AbstractPopupEditor<TaxonNameDTO, TaxonNameEditorPresenter,TaxonNamePopupEditorView>) getView())
815 .getBean().getNomenclaturalReference();
816 namePopup.setCdmEntityInstantiator(new BeanInstantiator<TaxonName>() {
817
818 @Override
819 public TaxonName createNewBean() {
820 TaxonName newTaxonName = TaxonNameFactory
821 .NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
822 newTaxonName.setNomenclaturalReference(getRepo().getReferenceService()
823 .load(nomrefPreset.getUuid(), TaxonNameEditorPresenter.REFERENCE_INIT_STRATEGY));
824 return newTaxonName;
825 }
826 });
827 namePopup.getOrthographicVariantToggle().setVisible(false);
828 }
829 namePopup.loadInEditor(null);
830 }
831 }
832 }
833
834 @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
835 public void onTaxonNameEditorActionStrRepAdd(TaxonNameEditorActionStrRep event) {
836
837 if (getView() == null || event.getSourceView() != getView()) {
838 return;
839 }
840
841 PropertyIdPath boundPropertyId = boundPropertyIdPath(event.getTarget());
842
843 if (boundPropertyId != null) {
844 if (boundPropertyId.matches("genusOrUninomial") || boundPropertyId.matches("specificEpithet")) {
845 TaxonNamePopupEditor namePopup = openPopupEditor(TaxonNamePopupEditor.class, event);
846 namePopup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
847 namePopup.withDeleteButton(true);
848 getView().getModesActive().stream()
849 .filter(m -> !TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY.equals(m))
850 .forEach(m -> namePopup.enableMode(m));
851 namePopup.loadInEditor(null);
852 if (boundPropertyId.matches("genusOrUninomial")) {
853 namePopup.getRankSelect().setValue(Rank.GENUS());
854 }
855 if (boundPropertyId.matches("specificEpithet")) {
856 namePopup.getGenusOrUninomialField().setValue(getView().getGenusOrUninomialField().getValue());
857 namePopup.getRankSelect().setValue(Rank.SPECIES());
858 }
859 if (WeaklyRelatedEntityField.class.isAssignableFrom(event.getTarget().getClass())) {
860 WeaklyRelatedEntityField<TaxonName> taxoNameField = (WeaklyRelatedEntityField<TaxonName>) event
861 .getTarget();
862 if (!taxoNameField.isValueInOptions()) {
863 String nameString = event.getTarget().getValue();
864 if (StringUtils.isNotEmpty(nameString)) {
865 if (boundPropertyId.matches("genusOrUninomial")) {
866 namePopup.getGenusOrUninomialField().setValue(nameString);
867 }
868 if (boundPropertyId.matches("specificEpithet")) {
869 namePopup.getSpecificEpithetField().setValue(nameString);
870 }
871 }
872 }
873 }
874 }
875 }
876 }
877
878 @Override
879 protected TaxonNameDTO createDTODecorator(TaxonName cdmEntitiy) {
880 return new TaxonNameDTO(cdmEntitiy);
881 }
882
883 @Override
884 protected BeanInstantiator<TaxonName> defaultCdmEntityInstantiator() {
885 return new BeanInstantiator<TaxonName>() {
886
887 @Override
888 public TaxonName createNewBean() {
889 return TaxonNameFactory.NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
890 }
891 };
892 }
893
894 }