a8a1eda71d5c5695a26a9a2ea860cf6db042adf1
[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.EnumSet;
14 import java.util.HashSet;
15 import java.util.List;
16 import java.util.Objects;
17 import java.util.Set;
18 import java.util.Stack;
19 import java.util.UUID;
20
21 import org.apache.log4j.Logger;
22 import org.hibernate.Session;
23 import org.hibernate.Transaction;
24 import org.springframework.beans.factory.annotation.Autowired;
25 import org.springframework.security.core.Authentication;
26 import org.springframework.transaction.TransactionStatus;
27 import org.vaadin.spring.events.EventScope;
28 import org.vaadin.spring.events.annotation.EventBusListenerMethod;
29
30 import com.vaadin.server.SystemError;
31 import com.vaadin.spring.annotation.SpringComponent;
32 import com.vaadin.spring.annotation.ViewScope;
33 import com.vaadin.ui.AbstractField;
34 import com.vaadin.ui.Button;
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.INameService;
41 import eu.etaxonomy.cdm.api.service.IRegistrationService;
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.RegistrationValidationException;
46 import eu.etaxonomy.cdm.api.service.idminter.IdentifierMinter.Identifier;
47 import eu.etaxonomy.cdm.api.service.idminter.RegistrationIdentifierMinter;
48 import eu.etaxonomy.cdm.api.service.name.TypeDesignationSetManager.TypeDesignationWorkingSetType;
49 import eu.etaxonomy.cdm.api.service.registration.IRegistrationWorkingSetService;
50 import eu.etaxonomy.cdm.api.utility.UserHelper;
51 import eu.etaxonomy.cdm.ext.common.ExternalServiceException;
52 import eu.etaxonomy.cdm.ext.registration.messages.IRegistrationMessageService;
53 import eu.etaxonomy.cdm.model.common.User;
54 import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
55 import eu.etaxonomy.cdm.model.name.Rank;
56 import eu.etaxonomy.cdm.model.name.Registration;
57 import eu.etaxonomy.cdm.model.name.RegistrationStatus;
58 import eu.etaxonomy.cdm.model.name.TaxonName;
59 import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
60 import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
61 import eu.etaxonomy.cdm.model.reference.Reference;
62 import eu.etaxonomy.cdm.model.reference.ReferenceType;
63 import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
64 import eu.etaxonomy.cdm.persistence.hibernate.permission.Operation;
65 import eu.etaxonomy.cdm.ref.EntityReference;
66 import eu.etaxonomy.cdm.ref.TypedEntityReference;
67 import eu.etaxonomy.cdm.service.CdmFilterablePagingProvider;
68 import eu.etaxonomy.cdm.service.CdmStore;
69 import eu.etaxonomy.cdm.service.UserHelperAccess;
70 import eu.etaxonomy.cdm.vaadin.component.CdmBeanItemContainerFactory;
71 import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationItem;
72 import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusFieldInstantiator;
73 import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusSelect;
74 import eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.EditorActionContext;
75 import eu.etaxonomy.cdm.vaadin.event.EditorActionTypeFilter;
76 import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
77 import eu.etaxonomy.cdm.vaadin.event.ReferenceEditorAction;
78 import eu.etaxonomy.cdm.vaadin.event.RegistrationEditorAction;
79 import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEvent;
80 import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEventEntityTypeFilter;
81 import eu.etaxonomy.cdm.vaadin.event.TaxonNameEditorAction;
82 import eu.etaxonomy.cdm.vaadin.event.TypeDesignationWorkingsetEditorAction;
83 import eu.etaxonomy.cdm.vaadin.event.registration.RegistrationWorkingsetAction;
84 import eu.etaxonomy.cdm.vaadin.permission.RegistrationCuratorRoleProbe;
85 import eu.etaxonomy.cdm.vaadin.theme.EditValoTheme;
86 import eu.etaxonomy.cdm.vaadin.ui.RegistrationUIDefaults;
87 import eu.etaxonomy.cdm.vaadin.util.CdmTitleCacheCaptionGenerator;
88 import eu.etaxonomy.cdm.vaadin.view.name.NameTypeDesignationPopupEditor;
89 import eu.etaxonomy.cdm.vaadin.view.name.SpecimenTypeDesignationWorkingsetPopupEditor;
90 import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditor;
91 import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditorMode;
92 import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditorView;
93 import eu.etaxonomy.cdm.vaadin.view.name.TypeDesignationWorkingsetEditorIdSet;
94 import eu.etaxonomy.cdm.vaadin.view.reference.ReferencePopupEditor;
95 import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
96 import eu.etaxonomy.vaadin.mvp.AbstractPresenter;
97 import eu.etaxonomy.vaadin.mvp.AbstractView;
98 import eu.etaxonomy.vaadin.mvp.BeanInstantiator;
99 import eu.etaxonomy.vaadin.ui.navigation.NavigationEvent;
100 import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent;
101 import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent.Reason;
102
103 /**
104 * @author a.kohlbecker
105 * @since Mar 3, 2017
106 *
107 */
108 @SpringComponent
109 @ViewScope
110 public class RegistrationWorkingsetPresenter extends AbstractPresenter<RegistrationWorkingsetView> {
111
112 private static final Logger logger = Logger.getLogger(RegistrationWorkingsetPresenter.class);
113
114 private static final List<String> REGISTRATION_INIT_STRATEGY = Arrays.asList(
115 "$",
116 "blockedBy",
117 "name.combinationAuthorship",
118 "name.exCombinationAuthorship",
119 "name.basionymAuthorship",
120 "name.exBasionymAuthorship"
121 );
122
123 private static final long serialVersionUID = 1L;
124
125 @Autowired
126 private IRegistrationWorkingSetService regWorkingSetService;
127
128 @Autowired
129 private RegistrationIdentifierMinter minter;
130
131 @Autowired
132 private IRegistrationMessageService messageService;
133
134 /**
135 * @return the regWorkingSetService
136 */
137 public IRegistrationWorkingSetService getWorkingSetService() {
138 return regWorkingSetService;
139 }
140
141 private RegistrationWorkingSet workingset;
142
143 private TaxonName newTaxonNameForRegistration = null;
144
145 private RegistrationDTO newRegistrationDTOWithExistingName;
146
147 private RegistrationDTO newNameTypeDesignationTarget;
148
149
150 /**
151 *
152 */
153 public RegistrationWorkingsetPresenter() {
154 }
155
156 /**
157 * Always create a new Store
158 *
159 * @return
160 */
161 protected CdmStore<Registration, IRegistrationService> getRegistrationStore(){
162 return new CdmStore<Registration, IRegistrationService>(getRepo(), getRepo().getRegistrationService());
163 }
164
165 /**
166 * Always create a new Store
167 *
168 * @return
169 */
170 protected CdmStore<TaxonName, INameService> getTaxonNameStore(){
171 return new CdmStore<TaxonName, INameService>(getRepo(), getRepo().getNameService());
172 }
173
174 /**
175 * Checks
176 * <ol>
177 * <li>if there is any registration for this name created in the current registration system</li>
178 * <li>Checks if the name belongs to the current workingset</li>
179 * </ol>
180 * If both checks are successful the method returns <code>true</code>.
181 */
182 public boolean canCreateRegistrationForName(TaxonName name) {
183 for(Registration reg : name.getRegistrations()){
184 if(minter.isFromOwnRegistration(reg.getIdentifier())){
185 return false;
186 }
187 }
188 Reference nomRef = name.getNomenclaturalReference();
189 UUID citationUuid = workingset.getCitationUuid();
190 // @formatter:off
191 return nomRef != null && (
192 // nomref matches
193 nomRef.getUuid().equals(citationUuid) ||
194 // nomref.inreference matches
195 (nomRef.getType() != null && nomRef.getType() == ReferenceType.Section && nomRef.getInReference() != null && nomRef.getInReference().getUuid().equals(citationUuid))
196 );
197 // @formatter:on
198 }
199
200
201 /**
202 * @param taxonNameId
203 * @return
204 */
205 protected Registration createNewRegistrationForName(UUID taxonNameUuid) {
206 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
207 // move into RegistrationWorkflowStateMachine
208 TransactionStatus txStatus = getRepo().startTransaction();
209
210 Identifier<String> identifiers = minter.mint();
211 if(identifiers.getIdentifier() == null){
212 throw new RuntimeException("RegistrationIdentifierMinter configuration incomplete.");
213 }
214 Registration reg = Registration.NewInstance(
215 identifiers.getIdentifier(),
216 identifiers.getLocalId(),
217 taxonNameUuid != null ? getRepo().getNameService().load(taxonNameUuid, Arrays.asList("nomenclaturalReference.inReference")) : null,
218 null);
219 Authentication authentication = currentSecurityContext().getAuthentication();
220 reg.setSubmitter((User)authentication.getPrincipal());
221 EntityChangeEvent event = getRegistrationStore().saveBean(reg, (AbstractView) getView());
222 UserHelperAccess.userHelper().createAuthorityForCurrentUser(Registration.class, event.getEntityUuid(), Operation.UPDATE, RegistrationStatus.PREPARATION.name());
223 getRepo().commitTransaction(txStatus);
224 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
225 return getRepo().getRegistrationService().load(event.getEntityUuid(), Arrays.asList(new String []{"blockedBy"}));
226 }
227
228 /**
229 * @param doReload TODO
230 *
231 */
232 protected void refreshView(boolean doReload) {
233 if(workingset == null){
234 return; // nothing to do
235 }
236 if(doReload){
237 loadWorkingSet(workingset.getCitationUuid());
238 }
239 applyWorkingset();
240 }
241
242 /**
243 * {@inheritDoc}
244 */
245 @Override
246 public void handleViewEntered() {
247 super.handleViewEntered();
248 // TODO currently cannot specify type more precisely, see AbstractSelect
249 // FIXME externalize into class file!!!!!!!!!!!!
250 getView().setStatusComponentInstantiator(new RegistrationStatusFieldInstantiator<Object>(){
251
252 private static final long serialVersionUID = 7099181280977511048L;
253
254 @Override
255 public AbstractField<Object> create(RegistrationDTO regDto) {
256
257 CdmBeanItemContainerFactory selectFieldFactory = new CdmBeanItemContainerFactory(getRepo());
258 // submitters have GrantedAuthorities like REGISTRATION(PREPARATION).[UPDATE]{ab4459eb-3b96-40ba-bfaa-36915107d59e}
259 UserHelper userHelper = UserHelperAccess.userHelper();
260 Set<RegistrationStatus> availableStatus = new HashSet<>();
261
262 boolean canChangeStatus = userHelper.userHasPermission(regDto.registration(), CRUD.UPDATE);
263 availableStatus.add(regDto.getStatus());
264 if(canChangeStatus){
265 if(userHelper.userIsAdmin()){
266 availableStatus.addAll(Arrays.asList(RegistrationStatus.values()));
267 } else {
268 availableStatus.addAll(RegistrationStatusTransitions.possibleTransitions(regDto.getStatus()));
269 }
270 }
271
272 RegistrationStatusSelect select = new RegistrationStatusSelect(null, selectFieldFactory.buildBeanItemContainer(
273 RegistrationStatus.class,
274 availableStatus.toArray(new RegistrationStatus[availableStatus.size()]))
275 );
276 select.addValueChangeListener(e -> saveRegistrationStatusChange(regDto.getUuid(), e.getProperty().getValue()));
277 select.setEnabled(canChangeStatus);
278 select.setNullSelectionAllowed(false);
279 return select;
280 }
281
282
283 });
284 loadWorkingSet(getView().getCitationUuid());
285 applyWorkingset();
286
287 }
288
289 private void applyWorkingset(){
290 getView().setWorkingset(workingset);
291 // PagingProviders and CacheGenerator for the existingNameCombobox
292 activateComboboxes();
293 // update the messages
294 updateMessages();
295 }
296
297 /**
298 *
299 */
300 protected void activateComboboxes() {
301 CdmFilterablePagingProvider<TaxonName, TaxonName> pagingProvider = new CdmFilterablePagingProvider<TaxonName, TaxonName>(
302 getRepo().getNameService());
303 pagingProvider.setInitStrategy(Arrays.asList("registrations", "nomenclaturalReference"));
304 CdmTitleCacheCaptionGenerator<TaxonName> titleCacheGenerator = new CdmTitleCacheCaptionGenerator<TaxonName>();
305 getView().getAddExistingNameCombobox().setCaptionGenerator(titleCacheGenerator);
306 getView().getAddExistingNameCombobox().loadFrom(pagingProvider, pagingProvider, pagingProvider.getPageSize());
307 }
308
309 /**
310 *
311 */
312 protected void updateMessages() {
313 User user = UserHelperAccess.userHelper().user();
314 for (UUID registrationUuid : getView().getRegistrationItemMap().keySet()) {
315 Button messageButton = getView().getRegistrationItemMap().get(registrationUuid).regItemButtons.getMessagesButton();
316
317 RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
318 try {
319 int messageCount = messageService.countActiveMessagesFor(regDto.registration(), user);
320
321 boolean activeMessages = messageCount > 0;
322 boolean currentUserIsSubmitter = regDto.getSubmitterUserName() != null && regDto.getSubmitterUserName().equals(UserHelperAccess.userHelper().userName());
323 boolean currentUserIsCurator = UserHelperAccess.userHelper().userIs(new RegistrationCuratorRoleProbe());
324 messageButton.setEnabled(false);
325 if(currentUserIsCurator){
326 if(currentUserIsSubmitter){
327 messageButton.setDescription("No point sending messages to your self.");
328 } else {
329 messageButton.setEnabled(true);
330 messageButton.setDescription("Open the messages dialog.");
331 }
332 } else {
333 messageButton.setDescription("Sorry, only a curator can start a conversation.");
334 }
335 if(activeMessages){
336 messageButton.setEnabled(true);
337 messageButton.addStyleName(EditValoTheme.BUTTON_HIGHLITE);
338 String who = currentUserIsSubmitter ? "curator" : "submitter";
339 messageButton.setDescription("The " + who + " is looking forward to your reply.");
340
341 }
342 } catch (ExternalServiceException e) {
343 messageButton.setComponentError(new SystemError(e.getMessage(), e));
344 }
345 }
346 }
347
348
349 /**
350 * @param referenceID
351 */
352 protected void loadWorkingSet(UUID referenceUuid) {
353 try {
354 workingset = getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid, true);
355 } catch (RegistrationValidationException error) {
356 logger.error(error);
357 Window errorDialog = new Window("Validation Error");
358 errorDialog.setModal(true);
359 VerticalLayout subContent = new VerticalLayout();
360 subContent.setMargin(true);
361 errorDialog.setContent(subContent);
362 subContent.addComponent(new Label(error.getMessage()));
363 UI.getCurrent().addWindow(errorDialog);
364 }
365 if(workingset == null || workingset.getCitationUuid() == null){
366 Reference citation = getRepo().getReferenceService().find(referenceUuid);
367 workingset = new RegistrationWorkingSet(citation);
368 }
369 }
370
371 private void saveRegistrationStatusChange(UUID uuid, Object value) {
372 Registration reg = getRepo().getRegistrationService().load(uuid);
373 if(value != null && value instanceof RegistrationStatus){
374 if(!Objects.equals(value, reg.getStatus())){
375 reg.setStatus((RegistrationStatus)value);
376 getRegistrationStore().saveBean(reg, (AbstractView)getView());
377 refreshView(true);
378 }
379 } else {
380 // only log here as error
381 logger.error("Ivalid attempt to set RegistrationStatus to " + Objects.toString(value.toString(), "NULL"));
382 }
383 }
384
385
386 @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
387 public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
388
389 if(!checkFromOwnView(event)){
390 return;
391 }
392
393 ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
394 popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
395 popup.loadInEditor(null);
396 }
397
398 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
399 public void onReferenceEditorActionEdit(ReferenceEditorAction event) {
400
401 if(!checkFromOwnView(event)){
402 return;
403 }
404 ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
405 popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
406 popup.withDeleteButton(true);
407 popup.loadInEditor(event.getEntityUuid());
408 }
409
410 @EventBusListenerMethod
411 public void onDoneWithReferencePopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
412 if(event.getPopup() instanceof ReferencePopupEditor){
413 if(event.getReason().equals(Reason.SAVE)){
414 refreshView(true);
415 }
416 }
417 }
418
419 @EventBusListenerMethod
420 public void onDoneWithSpecimenTypeDesignationWorkingsetPopupEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
421 if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
422 if(event.getReason().equals(Reason.SAVE)){
423 refreshView(true);
424 }
425 }
426 }
427
428 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
429 public void onRegistrationEditorAction(RegistrationEditorAction event) {
430
431 if(!checkFromOwnView(event)){
432 return;
433 }
434
435 RegistrationPopupEditor popup = openPopupEditor(RegistrationPopupEditor.class, event);
436 popup.loadInEditor(event.getEntityUuid());
437 }
438
439 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
440 public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
441
442 if(!checkFromOwnView(event)){
443 return;
444 }
445
446 TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
447 popup.setParentEditorActionContext(event.getContext());
448 popup.withDeleteButton(true);
449 configureTaxonNameEditor(popup);
450 popup.loadInEditor(event.getEntityUuid());
451 if(event.hasSource() && event.getSource().isReadOnly()){
452 // avoid resetting readonly to false
453 popup.setReadOnly(true);
454 }
455
456 }
457
458
459 @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
460 public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
461
462 if(!checkFromOwnView(event)){
463 return;
464 }
465
466 newTaxonNameForRegistration = TaxonNameFactory.NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
467 newTaxonNameForRegistration.setNomenclaturalReference(getRepo().getReferenceService().find(workingset.getCitationUuid()));
468 EntityChangeEvent nameSaveEvent = getTaxonNameStore().saveBean(newTaxonNameForRegistration, (AbstractView) getView());
469 newTaxonNameForRegistration = getRepo().getNameService().find(nameSaveEvent.getEntityUuid());
470 TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
471 popup.setParentEditorActionContext(event.getContext());
472 popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE,CRUD.DELETE));
473 popup.withDeleteButton(true);
474 configureTaxonNameEditor(popup);
475 popup.loadInEditor(newTaxonNameForRegistration.getUuid());
476 }
477
478 /**
479 * TODO consider putting this into a Configurer Bean per UIScope.
480 * In the configurator bean this methods popup papamerter should be of the type
481 * AbstractPopupEditor
482 *
483 * @param popup
484 */
485 protected void configureTaxonNameEditor(TaxonNamePopupEditorView popup) {
486 popup.enableMode(TaxonNamePopupEditorMode.AUTOFILL_AUTHORSHIP_DATA);
487 popup.enableMode(TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY);
488 popup.enableMode(TaxonNamePopupEditorMode.VALIDATE_AGAINST_HIGHER_NAME_PART);
489 // popup.enableMode(TaxonNamePopupEditorMode.REQUIRE_NOMENCLATURALREFERENCE);
490 }
491
492 /**
493 * Creates a new <code>Registration</code> for a new name that has just been edited
494 * using the <code>TaxonNamePopupEditor</code>. The new name was previously created
495 * in this presenter as <code>newTaxonNameForRegistration</code> (see {@link #onTaxonNameEditorActionAdd(TaxonNameEditorAction)})
496 * and is either filled with data (<code>Reason.SAVE</code>) or it is still empty
497 * (<code>Reason.CANCEL</code>).
498 *
499 *
500 * @param event
501 * @throws RegistrationValidationException
502 */
503 @EventBusListenerMethod
504 public void onDoneWithTaxonnameEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
505 if(event.getPopup() instanceof TaxonNamePopupEditor){
506 TransactionStatus txStatus = getRepo().startTransaction();
507 if(event.getReason().equals(Reason.SAVE)){
508 if(newTaxonNameForRegistration != null){
509 UUID taxonNameUuid = newTaxonNameForRegistration.getUuid();
510 getRepo().getSession().refresh(newTaxonNameForRegistration);
511 Registration reg = createNewRegistrationForName(taxonNameUuid);
512 // reload workingset into current session
513 loadWorkingSet(workingset.getCitationUuid());
514 workingset.add(reg);
515 }
516 refreshView(true);
517 } else if(event.getReason().equals(Reason.CANCEL)){
518 if(newTaxonNameForRegistration != null){
519 // clean up
520 getTaxonNameStore().deleteBean(newTaxonNameForRegistration, (AbstractView) getView());
521 }
522 }
523 getRepo().commitTransaction(txStatus);
524 newTaxonNameForRegistration = null;
525 }
526 }
527
528
529 /**
530 * Creates a new Registration for an exiting (previously published name).
531 *
532 * @param event
533 * @throws RegistrationValidationException
534 */
535 @EventBusListenerMethod
536 public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event) throws RegistrationValidationException {
537
538 if(!event.isStart()){
539 return;
540 }
541
542 getView().getAddExistingNameCombobox().commit(); // update the chosen value in the datasource
543 TaxonName typifiedName = getView().getAddExistingNameCombobox().getValue();
544 if(typifiedName != null){
545 boolean reloadWorkingSet = false;
546 Reference citation = getRepo().getReferenceService().find(workingset.getCitationUuid());
547 // here we completely ignore the ExistingNameRegistrationType since the user should not have the choice
548 // to create a typification only registration in the working (publication) set which contains
549 // the protologe. This is known from the nomenclatural reference.
550 if(canCreateRegistrationForName(typifiedName)){
551 // the citation which is the base for workingset contains the protologe of the name and the name hast not
552 // been registered before:
553 // create a registration for the name and the first typifications
554 Registration newRegistrationWithExistingName = createNewRegistrationForName(typifiedName.getUuid());
555 newRegistrationDTOWithExistingName = new RegistrationDTO(newRegistrationWithExistingName, typifiedName, citation);
556 reloadWorkingSet = true;
557 } else {
558 // create a typification only registration
559 // FIXME: this should not be possible if the names protologue is in the workingset --> #
560 Registration newRegistrationWithExistingName = createNewRegistrationForName(null);
561 newRegistrationDTOWithExistingName = new RegistrationDTO(newRegistrationWithExistingName, typifiedName, citation);
562 }
563 workingset.add(newRegistrationDTOWithExistingName);
564 // tell the view to update the workingset
565 refreshView(reloadWorkingSet);
566 getView().getAddExistingNameRegistrationButton().setEnabled(false);
567 if(newRegistrationDTOWithExistingName.registration().getName() == null){
568 getView().getAddExistingNameCombobox().setEnabled(false);
569 getView().getAddNewNameRegistrationButton().setEnabled(false);
570 getView().getAddNewNameRegistrationButton().setDescription("You first need to add a type designation to the previously created registration.");
571 getView().getAddExistingNameCombobox().setDescription("You first need to add a type designation to the previously created registration.");
572 getView().getAddExistingNameRegistrationButton().setDescription("You first need to add a type designation to the previously created registration.");
573 }
574 } else {
575 logger.error("Seletced name is NULL");
576 }
577
578 }
579
580
581 @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
582 public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event) {
583
584 if(!checkFromOwnView(event)){
585 return;
586 }
587
588 if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET ){
589 SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
590 popup.setParentEditorActionContext(event.getContext());
591 popup.withDeleteButton(true);
592 popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
593 if(event.hasSource()){
594 // propagate readonly state from source button to popup
595 popup.setReadOnly(event.getSource().isReadOnly());
596 }
597 } else {
598 NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
599 popup.setParentEditorActionContext(event.getContext());
600 popup.withDeleteButton(true);
601 popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
602
603 popup.getCitationCombobox().setEnabled(false);
604 popup.getTypifiedNamesComboboxSelect().setEnabled(false);
605
606 if(event.hasSource()){
607 // propagate readonly state from source button to popup
608 popup.setReadOnly(event.getSource().isReadOnly());
609 }
610 newNameTypeDesignationTarget = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
611 }
612 }
613
614 @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
615 public void onTypeDesignationWorkingsetAdd(TypeDesignationWorkingsetEditorAction event) {
616
617 if(!event.hasSource()){
618 return;
619 }
620
621 if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
622 SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
623 popup.setParentEditorActionContext(event.getContext());
624 TypeDesignationWorkingsetEditorIdSet identifierSet;
625 UUID typifiedNameUuid;
626 if(newRegistrationDTOWithExistingName != null){
627 typifiedNameUuid = newRegistrationDTOWithExistingName.getTypifiedNameRef().getUuid();
628 } else {
629 RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
630 EntityReference typifiedNameRef = registrationDTO.getTypifiedNameRef();
631 if(typifiedNameRef != null){
632 // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
633 typifiedNameUuid = typifiedNameRef.getUuid();
634 } else {
635 // case of registrations with a name in the nomenclatural act.
636 typifiedNameUuid = registrationDTO.getNameRef().getUuid();
637 }
638 }
639 identifierSet = new TypeDesignationWorkingsetEditorIdSet(
640 event.getRegistrationUuid(),
641 getView().getCitationUuid(),
642 typifiedNameUuid
643 );
644 popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
645 popup.loadInEditor(identifierSet);
646 popup.withDeleteButton(true);
647 if(event.hasSource()){
648 // propagate readonly state from source component to popup
649 popup.setReadOnly(event.getSource().isReadOnly());
650 }
651 } else {
652 NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
653 popup.setParentEditorActionContext(event.getContext());
654 popup.withDeleteButton(true);
655 popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
656 newNameTypeDesignationTarget = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
657 popup.setBeanInstantiator(new BeanInstantiator<NameTypeDesignation>() {
658
659 @Override
660 public NameTypeDesignation createNewBean() {
661
662 TaxonName typifiedName = getRepo().getNameService().load(event.getTypifiedNameUuid(), Arrays.asList(new String[]{"typeDesignations", "homotypicalGroup"}));
663 NameTypeDesignation nameTypeDesignation = NameTypeDesignation.NewInstance();
664 nameTypeDesignation.setCitation(newNameTypeDesignationTarget.getCitation());
665 nameTypeDesignation.getTypifiedNames().add(typifiedName);
666 return nameTypeDesignation;
667 }
668 });
669 popup.loadInEditor(null);
670 popup.getCitationCombobox().setEnabled(false);
671 popup.getTypifiedNamesComboboxSelect().setEnabled(false);
672 if(event.hasSource()){
673 // propagate readonly state from source component to popup
674 popup.setReadOnly(event.getSource().isReadOnly());
675 }
676 }
677 }
678
679 /**
680 * Performs final actions after a TypeDesignationEditor which has been
681 * opened to add a TypeDesignation to a Registration object which was
682 * created for an previously published name. Prior adding a typedesignation,
683 * the according Registration object is dangling, that has no association to
684 * any entity denoting an nomenclatural act which has a reference to a
685 * publication. This means that the registration object is not in the
686 * working set.
687 *
688 *
689 * @param event
690 * @throws RegistrationValidationException
691 */
692 @EventBusListenerMethod
693 public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event) throws RegistrationValidationException{
694 if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
695 if(event.getReason().equals(Reason.SAVE)){
696 refreshView(true);
697 } else if(event.getReason().equals(Reason.CANCEL)){
698 // noting to do
699 }
700 newRegistrationDTOWithExistingName = null;
701 } else if(event.getPopup() instanceof NameTypeDesignationPopupEditor){
702 if(event.getReason().equals(Reason.SAVE)){
703 UUID uuid = ((NameTypeDesignationPopupEditor)event.getPopup()).getBean().getUuid();
704
705 Session session = getRepo().getSessionFactory().openSession();
706 Transaction txstate = session.beginTransaction();
707 TypeDesignationBase<?> nameTypeDesignation = getRepo().getNameService().loadTypeDesignation(uuid, Arrays.asList(""));
708 // only load the typeDesignations with the registration so that the typified name can not be twice in the session
709 // otherwise multiple representation problems might occur
710 Registration registration = getRepo().getRegistrationService().load(newNameTypeDesignationTarget.getUuid(), Arrays.asList("typeDesignations"));
711 registration.getTypeDesignations().add(nameTypeDesignation);
712 session.merge(registration);
713 txstate.commit();
714 session.close();
715
716 refreshView(true);
717 } else if(event.getReason().equals(Reason.CANCEL)){
718 // noting to do
719 }
720 newNameTypeDesignationTarget = null;
721 }
722 // ignore other editors
723 }
724
725
726 @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationWorkingSet.class)
727 public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent<RegistrationWorkingSet,?> event) {
728
729 if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
730 List<String> messages = new ArrayList<>();
731 for(RegistrationDTO dto : workingset.getRegistrationDTOs()){
732 dto.getValidationProblems().forEach(m -> messages.add(dto.getSummary() + ": " + m));
733 }
734 getView().openDetailsPopup("Validation Problems", messages);
735 }
736 }
737
738 @EventBusListenerMethod
739 public void onEntityChangeEvent(EntityChangeEvent event){
740
741 if(workingset == null){
742 return;
743 }
744 if(Reference.class.isAssignableFrom(event.getEntityType())){
745
746 if(workingset.getCitationUuid().equals(event.getEntityUuid())){
747 if(event.isRemovedType()){
748 viewEventBus.publish(EventScope.UI, this, new NavigationEvent(StartRegistrationViewBean.NAME));
749 } else {
750 refreshView(true);
751 }
752 }
753
754 } else
755 if(Registration.class.isAssignableFrom(event.getEntityType())){
756 if(workingset.getRegistrations().stream().anyMatch(reg -> reg.getUuid() == event.getEntityUuid())){
757 refreshView(true);
758 }
759 } else
760 if(TaxonName.class.isAssignableFrom(event.getEntityType()) && isFromOwnView(event)){
761 if(event.getType().equals(EntityChangeEvent.Type.CREATED)){
762 // new name! create a blocking registration
763 Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getSourceView()).getEditorActionContext();
764 EditorActionContext rootContext = context.get(0);
765 if(rootContext.getParentView().equals(getView())){
766 Registration blockingRegistration = createNewRegistrationForName(event.getEntityUuid());
767 TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootContext.getParentEntity();
768 Registration registration = getRepo().getRegistrationService().load(regReference.getUuid(), REGISTRATION_INIT_STRATEGY);
769 registration.getBlockedBy().add(blockingRegistration);
770 getRepo().getRegistrationService().saveOrUpdate(registration);
771 logger.debug("Blocking registration created");
772 } else {
773 logger.debug("Non blocking registration, since a new name for a new registration has been created");
774 }
775 }
776 if(workingset.getRegistrationDTOs().stream().anyMatch(reg ->
777 reg.getTypifiedNameRef() != null
778 && reg.getTypifiedNameRef().getUuid().equals(event.getEntityUuid()))){
779 refreshView(true);
780 }
781 } else
782 if(TypeDesignationBase.class.isAssignableFrom(event.getEntityType())){
783 if(workingset.getRegistrationDTOs().stream().anyMatch(
784 reg -> reg.typeDesignations() != null && reg.typeDesignations().stream().anyMatch(
785 td -> td.getUuid() == event.getEntityUuid()
786 )
787 )
788 ){
789 refreshView(true);
790 }
791 }
792 }
793
794
795 @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
796 public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
797
798 // FIXME check from own view!!!
799 if(getView() == null){
800 return;
801 }
802
803 UUID registrationUuid = event.getIdentifier();
804
805 RegistrationDTO regDto = getWorkingSetService().loadDtoByUuid(registrationUuid);
806 if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
807
808 Set<RegistrationDTO> blockingRegs = getWorkingSetService().loadBlockingRegistrations(registrationUuid);
809 getView().setBlockingRegistrations(registrationUuid, blockingRegs);
810 } else if(event.getProperty().equals(RegistrationItem.MESSAGES)){
811
812 RegistrationMessagesPopup popup = openPopupEditor(RegistrationMessagesPopup.class, null);
813 popup.loadMessagesFor(regDto.getUuid());
814
815 } else if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
816 getView().openDetailsPopup("Validation Problems", regDto.getValidationProblems());
817 }
818
819
820 }
821
822 }