2 * Copyright (C) 2017 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
9 package eu
.etaxonomy
.cdm
.vaadin
.view
.name
;
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
;
17 import java
.util
.Optional
;
19 import java
.util
.UUID
;
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
;
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
;
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
;
92 * @author a.kohlbecker
97 public class TaxonNameEditorPresenter
98 extends AbstractCdmDTOEditorPresenter
<TaxonNameDTO
, TaxonName
, TaxonNameEditorPresenter
, TaxonNamePopupEditorView
> {
100 private static final long serialVersionUID
= -3538980627079389221L;
102 private static final EnumSet
<CRUD
> SUB_EDITOR_CRUD
= EnumSet
.of(CRUD
.UPDATE
, CRUD
.DELETE
);
104 private static final List
<String
> RELATED_NAME_INIT_STRATEGY
= Arrays
.asList("$", "nomenclaturalSource.annotations",
105 "relationsFromThisName", "relationsToThisName.type", "homotypicalGroup.typifiedNames");
107 public static List
<String
> REFERENCE_INIT_STRATEGY
= ReferenceEllypsisFormatter
.INIT_STRATEGY
;
109 private CdmFilterablePagingProvider
<Reference
, Reference
> nomReferencePagingProvider
;
111 private Reference publishedUnit
;
113 private BeanInstantiator
<Reference
> newReferenceInstantiator
;
115 private Map
<ReferencePopupEditor
, NomenclaturalStatusRow
> statusTypeReferencePopupEditorsRowMap
= new HashMap
<>();
117 private TaxonNameStringFilterablePagingProvider genusOrUninomialPartPagingProvider
;
119 private TaxonNameStringFilterablePagingProvider specificEpithetPartPagingProvider
;
121 private Property
.ValueChangeListener refreshSpecificEpithetComboBoxListener
;
123 private CdmFilterablePagingProvider
<TaxonName
, TaxonName
> relatedNamePagingProvider
;
125 private CdmFilterablePagingProvider
<TaxonName
, TaxonName
> orthographicVariantNamePagingProvider
;
127 private Restriction
<Reference
> orthographicCorrectionRestriction
;
129 private Integer taxonNameId
;
131 private BeanItemContainer
<DefinedTermBase
> rankTermItemContainer
;
133 private Filter rankListFilter
;
136 * the taxon names rank as loaded from the persistence layer
138 private Rank initialRank
;
141 @SuppressWarnings("serial")
143 public void handleViewEntered() {
145 super.handleViewEntered();
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()]));
153 rankTermItemContainer
= cdmBeanItemContainerFactory
.buildTermItemContainer(TermType
.Rank
);
154 rankListFilter
= new Filter() {
156 public boolean passesFilter(Object itemId
, Item item
) throws UnsupportedOperationException
{
157 return getView().isRanksFullList() || RegistrationUIDefaults
.RANK_SET_COMPACT
.contains(itemId
) || itemId
.equals(initialRank
);
160 public boolean appliesToProperty(Object propertyId
) {
163 rankTermItemContainer
.addContainerFilter(rankListFilter
);
164 getView().getRankSelect()
165 .setContainerDataSource(rankTermItemContainer
);
166 getView().getRankSelect().setItemCaptionPropertyId("label");
167 getView().getRankSelectFullListToggle().addClickListener(e
-> {
168 updateRankTermItemContainer();
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();
177 getView().getCombinationAuthorshipField().setFilterableTeamPagingProvider(termOrPersonPagingProvider
, this);
178 getView().getCombinationAuthorshipField().setFilterablePersonPagingProvider(personPagingProvider
, this);
180 getView().getExCombinationAuthorshipField().setFilterableTeamPagingProvider(termOrPersonPagingProvider
, this);
181 getView().getExCombinationAuthorshipField().setFilterablePersonPagingProvider(personPagingProvider
, this);
183 getView().getBasionymAuthorshipField().setFilterableTeamPagingProvider(termOrPersonPagingProvider
, this);
184 getView().getBasionymAuthorshipField().setFilterablePersonPagingProvider(personPagingProvider
, this);
186 getView().getExBasionymAuthorshipField().setFilterableTeamPagingProvider(termOrPersonPagingProvider
, this);
187 getView().getExBasionymAuthorshipField().setFilterablePersonPagingProvider(personPagingProvider
, this);
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());
202 CdmFilterablePagingProvider
<Reference
, Reference
> icbnCodesPagingProvider
= pagingProviderFactory
203 .referencePagingProvider();
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
217 statusTypeReferencePopupEditorsRowMap
.clear();
218 getView().getNomStatusCollectionField().addElementAddedListener(e
-> addNomenclaturalStatus(e
.getElement()));
219 getView().getNomStatusCollectionField()
220 .setEditorInstantiator(new AbstractElementCollection
.Instantiator
<NomenclaturalStatusRow
>() {
223 public NomenclaturalStatusRow
create() {
224 NomenclaturalStatusRow row
= new NomenclaturalStatusRow();
227 BeanItemContainer
<DefinedTermBase
> statusTypeItemContainer
= cdmBeanItemContainerFactory
.buildTermItemContainer(
228 RegistrationTermLists
.NOMENCLATURAL_STATUS_TYPE_UUIDS()
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());
236 row
.type
.setNullSelectionAllowed(false);
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
);
250 row
.codeEdition
.setContainerDataSource(codeEditionItemContainer
);
252 getView().applyDefaultComponentStyle(row
.components());
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);
264 getView().getReplacedSynonymsComboboxSelect()
265 .setCaptionGenerator(new CdmTitleCacheCaptionGenerator
<TaxonName
>());
266 getView().getReplacedSynonymsComboboxSelect().setPagingProviders(relatedNamePagingProvider
,
267 relatedNamePagingProvider
, relatedNamePagingProvider
.getPageSize(), this);
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
);
284 getView().getOrthographicVariantField().getRelatedNameComboBox().getSelect()
285 .setCaptionGenerator(new CdmTitleCacheCaptionGenerator
<TaxonName
>());
286 getView().getOrthographicVariantField().getRelatedNameComboBox().getSelect().addValueChangeListener(
287 new ToOneRelatedEntityReloader
<>(getView().getOrthographicVariantField().getRelatedNameComboBox(),
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
);
302 getView().getAnnotationsField().setAnnotationTypeItemContainer(cdmBeanItemContainerFactory
303 .buildVocabularyTermsItemContainer(AnnotationType
.EDITORIAL().getVocabulary().getUuid()));
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
);
314 private void addNomenclaturalStatus(NomenclaturalStatusDTO element
) {
319 protected void adaptDataProviders() {
320 updateOrthographicCorrectionRestriction();
321 updateRankTermItemContainer();
324 private void updateOrthographicCorrectionRestriction() {
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());
337 Reference nomReference
= getView().getNomReferenceCombobox().getValue();
338 if (nomReference
== null && orthographicCorrectionRestriction
!= null) {
339 orthographicVariantNamePagingProvider
.getRestrictions().remove(orthographicCorrectionRestriction
);
341 if (orthographicCorrectionRestriction
== null) {
342 orthographicCorrectionRestriction
= new Restriction
<>("nomenclaturalSource.citation", Operator
.AND
,
344 orthographicVariantNamePagingProvider
.addRestriction(orthographicCorrectionRestriction
);
346 orthographicCorrectionRestriction
.setValues(Arrays
.asList(nomReference
));
349 getView().getOrthographicVariantField().getRelatedNameComboBox().getSelect().refresh();
354 protected TaxonName
loadCdmEntity(UUID identifier
) {
356 EntityInitStrategy initStrategy
= new EntityInitStrategy(
360 "annotations.*", // needed as log as we are using a table in FilterableAnnotationsField
361 "rank.vocabulary", // needed for comparing ranks
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()
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()
374 "combinationAuthorship",
375 "exCombinationAuthorship",
376 "basionymAuthorship",
377 "exBasionymAuthorship",
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"
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);
405 if (identifier
!= null) {
406 taxonName
= getRepo().getNameService().load(identifier
, initStrategy
.getPropertyPaths());
408 taxonName
= createCdmEntity();
411 if (getView().isModeEnabled(TaxonNamePopupEditorMode
.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY
)) {
412 Reference nomRef
= taxonName
.getNomenclaturalReference();
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();
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())));
429 // and remove the empty option
430 getView().getNomReferenceCombobox().getSelect().setNullSelectionAllowed(false);
432 // new Reference only a sub sections of the publishedUnit
433 newReferenceInstantiator
= new BeanInstantiator
<Reference
>() {
435 public Reference
createNewBean() {
436 Reference newRef
= ReferenceFactory
.newSection();
437 newRef
.setInReference(publishedUnit
);
444 taxonNameId
= Integer
.valueOf(taxonName
.getId());
445 initialRank
= taxonName
.getRank();
446 relatedNamePagingProvider
.addRestriction(new Restriction
<>("id", Operator
.AND_NOT
, null, taxonNameId
));
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());
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?");
467 // all new status with id = 0
468 bean
.cdmEntity().addStatus(statusDTO
.update(null));
471 for(NomenclaturalStatus toBeRemoved
: removeCandidates
) {
472 bean
.cdmEntity().removeStatus(toBeRemoved
);
474 return super.preSaveBean(bean
);
478 protected void guaranteePerEntityCRUDPermissions(UUID identifier
) {
480 newAuthorityCreated
= UserHelperAccess
.userHelper().createAuthorityForCurrentUser(TaxonName
.class,
481 identifier
, crud
, null);
486 protected void guaranteePerEntityCRUDPermissions(TaxonName bean
) {
488 newAuthorityCreated
= UserHelperAccess
.userHelper().createAuthorityForCurrentUser(bean
, crud
, null);
493 protected INameService
getService() {
494 return getRepo().getNameService();
497 public void doReferenceEditorAdd(NomenclaturalStatusRow row
) {
499 ReferencePopupEditor referencePopupEditor
= openPopupEditor(ReferencePopupEditor
.class, null);
501 referencePopupEditor
.withReferenceTypes(RegistrationUIDefaults
.MEDIA_REFERENCE_TYPES
);
502 referencePopupEditor
.grantToCurrentUser(SUB_EDITOR_CRUD
);
503 referencePopupEditor
.withDeleteButton(true);
504 referencePopupEditor
.loadInEditor(null);
506 statusTypeReferencePopupEditorsRowMap
.put(referencePopupEditor
, row
);
509 public void doReferenceEditorEdit(NomenclaturalStatusRow row
) {
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());
517 statusTypeReferencePopupEditorsRowMap
.put(referencePopupEditor
, row
);
520 private void configureReferencePopupEditor(ReferencePopupEditor referenceEditorPopup
, UUID referenceUUID
) {
522 boolean nomRefSectionEditingOnly
= getView()
523 .isModeEnabled(TaxonNamePopupEditorMode
.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY
);
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);
532 referenceEditorPopup
.loadInEditor(referenceUUID
);
533 if (!nomRefSectionEditingOnly
) {
534 referenceEditorPopup
.getTypeSelect().setValue(ReferenceType
.Article
);
538 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Add
.class)
539 public void onReferenceEditorActionAdd(ReferenceEditorAction event
) {
541 if (getView() == null || event
.getSourceView() != getView()) {
545 ReferencePopupEditor referenceEditorPopup
= openPopupEditor(ReferencePopupEditor
.class, event
);
547 referenceEditorPopup
.grantToCurrentUser(EnumSet
.of(CRUD
.UPDATE
, CRUD
.DELETE
));
548 referenceEditorPopup
.withDeleteButton(true);
549 configureReferencePopupEditor(referenceEditorPopup
, null);
552 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Edit
.class)
553 public void onReferenceEditorActionEdit(ReferenceEditorAction event
) {
555 if (!isFromOwnView(event
)) {
558 ReferencePopupEditor referenceEditorPopup
= openPopupEditor(ReferencePopupEditor
.class, event
);
560 referenceEditorPopup
.withDeleteButton(true);
561 configureReferencePopupEditor(referenceEditorPopup
, event
.getEntityUuid());
564 @EventBusListenerMethod
565 public void onFieldReplaceEvent(FieldReplaceEvent
<String
> event
) {
567 PropertyIdPath boundPropertyIdPath
= boundPropertyIdPath(event
.getNewField());
568 if (boundPropertyIdPath
!= null) {
569 TaxonNameDTO taxonNamedto
= ((AbstractPopupEditor
<TaxonNameDTO
, TaxonNameEditorPresenter
,TaxonNamePopupEditorView
>) getView())
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());
578 specificEpithetPartPagingProvider
.listenToFields(genusOrUninomialField
, null, null, null);
579 specificEpithetPartPagingProvider
.excludeNames(taxonNamedto
.cdmEntity());
580 specificEpithetPartPagingProvider
.updateFromFields();
581 WeaklyRelatedEntityCombobox
<TaxonName
> specificEpithetField
= (WeaklyRelatedEntityCombobox
<TaxonName
>) event
583 refreshSpecificEpithetComboBoxListener
= e
-> {
584 specificEpithetField
.getSelect().refresh();
585 specificEpithetField
.setValue(null);
587 specificEpithetField
.loadFrom(specificEpithetPartPagingProvider
, specificEpithetPartPagingProvider
,
588 specificEpithetPartPagingProvider
.getPageSize());
589 specificEpithetField
.setValue(event
.getOldField().getValue());
590 specificEpithetField
.reload();
591 genusOrUninomialField
.addValueChangeListener(refreshSpecificEpithetComboBoxListener
);
593 if (specificEpithetPartPagingProvider
!= null) {
594 specificEpithetPartPagingProvider
.unlistenAllFields();
596 if (refreshSpecificEpithetComboBoxListener
!= null) {
597 genusOrUninomialField
.removeValueChangeListener(refreshSpecificEpithetComboBoxListener
);
598 refreshSpecificEpithetComboBoxListener
= null;
601 } else if (boundPropertyIdPath
.matches("genusOrUninomial")) {
602 if (event
.getNewField() instanceof CompositeCustomField
) {
603 if (genusOrUninomialPartPagingProvider
== null) {
604 genusOrUninomialPartPagingProvider
= new TaxonNameStringFilterablePagingProvider(
605 getRepo().getNameService());
607 genusOrUninomialPartPagingProvider
.listenToFields(null, getView().getInfraGenericEpithetField(),
608 getView().getSpecificEpithetField(), getView().getInfraSpecificEpithetField());
609 genusOrUninomialPartPagingProvider
.excludeNames(taxonNamedto
.cdmEntity());
610 WeaklyRelatedEntityCombobox
<TaxonName
> genusOrUninomialField
= (WeaklyRelatedEntityCombobox
<TaxonName
>) event
612 genusOrUninomialField
.loadFrom(genusOrUninomialPartPagingProvider
,
613 genusOrUninomialPartPagingProvider
, genusOrUninomialPartPagingProvider
.getPageSize());
614 genusOrUninomialField
.setValue(event
.getOldField().getValue());
615 genusOrUninomialField
.reload();
617 if (genusOrUninomialPartPagingProvider
!= null) {
618 genusOrUninomialPartPagingProvider
.unlistenAllFields();
627 @EventBusListenerMethod
628 public void onEntityChangeEvent(EntityChangeEvent
<?
> event
) {
630 if (event
.getSourceView() instanceof AbstractPopupEditor
) {
632 BoundField boundTargetField
= boundTargetField((PopupView
) event
.getSourceView());
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();
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();
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());
667 getView().getNomReferenceCombobox().reload(); // refreshSelectedValue(modifiedReference);
669 getView().getCombinationAuthorshipField().discard(); //refresh from the datasource
670 getView().updateAuthorshipFields();
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
);
684 otherNameField
.reloadWith(otherName
);
687 } else if (event
.isRemovedType()) {
688 otherNameField
.setValue(null);
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());
700 basionymSourceField
.reloadWith((TaxonName
) event
.getEntity());
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();
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());
719 replacedSynonyms
.reloadWith((TaxonName
) event
.getEntity());
721 getView().getExCombinationAuthorshipField().discard(); //refresh from the datasource
722 getView().updateAuthorshipFields();
723 } else if (event
.isRemovedType()) {
724 replacedSynonyms
.setValue(null);
725 getView().updateAuthorshipFields();
733 protected <CDM
extends CdmBase
> ReloadableLazyComboBox
<CDM
> asReloadableLazyComboBox(Field
<CDM
> field
) {
735 if (field
instanceof ToOneRelatedEntityCombobox
) {
736 field
= ((ToOneRelatedEntityCombobox
<CDM
>) field
).getSelect();
738 return (ReloadableLazyComboBox
<CDM
>) field
;
741 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Edit
.class)
742 public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event
) {
744 if (getView() == null || event
.getSourceView() != getView()) {
748 PropertyIdPath boundPropertyId
= boundPropertyIdPath(event
.getTarget());
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);
765 namePopup
.loadInEditor(event
.getEntityUuid());
770 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Edit
.class)
771 public void onTaxonNameEditorActionStrRepEdit(TaxonNameEditorActionStrRep event
) {
773 if (getView() == null || event
.getSourceView() != getView()) {
777 PropertyIdPath boundPropertyId
= boundPropertyIdPath(event
.getTarget());
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());
791 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Add
.class)
792 public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event
) {
794 if (getView() == null || event
.getSourceView() != getView()) {
798 PropertyIdPath boundPropertyId
= boundPropertyIdPath(event
.getTarget());
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
>() {
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
));
827 namePopup
.getOrthographicVariantToggle().setVisible(false);
829 namePopup
.loadInEditor(null);
834 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Add
.class)
835 public void onTaxonNameEditorActionStrRepAdd(TaxonNameEditorActionStrRep event
) {
837 if (getView() == null || event
.getSourceView() != getView()) {
841 PropertyIdPath boundPropertyId
= boundPropertyIdPath(event
.getTarget());
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());
855 if (boundPropertyId
.matches("specificEpithet")) {
856 namePopup
.getGenusOrUninomialField().setValue(getView().getGenusOrUninomialField().getValue());
857 namePopup
.getRankSelect().setValue(Rank
.SPECIES());
859 if (WeaklyRelatedEntityField
.class.isAssignableFrom(event
.getTarget().getClass())) {
860 WeaklyRelatedEntityField
<TaxonName
> taxoNameField
= (WeaklyRelatedEntityField
<TaxonName
>) event
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
);
868 if (boundPropertyId
.matches("specificEpithet")) {
869 namePopup
.getSpecificEpithetField().setValue(nameString
);
879 protected TaxonNameDTO
createDTODecorator(TaxonName cdmEntitiy
) {
880 return new TaxonNameDTO(cdmEntitiy
);
884 protected BeanInstantiator
<TaxonName
> defaultCdmEntityInstantiator() {
885 return new BeanInstantiator
<TaxonName
>() {
888 public TaxonName
createNewBean() {
889 return TaxonNameFactory
.NewNameInstance(RegistrationUIDefaults
.NOMENCLATURAL_CODE
, Rank
.SPECIES());