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
.log4j
.Logger
;
26 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
27 import org
.vaadin
.spring
.events
.EventScope
;
28 import org
.vaadin
.spring
.events
.annotation
.EventBusListenerMethod
;
30 import com
.vaadin
.server
.ClientConnector
.DetachEvent
;
31 import com
.vaadin
.server
.ClientConnector
.DetachListener
;
32 import com
.vaadin
.spring
.annotation
.SpringComponent
;
33 import com
.vaadin
.spring
.annotation
.ViewScope
;
34 import com
.vaadin
.ui
.AbstractField
;
35 import com
.vaadin
.ui
.Label
;
36 import com
.vaadin
.ui
.UI
;
37 import com
.vaadin
.ui
.VerticalLayout
;
38 import com
.vaadin
.ui
.Window
;
40 import eu
.etaxonomy
.cdm
.api
.service
.config
.RegistrationStatusTransitions
;
41 import eu
.etaxonomy
.cdm
.api
.service
.dto
.RegistrationDTO
;
42 import eu
.etaxonomy
.cdm
.api
.service
.dto
.RegistrationWorkingSet
;
43 import eu
.etaxonomy
.cdm
.api
.service
.exception
.RegistrationValidationException
;
44 import eu
.etaxonomy
.cdm
.api
.service
.name
.TypeDesignationWorkingSet
.TypeDesignationWorkingSetType
;
45 import eu
.etaxonomy
.cdm
.api
.service
.registration
.IRegistrationWorkingSetService
;
46 import eu
.etaxonomy
.cdm
.api
.util
.UserHelper
;
47 import eu
.etaxonomy
.cdm
.cache
.CdmTransientEntityAndUuidCacher
;
48 import eu
.etaxonomy
.cdm
.model
.ICdmEntityUuidCacher
;
49 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
50 import eu
.etaxonomy
.cdm
.model
.name
.NameTypeDesignation
;
51 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
52 import eu
.etaxonomy
.cdm
.model
.name
.Registration
;
53 import eu
.etaxonomy
.cdm
.model
.name
.RegistrationStatus
;
54 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
55 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameFactory
;
56 import eu
.etaxonomy
.cdm
.model
.name
.TypeDesignationBase
;
57 import eu
.etaxonomy
.cdm
.model
.occurrence
.FieldUnit
;
58 import eu
.etaxonomy
.cdm
.model
.permission
.CRUD
;
59 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
60 import eu
.etaxonomy
.cdm
.ref
.TypedEntityReference
;
61 import eu
.etaxonomy
.cdm
.service
.CdmBeanItemContainerFactory
;
62 import eu
.etaxonomy
.cdm
.service
.CdmFilterablePagingProvider
;
63 import eu
.etaxonomy
.cdm
.service
.CdmFilterablePagingProviderFactory
;
64 import eu
.etaxonomy
.cdm
.service
.CdmStore
;
65 import eu
.etaxonomy
.cdm
.service
.IRegistrationWorkflowService
;
66 import eu
.etaxonomy
.cdm
.service
.UserHelperAccess
;
67 import eu
.etaxonomy
.cdm
.vaadin
.component
.registration
.RegistrationItem
;
68 import eu
.etaxonomy
.cdm
.vaadin
.component
.registration
.RegistrationStatusFieldInstantiator
;
69 import eu
.etaxonomy
.cdm
.vaadin
.component
.registration
.RegistrationStatusSelect
;
70 import eu
.etaxonomy
.cdm
.vaadin
.event
.EditorActionContext
;
71 import eu
.etaxonomy
.cdm
.vaadin
.event
.EditorActionTypeFilter
;
72 import eu
.etaxonomy
.cdm
.vaadin
.event
.EntityChangeEvent
;
73 import eu
.etaxonomy
.cdm
.vaadin
.event
.ReferenceEditorAction
;
74 import eu
.etaxonomy
.cdm
.vaadin
.event
.RegistrationEditorAction
;
75 import eu
.etaxonomy
.cdm
.vaadin
.event
.ShowDetailsEvent
;
76 import eu
.etaxonomy
.cdm
.vaadin
.event
.ShowDetailsEventEntityTypeFilter
;
77 import eu
.etaxonomy
.cdm
.vaadin
.event
.TaxonNameEditorAction
;
78 import eu
.etaxonomy
.cdm
.vaadin
.event
.TypeDesignationWorkingsetEditorAction
;
79 import eu
.etaxonomy
.cdm
.vaadin
.event
.registration
.RegistrationWorkingsetAction
;
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
.NameTypeDesignationWorkingsetIds
;
86 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.SpecimenTypeDesignationWorkingsetIds
;
87 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.SpecimenTypeDesignationWorkingsetPopupEditor
;
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
108 public class RegistrationWorkingsetPresenter
extends AbstractPresenter
<RegistrationWorkingsetView
> implements CachingPresenter
{
110 private static final Logger logger
= Logger
.getLogger(RegistrationWorkingsetPresenter
.class);
112 private static final long serialVersionUID
= 1L;
115 private IRegistrationWorkingSetService regWorkingSetService
;
118 private IRegistrationWorkflowService registrationWorkflowService
;
121 private CdmFilterablePagingProviderFactory pagingProviderFactory
;
124 private CdmBeanItemContainerFactory selectFieldFactory
;
127 private CdmStore cdmStore
;
130 * @return the regWorkingSetService
132 public IRegistrationWorkingSetService
getWorkingSetService() {
133 return regWorkingSetService
;
136 private RegistrationWorkingSet workingset
;
139 * 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.
140 * There can always only be one popup editor for this purpose.
142 private TaxonNamePopupEditor newNameForRegistrationPopupEditor
= null;
147 private List
<Registration
> newNameBlockingRegistrations
= new ArrayList
<>();
150 * TODO is this still needed? The registration UUID should be accessible in the popup editor context,
151 * see findRegistrationInContext()
153 private Map
<NameTypeDesignationPopupEditor
, UUID
> nameTypeDesignationPopupEditorRegistrationUUIDMap
= new HashMap
<>();
156 private ICdmEntityUuidCacher cache
;
158 private Collection
<CdmBase
> rootEntities
= new HashSet
<>();
161 public RegistrationWorkingsetPresenter() {
165 * @param doReload reload the workingset from the persistent storage.
166 * Workingsets which are not yet persisted are preserved.
168 protected void refreshView(boolean doReload
) {
170 if(workingset
== null){
171 return; // nothing to do
174 if(logger
.isDebugEnabled()){
175 logger
.debug("refreshView() - workingset:\n" + workingset
.toString());
177 List
<RegistrationDTO
> unpersisted
= new ArrayList
<>();
178 for(RegistrationDTO regDto
: workingset
.getRegistrationDTOs()){
179 if(!regDto
.registration().isPersited()){
180 unpersisted
.add(regDto
);
183 loadWorkingSet(workingset
.getCitationUuid());
184 for(RegistrationDTO regDtoUnpersisted
: unpersisted
){
185 if(!workingset
.getRegistrationDTOs().stream().anyMatch(dto
-> dto
.getUuid().equals(regDtoUnpersisted
.getUuid()))){
186 // only add if the regDtoUnpersisted has not been persisted meanwhile
188 workingset
.add(regDtoUnpersisted
);
189 } catch (RegistrationValidationException e
) {
190 // would never happen here //
194 if(logger
.isDebugEnabled()){
195 logger
.debug("refreshView() - workingset reloaded:\n" + workingset
.toString());
202 public void handleViewEntered() {
203 super.handleViewEntered();
204 // TODO currently cannot specify type more precisely, see AbstractSelect
205 // FIXME externalize into class file!!!!!!!!!!!!
206 getView().setStatusComponentInstantiator(new RegistrationStatusFieldInstantiator
<Object
>(){
208 private static final long serialVersionUID
= 7099181280977511048L;
211 public AbstractField
<Object
> create(RegistrationDTO regDto
) {
213 // submitters have GrantedAuthorities like REGISTRATION(PREPARATION).[UPDATE]{ab4459eb-3b96-40ba-bfaa-36915107d59e}
214 UserHelper userHelper
= UserHelperAccess
.userHelper().withCache(getCache());
215 Set
<RegistrationStatus
> availableStatus
= new HashSet
<>();
217 boolean canChangeStatus
= userHelper
.userHasPermission(regDto
.registration(), CRUD
.UPDATE
);
218 availableStatus
.add(regDto
.getStatus());
220 if(userHelper
.userIsAdmin()){
221 availableStatus
.addAll(Arrays
.asList(RegistrationStatus
.values()));
223 availableStatus
.addAll(RegistrationStatusTransitions
.possibleTransitions(regDto
.getStatus()));
227 RegistrationStatusSelect select
= new RegistrationStatusSelect(null, selectFieldFactory
.buildEnumTermItemContainer(
228 RegistrationStatus
.class,
229 availableStatus
.toArray(new RegistrationStatus
[availableStatus
.size()]))
231 select
.setValue(regDto
.getStatus());
232 select
.addValueChangeListener(e
-> saveRegistrationStatusChange(regDto
.getUuid(), e
.getProperty().getValue()));
233 select
.setEnabled(canChangeStatus
);
234 select
.setNullSelectionAllowed(false);
241 loadWorkingSet(getView().getCitationUuid());
246 private void applyWorkingset(){
247 getView().setWorkingset(workingset
);
248 // PagingProviders and CacheGenerator for the existingNameCombobox
249 activateComboboxes();
252 protected void activateComboboxes() {
253 CdmTitleCacheCaptionGenerator
<TaxonName
> titleCacheGenerator
= new CdmTitleCacheCaptionGenerator
<TaxonName
>();
254 getView().getAddExistingNameCombobox().setCaptionGenerator(titleCacheGenerator
);
255 CdmFilterablePagingProvider
<TaxonName
, TaxonName
> pagingProvider
= pagingProviderFactory
.taxonNamesWithoutOrthophicIncorrect();
256 getView().getAddExistingNameCombobox().loadFrom(pagingProvider
, pagingProvider
, pagingProvider
.getPageSize());
262 protected void loadWorkingSet(UUID referenceUuid
) {
265 workingset
= getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid
, true);
266 } catch (RegistrationValidationException error
) {
268 showErrorDialog("Validation Error", error
.getMessage());
270 cache
= new CdmTransientEntityAndUuidCacher(this);
271 for(Registration registration
: workingset
.getRegistrations()) {
272 addRootEntity(registration
);
277 * @param errorDialogCaption
278 * @param errorMessage
280 public void showErrorDialog(String errorDialogCaption
, String errorMessage
) {
281 Window errorDialog
= new Window(errorDialogCaption
);
282 errorDialog
.setModal(true);
283 VerticalLayout subContent
= new VerticalLayout();
284 subContent
.setMargin(true);
285 errorDialog
.setContent(subContent
);
286 subContent
.addComponent(new Label(errorMessage
));
287 UI
.getCurrent().addWindow(errorDialog
);
290 private void saveRegistrationStatusChange(UUID uuid
, Object value
) {
291 Registration reg
= getRepo().getRegistrationService().load(uuid
);
293 // registration was not yet persisted, ignore
296 if(value
!= null && value
instanceof RegistrationStatus
){
297 if(!Objects
.equals(value
, reg
.getStatus())){
298 reg
.updateStatusAndDate((RegistrationStatus
)value
);
299 cdmStore
.saveBean(reg
, (AbstractView
)getView());
303 // only log here as error
304 logger
.error("Ivalid attempt to set RegistrationStatus to " + Objects
.toString(value
.toString(), "NULL"));
309 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Add
.class)
310 public void onReferenceEditorActionAdd(ReferenceEditorAction event
) {
312 if(!checkFromOwnView(event
)){
316 ReferencePopupEditor popup
= openPopupEditor(ReferencePopupEditor
.class, event
);
317 popup
.withReferenceTypes(RegistrationUIDefaults
.PRINTPUB_REFERENCE_TYPES
);
318 popup
.loadInEditor(null);
321 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Edit
.class)
322 public void onReferenceEditorActionEdit(ReferenceEditorAction event
) {
324 if(!checkFromOwnView(event
)){
327 ReferencePopupEditor popup
= openPopupEditor(ReferencePopupEditor
.class, event
);
328 popup
.withReferenceTypes(RegistrationUIDefaults
.PRINTPUB_REFERENCE_TYPES
);
329 popup
.withDeleteButton(true);
330 popup
.loadInEditor(event
.getEntityUuid());
333 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Edit
.class)
334 public void onRegistrationEditorAction(RegistrationEditorAction event
) {
336 if(!checkFromOwnView(event
)){
340 RegistrationPopupEditor popup
= openPopupEditor(RegistrationPopupEditor
.class, event
);
341 popup
.loadInEditor(event
.getEntityUuid());
344 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Edit
.class)
345 public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event
) {
347 if(!checkFromOwnView(event
)){
351 boolean isAddExistingNameRegistration
= event
.getTarget() != null && event
.getTarget().equals(getView().getAddExistingNameCombobox());
353 TaxonNamePopupEditor popup
= openPopupEditor(TaxonNamePopupEditor
.class, event
);
355 popup
.setParentEditorActionContext(event
.getContext(), event
.getTarget());
356 popup
.withDeleteButton(!isAddExistingNameRegistration
);
357 TaxonNamePopupEditorConfig
.configureForNomenclaturalAct(popup
);
358 if(isAddExistingNameRegistration
){
359 // allow saving even if the name parts are not valid
360 // the user will need to fix this in a later step
361 popup
.disableMode(TaxonNamePopupEditorMode
.VALIDATE_AGAINST_HIGHER_NAME_PART
);
362 getView().getAddExistingNameRegistrationButton().setEnabled(false);
363 popup
.addDetachListener(new DetachListener() {
366 public void detach(DetachEvent event
) {
367 getView().getAddExistingNameRegistrationButton().setEnabled(true);
372 popup
.loadInEditor(event
.getEntityUuid());
373 if(event
.hasSource() && event
.getSource().isReadOnly()){
374 // avoid resetting readonly to false
375 popup
.setReadOnly(true);
378 boolean hasNomRef
= popup
.getBean().getNomenclaturalReference() != null;
379 if(isAddExistingNameRegistration
){
380 popup
.setAllFieldsReadOnly(true);
382 // only allow editing the nomenclatural reference, all other
383 // editing need to be done another way.
384 // Otherwise we would need to be prepared for creating blocking registrations
385 // in turn of creation, modification of related taxon names.
386 popup
.disableMode(TaxonNamePopupEditorMode
.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY
);
387 popup
.getNomReferenceCombobox().setReadOnly(false);
388 popup
.getNomenclaturalReferenceDetail().setReadOnly(false);
389 popup
.addStatusMessage("The chosen name needs to be completed before it can be used. "
390 + "Please add the nomenclatural reference and click on \"Save\" to proceed with entering the type of this name.");
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 been switched to readonly state. "
394 + "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 RegistrationValidationException
441 * passes on the Exception which may come from onRegistrationWorkflowEventActionStart()
443 @EventBusListenerMethod
444 public void onDoneWithTaxonnameEditor(DoneWithPopupEvent event
) throws RegistrationValidationException
{
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().getAddExistingNameCombobox());
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()));
514 * Creates a new Registration for an exiting (previously published) name.
517 * @throws RegistrationValidationException
519 @EventBusListenerMethod
520 public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event
) throws RegistrationValidationException
{
522 if(!event
.isStart()){
526 getView().getAddExistingNameCombobox().commit(); // update the chosen value in the datasource
527 TaxonName typifiedName
= getView().getAddExistingNameCombobox().getValue();
528 if(typifiedName
!= null){
529 boolean doReloadWorkingSet
= false;
531 doReloadWorkingSet
= registrationWorkflowService
.createRegistrationforExistingName(workingset
, typifiedName
);
534 refreshView(doReloadWorkingSet
);
535 getView().getAddExistingNameRegistrationButton().setEnabled(false);
538 logger
.error("Seletced name is NULL");
543 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Edit
.class)
544 public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event
) {
546 if(!checkFromOwnView(event
)){
550 RegistrationDTO registrationDTO
= workingset
.getRegistrationDTO(event
.getRegistrationUuid()).get();
552 if(event
.getWorkingSetType() == TypeDesignationWorkingSetType
.SPECIMEN_TYPE_DESIGNATION_WORKINGSET
){
553 SpecimenTypeDesignationWorkingsetPopupEditor popup
= openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor
.class, event
);
554 popup
.setParentEditorActionContext(event
.getContext(), event
.getTarget());
555 popup
.withDeleteButton(true);
556 popup
.loadInEditor(new SpecimenTypeDesignationWorkingsetIds(
557 workingset
.getCitationUuid(),
558 event
.getRegistrationUuid(),
559 CdmBase
.deproxy(event
.getBaseEntity(), FieldUnit
.class), null));
560 if(event
.hasSource()){
561 // propagate readonly state from source button to popup
562 popup
.setReadOnly(event
.getSource().isReadOnly());
565 NameTypeDesignationPopupEditor popup
= openPopupEditor(NameTypeDesignationPopupEditor
.class, event
);
566 popup
.setParentEditorActionContext(event
.getContext(), event
.getTarget());
567 popup
.withDeleteButton(true);
568 popup
.loadInEditor(NameTypeDesignationWorkingsetIds
.forExistingTypeDesignation(
569 registrationDTO
.getCitationUuid(),
570 CdmBase
.deproxy(event
.getBaseEntity(), NameTypeDesignation
.class))
572 popup
.getTypifiedNamesComboboxSelect().setEnabled(false);
573 if(event
.hasSource()){
574 // propagate readonly state from source button to popup
575 popup
.setReadOnly(event
.getSource().isReadOnly());
577 nameTypeDesignationPopupEditorRegistrationUUIDMap
.put(popup
, event
.getRegistrationUuid());
581 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Add
.class)
582 public void onTypeDesignationWorkingsetAdd(TypeDesignationWorkingsetEditorAction event
) {
584 if(!event
.hasSource()){
588 RegistrationDTO registrationDTO
= workingset
.getRegistrationDTO(event
.getRegistrationUuid()).get();
590 if(event
.getWorkingSetType() == TypeDesignationWorkingSetType
.SPECIMEN_TYPE_DESIGNATION_WORKINGSET
){
591 SpecimenTypeDesignationWorkingsetPopupEditor popup
= openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor
.class, event
);
592 popup
.setParentEditorActionContext(event
.getContext(), event
.getTarget());
593 TypedEntityReference
<TaxonName
> typifiedNameRef
;
594 if(registrationDTO
.getTypifiedNameRef() != null){
595 // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
596 typifiedNameRef
= new TypedEntityReference(TaxonName
.class, registrationDTO
.getTypifiedNameRef().getUuid());
598 // case of registrations with a name in the nomenclatural act.
599 typifiedNameRef
= new TypedEntityReference(TaxonName
.class, registrationDTO
.getNameRef().getUuid());
602 popup
.grantToCurrentUser(EnumSet
.of(CRUD
.UPDATE
, CRUD
.DELETE
));
603 popup
.withDeleteButton(false);
604 popup
.loadInEditor(new SpecimenTypeDesignationWorkingsetIds(
605 workingset
.getCitationUuid(),
606 event
.getRegistrationUuid(),
608 typifiedNameRef
.getUuid()
611 if(event
.hasSource()){
612 // propagate readonly state from source component to popup
613 popup
.setReadOnly(event
.getSource().isReadOnly());
616 NameTypeDesignationPopupEditor popup
= openPopupEditor(NameTypeDesignationPopupEditor
.class, event
);
617 popup
.setParentEditorActionContext(event
.getContext(), event
.getTarget());
618 popup
.grantToCurrentUser(EnumSet
.of(CRUD
.UPDATE
, CRUD
.DELETE
));
619 nameTypeDesignationPopupEditorRegistrationUUIDMap
.put(popup
, event
.getRegistrationUuid());
620 popup
.setBeanInstantiator(new BeanInstantiator
<NameTypeDesignation
>() {
623 public NameTypeDesignation
createNewBean() {
625 TaxonName typifiedName
= getRepo().getNameService().load(event
.getTypifiedNameUuid(), Arrays
.asList(new String
[]{
628 "nomenclaturalSource.citation"
630 NameTypeDesignation nameTypeDesignation
= NameTypeDesignation
.NewInstance();
631 nameTypeDesignation
.getTypifiedNames().add(typifiedName
);
632 return nameTypeDesignation
;
635 popup
.withDeleteButton(false);
636 popup
.loadInEditor(NameTypeDesignationWorkingsetIds
.forNewTypeDesignation(
637 registrationDTO
.getCitationUuid(),
638 event
.getTypifiedNameUuid()
641 popup
.getTypifiedNamesComboboxSelect().setEnabled(false);
642 if(event
.hasSource()){
643 // propagate readonly state from source component to popup
644 popup
.setReadOnly(event
.getSource().isReadOnly());
650 * Performs final actions after a TypeDesignationEditor which has been
651 * opened to add a TypeDesignation to a Registration object which was
652 * created for an previously published name. Prior adding a typedesignation,
653 * the according Registration object is dangling, that has no association to
654 * any entity denoting an nomenclatural act which has a reference to a
655 * publication. This means that the registration object is not in the
660 * @throws RegistrationValidationException
662 @EventBusListenerMethod
663 public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event
) {
665 if(!isFromOwnView(event
)){
669 if(event
.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor
){
670 if(event
.getReason().equals(Reason
.SAVE
)){
671 // NOTE: adding the SpecimenTypeDesignations to the registration is done in the
672 // SpecimenTypeDesignationWorkingSetServiceImpl.save(SpecimenTypeDesignationWorkingSetDTO dto) method
674 // always reload if the first editor is closed as the data might have been changed through any other sub-popupeditor
675 refreshView(isAtContextRoot(event
.getPopup()));
676 } else if(event
.getPopup() instanceof NameTypeDesignationPopupEditor
){
677 if(event
.getReason().equals(Reason
.SAVE
)){
679 Optional
<Registration
> registrationOpt
= Optional
.ofNullable(null);
680 UUID typeDesignationUuid
= ((NameTypeDesignationPopupEditor
)event
.getPopup()).getBean().getUuid();
683 registrationOpt
= findRegistrationInContext(event
.getPopup());
684 registrationOpt
.ifPresent(reg
-> {
685 registrationWorkflowService
.addTypeDesignation(typeDesignationUuid
, reg
);
686 nameTypeDesignationPopupEditorRegistrationUUIDMap
.remove(event
.getPopup());
693 // Check if other names used in the context of the name are registered yet.
694 NameTypeDesignationPopupEditor nameTypeDesignationEditor
= (NameTypeDesignationPopupEditor
)event
.getPopup();
695 Set
<TaxonName
> namesToCheck
= new HashSet
<>();
697 namesToCheck
.add(nameTypeDesignationEditor
.getTypeNameField().getValue());
699 for(TaxonName name
: namesToCheck
){
701 assocciateOrQueueBlockingRegistration(registrationOpt
, name
.getUuid());
706 } else if(event
.getReason().equals(Reason
.CANCEL
)){
709 // always reload if the first editor is closed as the data might have been changed through any other sub-popupeditor
710 refreshView(isAtContextRoot(event
.getPopup()));
713 // ignore other editors
716 private void assocciateOrQueueBlockingRegistration(Optional
<Registration
> registrationOpt
, UUID nameUuid
) {
717 registrationOpt
.ifPresent(reg
-> registrationWorkflowService
.addBlockingRegistration(nameUuid
, reg
));
718 if(!registrationOpt
.isPresent()){
720 Registration blockingRegistration
= registrationWorkflowService
.prepareBlockingRegistration(nameUuid
);
721 if(blockingRegistration
!= null){
722 newNameBlockingRegistrations
.add(blockingRegistration
);
723 logger
.debug("Blocking registration created and queued for later association with the main registration.");
729 public void clearSession() {
730 getRepo().clearSession();
733 @EventBusListenerMethod(filter
= ShowDetailsEventEntityTypeFilter
.RegistrationWorkingSet
.class)
734 public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent
<RegistrationWorkingSet
,?
> event
) {
736 if(event
.getProperty().equals(RegistrationItem
.VALIDATION_PROBLEMS
)){
737 List
<String
> messages
= new ArrayList
<>();
738 for(RegistrationDTO dto
: workingset
.getRegistrationDTOs()){
739 dto
.getValidationProblems().forEach(m
-> messages
.add(dto
.getSummary() + ": " + m
));
741 getView().openDetailsPopup("Validation Problems", messages
);
745 @EventBusListenerMethod
746 public void onEntityChangeEvent(EntityChangeEvent event
){
748 if(!isFromOwnView(event
)){
752 if(workingset
== null){
755 if(Reference
.class.isAssignableFrom(event
.getEntityType())){
757 if(workingset
.getCitationUuid().equals(event
.getEntityUuid())){
758 if(event
.isRemovedType()){
759 viewEventBus
.publish(EventScope
.UI
, this, new NavigationEvent(StartRegistrationViewBean
.NAME
));
766 if(Registration
.class.isAssignableFrom(event
.getEntityType())){
767 if(workingset
.getRegistrations().stream().anyMatch(reg
-> reg
.getUuid() == event
.getEntityUuid())){
771 if(TaxonName
.class.isAssignableFrom(event
.getEntityType())){
772 if(event
.getType().equals(EntityChangeEvent
.Type
.CREATED
)){
773 Stack
<EditorActionContext
>context
= ((AbstractPopupEditor
)event
.getSourceView()).getEditorActionContext();
774 EditorActionContext rootContext
= context
.get(0);
775 if(rootContext
.getParentView().equals(getView()) && event
.getSourceView() != newNameForRegistrationPopupEditor
){
778 // create a blocking registration
779 UUID taxonNameUUID
= event
.getEntityUuid();
780 Optional
<Registration
> registrationOpt
= findRegistrationInContext(context
);
781 assocciateOrQueueBlockingRegistration(registrationOpt
, taxonNameUUID
);
787 // in case of creating a new name for a registration the parent view is the TaxonNamePopupEditor
789 logger
.debug("Non blocking registration, since a new name for a new registration has been created");
792 if(workingset
.getRegistrationDTOs().stream().anyMatch(reg
->
793 reg
.getTypifiedNameRef() != null
794 && reg
.getTypifiedNameRef().getUuid().equals(event
.getEntityUuid()))){
798 if(TypeDesignationBase
.class.isAssignableFrom(event
.getEntityType())){
799 if(workingset
.getRegistrationDTOs().stream().anyMatch(
800 reg
-> reg
.typeDesignations() != null && reg
.typeDesignations().stream().anyMatch(
801 td
-> td
.getUuid() == event
.getEntityUuid()
810 public Optional
<Registration
> findRegistrationInContext(PopupView popupView
) {
811 Stack
<EditorActionContext
>context
= ((AbstractPopupEditor
)popupView
).getEditorActionContext();
812 return findRegistrationInContext(context
);
816 * Finds the Registration in the EditorContext stack
818 public Optional
<Registration
> findRegistrationInContext(Stack
<EditorActionContext
> context
) {
819 EditorActionContext rootCtx
= context
.get(0);
820 TypedEntityReference
<Registration
> regReference
= (TypedEntityReference
<Registration
>)rootCtx
.getParentEntity();
821 Optional
<RegistrationDTO
> registrationDTOOptional
= workingset
.getRegistrationDTO(regReference
.getUuid());
822 Optional
<Registration
> registrationOptional
;
823 if(!registrationDTOOptional
.isPresent()){
824 logger
.debug("No RegistrationDTO in found rootCtx -> user is about to create a registration for a new name.");
825 registrationOptional
= Optional
.ofNullable(null);
828 Optional
<Registration
> regOpt
;
829 if(registrationDTOOptional
.isPresent()){
830 regOpt
= Optional
.of(registrationDTOOptional
.get().registration());
832 regOpt
= Optional
.ofNullable(null);
838 @EventBusListenerMethod(filter
= ShowDetailsEventEntityTypeFilter
.RegistrationDTO
.class)
839 public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent
<RegistrationDTO
, UUID
> event
) {
841 // FIXME check from own view!!!
842 if(getView() == null){
846 UUID registrationUuid
= event
.getIdentifier();
848 RegistrationDTO regDto
= workingset
.getRegistrationDTO(registrationUuid
).get();
849 if(event
.getProperty().equals(RegistrationItem
.BLOCKED_BY
)){
851 Set
<RegistrationDTO
> blockingRegs
;
852 if(regDto
.registration().isPersited()){
853 blockingRegs
= getWorkingSetService().loadBlockingRegistrations(registrationUuid
);
855 blockingRegs
= new HashSet
<RegistrationDTO
>(getWorkingSetService().makeDTOs(regDto
.registration().getBlockedBy()));
857 getView().setBlockingRegistrations(registrationUuid
, blockingRegs
);
858 } else if(event
.getProperty().equals(RegistrationItem
.VALIDATION_PROBLEMS
)){
859 getView().openDetailsPopup("Validation Problems", regDto
.getValidationProblems());
864 public ICdmEntityUuidCacher
getCache() {
869 public void addRootEntity(CdmBase entity
) {
870 rootEntities
.add(entity
);
875 public Collection
<CdmBase
> getRootEntities() {
880 public void destroy() throws Exception
{
886 public void disposeCache() {
890 public boolean canCreateNameRegistrationFor(TaxonName name
) {
891 return registrationWorkflowService
.canCreateNameRegistrationFor(workingset
, name
);
894 public boolean checkWokingsetContainsProtologe(TaxonName name
) {
895 return registrationWorkflowService
.checkWokingsetContainsProtologe(workingset
, name
);