ref #10089 remove TypedEntityReference from TypeDesignationWorkingSet in vaadin
[cdm-vaadin.git] / src / main / java / eu / etaxonomy / cdm / vaadin / view / registration / RegistrationWorkingsetPresenter.java
1 /**
2 * Copyright (C) 2017 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.cdm.vaadin.view.registration;
10
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;
18 import java.util.Map;
19 import java.util.Objects;
20 import java.util.Optional;
21 import java.util.Set;
22 import java.util.Stack;
23 import java.util.UUID;
24
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;
29
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;
39
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;
100
101 /**
102 * @author a.kohlbecker
103 * @since Mar 3, 2017
104 *
105 */
106 @SpringComponent
107 @ViewScope
108 public class RegistrationWorkingsetPresenter extends AbstractPresenter<RegistrationWorkingsetView> implements CachingPresenter {
109
110 private static final Logger logger = Logger.getLogger(RegistrationWorkingsetPresenter.class);
111
112 private static final long serialVersionUID = 1L;
113
114 @Autowired
115 private IRegistrationWorkingSetService regWorkingSetService;
116
117 @Autowired
118 private IRegistrationWorkflowService registrationWorkflowService;
119
120 @Autowired
121 private CdmFilterablePagingProviderFactory pagingProviderFactory;
122
123 @Autowired
124 private CdmBeanItemContainerFactory selectFieldFactory;
125
126 @Autowired
127 private CdmStore cdmStore;
128
129 /**
130 * @return the regWorkingSetService
131 */
132 public IRegistrationWorkingSetService getWorkingSetService() {
133 return regWorkingSetService;
134 }
135
136 private RegistrationWorkingSet workingset;
137
138 /**
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.
141 */
142 private TaxonNamePopupEditor newNameForRegistrationPopupEditor = null;
143
144 /**
145 * Contains
146 */
147 private List<Registration> newNameBlockingRegistrations = new ArrayList<>();
148
149 /**
150 * TODO is this still needed? The registration UUID should be accessible in the popup editor context,
151 * see findRegistrationInContext()
152 */
153 private Map<NameTypeDesignationPopupEditor, UUID> nameTypeDesignationPopupEditorRegistrationUUIDMap = new HashMap<>();
154
155
156 private ICdmEntityUuidCacher cache;
157
158 private Collection<CdmBase> rootEntities = new HashSet<>();
159
160
161 public RegistrationWorkingsetPresenter() {
162 }
163
164 /**
165 * @param doReload reload the workingset from the persistent storage.
166 * Workingsets which are not yet persisted are preserved.
167 */
168 protected void refreshView(boolean doReload) {
169
170 if(workingset == null){
171 return; // nothing to do
172 }
173 if(doReload){
174 if(logger.isDebugEnabled()){
175 logger.debug("refreshView() - workingset:\n" + workingset.toString());
176 }
177 List<RegistrationDTO> unpersisted = new ArrayList<>();
178 for(RegistrationDTO regDto : workingset.getRegistrationDTOs()){
179 if(!regDto.registration().isPersited()){
180 unpersisted.add(regDto);
181 }
182 }
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
187 try {
188 workingset.add(regDtoUnpersisted);
189 } catch (RegistrationValidationException e) {
190 // would never happen here //
191 }
192 }
193 }
194 if(logger.isDebugEnabled()){
195 logger.debug("refreshView() - workingset reloaded:\n" + workingset.toString());
196 }
197 }
198 applyWorkingset();
199 }
200
201 @Override
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>(){
207
208 private static final long serialVersionUID = 7099181280977511048L;
209
210 @Override
211 public AbstractField<Object> create(RegistrationDTO regDto) {
212
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<>();
216
217 boolean canChangeStatus = userHelper.userHasPermission(regDto.registration(), CRUD.UPDATE);
218 availableStatus.add(regDto.getStatus());
219 if(canChangeStatus){
220 if(userHelper.userIsAdmin()){
221 availableStatus.addAll(Arrays.asList(RegistrationStatus.values()));
222 } else {
223 availableStatus.addAll(RegistrationStatusTransitions.possibleTransitions(regDto.getStatus()));
224 }
225 }
226
227 RegistrationStatusSelect select = new RegistrationStatusSelect(null, selectFieldFactory.buildEnumTermItemContainer(
228 RegistrationStatus.class,
229 availableStatus.toArray(new RegistrationStatus[availableStatus.size()]))
230 );
231 select.setValue(regDto.getStatus());
232 select.addValueChangeListener(e -> saveRegistrationStatusChange(regDto.getUuid(), e.getProperty().getValue()));
233 select.setEnabled(canChangeStatus);
234 select.setNullSelectionAllowed(false);
235 return select;
236 }
237
238
239 });
240
241 loadWorkingSet(getView().getCitationUuid());
242 applyWorkingset();
243
244 }
245
246 private void applyWorkingset(){
247 getView().setWorkingset(workingset);
248 // PagingProviders and CacheGenerator for the existingNameCombobox
249 activateComboboxes();
250 }
251
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());
257 }
258
259 /**
260 * @param referenceID
261 */
262 protected void loadWorkingSet(UUID referenceUuid) {
263
264 try {
265 workingset = getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid, true);
266 } catch (RegistrationValidationException error) {
267 logger.error(error);
268 showErrorDialog("Validation Error", error.getMessage());
269 }
270 cache = new CdmTransientEntityAndUuidCacher(this);
271 for(Registration registration : workingset.getRegistrations()) {
272 addRootEntity(registration);
273 }
274 }
275
276 /**
277 * @param errorDialogCaption
278 * @param errorMessage
279 */
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);
288 }
289
290 private void saveRegistrationStatusChange(UUID uuid, Object value) {
291 Registration reg = getRepo().getRegistrationService().load(uuid);
292 if(reg == null){
293 // registration was not yet persisted, ignore
294 return;
295 }
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());
300 refreshView(true);
301 }
302 } else {
303 // only log here as error
304 logger.error("Ivalid attempt to set RegistrationStatus to " + Objects.toString(value.toString(), "NULL"));
305 }
306 }
307
308
309 @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
310 public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
311
312 if(!checkFromOwnView(event)){
313 return;
314 }
315
316 ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
317 popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
318 popup.loadInEditor(null);
319 }
320
321 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
322 public void onReferenceEditorActionEdit(ReferenceEditorAction event) {
323
324 if(!checkFromOwnView(event)){
325 return;
326 }
327 ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
328 popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
329 popup.withDeleteButton(true);
330 popup.loadInEditor(event.getEntityUuid());
331 }
332
333 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
334 public void onRegistrationEditorAction(RegistrationEditorAction event) {
335
336 if(!checkFromOwnView(event)){
337 return;
338 }
339
340 RegistrationPopupEditor popup = openPopupEditor(RegistrationPopupEditor.class, event);
341 popup.loadInEditor(event.getEntityUuid());
342 }
343
344 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
345 public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
346
347 if(!checkFromOwnView(event)){
348 return;
349 }
350
351 boolean isAddExistingNameRegistration = event.getTarget() != null && event.getTarget().equals(getView().getAddExistingNameCombobox());
352
353 TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
354
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() {
364
365 @Override
366 public void detach(DetachEvent event) {
367 getView().getAddExistingNameRegistrationButton().setEnabled(true);
368
369 }
370 });
371 }
372 popup.loadInEditor(event.getEntityUuid());
373 if(event.hasSource() && event.getSource().isReadOnly()){
374 // avoid resetting readonly to false
375 popup.setReadOnly(true);
376 }
377
378 boolean hasNomRef = popup.getBean().getNomenclaturalReference() != null;
379 if(isAddExistingNameRegistration){
380 popup.setAllFieldsReadOnly(true);
381 if(!hasNomRef){
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.");
391 } else {
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.");
395 }
396 }
397 }
398
399
400 @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
401 public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
402
403 if(!checkFromOwnView(event)){
404 return;
405 }
406
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>() {
415
416 @Override
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 ));
420 return newTaxonName;
421 }
422 });
423 TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
424 popup.loadInEditor(null);
425 }
426 }
427
428 /**
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.
436 * <p>
437 * See also {@link #onTaxonNameEditorActionAdd(TaxonNameEditorAction)}).
438 *
439 * @param event
440 * @throws RegistrationValidationException
441 * passes on the Exception which may come from onRegistrationWorkflowEventActionStart()
442 */
443 @EventBusListenerMethod
444 public void onDoneWithTaxonnameEditor(DoneWithPopupEvent event) throws RegistrationValidationException {
445
446 if(!isFromOwnView(event)){
447 return;
448 }
449
450 if(event.getPopup() instanceof TaxonNamePopupEditor){
451
452 EditorActionContext rootContext = editorActionContextRoot(event.getPopup());
453 boolean isAddExistingNameRegistration = rootContext.getTargetField() != null && rootContext.getTargetField().equals(getView().getAddExistingNameCombobox());
454
455 if(isAddExistingNameRegistration){
456 if(event.getReason().equals(Reason.SAVE)){
457 onRegistrationWorkflowEventActionStart(new RegistrationWorkingsetAction(workingset.getCitationUuid(),
458 RegistrationWorkingsetAction.Action.start));
459 }
460 // just ignore on CANCEL
461 } else {
462 Optional<Registration> registrationOpt = Optional.ofNullable(null);
463 if(newNameForRegistrationPopupEditor != null && event.getPopup().equals(newNameForRegistrationPopupEditor)){
464 if(event.getReason().equals(Reason.SAVE)){
465 try {
466 TaxonName taxonName = newNameForRegistrationPopupEditor.getBean().cdmEntity();
467 registrationOpt = Optional.of(registrationWorkflowService.createRegistration(taxonName, newNameBlockingRegistrations));
468 loadWorkingSet(workingset.getCitationUuid());
469 } finally {
470 clearSession();
471 getView().getAddNewNameRegistrationButton().setEnabled(true);
472 }
473 }
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);
478 }
479
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());
484 }
485
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<>();
489
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
496
497 for(TaxonName name : namesToCheck){
498 if(name != null){
499 clearSession();
500 assocciateOrQueueBlockingRegistration(registrationOpt, name.getUuid());
501 }
502 }
503 } else if (event.getReason().equals(Reason.DELETE)){
504 //FIXME handle delete: need to remove blocking registrations?
505 }
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()));
508 }
509 }
510 }
511
512
513 /**
514 * Creates a new Registration for an exiting (previously published) name.
515 *
516 * @param event
517 * @throws RegistrationValidationException
518 */
519 @EventBusListenerMethod
520 public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event) throws RegistrationValidationException {
521
522 if(!event.isStart()){
523 return;
524 }
525
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;
530 try {
531 doReloadWorkingSet = registrationWorkflowService.createRegistrationforExistingName(workingset, typifiedName);
532 } finally {
533 clearSession();
534 refreshView(doReloadWorkingSet);
535 getView().getAddExistingNameRegistrationButton().setEnabled(false);
536 }
537 } else {
538 logger.error("Seletced name is NULL");
539 }
540
541 }
542
543 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
544 public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event) {
545
546 if(!checkFromOwnView(event)){
547 return;
548 }
549
550 RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
551
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());
563 }
564 } else {
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))
571 );
572 popup.getTypifiedNamesComboboxSelect().setEnabled(false);
573 if(event.hasSource()){
574 // propagate readonly state from source button to popup
575 popup.setReadOnly(event.getSource().isReadOnly());
576 }
577 nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
578 }
579 }
580
581 @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
582 public void onTypeDesignationWorkingsetAdd(TypeDesignationWorkingsetEditorAction event) {
583
584 if(!event.hasSource()){
585 return;
586 }
587
588 RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
589
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());
597 } else {
598 // case of registrations with a name in the nomenclatural act.
599 typifiedNameRef = new TypedEntityReference(TaxonName.class, registrationDTO.getNameRef().getUuid());
600 }
601
602 popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
603 popup.withDeleteButton(false);
604 popup.loadInEditor(new SpecimenTypeDesignationWorkingsetIds(
605 workingset.getCitationUuid(),
606 event.getRegistrationUuid(),
607 null,
608 typifiedNameRef.getUuid()
609 )
610 );
611 if(event.hasSource()){
612 // propagate readonly state from source component to popup
613 popup.setReadOnly(event.getSource().isReadOnly());
614 }
615 } else {
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>() {
621
622 @Override
623 public NameTypeDesignation createNewBean() {
624
625 TaxonName typifiedName = getRepo().getNameService().load(event.getTypifiedNameUuid(), Arrays.asList(new String[]{
626 "typeDesignations",
627 "homotypicalGroup",
628 "nomenclaturalSource.citation"
629 }));
630 NameTypeDesignation nameTypeDesignation = NameTypeDesignation.NewInstance();
631 nameTypeDesignation.getTypifiedNames().add(typifiedName);
632 return nameTypeDesignation;
633 }
634 });
635 popup.withDeleteButton(false);
636 popup.loadInEditor(NameTypeDesignationWorkingsetIds.forNewTypeDesignation(
637 registrationDTO.getCitationUuid(),
638 event.getTypifiedNameUuid()
639 )
640 );
641 popup.getTypifiedNamesComboboxSelect().setEnabled(false);
642 if(event.hasSource()){
643 // propagate readonly state from source component to popup
644 popup.setReadOnly(event.getSource().isReadOnly());
645 }
646 }
647 }
648
649 /**
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
656 * working set.
657 *
658 *
659 * @param event
660 * @throws RegistrationValidationException
661 */
662 @EventBusListenerMethod
663 public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event) {
664
665 if(!isFromOwnView(event)){
666 return;
667 }
668
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
673 }
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)){
678
679 Optional<Registration> registrationOpt = Optional.ofNullable(null);
680 UUID typeDesignationUuid = ((NameTypeDesignationPopupEditor)event.getPopup()).getBean().getUuid();
681 try {
682 clearSession();
683 registrationOpt = findRegistrationInContext(event.getPopup());
684 registrationOpt.ifPresent(reg -> {
685 registrationWorkflowService.addTypeDesignation(typeDesignationUuid, reg);
686 nameTypeDesignationPopupEditorRegistrationUUIDMap.remove(event.getPopup());
687 });
688
689 } finally {
690 clearSession();
691 }
692
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<>();
696
697 namesToCheck.add(nameTypeDesignationEditor.getTypeNameField().getValue());
698
699 for(TaxonName name : namesToCheck){
700 if(name != null){
701 assocciateOrQueueBlockingRegistration(registrationOpt, name.getUuid());
702 }
703
704 }
705
706 } else if(event.getReason().equals(Reason.CANCEL)){
707 // noting to do
708 }
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()));
711
712 }
713 // ignore other editors
714 }
715
716 private void assocciateOrQueueBlockingRegistration(Optional<Registration> registrationOpt, UUID nameUuid) {
717 registrationOpt.ifPresent(reg -> registrationWorkflowService.addBlockingRegistration(nameUuid, reg));
718 if(!registrationOpt.isPresent()){
719 // not present!
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.");
724 }
725 }
726 }
727
728
729 public void clearSession() {
730 getRepo().clearSession();
731 }
732
733 @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationWorkingSet.class)
734 public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent<RegistrationWorkingSet,?> event) {
735
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));
740 }
741 getView().openDetailsPopup("Validation Problems", messages);
742 }
743 }
744
745 @EventBusListenerMethod
746 public void onEntityChangeEvent(EntityChangeEvent event){
747
748 if(!isFromOwnView(event)){
749 return;
750 }
751
752 if(workingset == null){
753 return;
754 }
755 if(Reference.class.isAssignableFrom(event.getEntityType())){
756
757 if(workingset.getCitationUuid().equals(event.getEntityUuid())){
758 if(event.isRemovedType()){
759 viewEventBus.publish(EventScope.UI, this, new NavigationEvent(StartRegistrationViewBean.NAME));
760 } else {
761 refreshView(true);
762 }
763 }
764
765 } else
766 if(Registration.class.isAssignableFrom(event.getEntityType())){
767 if(workingset.getRegistrations().stream().anyMatch(reg -> reg.getUuid() == event.getEntityUuid())){
768 refreshView(true);
769 }
770 } else
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){
776 try {
777 clearSession();
778 // create a blocking registration
779 UUID taxonNameUUID = event.getEntityUuid();
780 Optional<Registration> registrationOpt = findRegistrationInContext(context);
781 assocciateOrQueueBlockingRegistration(registrationOpt, taxonNameUUID);
782 } finally {
783 clearSession();
784 }
785
786 } else {
787 // in case of creating a new name for a registration the parent view is the TaxonNamePopupEditor
788 // this is set
789 logger.debug("Non blocking registration, since a new name for a new registration has been created");
790 }
791 }
792 if(workingset.getRegistrationDTOs().stream().anyMatch(reg ->
793 reg.getTypifiedNameRef() != null
794 && reg.getTypifiedNameRef().getUuid().equals(event.getEntityUuid()))){
795 //refreshView(true);
796 }
797 } else
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()
802 )
803 )
804 ){
805 //refreshView(true);
806 }
807 }
808 }
809
810 public Optional<Registration> findRegistrationInContext(PopupView popupView) {
811 Stack<EditorActionContext>context = ((AbstractPopupEditor)popupView).getEditorActionContext();
812 return findRegistrationInContext(context);
813 }
814
815 /**
816 * Finds the Registration in the EditorContext stack
817 */
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);
826 }
827
828 Optional<Registration> regOpt;
829 if(registrationDTOOptional.isPresent()){
830 regOpt = Optional.of(registrationDTOOptional.get().registration());
831 } else {
832 regOpt = Optional.ofNullable(null);
833 }
834
835 return regOpt;
836 }
837
838 @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
839 public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
840
841 // FIXME check from own view!!!
842 if(getView() == null){
843 return;
844 }
845
846 UUID registrationUuid = event.getIdentifier();
847
848 RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
849 if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
850
851 Set<RegistrationDTO> blockingRegs;
852 if(regDto.registration().isPersited()){
853 blockingRegs = getWorkingSetService().loadBlockingRegistrations(registrationUuid);
854 } else {
855 blockingRegs = new HashSet<RegistrationDTO>(getWorkingSetService().makeDTOs(regDto.registration().getBlockedBy()));
856 }
857 getView().setBlockingRegistrations(registrationUuid, blockingRegs);
858 } else if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
859 getView().openDetailsPopup("Validation Problems", regDto.getValidationProblems());
860 }
861 }
862
863 @Override
864 public ICdmEntityUuidCacher getCache() {
865 return cache;
866 }
867
868 @Override
869 public void addRootEntity(CdmBase entity) {
870 rootEntities.add(entity);
871 cache.load(entity);
872 }
873
874 @Override
875 public Collection<CdmBase> getRootEntities() {
876 return rootEntities;
877 }
878
879 @Override
880 public void destroy() throws Exception {
881 super.destroy();
882 disposeCache();
883 }
884
885 @Override
886 public void disposeCache() {
887 cache.dispose();
888 }
889
890 public boolean canCreateNameRegistrationFor(TaxonName name) {
891 return registrationWorkflowService.canCreateNameRegistrationFor(workingset, name);
892 }
893
894 public boolean checkWokingsetContainsProtologe(TaxonName name) {
895 return registrationWorkflowService.checkWokingsetContainsProtologe(workingset, name);
896 }
897 }