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
.registration
;
11 import java
.util
.ArrayList
;
12 import java
.util
.Arrays
;
13 import java
.util
.Collection
;
14 import java
.util
.EnumSet
;
15 import java
.util
.HashMap
;
16 import java
.util
.HashSet
;
17 import java
.util
.List
;
19 import java
.util
.Objects
;
20 import java
.util
.Optional
;
22 import java
.util
.Stack
;
23 import java
.util
.UUID
;
25 import org
.apache
.logging
.log4j
.LogManager
;
26 import org
.apache
.logging
.log4j
.Logger
;
27 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
28 import org
.vaadin
.spring
.events
.EventScope
;
29 import org
.vaadin
.spring
.events
.annotation
.EventBusListenerMethod
;
31 import com
.vaadin
.spring
.annotation
.SpringComponent
;
32 import com
.vaadin
.spring
.annotation
.ViewScope
;
33 import com
.vaadin
.ui
.AbstractField
;
34 import com
.vaadin
.ui
.Label
;
35 import com
.vaadin
.ui
.UI
;
36 import com
.vaadin
.ui
.VerticalLayout
;
37 import com
.vaadin
.ui
.Window
;
39 import eu
.etaxonomy
.cdm
.api
.service
.config
.RegistrationStatusTransitions
;
40 import eu
.etaxonomy
.cdm
.api
.service
.dto
.RegistrationDTO
;
41 import eu
.etaxonomy
.cdm
.api
.service
.dto
.RegistrationWorkingSet
;
42 import eu
.etaxonomy
.cdm
.api
.service
.exception
.TypeDesignationSetException
;
43 import eu
.etaxonomy
.cdm
.api
.service
.name
.TypeDesignationSet
.TypeDesignationSetType
;
44 import eu
.etaxonomy
.cdm
.api
.service
.registration
.IRegistrationWorkingSetService
;
45 import eu
.etaxonomy
.cdm
.api
.util
.UserHelper
;
46 import eu
.etaxonomy
.cdm
.cache
.CdmTransientEntityWithUuidCacher
;
47 import eu
.etaxonomy
.cdm
.model
.ICdmEntityUuidCacher
;
48 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
49 import eu
.etaxonomy
.cdm
.model
.name
.NameTypeDesignation
;
50 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
51 import eu
.etaxonomy
.cdm
.model
.name
.Registration
;
52 import eu
.etaxonomy
.cdm
.model
.name
.RegistrationStatus
;
53 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
54 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameFactory
;
55 import eu
.etaxonomy
.cdm
.model
.name
.TypeDesignationBase
;
56 import eu
.etaxonomy
.cdm
.model
.occurrence
.FieldUnit
;
57 import eu
.etaxonomy
.cdm
.model
.permission
.CRUD
;
58 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
59 import eu
.etaxonomy
.cdm
.ref
.TypedEntityReference
;
60 import eu
.etaxonomy
.cdm
.service
.CdmBeanItemContainerFactory
;
61 import eu
.etaxonomy
.cdm
.service
.CdmFilterablePagingProvider
;
62 import eu
.etaxonomy
.cdm
.service
.CdmFilterablePagingProviderFactory
;
63 import eu
.etaxonomy
.cdm
.service
.CdmStore
;
64 import eu
.etaxonomy
.cdm
.service
.IRegistrationWorkflowService
;
65 import eu
.etaxonomy
.cdm
.service
.UserHelperAccess
;
66 import eu
.etaxonomy
.cdm
.vaadin
.component
.registration
.RegistrationItem
;
67 import eu
.etaxonomy
.cdm
.vaadin
.component
.registration
.RegistrationStatusFieldInstantiator
;
68 import eu
.etaxonomy
.cdm
.vaadin
.component
.registration
.RegistrationStatusSelect
;
69 import eu
.etaxonomy
.cdm
.vaadin
.event
.EditorActionContext
;
70 import eu
.etaxonomy
.cdm
.vaadin
.event
.EditorActionTypeFilter
;
71 import eu
.etaxonomy
.cdm
.vaadin
.event
.EntityChangeEvent
;
72 import eu
.etaxonomy
.cdm
.vaadin
.event
.ReferenceEditorAction
;
73 import eu
.etaxonomy
.cdm
.vaadin
.event
.RegistrationEditorAction
;
74 import eu
.etaxonomy
.cdm
.vaadin
.event
.ShowDetailsEvent
;
75 import eu
.etaxonomy
.cdm
.vaadin
.event
.ShowDetailsEventEntityTypeFilter
;
76 import eu
.etaxonomy
.cdm
.vaadin
.event
.TaxonNameEditorAction
;
77 import eu
.etaxonomy
.cdm
.vaadin
.event
.TypeDesignationSetEditorAction
;
78 import eu
.etaxonomy
.cdm
.vaadin
.event
.registration
.RegistrationWorkingsetAction
;
79 import eu
.etaxonomy
.cdm
.vaadin
.ui
.RegistrationUI
;
80 import eu
.etaxonomy
.cdm
.vaadin
.ui
.RegistrationUIDefaults
;
81 import eu
.etaxonomy
.cdm
.vaadin
.ui
.config
.TaxonNamePopupEditorConfig
;
82 import eu
.etaxonomy
.cdm
.vaadin
.util
.CdmTitleCacheCaptionGenerator
;
83 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.CachingPresenter
;
84 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.NameTypeDesignationPopupEditor
;
85 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.NameTypeDesignationSetIds
;
86 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.SpecimenTypeDesignationSetIds
;
87 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.SpecimenTypeDesignationSetPopupEditor
;
88 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.TaxonNameEditorPresenter
;
89 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.TaxonNamePopupEditor
;
90 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.TaxonNamePopupEditorMode
;
91 import eu
.etaxonomy
.cdm
.vaadin
.view
.reference
.ReferencePopupEditor
;
92 import eu
.etaxonomy
.vaadin
.mvp
.AbstractPopupEditor
;
93 import eu
.etaxonomy
.vaadin
.mvp
.AbstractPresenter
;
94 import eu
.etaxonomy
.vaadin
.mvp
.AbstractView
;
95 import eu
.etaxonomy
.vaadin
.mvp
.BeanInstantiator
;
96 import eu
.etaxonomy
.vaadin
.ui
.navigation
.NavigationEvent
;
97 import eu
.etaxonomy
.vaadin
.ui
.view
.DoneWithPopupEvent
;
98 import eu
.etaxonomy
.vaadin
.ui
.view
.DoneWithPopupEvent
.Reason
;
99 import eu
.etaxonomy
.vaadin
.ui
.view
.PopupView
;
102 * @author a.kohlbecker
107 public class RegistrationWorkingsetPresenter
108 extends AbstractPresenter
<RegistrationWorkingsetPresenter
,RegistrationWorkingsetView
>
109 implements CachingPresenter
{
111 private static final long serialVersionUID
= 2618456456539802265L;
113 private static final Logger logger
= LogManager
.getLogger();
116 private IRegistrationWorkingSetService regWorkingSetService
;
119 private IRegistrationWorkflowService registrationWorkflowService
;
122 private CdmFilterablePagingProviderFactory pagingProviderFactory
;
125 private CdmBeanItemContainerFactory selectFieldFactory
;
128 private CdmStore cdmStore
;
131 * @return the regWorkingSetService
133 public IRegistrationWorkingSetService
getWorkingSetService() {
134 return regWorkingSetService
;
137 private RegistrationWorkingSet workingset
;
140 * Contains the poupeditor which has been opened to start the registration of a new name as long as it has not been saved or canceled.
141 * There can always only be one popup editor for this purpose.
143 private TaxonNamePopupEditor newNameForRegistrationPopupEditor
= null;
148 private List
<Registration
> newNameBlockingRegistrations
= new ArrayList
<>();
151 * TODO is this still needed? The registration UUID should be accessible in the popup editor context,
152 * see findRegistrationInContext()
154 private Map
<NameTypeDesignationPopupEditor
, UUID
> nameTypeDesignationPopupEditorRegistrationUUIDMap
= new HashMap
<>();
157 private ICdmEntityUuidCacher cache
;
159 private Collection
<CdmBase
> rootEntities
= new HashSet
<>();
162 public RegistrationWorkingsetPresenter() {
166 * @param doReload reload the workingset from the persistent storage.
167 * Workingsets which are not yet persisted are preserved.
169 protected void refreshView(boolean doReload
) {
171 if(workingset
== null){
172 return; // nothing to do
175 if(logger
.isDebugEnabled()){
176 logger
.debug("refreshView() - workingset:\n" + workingset
.toString());
178 List
<RegistrationDTO
> unpersisted
= new ArrayList
<>();
179 for(RegistrationDTO regDto
: workingset
.getRegistrationDTOs()){
180 if(!regDto
.registration().isPersisted()){
181 unpersisted
.add(regDto
);
184 loadWorkingSet(workingset
.getCitationUuid());
185 for(RegistrationDTO regDtoUnpersisted
: unpersisted
){
186 if(!workingset
.getRegistrationDTOs().stream().anyMatch(dto
-> dto
.getUuid().equals(regDtoUnpersisted
.getUuid()))){
187 // only add if the regDtoUnpersisted has not been persisted meanwhile
189 workingset
.add(regDtoUnpersisted
);
190 } catch (TypeDesignationSetException e
) {
191 // would never happen here //
195 if(logger
.isDebugEnabled()){
196 logger
.debug("refreshView() - workingset reloaded:\n" + workingset
.toString());
203 public void handleViewEntered() {
204 super.handleViewEntered();
205 // TODO currently cannot specify type more precisely, see AbstractSelect
206 // FIXME externalize into class file!!!!!!!!!!!!
207 getView().setStatusComponentInstantiator(new RegistrationStatusFieldInstantiator
<Object
>(){
209 private static final long serialVersionUID
= 7099181280977511048L;
212 public AbstractField
<Object
> create(RegistrationDTO regDto
) {
214 // submitters have GrantedAuthorities like REGISTRATION(PREPARATION).[UPDATE]{ab4459eb-3b96-40ba-bfaa-36915107d59e}
215 UserHelper userHelper
= UserHelperAccess
.userHelper().withCache(getCache());
216 Set
<RegistrationStatus
> availableStatus
= new HashSet
<>();
218 boolean canChangeStatus
= userHelper
.userHasPermission(regDto
.registration(), CRUD
.UPDATE
);
219 availableStatus
.add(regDto
.getStatus());
221 if(userHelper
.userIsAdmin()){
222 availableStatus
.addAll(Arrays
.asList(RegistrationStatus
.values()));
224 availableStatus
.addAll(RegistrationStatusTransitions
.possibleTransitions(regDto
.getStatus()));
228 RegistrationStatusSelect select
= new RegistrationStatusSelect(null, selectFieldFactory
.buildEnumTermItemContainer(
229 RegistrationStatus
.class,
230 availableStatus
.toArray(new RegistrationStatus
[availableStatus
.size()]))
232 select
.setValue(regDto
.getStatus());
233 select
.addValueChangeListener(e
-> saveRegistrationStatusChange(regDto
.getUuid(), e
.getProperty().getValue()));
234 select
.setEnabled(canChangeStatus
);
235 select
.setNullSelectionAllowed(false);
240 loadWorkingSet(getView().getCitationUuid());
245 private void applyWorkingset(){
246 getView().setWorkingset(workingset
);
247 // PagingProviders and CacheGenerator for the existingNameCombobox
248 activateComboboxes();
251 protected void activateComboboxes() {
252 CdmTitleCacheCaptionGenerator
<TaxonName
> titleCacheGenerator
= new CdmTitleCacheCaptionGenerator
<TaxonName
>();
253 getView().getExistingNameCombobox().setCaptionGenerator(titleCacheGenerator
);
254 CdmFilterablePagingProvider
<TaxonName
, TaxonName
> pagingProvider
= pagingProviderFactory
.taxonNamesWithoutOrthophicIncorrect();
255 getView().getExistingNameCombobox().loadFrom(pagingProvider
, pagingProvider
, pagingProvider
.getPageSize());
258 protected void loadWorkingSet(UUID referenceUuid
) {
261 workingset
= getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid
, true);
262 } catch (TypeDesignationSetException error
) {
264 showErrorDialog("Validation Error", error
.getMessage());
266 cache
= new CdmTransientEntityWithUuidCacher(this);
267 for(Registration registration
: workingset
.getRegistrations()) {
268 addRootEntity(registration
);
272 public void showErrorDialog(String errorDialogCaption
, String errorMessage
) {
273 Window errorDialog
= new Window(errorDialogCaption
);
274 errorDialog
.setModal(true);
275 VerticalLayout subContent
= new VerticalLayout();
276 subContent
.setMargin(true);
277 errorDialog
.setContent(subContent
);
278 subContent
.addComponent(new Label(errorMessage
));
279 UI
.getCurrent().addWindow(errorDialog
);
282 private void saveRegistrationStatusChange(UUID uuid
, Object value
) {
283 Registration reg
= getRepo().getRegistrationService().load(uuid
);
285 // registration was not yet persisted, ignore
288 if(value
!= null && value
instanceof RegistrationStatus
){
289 if(!Objects
.equals(value
, reg
.getStatus())){
290 reg
.updateStatusAndDate((RegistrationStatus
)value
);
291 cdmStore
.saveBean(reg
, (AbstractView
<?
,?
>)getView());
295 // only log here as error
296 logger
.error("Ivalid attempt to set RegistrationStatus to " + Objects
.toString(value
.toString(), "NULL"));
300 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Add
.class)
301 public void onReferenceEditorActionAdd(ReferenceEditorAction event
) {
303 if(!checkFromOwnView(event
)){
307 ReferencePopupEditor popup
= openPopupEditor(ReferencePopupEditor
.class, event
);
308 popup
.withReferenceTypes(RegistrationUIDefaults
.PRINTPUB_REFERENCE_TYPES
);
309 popup
.loadInEditor(null);
312 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Edit
.class)
313 public void onReferenceEditorActionEdit(ReferenceEditorAction event
) {
315 if(!checkFromOwnView(event
)){
318 ReferencePopupEditor popup
= openPopupEditor(ReferencePopupEditor
.class, event
);
319 popup
.withReferenceTypes(RegistrationUIDefaults
.PRINTPUB_REFERENCE_TYPES
);
320 popup
.withDeleteButton(true);
321 popup
.loadInEditor(event
.getEntityUuid());
324 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Edit
.class)
325 public void onRegistrationEditorAction(RegistrationEditorAction event
) {
327 if(!checkFromOwnView(event
)){
331 RegistrationPopupEditor popup
= openPopupEditor(RegistrationPopupEditor
.class, event
);
332 popup
.loadInEditor(event
.getEntityUuid());
335 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Edit
.class)
336 public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event
) {
338 if(!checkFromOwnView(event
)){
342 boolean isRegistrationForExistingName
= event
.getTarget() != null && event
.getTarget().equals(getView().getExistingNameCombobox());
344 TaxonNamePopupEditor popup
= openPopupEditor(TaxonNamePopupEditor
.class, event
);
346 popup
.setParentEditorActionContext(event
.getContext(), event
.getTarget());
347 popup
.withDeleteButton(!isRegistrationForExistingName
);
348 TaxonNamePopupEditorConfig
.configureForNomenclaturalAct(popup
);
349 if(isRegistrationForExistingName
){
350 // allow saving even if the name parts are not valid
351 // the user will need to fix this in a later step
352 popup
.disableMode(TaxonNamePopupEditorMode
.VALIDATE_AGAINST_HIGHER_NAME_PART
);
353 getView().getAddExistingNameRegistrationButton().setEnabled(false);
354 popup
.addDetachListener(ev
->
355 getView().getAddExistingNameRegistrationButton().setEnabled(true)
358 popup
.loadInEditor(event
.getEntityUuid());
359 if(event
.hasSource() && event
.getSource().isReadOnly()){
360 // avoid resetting read-only to false
361 logger
.info("Set popup to read-only as event source is read only");
362 popup
.setReadOnly(true);
365 boolean hasNomRef
= popup
.getBean().getNomenclaturalReference() != null;
366 if(isRegistrationForExistingName
){
367 popup
.setAllFieldsReadOnly(true);
368 popup
.removeStatusMessage(RegistrationUI
.CHECK_IN_SEARCH_INDEX
);
371 //#10269 for now we do not allow registrations for names with no nom. ref.
373 // // only allow editing the nomenclatural reference, all other
374 // // editing need to be done another way.
375 // // Otherwise we would need to be prepared for creating blocking registrations
376 // // in turn of creation, modification of related taxon names.
377 // popup.disableMode(TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY);
378 // popup.getNomReferenceCombobox().setReadOnly(false);
379 // popup.getNomenclaturalReferenceDetail().setReadOnly(false);
380 // popup.addStatusMessage("The chosen name needs to be completed before it can be used. "
381 // + "Please add the nomenclatural reference and click on \"Save\" to proceed with entering the type of this name.");
383 //instead we show status message:
384 // popup.setToCancelOnly();
385 popup
.addStatusMessage("<p style='color:red;'><strong>The data entry is aborted "
386 + "due to a data issue that should be fixed "
387 + "by the curator</strong>.<BR>"
388 + "Please send an e-mail with the scientific name "
389 + "to <i>curation@phycobank.org</i></p>");
391 popup
.setToSelect(); //sets the save button to "save & select"
392 popup
.addStatusMessage("You are about to create a registration for this name. "
393 + "This editor is for reviewing the name only. Therefore, all fields have "
394 + "been switched to read-only state. "
395 + "Click on \"Save\" to proceed with entering the type of this name.");
400 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Add
.class)
401 public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event
) {
403 if(!checkFromOwnView(event
)){
407 getView().getAddNewNameRegistrationButton().setEnabled(false);
408 if(newNameForRegistrationPopupEditor
== null){
409 TaxonNamePopupEditor popup
= openPopupEditor(TaxonNamePopupEditor
.class, event
);
410 newNameForRegistrationPopupEditor
= popup
;
411 popup
.setParentEditorActionContext(event
.getContext(), event
.getTarget());
412 popup
.grantToCurrentUser(EnumSet
.of(CRUD
.UPDATE
,CRUD
.DELETE
));
413 popup
.withDeleteButton(true);
414 popup
.setCdmEntityInstantiator(new BeanInstantiator
<TaxonName
>() {
417 public TaxonName
createNewBean() {
418 TaxonName newTaxonName
= TaxonNameFactory
.NewNameInstance(RegistrationUIDefaults
.NOMENCLATURAL_CODE
, Rank
.SPECIES());
419 newTaxonName
.setNomenclaturalReference(getRepo().getReferenceService().load(workingset
.getCitationUuid(), TaxonNameEditorPresenter
.REFERENCE_INIT_STRATEGY
));
423 TaxonNamePopupEditorConfig
.configureForNomenclaturalAct(popup
);
424 popup
.loadInEditor(null);
429 * Creates a new <code>Registration</code> for a new name that has just been edited
430 * using a <code>TaxonNamePopupEditor</code>. The popup editor which has been opened to
431 * edit the new name was remembered in <code>newNameForRegistrationPopupEditor</code>.
432 * Any blocking registrations which have been created while editing the new name are
433 * temporarily stored in <code>newNameBlockingRegistrations</code> until the registration
434 * for the first name has been created. Additional new names are created for example
435 * when a new name as basionym, replaced synonym, etc to the new name is created.
437 * See also {@link #onTaxonNameEditorActionAdd(TaxonNameEditorAction)}).
440 * @throws TypeDesignationSetException
441 * passes on the Exception which may come from onRegistrationWorkflowEventActionStart()
443 @EventBusListenerMethod
444 public void onDoneWithTaxonnameEditor(DoneWithPopupEvent event
) throws TypeDesignationSetException
{
446 if(!isFromOwnView(event
)){
450 if(event
.getPopup() instanceof TaxonNamePopupEditor
){
452 EditorActionContext rootContext
= editorActionContextRoot(event
.getPopup());
453 boolean isAddExistingNameRegistration
= rootContext
.getTargetField() != null && rootContext
.getTargetField().equals(getView().getExistingNameCombobox());
455 if(isAddExistingNameRegistration
){
456 if(event
.getReason().equals(Reason
.SAVE
)){
457 onRegistrationWorkflowEventActionStart(new RegistrationWorkingsetAction(workingset
.getCitationUuid(),
458 RegistrationWorkingsetAction
.Action
.start
));
460 // just ignore on CANCEL
462 Optional
<Registration
> registrationOpt
= Optional
.ofNullable(null);
463 if(newNameForRegistrationPopupEditor
!= null && event
.getPopup().equals(newNameForRegistrationPopupEditor
)){
464 if(event
.getReason().equals(Reason
.SAVE
)){
466 TaxonName taxonName
= newNameForRegistrationPopupEditor
.getBean().cdmEntity();
467 registrationOpt
= Optional
.of(registrationWorkflowService
.createRegistration(taxonName
, newNameBlockingRegistrations
));
468 loadWorkingSet(workingset
.getCitationUuid());
471 getView().getAddNewNameRegistrationButton().setEnabled(true);
474 // nullify and clear the memory on this popup editor in any case (SAVE, DELETE, CANCEL)
475 newNameForRegistrationPopupEditor
= null;
476 newNameBlockingRegistrations
.clear();
477 getView().getAddNewNameRegistrationButton().setEnabled(true);
480 if(event
.getReason().equals(Reason
.SAVE
)){
481 if(!registrationOpt
.isPresent()){
482 // no new registration has been created above, so there must be an existing one.
483 registrationOpt
= findRegistrationInContext(event
.getPopup());
486 // Check if the other names used in the context of the name are registered yet.
487 TaxonNamePopupEditor nameEditor
= (TaxonNamePopupEditor
)event
.getPopup();
488 Set
<TaxonName
> namesToCheck
= new HashSet
<>();
490 namesToCheck
.addAll(nameEditor
.getBasionymComboboxSelect().getValue());
491 namesToCheck
.addAll(nameEditor
.getReplacedSynonymsComboboxSelect().getValue());
492 namesToCheck
.add(nameEditor
.getValidationField().getRelatedNameComboBox().getValue());
493 namesToCheck
.add(nameEditor
.getOrthographicVariantField().getRelatedNameComboBox().getValue());
494 // NOTE: according to https://dev.e-taxonomy.eu/redmine/issues/8049#note-2 we will not create blocking
495 // registrations for names in WeaklyRelatedEntityFields
497 for(TaxonName name
: namesToCheck
){
500 assocciateOrQueueBlockingRegistration(registrationOpt
, name
.getUuid());
503 } else if (event
.getReason().equals(Reason
.DELETE
)){
504 //FIXME handle delete: need to remove blocking registrations?
506 // always reload if the first editor is closed as the data might have been changed through any other sub-popupeditor
507 refreshView(isAtContextRoot(event
.getPopup()));
513 * Creates a new Registration for an exiting (previously published) name.
515 @EventBusListenerMethod
516 public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event
) throws TypeDesignationSetException
{
518 if(!event
.isStart()){
522 getView().getExistingNameCombobox().commit(); // update the chosen value in the datasource
523 TaxonName typifiedName
= getView().getExistingNameCombobox().getValue();
524 if(typifiedName
!= null){
525 boolean doReloadWorkingSet
= false;
527 doReloadWorkingSet
= registrationWorkflowService
.createRegistrationforExistingName(workingset
, typifiedName
);
530 refreshView(doReloadWorkingSet
);
531 getView().getAddExistingNameRegistrationButton().setEnabled(false);
534 logger
.error("Seletced name is NULL");
539 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Edit
.class)
540 public void onTypeDesignationsEditorActionEdit(TypeDesignationSetEditorAction event
) {
542 if(!checkFromOwnView(event
)){
546 RegistrationDTO registrationDTO
= workingset
.getRegistrationDTO(event
.getRegistrationUuid()).get();
548 if(event
.getWorkingSetType() == TypeDesignationSetType
.SPECIMEN_TYPE_DESIGNATION_SET
){
549 SpecimenTypeDesignationSetPopupEditor popup
= openPopupEditor(SpecimenTypeDesignationSetPopupEditor
.class, event
);
550 popup
.setParentEditorActionContext(event
.getContext(), event
.getTarget());
551 popup
.withDeleteButton(true);
552 popup
.loadInEditor(new SpecimenTypeDesignationSetIds(
553 workingset
.getCitationUuid(),
554 event
.getRegistrationUuid(),
555 CdmBase
.deproxy(event
.getBaseEntity(), FieldUnit
.class), null));
556 if(event
.hasSource()){
557 // propagate readonly state from source button to popup
558 popup
.setReadOnly(event
.getSource().isReadOnly());
561 NameTypeDesignationPopupEditor popup
= openPopupEditor(NameTypeDesignationPopupEditor
.class, event
);
562 popup
.setParentEditorActionContext(event
.getContext(), event
.getTarget());
563 popup
.withDeleteButton(true);
564 popup
.loadInEditor(NameTypeDesignationSetIds
.forExistingTypeDesignation(
565 registrationDTO
.getCitationUuid(),
566 CdmBase
.deproxy(event
.getBaseEntity(), NameTypeDesignation
.class))
568 popup
.getTypifiedNamesComboboxSelect().setEnabled(false);
569 if(event
.hasSource()){
570 // propagate readonly state from source button to popup
571 popup
.setReadOnly(event
.getSource().isReadOnly());
573 nameTypeDesignationPopupEditorRegistrationUUIDMap
.put(popup
, event
.getRegistrationUuid());
577 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Add
.class)
578 public void onTypeDesignationSetAdd(TypeDesignationSetEditorAction event
) {
580 if(!event
.hasSource()){
584 RegistrationDTO registrationDTO
= workingset
.getRegistrationDTO(event
.getRegistrationUuid()).get();
586 if(event
.getWorkingSetType() == TypeDesignationSetType
.SPECIMEN_TYPE_DESIGNATION_SET
){
587 SpecimenTypeDesignationSetPopupEditor popup
= openPopupEditor(SpecimenTypeDesignationSetPopupEditor
.class, event
);
588 popup
.setParentEditorActionContext(event
.getContext(), event
.getTarget());
589 TypedEntityReference
<TaxonName
> typifiedNameRef
;
590 if(registrationDTO
.getTypifiedNameRef() != null){
591 // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
592 typifiedNameRef
= new TypedEntityReference(TaxonName
.class, registrationDTO
.getTypifiedNameRef().getUuid());
594 // case of registrations with a name in the nomenclatural act.
595 typifiedNameRef
= new TypedEntityReference(TaxonName
.class, registrationDTO
.getNameRef().getUuid());
598 popup
.grantToCurrentUser(EnumSet
.of(CRUD
.UPDATE
, CRUD
.DELETE
));
599 popup
.withDeleteButton(false);
600 popup
.loadInEditor(new SpecimenTypeDesignationSetIds(
601 workingset
.getCitationUuid(),
602 event
.getRegistrationUuid(),
604 typifiedNameRef
.getUuid()
607 if(event
.hasSource()){
608 // propagate readonly state from source component to popup
609 popup
.setReadOnly(event
.getSource().isReadOnly());
612 NameTypeDesignationPopupEditor popup
= openPopupEditor(NameTypeDesignationPopupEditor
.class, event
);
613 popup
.setParentEditorActionContext(event
.getContext(), event
.getTarget());
614 popup
.grantToCurrentUser(EnumSet
.of(CRUD
.UPDATE
, CRUD
.DELETE
));
615 nameTypeDesignationPopupEditorRegistrationUUIDMap
.put(popup
, event
.getRegistrationUuid());
616 popup
.setBeanInstantiator(new BeanInstantiator
<NameTypeDesignation
>() {
619 public NameTypeDesignation
createNewBean() {
621 TaxonName typifiedName
= getRepo().getNameService().load(event
.getTypifiedNameUuid(), Arrays
.asList(new String
[]{
624 "nomenclaturalSource.citation"
626 NameTypeDesignation nameTypeDesignation
= NameTypeDesignation
.NewInstance();
627 nameTypeDesignation
.getTypifiedNames().add(typifiedName
);
628 return nameTypeDesignation
;
631 popup
.withDeleteButton(false);
632 popup
.loadInEditor(NameTypeDesignationSetIds
.forNewTypeDesignation(
633 registrationDTO
.getCitationUuid(),
634 event
.getTypifiedNameUuid()
637 popup
.getTypifiedNamesComboboxSelect().setEnabled(false);
638 if(event
.hasSource()){
639 // propagate readonly state from source component to popup
640 popup
.setReadOnly(event
.getSource().isReadOnly());
646 * Performs final actions after a TypeDesignationEditor which has been
647 * opened to add a TypeDesignation to a Registration object which was
648 * created for an previously published name. Prior adding a typedesignation,
649 * the according Registration object is dangling, that has no association to
650 * any entity denoting an nomenclatural act which has a reference to a
651 * publication. This means that the registration object is not in the
656 * @throws TypeDesignationSetException
658 @EventBusListenerMethod
659 public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event
) {
661 if(!isFromOwnView(event
)){
665 if(event
.getPopup() instanceof SpecimenTypeDesignationSetPopupEditor
){
666 if(event
.getReason().equals(Reason
.SAVE
)){
667 // NOTE: adding the SpecimenTypeDesignations to the registration is done in the
668 // SpecimenTypeDesignationSetServiceImpl.save(SpecimenTypeDesignationSetDTO dto) method
670 // always reload if the first editor is closed as the data might have been changed through any other sub-popupeditor
671 refreshView(isAtContextRoot(event
.getPopup()));
672 } else if(event
.getPopup() instanceof NameTypeDesignationPopupEditor
){
673 if(event
.getReason().equals(Reason
.SAVE
)){
675 Optional
<Registration
> registrationOpt
= Optional
.ofNullable(null);
676 UUID typeDesignationUuid
= ((NameTypeDesignationPopupEditor
)event
.getPopup()).getBean().getUuid();
679 registrationOpt
= findRegistrationInContext(event
.getPopup());
680 registrationOpt
.ifPresent(reg
-> {
681 registrationWorkflowService
.addTypeDesignation(typeDesignationUuid
, reg
);
682 nameTypeDesignationPopupEditorRegistrationUUIDMap
.remove(event
.getPopup());
689 // Check if other names used in the context of the name are registered yet.
690 NameTypeDesignationPopupEditor nameTypeDesignationEditor
= (NameTypeDesignationPopupEditor
)event
.getPopup();
691 Set
<TaxonName
> namesToCheck
= new HashSet
<>();
693 namesToCheck
.add(nameTypeDesignationEditor
.getTypeNameField().getValue());
695 for(TaxonName name
: namesToCheck
){
697 assocciateOrQueueBlockingRegistration(registrationOpt
, name
.getUuid());
702 } else if(event
.getReason().equals(Reason
.CANCEL
)){
705 // always reload if the first editor is closed as the data might have been changed through any other sub-popupeditor
706 refreshView(isAtContextRoot(event
.getPopup()));
709 // ignore other editors
712 private void assocciateOrQueueBlockingRegistration(Optional
<Registration
> registrationOpt
, UUID nameUuid
) {
713 registrationOpt
.ifPresent(reg
-> registrationWorkflowService
.addBlockingRegistration(nameUuid
, reg
));
714 if(!registrationOpt
.isPresent()){
716 Registration blockingRegistration
= registrationWorkflowService
.prepareBlockingRegistration(nameUuid
);
717 if(blockingRegistration
!= null){
718 newNameBlockingRegistrations
.add(blockingRegistration
);
719 logger
.debug("Blocking registration created and queued for later association with the main registration.");
725 public void clearSession() {
726 getRepo().clearSession();
729 @EventBusListenerMethod(filter
= ShowDetailsEventEntityTypeFilter
.RegistrationWorkingSet
.class)
730 public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent
<RegistrationWorkingSet
,?
> event
) {
732 if(event
.getProperty().equals(RegistrationItem
.VALIDATION_PROBLEMS
)){
733 List
<String
> messages
= new ArrayList
<>();
734 for(RegistrationDTO dto
: workingset
.getRegistrationDTOs()){
735 dto
.getValidationProblems().forEach(m
-> messages
.add(dto
.getSummary() + ": " + m
));
737 getView().openDetailsPopup("Validation Problems", messages
);
741 @EventBusListenerMethod
742 public void onEntityChangeEvent(EntityChangeEvent event
){
744 if(!isFromOwnView(event
)){
748 if(workingset
== null){
751 if(Reference
.class.isAssignableFrom(event
.getEntityType())){
753 if(workingset
.getCitationUuid().equals(event
.getEntityUuid())){
754 if(event
.isRemovedType()){
755 viewEventBus
.publish(EventScope
.UI
, this, new NavigationEvent(StartRegistrationViewBean
.NAME
));
762 if(Registration
.class.isAssignableFrom(event
.getEntityType())){
763 if(workingset
.getRegistrations().stream().anyMatch(reg
-> reg
.getUuid() == event
.getEntityUuid())){
767 if(TaxonName
.class.isAssignableFrom(event
.getEntityType())){
768 if(event
.getType().equals(EntityChangeEvent
.Type
.CREATED
)){
769 Stack
<EditorActionContext
>context
= ((AbstractPopupEditor
)event
.getSourceView()).getEditorActionContext();
770 EditorActionContext rootContext
= context
.get(0);
771 if(rootContext
.getParentView().equals(getView()) && event
.getSourceView() != newNameForRegistrationPopupEditor
){
774 // create a blocking registration
775 UUID taxonNameUUID
= event
.getEntityUuid();
776 Optional
<Registration
> registrationOpt
= findRegistrationInContext(context
);
777 assocciateOrQueueBlockingRegistration(registrationOpt
, taxonNameUUID
);
783 // in case of creating a new name for a registration the parent view is the TaxonNamePopupEditor
785 logger
.debug("Non blocking registration, since a new name for a new registration has been created");
788 if(workingset
.getRegistrationDTOs().stream().anyMatch(reg
->
789 reg
.getTypifiedNameRef() != null
790 && reg
.getTypifiedNameRef().getUuid().equals(event
.getEntityUuid()))){
794 if(TypeDesignationBase
.class.isAssignableFrom(event
.getEntityType())){
795 if(workingset
.getRegistrationDTOs().stream().anyMatch(
796 reg
-> reg
.typeDesignations() != null && reg
.typeDesignations().stream().anyMatch(
797 td
-> td
.getUuid() == event
.getEntityUuid()
806 public Optional
<Registration
> findRegistrationInContext(PopupView popupView
) {
807 Stack
<EditorActionContext
>context
= ((AbstractPopupEditor
)popupView
).getEditorActionContext();
808 return findRegistrationInContext(context
);
812 * Finds the Registration in the EditorContext stack
814 public Optional
<Registration
> findRegistrationInContext(Stack
<EditorActionContext
> context
) {
815 EditorActionContext rootCtx
= context
.get(0);
816 TypedEntityReference
<Registration
> regReference
= (TypedEntityReference
<Registration
>)rootCtx
.getParentEntity();
817 Optional
<RegistrationDTO
> registrationDTOOptional
= workingset
.getRegistrationDTO(regReference
.getUuid());
818 Optional
<Registration
> registrationOptional
;
819 if(!registrationDTOOptional
.isPresent()){
820 logger
.debug("No RegistrationDTO in found rootCtx -> user is about to create a registration for a new name.");
821 registrationOptional
= Optional
.ofNullable(null);
824 Optional
<Registration
> regOpt
;
825 if(registrationDTOOptional
.isPresent()){
826 regOpt
= Optional
.of(registrationDTOOptional
.get().registration());
828 regOpt
= Optional
.ofNullable(null);
834 @EventBusListenerMethod(filter
= ShowDetailsEventEntityTypeFilter
.RegistrationDTO
.class)
835 public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent
<RegistrationDTO
, UUID
> event
) {
837 // FIXME check from own view!!!
838 if(getView() == null){
842 UUID registrationUuid
= event
.getIdentifier();
844 RegistrationDTO regDto
= workingset
.getRegistrationDTO(registrationUuid
).get();
845 if(event
.getProperty().equals(RegistrationItem
.BLOCKED_BY
)){
847 Set
<RegistrationDTO
> blockingRegs
;
848 if(regDto
.registration().isPersisted()){
849 blockingRegs
= getWorkingSetService().loadBlockingRegistrations(registrationUuid
);
851 blockingRegs
= new HashSet
<RegistrationDTO
>(getWorkingSetService().makeDTOs(regDto
.registration().getBlockedBy()));
853 getView().setBlockingRegistrations(registrationUuid
, blockingRegs
);
854 } else if(event
.getProperty().equals(RegistrationItem
.VALIDATION_PROBLEMS
)){
855 getView().openDetailsPopup("Validation Problems", regDto
.getValidationProblems());
860 public ICdmEntityUuidCacher
getCache() {
865 public void addRootEntity(CdmBase entity
) {
866 rootEntities
.add(entity
);
871 public Collection
<CdmBase
> getRootEntities() {
876 public void destroy() throws Exception
{
882 public void disposeCache() {
886 public boolean canCreateNameRegistrationFor(TaxonName name
) {
887 return registrationWorkflowService
.canCreateNameRegistrationFor(workingset
, name
);
890 public boolean checkWokingsetContainsProtologe(TaxonName name
) {
891 return registrationWorkflowService
.checkWokingsetContainsProtologe(workingset
, name
);