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
.event
.ShortcutAction
.KeyCode
;
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
.Alignment
;
36 import com
.vaadin
.ui
.Button
;
37 import com
.vaadin
.ui
.Label
;
38 import com
.vaadin
.ui
.UI
;
39 import com
.vaadin
.ui
.VerticalLayout
;
40 import com
.vaadin
.ui
.Window
;
42 import eu
.etaxonomy
.cdm
.api
.service
.config
.RegistrationStatusTransitions
;
43 import eu
.etaxonomy
.cdm
.api
.service
.dto
.RegistrationDTO
;
44 import eu
.etaxonomy
.cdm
.api
.service
.dto
.RegistrationWorkingSet
;
45 import eu
.etaxonomy
.cdm
.api
.service
.exception
.TypeDesignationSetException
;
46 import eu
.etaxonomy
.cdm
.api
.service
.name
.TypeDesignationSet
.TypeDesignationSetType
;
47 import eu
.etaxonomy
.cdm
.api
.service
.registration
.IRegistrationWorkingSetService
;
48 import eu
.etaxonomy
.cdm
.api
.util
.UserHelper
;
49 import eu
.etaxonomy
.cdm
.cache
.CdmTransientEntityWithUuidCacher
;
50 import eu
.etaxonomy
.cdm
.model
.ICdmEntityUuidCacher
;
51 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
52 import eu
.etaxonomy
.cdm
.model
.name
.NameTypeDesignation
;
53 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
54 import eu
.etaxonomy
.cdm
.model
.name
.Registration
;
55 import eu
.etaxonomy
.cdm
.model
.name
.RegistrationStatus
;
56 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
57 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameFactory
;
58 import eu
.etaxonomy
.cdm
.model
.name
.TypeDesignationBase
;
59 import eu
.etaxonomy
.cdm
.model
.occurrence
.FieldUnit
;
60 import eu
.etaxonomy
.cdm
.model
.permission
.CRUD
;
61 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
62 import eu
.etaxonomy
.cdm
.persistence
.permission
.PermissionDeniedException
;
63 import eu
.etaxonomy
.cdm
.ref
.TypedEntityReference
;
64 import eu
.etaxonomy
.cdm
.service
.CdmBeanItemContainerFactory
;
65 import eu
.etaxonomy
.cdm
.service
.CdmFilterablePagingProvider
;
66 import eu
.etaxonomy
.cdm
.service
.CdmFilterablePagingProviderFactory
;
67 import eu
.etaxonomy
.cdm
.service
.CdmStore
;
68 import eu
.etaxonomy
.cdm
.service
.IRegistrationWorkflowService
;
69 import eu
.etaxonomy
.cdm
.service
.UserHelperAccess
;
70 import eu
.etaxonomy
.cdm
.vaadin
.component
.registration
.RegistrationItem
;
71 import eu
.etaxonomy
.cdm
.vaadin
.component
.registration
.RegistrationStatusFieldInstantiator
;
72 import eu
.etaxonomy
.cdm
.vaadin
.component
.registration
.RegistrationStatusSelect
;
73 import eu
.etaxonomy
.cdm
.vaadin
.event
.EditorActionContext
;
74 import eu
.etaxonomy
.cdm
.vaadin
.event
.EditorActionTypeFilter
;
75 import eu
.etaxonomy
.cdm
.vaadin
.event
.EntityChangeEvent
;
76 import eu
.etaxonomy
.cdm
.vaadin
.event
.ReferenceEditorAction
;
77 import eu
.etaxonomy
.cdm
.vaadin
.event
.RegistrationEditorAction
;
78 import eu
.etaxonomy
.cdm
.vaadin
.event
.ShowDetailsEvent
;
79 import eu
.etaxonomy
.cdm
.vaadin
.event
.ShowDetailsEventEntityTypeFilter
;
80 import eu
.etaxonomy
.cdm
.vaadin
.event
.TaxonNameEditorAction
;
81 import eu
.etaxonomy
.cdm
.vaadin
.event
.TypeDesignationSetEditorAction
;
82 import eu
.etaxonomy
.cdm
.vaadin
.event
.registration
.RegistrationWorkingsetAction
;
83 import eu
.etaxonomy
.cdm
.vaadin
.ui
.RegistrationUI
;
84 import eu
.etaxonomy
.cdm
.vaadin
.ui
.RegistrationUIDefaults
;
85 import eu
.etaxonomy
.cdm
.vaadin
.ui
.config
.TaxonNamePopupEditorConfig
;
86 import eu
.etaxonomy
.cdm
.vaadin
.util
.CdmTitleCacheCaptionGenerator
;
87 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.CachingPresenter
;
88 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.NameTypeDesignationPopupEditor
;
89 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.NameTypeDesignationSetIds
;
90 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.SpecimenTypeDesignationSetIds
;
91 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.SpecimenTypeDesignationSetPopupEditor
;
92 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.TaxonNameEditorPresenter
;
93 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.TaxonNamePopupEditor
;
94 import eu
.etaxonomy
.cdm
.vaadin
.view
.name
.TaxonNamePopupEditorMode
;
95 import eu
.etaxonomy
.cdm
.vaadin
.view
.reference
.ReferencePopupEditor
;
96 import eu
.etaxonomy
.vaadin
.mvp
.AbstractPopupEditor
;
97 import eu
.etaxonomy
.vaadin
.mvp
.AbstractPresenter
;
98 import eu
.etaxonomy
.vaadin
.mvp
.AbstractView
;
99 import eu
.etaxonomy
.vaadin
.mvp
.BeanInstantiator
;
100 import eu
.etaxonomy
.vaadin
.ui
.navigation
.NavigationEvent
;
101 import eu
.etaxonomy
.vaadin
.ui
.view
.DoneWithPopupEvent
;
102 import eu
.etaxonomy
.vaadin
.ui
.view
.DoneWithPopupEvent
.Reason
;
103 import eu
.etaxonomy
.vaadin
.ui
.view
.PopupView
;
106 * @author a.kohlbecker
111 public class RegistrationWorkingsetPresenter
112 extends AbstractPresenter
<RegistrationWorkingsetPresenter
,RegistrationWorkingsetView
>
113 implements CachingPresenter
{
115 private static final long serialVersionUID
= 2618456456539802265L;
117 private static final Logger logger
= LogManager
.getLogger();
120 private IRegistrationWorkingSetService regWorkingSetService
;
123 private IRegistrationWorkflowService registrationWorkflowService
;
126 private CdmFilterablePagingProviderFactory pagingProviderFactory
;
129 private CdmBeanItemContainerFactory selectFieldFactory
;
132 private CdmStore cdmStore
;
135 * @return the regWorkingSetService
137 public IRegistrationWorkingSetService
getWorkingSetService() {
138 return regWorkingSetService
;
141 private RegistrationWorkingSet workingset
;
144 * 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.
145 * There can always only be one popup editor for this purpose.
147 private TaxonNamePopupEditor newNameForRegistrationPopupEditor
= null;
152 private List
<Registration
> newNameBlockingRegistrations
= new ArrayList
<>();
155 * TODO is this still needed? The registration UUID should be accessible in the popup editor context,
156 * see findRegistrationInContext()
158 private Map
<NameTypeDesignationPopupEditor
, UUID
> nameTypeDesignationPopupEditorRegistrationUUIDMap
= new HashMap
<>();
161 private ICdmEntityUuidCacher cache
;
163 private Collection
<CdmBase
> rootEntities
= new HashSet
<>();
166 public RegistrationWorkingsetPresenter() {
170 * @param doReload reload the workingset from the persistent storage.
171 * Workingsets which are not yet persisted are preserved.
173 protected void refreshView(boolean doReload
) {
175 if(workingset
== null){
176 return; // nothing to do
179 if(logger
.isDebugEnabled()){
180 logger
.debug("refreshView() - workingset:\n" + workingset
.toString());
182 List
<RegistrationDTO
> unpersisted
= new ArrayList
<>();
183 for(RegistrationDTO regDto
: workingset
.getRegistrationDTOs()){
184 if(!regDto
.registration().isPersisted()){
185 unpersisted
.add(regDto
);
188 loadWorkingSet(workingset
.getCitationUuid());
189 for(RegistrationDTO regDtoUnpersisted
: unpersisted
){
190 if(!workingset
.getRegistrationDTOs().stream().anyMatch(dto
-> dto
.getUuid().equals(regDtoUnpersisted
.getUuid()))){
191 // only add if the regDtoUnpersisted has not been persisted meanwhile
193 workingset
.add(regDtoUnpersisted
);
194 } catch (TypeDesignationSetException e
) {
195 // would never happen here //
199 if(logger
.isDebugEnabled()){
200 logger
.debug("refreshView() - workingset reloaded:\n" + workingset
.toString());
207 public void handleViewEntered() {
208 super.handleViewEntered();
209 // TODO currently cannot specify type more precisely, see AbstractSelect
210 // FIXME externalize into class file!!!!!!!!!!!!
211 getView().setStatusComponentInstantiator(new RegistrationStatusFieldInstantiator
<Object
>(){
213 private static final long serialVersionUID
= 7099181280977511048L;
216 public AbstractField
<Object
> create(RegistrationDTO regDto
) {
218 // submitters have GrantedAuthorities like REGISTRATION(PREPARATION).[UPDATE]{ab4459eb-3b96-40ba-bfaa-36915107d59e}
219 UserHelper userHelper
= UserHelperAccess
.userHelper().withCache(getCache());
220 Set
<RegistrationStatus
> availableStatus
= new HashSet
<>();
222 boolean canChangeStatus
= userHelper
.userHasPermission(regDto
.registration(), CRUD
.UPDATE
);
223 availableStatus
.add(regDto
.getStatus());
225 if(userHelper
.userIsAdmin()){
226 availableStatus
.addAll(Arrays
.asList(RegistrationStatus
.values()));
228 availableStatus
.addAll(RegistrationStatusTransitions
.possibleTransitions(regDto
.getStatus()));
232 RegistrationStatusSelect select
= new RegistrationStatusSelect(null, selectFieldFactory
.buildEnumTermItemContainer(
233 RegistrationStatus
.class,
234 availableStatus
.toArray(new RegistrationStatus
[availableStatus
.size()]))
236 select
.setValue(regDto
.getStatus());
237 select
.addValueChangeListener(e
-> saveRegistrationStatusChange(regDto
.getUuid(), e
.getProperty().getValue()));
238 select
.setEnabled(canChangeStatus
);
239 select
.setNullSelectionAllowed(false);
244 loadWorkingSet(getView().getCitationUuid());
249 private void applyWorkingset(){
250 if (workingset
!= null) {
251 getView().setWorkingset(workingset
);
252 // PagingProviders and CacheGenerator for the existingNameCombobox
253 activateComboboxes();
257 protected void activateComboboxes() {
258 CdmTitleCacheCaptionGenerator
<TaxonName
> titleCacheGenerator
= new CdmTitleCacheCaptionGenerator
<TaxonName
>();
259 getView().getExistingNameCombobox().setCaptionGenerator(titleCacheGenerator
);
260 CdmFilterablePagingProvider
<TaxonName
, TaxonName
> pagingProvider
= pagingProviderFactory
.taxonNamesWithoutOrthophicIncorrect();
261 getView().getExistingNameCombobox().loadFrom(pagingProvider
, pagingProvider
, pagingProvider
.getPageSize());
264 protected void loadWorkingSet(UUID referenceUuid
) {
267 workingset
= getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid
, true);
268 } catch (PermissionDeniedException error
) {
270 showErrorDialog("Permission denied", "You are not allowed to access this working set.");
272 } catch (TypeDesignationSetException error
) {
274 showErrorDialog("Validation Error", error
.getMessage());
275 //NOTE by AM: should we return here, too, or is this error not so
277 cache
= new CdmTransientEntityWithUuidCacher(this);
278 for(Registration registration
: workingset
.getRegistrations()) {
279 addRootEntity(registration
);
283 public void showErrorDialog(String errorDialogCaption
, String errorMessage
) {
285 final Window errorDialog
= new Window(errorDialogCaption
);
286 errorDialog
.setModal(true);
287 errorDialog
.setClosable(false);
288 errorDialog
.setResizable(false);
289 VerticalLayout subContent
= new VerticalLayout();
290 subContent
.setSpacing(true);
291 subContent
.setMargin(true);
292 errorDialog
.setContent(subContent
);
293 subContent
.addComponent(new Label(errorMessage
));
295 //close button (quick & dirty by AM, to fix #10373)
296 Button cancelButton
= new Button("Close");
297 subContent
.addComponent(cancelButton
);
298 cancelButton
.setWidth("-1px");
299 cancelButton
.setHeight("-1px");
300 subContent
.addComponent(cancelButton
);
301 subContent
.setComponentAlignment(cancelButton
, new Alignment(48));
302 cancelButton
.addClickListener((ev
)->errorDialog
.close());
303 cancelButton
.setClickShortcut(KeyCode
.ENTER
, null);
304 cancelButton
.focus();
306 UI
.getCurrent().addWindow(errorDialog
);
309 private void saveRegistrationStatusChange(UUID uuid
, Object value
) {
310 Registration reg
= getRepo().getRegistrationService().load(uuid
);
312 // registration was not yet persisted, ignore
315 if(value
!= null && value
instanceof RegistrationStatus
){
316 if(!Objects
.equals(value
, reg
.getStatus())){
317 reg
.updateStatusAndDate((RegistrationStatus
)value
);
318 cdmStore
.saveBean(reg
, (AbstractView
<?
,?
>)getView());
322 // only log here as error
323 logger
.error("Ivalid attempt to set RegistrationStatus to " + Objects
.toString(value
.toString(), "NULL"));
327 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Add
.class)
328 public void onReferenceEditorActionAdd(ReferenceEditorAction event
) {
330 if(!checkFromOwnView(event
)){
334 ReferencePopupEditor popup
= openPopupEditor(ReferencePopupEditor
.class, event
);
335 popup
.withReferenceTypes(RegistrationUIDefaults
.PRINTPUB_REFERENCE_TYPES
);
336 popup
.loadInEditor(null);
339 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Edit
.class)
340 public void onReferenceEditorActionEdit(ReferenceEditorAction event
) {
342 if(!checkFromOwnView(event
)){
345 ReferencePopupEditor popup
= openPopupEditor(ReferencePopupEditor
.class, event
);
346 popup
.withReferenceTypes(RegistrationUIDefaults
.PRINTPUB_REFERENCE_TYPES
);
347 popup
.withDeleteButton(true);
348 popup
.loadInEditor(event
.getEntityUuid());
351 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Edit
.class)
352 public void onRegistrationEditorAction(RegistrationEditorAction event
) {
354 if(!checkFromOwnView(event
)){
358 RegistrationPopupEditor popup
= openPopupEditor(RegistrationPopupEditor
.class, event
);
359 popup
.loadInEditor(event
.getEntityUuid());
362 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Edit
.class)
363 public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event
) {
365 if(!checkFromOwnView(event
)){
369 boolean isRegistrationForExistingName
= event
.getTarget() != null && event
.getTarget().equals(getView().getExistingNameCombobox());
371 TaxonNamePopupEditor popup
= openPopupEditor(TaxonNamePopupEditor
.class, event
);
373 popup
.setParentEditorActionContext(event
.getContext(), event
.getTarget());
374 popup
.withDeleteButton(!isRegistrationForExistingName
);
375 TaxonNamePopupEditorConfig
.configureForNomenclaturalAct(popup
);
376 if(isRegistrationForExistingName
){
377 // allow saving even if the name parts are not valid
378 // the user will need to fix this in a later step
379 popup
.disableMode(TaxonNamePopupEditorMode
.VALIDATE_AGAINST_HIGHER_NAME_PART
);
380 getView().getAddExistingNameRegistrationButton().setEnabled(false);
381 popup
.addDetachListener(ev
->
382 getView().getAddExistingNameRegistrationButton().setEnabled(true)
385 popup
.loadInEditor(event
.getEntityUuid());
386 if(event
.hasSource() && event
.getSource().isReadOnly()){
387 // avoid resetting read-only to false
388 logger
.info("Set popup to read-only as event source is read only");
389 popup
.setReadOnly(true);
392 boolean hasNomRef
= popup
.getBean().getNomenclaturalReference() != null;
393 if(isRegistrationForExistingName
){
394 popup
.setAllFieldsReadOnly(true);
395 popup
.removeStatusMessage(RegistrationUI
.CHECK_IN_SEARCH_INDEX
);
398 //#10269 for now we do not allow registrations for names with no nom. ref.
400 // // only allow editing the nomenclatural reference, all other
401 // // editing need to be done another way.
402 // // Otherwise we would need to be prepared for creating blocking registrations
403 // // in turn of creation, modification of related taxon names.
404 // popup.disableMode(TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY);
405 // popup.getNomReferenceCombobox().setReadOnly(false);
406 // popup.getNomenclaturalReferenceDetail().setReadOnly(false);
407 // popup.addStatusMessage("The chosen name needs to be completed before it can be used. "
408 // + "Please add the nomenclatural reference and click on \"Save\" to proceed with entering the type of this name.");
410 //instead we show status message:
411 // popup.setToCancelOnly();
412 popup
.addStatusMessage("<p style='color:red;'><strong>The data entry is aborted "
413 + "due to a data issue that should be fixed "
414 + "by the curator</strong>.<BR>"
415 + "Please send an e-mail with the scientific name "
416 + "to <i>curation@phycobank.org</i></p>");
418 popup
.setToSelect(); //sets the save button to "save & select"
419 popup
.addStatusMessage("You are about to create a registration for this name. "
420 + "This editor is for reviewing the name only. Therefore, all fields have "
421 + "been switched to read-only state. "
422 + "Click on \"Save\" to proceed with entering the type of this name.");
427 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Add
.class)
428 public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event
) {
430 if(!checkFromOwnView(event
)){
434 getView().getAddNewNameRegistrationButton().setEnabled(false);
435 if(newNameForRegistrationPopupEditor
== null){
436 TaxonNamePopupEditor popup
= openPopupEditor(TaxonNamePopupEditor
.class, event
);
437 newNameForRegistrationPopupEditor
= popup
;
438 popup
.setParentEditorActionContext(event
.getContext(), event
.getTarget());
439 popup
.grantToCurrentUser(EnumSet
.of(CRUD
.UPDATE
,CRUD
.DELETE
));
440 popup
.withDeleteButton(true);
441 popup
.setCdmEntityInstantiator(new BeanInstantiator
<TaxonName
>() {
444 public TaxonName
createNewBean() {
445 TaxonName newTaxonName
= TaxonNameFactory
.NewNameInstance(RegistrationUIDefaults
.NOMENCLATURAL_CODE
, Rank
.SPECIES());
446 newTaxonName
.setNomenclaturalReference(getRepo().getReferenceService().load(workingset
.getCitationUuid(), TaxonNameEditorPresenter
.REFERENCE_INIT_STRATEGY
));
450 TaxonNamePopupEditorConfig
.configureForNomenclaturalAct(popup
);
451 popup
.loadInEditor(null);
456 * Creates a new <code>Registration</code> for a new name that has just been edited
457 * using a <code>TaxonNamePopupEditor</code>. The popup editor which has been opened to
458 * edit the new name was remembered in <code>newNameForRegistrationPopupEditor</code>.
459 * Any blocking registrations which have been created while editing the new name are
460 * temporarily stored in <code>newNameBlockingRegistrations</code> until the registration
461 * for the first name has been created. Additional new names are created for example
462 * when a new name as basionym, replaced synonym, etc to the new name is created.
464 * See also {@link #onTaxonNameEditorActionAdd(TaxonNameEditorAction)}).
467 * @throws TypeDesignationSetException
468 * passes on the Exception which may come from onRegistrationWorkflowEventActionStart()
470 @EventBusListenerMethod
471 public void onDoneWithTaxonnameEditor(DoneWithPopupEvent event
) throws TypeDesignationSetException
{
473 if(!isFromOwnView(event
)){
477 if(event
.getPopup() instanceof TaxonNamePopupEditor
){
479 EditorActionContext rootContext
= editorActionContextRoot(event
.getPopup());
480 boolean isAddExistingNameRegistration
= rootContext
.getTargetField() != null && rootContext
.getTargetField().equals(getView().getExistingNameCombobox());
482 if(isAddExistingNameRegistration
){
483 if(event
.getReason().equals(Reason
.SAVE
)){
484 onRegistrationWorkflowEventActionStart(new RegistrationWorkingsetAction(workingset
.getCitationUuid(),
485 RegistrationWorkingsetAction
.Action
.start
));
487 // just ignore on CANCEL
489 Optional
<Registration
> registrationOpt
= Optional
.ofNullable(null);
490 if(newNameForRegistrationPopupEditor
!= null && event
.getPopup().equals(newNameForRegistrationPopupEditor
)){
491 if(event
.getReason().equals(Reason
.SAVE
)){
493 TaxonName taxonName
= newNameForRegistrationPopupEditor
.getBean().cdmEntity();
494 registrationOpt
= Optional
.of(registrationWorkflowService
.createRegistration(taxonName
, newNameBlockingRegistrations
));
495 loadWorkingSet(workingset
.getCitationUuid());
498 getView().getAddNewNameRegistrationButton().setEnabled(true);
501 // nullify and clear the memory on this popup editor in any case (SAVE, DELETE, CANCEL)
502 newNameForRegistrationPopupEditor
= null;
503 newNameBlockingRegistrations
.clear();
504 getView().getAddNewNameRegistrationButton().setEnabled(true);
507 if(event
.getReason().equals(Reason
.SAVE
)){
508 if(!registrationOpt
.isPresent()){
509 // no new registration has been created above, so there must be an existing one.
510 registrationOpt
= findRegistrationInContext(event
.getPopup());
513 // Check if the other names used in the context of the name are registered yet.
514 TaxonNamePopupEditor nameEditor
= (TaxonNamePopupEditor
)event
.getPopup();
515 Set
<TaxonName
> namesToCheck
= new HashSet
<>();
517 namesToCheck
.addAll(nameEditor
.getBasionymComboboxSelect().getValue());
518 namesToCheck
.addAll(nameEditor
.getReplacedSynonymsComboboxSelect().getValue());
519 namesToCheck
.add(nameEditor
.getValidationField().getRelatedNameComboBox().getValue());
520 namesToCheck
.add(nameEditor
.getOrthographicVariantField().getRelatedNameComboBox().getValue());
521 // NOTE: according to https://dev.e-taxonomy.eu/redmine/issues/8049#note-2 we will not create blocking
522 // registrations for names in WeaklyRelatedEntityFields
524 for(TaxonName name
: namesToCheck
){
527 assocciateOrQueueBlockingRegistration(registrationOpt
, name
.getUuid());
530 } else if (event
.getReason().equals(Reason
.DELETE
)){
531 //FIXME handle delete: need to remove blocking registrations?
533 // always reload if the first editor is closed as the data might have been changed through any other sub-popupeditor
534 refreshView(isAtContextRoot(event
.getPopup()));
540 * Creates a new Registration for an exiting (previously published) name.
542 @EventBusListenerMethod
543 public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event
) throws TypeDesignationSetException
{
545 if(!event
.isStart()){
549 getView().getExistingNameCombobox().commit(); // update the chosen value in the datasource
550 TaxonName typifiedName
= getView().getExistingNameCombobox().getValue();
551 if(typifiedName
!= null){
552 boolean doReloadWorkingSet
= false;
554 doReloadWorkingSet
= registrationWorkflowService
.createRegistrationforExistingName(workingset
, typifiedName
);
557 refreshView(doReloadWorkingSet
);
558 getView().getAddExistingNameRegistrationButton().setEnabled(false);
561 logger
.error("Seletced name is NULL");
566 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Edit
.class)
567 public void onTypeDesignationsEditorActionEdit(TypeDesignationSetEditorAction event
) {
569 if(!checkFromOwnView(event
)){
573 RegistrationDTO registrationDTO
= workingset
.getRegistrationDTO(event
.getRegistrationUuid()).get();
575 if(event
.getWorkingSetType() == TypeDesignationSetType
.SPECIMEN_TYPE_DESIGNATION_SET
){
576 SpecimenTypeDesignationSetPopupEditor popup
= openPopupEditor(SpecimenTypeDesignationSetPopupEditor
.class, event
);
577 popup
.setParentEditorActionContext(event
.getContext(), event
.getTarget());
578 popup
.withDeleteButton(true);
579 popup
.loadInEditor(new SpecimenTypeDesignationSetIds(
580 workingset
.getCitationUuid(),
581 event
.getRegistrationUuid(),
582 CdmBase
.deproxy(event
.getBaseEntity(), FieldUnit
.class), null));
583 if(event
.hasSource()){
584 // propagate readonly state from source button to popup
585 popup
.setReadOnly(event
.getSource().isReadOnly());
588 NameTypeDesignationPopupEditor popup
= openPopupEditor(NameTypeDesignationPopupEditor
.class, event
);
589 popup
.setParentEditorActionContext(event
.getContext(), event
.getTarget());
590 popup
.withDeleteButton(true);
591 popup
.loadInEditor(NameTypeDesignationSetIds
.forExistingTypeDesignation(
592 registrationDTO
.getCitationUuid(),
593 CdmBase
.deproxy(event
.getBaseEntity(), NameTypeDesignation
.class))
595 popup
.getTypifiedNamesComboboxSelect().setEnabled(false);
596 if(event
.hasSource()){
597 // propagate readonly state from source button to popup
598 popup
.setReadOnly(event
.getSource().isReadOnly());
600 nameTypeDesignationPopupEditorRegistrationUUIDMap
.put(popup
, event
.getRegistrationUuid());
604 @EventBusListenerMethod(filter
= EditorActionTypeFilter
.Add
.class)
605 public void onTypeDesignationSetAdd(TypeDesignationSetEditorAction event
) {
607 if(!event
.hasSource()){
611 RegistrationDTO registrationDTO
= workingset
.getRegistrationDTO(event
.getRegistrationUuid()).get();
613 if(event
.getWorkingSetType() == TypeDesignationSetType
.SPECIMEN_TYPE_DESIGNATION_SET
){
614 SpecimenTypeDesignationSetPopupEditor popup
= openPopupEditor(SpecimenTypeDesignationSetPopupEditor
.class, event
);
615 popup
.setParentEditorActionContext(event
.getContext(), event
.getTarget());
616 TypedEntityReference
<TaxonName
> typifiedNameRef
;
617 if(registrationDTO
.getTypifiedNameRef() != null){
618 // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
619 typifiedNameRef
= new TypedEntityReference(TaxonName
.class, registrationDTO
.getTypifiedNameRef().getUuid());
621 // case of registrations with a name in the nomenclatural act.
622 typifiedNameRef
= new TypedEntityReference(TaxonName
.class, registrationDTO
.getNameRef().getUuid());
625 popup
.grantToCurrentUser(EnumSet
.of(CRUD
.UPDATE
, CRUD
.DELETE
));
626 popup
.withDeleteButton(false);
627 popup
.loadInEditor(new SpecimenTypeDesignationSetIds(
628 workingset
.getCitationUuid(),
629 event
.getRegistrationUuid(),
631 typifiedNameRef
.getUuid()
634 if(event
.hasSource()){
635 // propagate readonly state from source component to popup
636 popup
.setReadOnly(event
.getSource().isReadOnly());
639 NameTypeDesignationPopupEditor popup
= openPopupEditor(NameTypeDesignationPopupEditor
.class, event
);
640 popup
.setParentEditorActionContext(event
.getContext(), event
.getTarget());
641 popup
.grantToCurrentUser(EnumSet
.of(CRUD
.UPDATE
, CRUD
.DELETE
));
642 nameTypeDesignationPopupEditorRegistrationUUIDMap
.put(popup
, event
.getRegistrationUuid());
643 popup
.setBeanInstantiator(new BeanInstantiator
<NameTypeDesignation
>() {
646 public NameTypeDesignation
createNewBean() {
648 TaxonName typifiedName
= getRepo().getNameService().load(event
.getTypifiedNameUuid(), Arrays
.asList(new String
[]{
651 "nomenclaturalSource.citation"
653 NameTypeDesignation nameTypeDesignation
= NameTypeDesignation
.NewInstance();
654 nameTypeDesignation
.getTypifiedNames().add(typifiedName
);
655 return nameTypeDesignation
;
658 popup
.withDeleteButton(false);
659 popup
.loadInEditor(NameTypeDesignationSetIds
.forNewTypeDesignation(
660 registrationDTO
.getCitationUuid(),
661 event
.getTypifiedNameUuid()
664 popup
.getTypifiedNamesComboboxSelect().setEnabled(false);
665 if(event
.hasSource()){
666 // propagate readonly state from source component to popup
667 popup
.setReadOnly(event
.getSource().isReadOnly());
673 * Performs final actions after a TypeDesignationEditor which has been
674 * opened to add a TypeDesignation to a Registration object which was
675 * created for an previously published name. Prior adding a typedesignation,
676 * the according Registration object is dangling, that has no association to
677 * any entity denoting an nomenclatural act which has a reference to a
678 * publication. This means that the registration object is not in the
683 * @throws TypeDesignationSetException
685 @EventBusListenerMethod
686 public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event
) {
688 if(!isFromOwnView(event
)){
692 if(event
.getPopup() instanceof SpecimenTypeDesignationSetPopupEditor
){
693 if(event
.getReason().equals(Reason
.SAVE
)){
694 // NOTE: adding the SpecimenTypeDesignations to the registration is done in the
695 // SpecimenTypeDesignationSetServiceImpl.save(SpecimenTypeDesignationSetDTO dto) method
697 // always reload if the first editor is closed as the data might have been changed through any other sub-popupeditor
698 refreshView(isAtContextRoot(event
.getPopup()));
699 } else if(event
.getPopup() instanceof NameTypeDesignationPopupEditor
){
700 if(event
.getReason().equals(Reason
.SAVE
)){
701 Optional
<Registration
> registrationOpt
= Optional
.ofNullable(null);
702 NameTypeDesignationPopupEditor popup
= ((NameTypeDesignationPopupEditor
)event
.getPopup());
703 UUID typeDesignationUuid
= popup
.getBean().getUuid();
706 registrationOpt
= findRegistrationInContext(popup
);
707 registrationOpt
.ifPresent(reg
-> {
708 registrationWorkflowService
.addTypeDesignation(typeDesignationUuid
, reg
);
709 nameTypeDesignationPopupEditorRegistrationUUIDMap
.remove(popup
);
716 // Check if other names used in the context of the name are registered yet.
717 Set
<TaxonName
> namesToCheck
= new HashSet
<>();
719 namesToCheck
.add(popup
.getTypeNameField().getValue());
721 for(TaxonName name
: namesToCheck
){
723 assocciateOrQueueBlockingRegistration(registrationOpt
, name
.getUuid());
727 } else if(event
.getReason().equals(Reason
.CANCEL
)){
730 // always reload if the first editor is closed as the data might have been changed through any other sub-popupeditor
731 refreshView(isAtContextRoot(event
.getPopup()));
734 // ignore other editors
737 private void assocciateOrQueueBlockingRegistration(Optional
<Registration
> registrationOpt
, UUID nameUuid
) {
738 registrationOpt
.ifPresent(reg
-> registrationWorkflowService
.addBlockingRegistration(nameUuid
, reg
));
739 if(!registrationOpt
.isPresent()){
741 Registration blockingRegistration
= registrationWorkflowService
.prepareBlockingRegistration(nameUuid
);
742 if(blockingRegistration
!= null){
743 newNameBlockingRegistrations
.add(blockingRegistration
);
744 logger
.debug("Blocking registration created and queued for later association with the main registration.");
750 public void clearSession() {
751 getRepo().clearSession();
754 @EventBusListenerMethod(filter
= ShowDetailsEventEntityTypeFilter
.RegistrationWorkingSet
.class)
755 public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent
<RegistrationWorkingSet
,?
> event
) {
757 if(event
.getProperty().equals(RegistrationItem
.VALIDATION_PROBLEMS
)){
758 List
<String
> messages
= new ArrayList
<>();
759 for(RegistrationDTO dto
: workingset
.getRegistrationDTOs()){
760 dto
.getValidationProblems().forEach(m
-> messages
.add(dto
.getSummary() + ": " + m
));
762 getView().openDetailsPopup("Validation Problems", messages
);
766 @EventBusListenerMethod
767 public void onEntityChangeEvent(EntityChangeEvent event
){
769 if(!isFromOwnView(event
)){
773 if(workingset
== null){
776 if(Reference
.class.isAssignableFrom(event
.getEntityType())){
778 if(workingset
.getCitationUuid().equals(event
.getEntityUuid())){
779 if(event
.isRemovedType()){
780 viewEventBus
.publish(EventScope
.UI
, this, new NavigationEvent(StartRegistrationViewBean
.NAME
));
787 if(Registration
.class.isAssignableFrom(event
.getEntityType())){
788 if(workingset
.getRegistrations().stream().anyMatch(reg
-> reg
.getUuid() == event
.getEntityUuid())){
792 if(TaxonName
.class.isAssignableFrom(event
.getEntityType())){
793 if(event
.getType().equals(EntityChangeEvent
.Type
.CREATED
)){
794 Stack
<EditorActionContext
>context
= ((AbstractPopupEditor
)event
.getSourceView()).getEditorActionContext();
795 EditorActionContext rootContext
= context
.get(0);
796 if(rootContext
.getParentView().equals(getView()) && event
.getSourceView() != newNameForRegistrationPopupEditor
){
799 // create a blocking registration
800 UUID taxonNameUUID
= event
.getEntityUuid();
801 Optional
<Registration
> registrationOpt
= findRegistrationInContext(context
);
802 assocciateOrQueueBlockingRegistration(registrationOpt
, taxonNameUUID
);
808 // in case of creating a new name for a registration the parent view is the TaxonNamePopupEditor
810 logger
.debug("Non blocking registration, since a new name for a new registration has been created");
813 if(workingset
.getRegistrationDTOs().stream().anyMatch(reg
->
814 reg
.getTypifiedNameRef() != null
815 && reg
.getTypifiedNameRef().getUuid().equals(event
.getEntityUuid()))){
819 if(TypeDesignationBase
.class.isAssignableFrom(event
.getEntityType())){
820 if(workingset
.getRegistrationDTOs().stream().anyMatch(
821 reg
-> reg
.typeDesignations() != null && reg
.typeDesignations().stream().anyMatch(
822 td
-> td
.getUuid() == event
.getEntityUuid()
831 public Optional
<Registration
> findRegistrationInContext(PopupView popupView
) {
832 Stack
<EditorActionContext
>context
= ((AbstractPopupEditor
)popupView
).getEditorActionContext();
833 return findRegistrationInContext(context
);
837 * Finds the Registration in the EditorContext stack
839 public Optional
<Registration
> findRegistrationInContext(Stack
<EditorActionContext
> context
) {
840 EditorActionContext rootCtx
= context
.get(0);
841 TypedEntityReference
<Registration
> regReference
= (TypedEntityReference
<Registration
>)rootCtx
.getParentEntity();
842 Optional
<RegistrationDTO
> registrationDTOOptional
= workingset
.getRegistrationDTO(regReference
.getUuid());
843 Optional
<Registration
> registrationOptional
;
844 if(!registrationDTOOptional
.isPresent()){
845 logger
.debug("No RegistrationDTO in found rootCtx -> user is about to create a registration for a new name.");
846 registrationOptional
= Optional
.ofNullable(null);
849 Optional
<Registration
> regOpt
;
850 if(registrationDTOOptional
.isPresent()){
851 regOpt
= Optional
.of(registrationDTOOptional
.get().registration());
853 regOpt
= Optional
.ofNullable(null);
859 @EventBusListenerMethod(filter
= ShowDetailsEventEntityTypeFilter
.RegistrationDTO
.class)
860 public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent
<RegistrationDTO
, UUID
> event
) {
862 // FIXME check from own view!!!
863 if(getView() == null){
867 UUID registrationUuid
= event
.getIdentifier();
869 RegistrationDTO regDto
= workingset
.getRegistrationDTO(registrationUuid
).get();
870 if(event
.getProperty().equals(RegistrationItem
.BLOCKED_BY
)){
872 Set
<RegistrationDTO
> blockingRegs
;
873 if(regDto
.registration().isPersisted()){
874 blockingRegs
= getWorkingSetService().loadBlockingRegistrations(registrationUuid
);
876 blockingRegs
= new HashSet
<RegistrationDTO
>(getWorkingSetService().makeDTOs(regDto
.registration().getBlockedBy()));
878 getView().setBlockingRegistrations(registrationUuid
, blockingRegs
);
879 } else if(event
.getProperty().equals(RegistrationItem
.VALIDATION_PROBLEMS
)){
880 getView().openDetailsPopup("Validation Problems", regDto
.getValidationProblems());
885 public ICdmEntityUuidCacher
getCache() {
890 public void addRootEntity(CdmBase entity
) {
891 rootEntities
.add(entity
);
896 public Collection
<CdmBase
> getRootEntities() {
901 public void destroy() throws Exception
{
907 public void disposeCache() {
911 public boolean canCreateNameRegistrationFor(TaxonName name
) {
912 return registrationWorkflowService
.canCreateNameRegistrationFor(workingset
, name
);
915 public boolean checkWokingsetContainsProtologe(TaxonName name
) {
916 return registrationWorkflowService
.checkWokingsetContainsProtologe(workingset
, name
);