Project

General

Profile

Download (39.5 KB) Statistics
| Branch: | Tag: | Revision:
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.utility.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.permission.CRUD;
58
import eu.etaxonomy.cdm.model.reference.Reference;
59
import eu.etaxonomy.cdm.ref.EntityReference;
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.SpecimenTypeDesignationWorkingsetPopupEditor;
86
import eu.etaxonomy.cdm.vaadin.view.name.TaxonNameEditorPresenter;
87
import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditor;
88
import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditorMode;
89
import eu.etaxonomy.cdm.vaadin.view.name.TypeDesignationWorkingsetEditorIdSet;
90
import eu.etaxonomy.cdm.vaadin.view.reference.ReferencePopupEditor;
91
import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
92
import eu.etaxonomy.vaadin.mvp.AbstractPresenter;
93
import eu.etaxonomy.vaadin.mvp.AbstractView;
94
import eu.etaxonomy.vaadin.mvp.BeanInstantiator;
95
import eu.etaxonomy.vaadin.ui.navigation.NavigationEvent;
96
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent;
97
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent.Reason;
98
import eu.etaxonomy.vaadin.ui.view.PopupView;
99

    
100
/**
101
 * @author a.kohlbecker
102
 * @since Mar 3, 2017
103
 *
104
 */
105
@SpringComponent
106
@ViewScope
107
public class RegistrationWorkingsetPresenter extends AbstractPresenter<RegistrationWorkingsetView> implements CachingPresenter {
108

    
109
    private static final Logger logger = Logger.getLogger(RegistrationWorkingsetPresenter.class);
110

    
111
    private static final long serialVersionUID = 1L;
112

    
113
    @Autowired
114
    private IRegistrationWorkingSetService regWorkingSetService;
115

    
116
    @Autowired
117
    private IRegistrationWorkflowService registrationWorkflowService;
118

    
119
    @Autowired
120
    private CdmFilterablePagingProviderFactory pagingProviderFactory;
121

    
122
    @Autowired
123
    private CdmBeanItemContainerFactory selectFieldFactory;
124

    
125
    @Autowired
126
    private CdmStore cdmStore;
127

    
128
    /**
129
     * @return the regWorkingSetService
130
     */
131
    public IRegistrationWorkingSetService getWorkingSetService() {
132
        return regWorkingSetService;
133
    }
134

    
135
    private RegistrationWorkingSet workingset;
136

    
137
    /**
138
     * 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.
139
     * There can always only be one popup editor for this purpose.
140
     */
141
    private TaxonNamePopupEditor newNameForRegistrationPopupEditor = null;
142

    
143
    /**
144
     * Contains
145
     */
146
    private List<Registration> newNameBlockingRegistrations = new ArrayList<>();
147

    
148
    /**
149
     * TODO is this still needed? The regitration UUID should be accessible in the popup editor context,
150
     * see findRegistrationInContext()
151
     */
152
    private Map<NameTypeDesignationPopupEditor, UUID> nameTypeDesignationPopupEditorRegistrationUUIDMap = new HashMap<>();
153

    
154

    
155
    private ICdmEntityUuidCacher cache;
156

    
157
    private Collection<CdmBase> rootEntities = new HashSet<>();
158

    
159

    
160
    public RegistrationWorkingsetPresenter() {
161
    }
162

    
163
    /**
164

    
165

    
166
    /**
167
     * @param doReload reload the workingset from the persistent storage.
168
     *  Workingsets which are not yet persisted are preserved.
169
     *
170
     */
171
    protected void refreshView(boolean doReload) {
172

    
173
        if(workingset == null){
174
            return; // nothing to do
175
        }
176
        if(doReload){
177
            if(logger.isDebugEnabled()){
178
                logger.debug("refreshView() - workingset:\n" + workingset.toString());
179
            }
180
            List<RegistrationDTO> unpersisted = new ArrayList<>();
181
            for(RegistrationDTO regDto : workingset.getRegistrationDTOs()){
182
                if(!regDto.registration().isPersited()){
183
                    unpersisted.add(regDto);
184
                }
185
            }
186
            loadWorkingSet(workingset.getCitationUuid());
187
            for(RegistrationDTO regDtoUnpersisted : unpersisted){
188
                if(!workingset.getRegistrationDTOs().stream().anyMatch(dto -> dto.getUuid().equals(regDtoUnpersisted.getUuid()))){
189
                    // only add if the regDtoUnpersisted has not been persisted meanwhile
190
                    try {
191
                        workingset.add(regDtoUnpersisted);
192
                    } catch (RegistrationValidationException e) {
193
                        // would never happen here //
194
                    }
195
                }
196
            }
197
            if(logger.isDebugEnabled()){
198
                logger.debug("refreshView() - workingset reloaded:\n" + workingset.toString());
199
            }
200
        }
201
        applyWorkingset();
202
    }
203

    
204
    /**
205
     * {@inheritDoc}
206
     */
207
    @Override
208
    public void handleViewEntered() {
209
        super.handleViewEntered();
210
        // TODO currently cannot specify type more precisely, see AbstractSelect
211
        // FIXME externalize into class file!!!!!!!!!!!!
212
        getView().setStatusComponentInstantiator(new RegistrationStatusFieldInstantiator<Object>(){
213

    
214
            private static final long serialVersionUID = 7099181280977511048L;
215

    
216
            @Override
217
            public AbstractField<Object> create(RegistrationDTO regDto) {
218

    
219
                // submitters have GrantedAuthorities like REGISTRATION(PREPARATION).[UPDATE]{ab4459eb-3b96-40ba-bfaa-36915107d59e}
220
                UserHelper userHelper = UserHelperAccess.userHelper().withCache(getCache());
221
                Set<RegistrationStatus> availableStatus = new HashSet<>();
222

    
223
                boolean canChangeStatus = userHelper.userHasPermission(regDto.registration(), CRUD.UPDATE);
224
                availableStatus.add(regDto.getStatus());
225
                if(canChangeStatus){
226
                    if(userHelper.userIsAdmin()){
227
                        availableStatus.addAll(Arrays.asList(RegistrationStatus.values()));
228
                    } else {
229
                        availableStatus.addAll(RegistrationStatusTransitions.possibleTransitions(regDto.getStatus()));
230
                    }
231
                }
232

    
233
                RegistrationStatusSelect select = new RegistrationStatusSelect(null, selectFieldFactory.buildEnumTermItemContainer(
234
                        RegistrationStatus.class,
235
                        availableStatus.toArray(new RegistrationStatus[availableStatus.size()]))
236
                        );
237
                select.setValue(regDto.getStatus());
238
                select.addValueChangeListener(e -> saveRegistrationStatusChange(regDto.getUuid(), e.getProperty().getValue()));
239
                select.setEnabled(canChangeStatus);
240
                select.setNullSelectionAllowed(false);
241
                return select;
242
            }
243

    
244

    
245
        });
246

    
247
        loadWorkingSet(getView().getCitationUuid());
248
        applyWorkingset();
249

    
250
    }
251

    
252
    private void applyWorkingset(){
253
         getView().setWorkingset(workingset);
254
        // PagingProviders and CacheGenerator for the existingNameCombobox
255
        activateComboboxes();
256
    }
257

    
258
    protected void activateComboboxes() {
259
        CdmTitleCacheCaptionGenerator<TaxonName> titleCacheGenerator = new CdmTitleCacheCaptionGenerator<TaxonName>();
260
        getView().getAddExistingNameCombobox().setCaptionGenerator(titleCacheGenerator);
261
        CdmFilterablePagingProvider<TaxonName, TaxonName> pagingProvider = pagingProviderFactory.taxonNamesWithoutOrthophicIncorrect();
262
        getView().getAddExistingNameCombobox().loadFrom(pagingProvider, pagingProvider, pagingProvider.getPageSize());
263
    }
264

    
265
    /**
266
     * @param referenceID
267
     */
268
    protected void loadWorkingSet(UUID referenceUuid) {
269

    
270
        try {
271
            workingset = getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid, true);
272
        } catch (RegistrationValidationException error) {
273
            logger.error(error);
274
            showErrorDialog("Validation Error", error.getMessage());
275
        }
276
        cache = new CdmTransientEntityAndUuidCacher(this);
277
        for(Registration registration : workingset.getRegistrations()) {
278
            addRootEntity(registration);
279
        }
280
    }
281

    
282
    /**
283
     * @param errorDialogCaption
284
     * @param errorMessage
285
     */
286
    public void showErrorDialog(String errorDialogCaption, String errorMessage) {
287
        Window errorDialog = new Window(errorDialogCaption);
288
        errorDialog.setModal(true);
289
        VerticalLayout subContent = new VerticalLayout();
290
        subContent.setMargin(true);
291
        errorDialog.setContent(subContent);
292
        subContent.addComponent(new Label(errorMessage));
293
        UI.getCurrent().addWindow(errorDialog);
294
    }
295

    
296
    private void saveRegistrationStatusChange(UUID uuid, Object value) {
297
        Registration reg = getRepo().getRegistrationService().load(uuid);
298
        if(reg == null){
299
            // registration was not yet persisted, ignore
300
            return;
301
        }
302
        if(value != null && value instanceof RegistrationStatus){
303
            if(!Objects.equals(value, reg.getStatus())){
304
                reg.updateStatusAndDate((RegistrationStatus)value);
305
                cdmStore.saveBean(reg, (AbstractView)getView());
306
                refreshView(true);
307
            }
308
        } else {
309
            // only log here as error
310
            logger.error("Ivalid attempt to set RegistrationStatus to " + Objects.toString(value.toString(), "NULL"));
311
        }
312
    }
313

    
314

    
315
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
316
    public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
317

    
318
        if(!checkFromOwnView(event)){
319
            return;
320
        }
321

    
322
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
323
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
324
        popup.loadInEditor(null);
325
    }
326

    
327
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
328
    public void onReferenceEditorActionEdit(ReferenceEditorAction event) {
329

    
330
        if(!checkFromOwnView(event)){
331
            return;
332
        }
333
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
334
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
335
        popup.withDeleteButton(true);
336
        popup.loadInEditor(event.getEntityUuid());
337
    }
338

    
339
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
340
    public void onRegistrationEditorAction(RegistrationEditorAction event) {
341

    
342
        if(!checkFromOwnView(event)){
343
            return;
344
        }
345

    
346
        RegistrationPopupEditor popup = openPopupEditor(RegistrationPopupEditor.class, event);
347
        popup.loadInEditor(event.getEntityUuid());
348
    }
349

    
350
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
351
    public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
352

    
353
        if(!checkFromOwnView(event)){
354
            return;
355
        }
356

    
357
        boolean isAddExistingNameRegistration = event.getTarget() != null && event.getTarget().equals(getView().getAddExistingNameCombobox());
358

    
359
        TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
360

    
361
        popup.setParentEditorActionContext(event.getContext(), event.getTarget());
362
        popup.withDeleteButton(!isAddExistingNameRegistration);
363
        TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
364
        if(isAddExistingNameRegistration){
365
            // allow saving even if the name parts are not valid
366
            // the user will need to fix this in a later step
367
            popup.disableMode(TaxonNamePopupEditorMode.VALIDATE_AGAINST_HIGHER_NAME_PART);
368
            getView().getAddExistingNameRegistrationButton().setEnabled(false);
369
            popup.addDetachListener(new DetachListener() {
370

    
371
                @Override
372
                public void detach(DetachEvent event) {
373
                    getView().getAddExistingNameRegistrationButton().setEnabled(true);
374

    
375
                }
376
            });
377
        }
378
        popup.loadInEditor(event.getEntityUuid());
379
        if(event.hasSource() && event.getSource().isReadOnly()){
380
            // avoid resetting readonly to false
381
            popup.setReadOnly(true);
382
        }
383

    
384
        boolean hasNomRef = popup.getBean().getNomenclaturalReference() != null;
385
        if(isAddExistingNameRegistration){
386
            popup.setAllFieldsReadOnly(true);
387
            if(!hasNomRef){
388
                // only allow editing the nomenclatural reference, all other
389
                // editing need to be done another way.
390
                // Otherwise we would need to be prepared for creating blocking registrations
391
                // in turn of creation, modification of related taxon names.
392
                popup.disableMode(TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY);
393
                popup.getNomReferenceCombobox().setReadOnly(false);
394
                popup.getNomenclaturalReferenceDetail().setReadOnly(false);
395
                popup.addStatusMessage("The chosen name needs to be completed before it can be used. "
396
                        + "Please add the nomenclatural reference and click on \"Save\" to proceed with entering the type of this name.");
397
            } else {
398
                popup.addStatusMessage("You are about to create a registration for this name. "
399
                        + "This editor is for reviewing the name only. Therefore, all fields have been switched to readonly state. "
400
                        + "Click on \"Save\" to proceed with entering the type of this name.");
401
            }
402
        }
403
    }
404

    
405

    
406
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
407
    public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
408

    
409
        if(!checkFromOwnView(event)){
410
            return;
411
        }
412

    
413
        getView().getAddNewNameRegistrationButton().setEnabled(false);
414
        if(newNameForRegistrationPopupEditor == null){
415
            TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
416
            newNameForRegistrationPopupEditor = popup;
417
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
418
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE,CRUD.DELETE));
419
            popup.withDeleteButton(true);
420
            popup.setCdmEntityInstantiator(new BeanInstantiator<TaxonName>() {
421

    
422
                @Override
423
                public TaxonName createNewBean() {
424
                    TaxonName newTaxonName = TaxonNameFactory.NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
425
                    newTaxonName.setNomenclaturalReference(getRepo().getReferenceService().load(workingset.getCitationUuid(), TaxonNameEditorPresenter.REFERENCE_INIT_STRATEGY ));
426
                    return newTaxonName;
427
                }
428
            });
429
            TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
430
            popup.loadInEditor(null);
431
        }
432
    }
433

    
434
    /**
435
     * Creates a new <code>Registration</code> for a new name that has just been edited
436
     * using a <code>TaxonNamePopupEditor</code>. The popup editor which has been opened to
437
     * edit the new name was remembered in <code>newNameForRegistrationPopupEditor</code>.
438
     * Any blocking registrations which have been created while editing the new name are
439
     * temporarily stored in <code>newNameBlockingRegistrations</code> until the registration
440
     * for the first name has been created. Additional new names are created for example
441
     * when a new name as basionym, replaced synonym, etc to the new name is created.
442
     * <p>
443
     * See also {@link #onTaxonNameEditorActionAdd(TaxonNameEditorAction)}).
444
     *
445
     * @param event
446
     * @throws RegistrationValidationException
447
     *      passes on the Exception which may come from onRegistrationWorkflowEventActionStart()
448
     */
449
    @EventBusListenerMethod
450
    public void onDoneWithTaxonnameEditor(DoneWithPopupEvent event) throws RegistrationValidationException {
451

    
452
        if(!isFromOwnView(event)){
453
            return;
454
        }
455

    
456
        if(event.getPopup() instanceof TaxonNamePopupEditor){
457

    
458
                EditorActionContext rootContext = editorActionContextRoot(event.getPopup());
459
                boolean isAddExistingNameRegistration = rootContext.getTargetField() != null && rootContext.getTargetField().equals(getView().getAddExistingNameCombobox());
460

    
461
                if(isAddExistingNameRegistration){
462
                    if(event.getReason().equals(Reason.SAVE)){
463
                    onRegistrationWorkflowEventActionStart(new RegistrationWorkingsetAction(workingset.getCitationUuid(),
464
                            RegistrationWorkingsetAction.Action.start));
465
                    }
466
                    // just ignore on CANCEL
467
                } else {
468
                    Optional<Registration> registrationOpt = Optional.ofNullable(null);
469
                    if(newNameForRegistrationPopupEditor != null && event.getPopup().equals(newNameForRegistrationPopupEditor)){
470
                        if(event.getReason().equals(Reason.SAVE)){
471
                            try {
472
                                TaxonName taxonName = newNameForRegistrationPopupEditor.getBean().cdmEntity();
473
                                registrationOpt = Optional.of(registrationWorkflowService.createRegistration(taxonName, newNameBlockingRegistrations));
474
                                loadWorkingSet(workingset.getCitationUuid());
475
                            } finally {
476
                                clearSession();
477
                                getView().getAddNewNameRegistrationButton().setEnabled(true);
478
                            }
479
                        }
480
                        // nullify and clear the memory on this popup editor in any case (SAVE, DELETE, CANCEL)
481
                        newNameForRegistrationPopupEditor = null;
482
                        newNameBlockingRegistrations.clear();
483
                        getView().getAddNewNameRegistrationButton().setEnabled(true);
484
                    }
485

    
486
                    if(event.getReason().equals(Reason.SAVE)){
487
                        if(!registrationOpt.isPresent()){
488
                            // no new registration has been created above, so there must be an existing one.
489
                            registrationOpt = findRegistrationInContext(event.getPopup());
490
                        }
491

    
492
                        // Check if the other names used in the context of the name are registered yet.
493
                        TaxonNamePopupEditor nameEditor = (TaxonNamePopupEditor)event.getPopup();
494
                        Set<TaxonName> namesToCheck = new HashSet<>();
495

    
496
                        namesToCheck.addAll(nameEditor.getBasionymComboboxSelect().getValue());
497
                        namesToCheck.addAll(nameEditor.getReplacedSynonymsComboboxSelect().getValue());
498
                        namesToCheck.add(nameEditor.getValidationField().getRelatedNameComboBox().getValue());
499
                        namesToCheck.add(nameEditor.getOrthographicVariantField().getRelatedNameComboBox().getValue());
500
                        // NOTE: according to https://dev.e-taxonomy.eu/redmine/issues/8049#note-2 we will not create blocking
501
                        // registrations for names in WeaklyRelatedEntityFields
502

    
503
                        for(TaxonName name : namesToCheck){
504
                            if(name != null){
505
                                clearSession();
506
                                assocciateOrQueueBlockingRegistration(registrationOpt, name.getUuid());
507
                            }
508
                        }
509
                    } else if (event.getReason().equals(Reason.DELETE)){
510
                        //FIXME handle delete: need to remove blocking registrations?
511
                    }
512
                    // always reload if the first editor is closed as the data might have been changed through any other sub-popupeditor
513
                    refreshView(isAtContextRoot(event.getPopup()));
514
                }
515
        }
516
    }
517

    
518

    
519
    /**
520
     * Creates a new Registration for an exiting (previously published) name.
521
     *
522
     * @param event
523
     * @throws RegistrationValidationException
524
     */
525
    @EventBusListenerMethod
526
    public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event) throws RegistrationValidationException {
527

    
528
        if(!event.isStart()){
529
            return;
530
        }
531

    
532
        getView().getAddExistingNameCombobox().commit(); // update the chosen value in the datasource
533
        TaxonName typifiedName = getView().getAddExistingNameCombobox().getValue();
534
        if(typifiedName != null){
535
            boolean doReloadWorkingSet = false;
536
            try {
537
                doReloadWorkingSet = registrationWorkflowService.createRegistrationforExistingName(workingset, typifiedName);
538
            } finally {
539
                clearSession();
540
                refreshView(doReloadWorkingSet);
541
                getView().getAddExistingNameRegistrationButton().setEnabled(false);
542
            }
543
        } else {
544
            logger.error("Seletced name is NULL");
545
        }
546

    
547
    }
548

    
549
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
550
    public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event) {
551

    
552
        if(!checkFromOwnView(event)){
553
            return;
554
        }
555

    
556
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET ){
557
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
558
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
559
            popup.withDeleteButton(true);
560
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
561
            if(event.hasSource()){
562
                // propagate readonly state from source button to popup
563
                popup.setReadOnly(event.getSource().isReadOnly());
564
            }
565
        } else {
566
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
567
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
568
            popup.withDeleteButton(true);
569
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
570
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
571
            if(event.hasSource()){
572
                // propagate readonly state from source button to popup
573
                popup.setReadOnly(event.getSource().isReadOnly());
574
            }
575
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
576
        }
577
    }
578

    
579
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
580
    public void onTypeDesignationWorkingsetAdd(TypeDesignationWorkingsetEditorAction event) {
581

    
582
        if(!event.hasSource()){
583
            return;
584
        }
585

    
586
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
587
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
588
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
589
            TypeDesignationWorkingsetEditorIdSet identifierSet;
590
            UUID typifiedNameUuid;
591

    
592
            RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
593
            EntityReference typifiedNameRef = registrationDTO.getTypifiedNameRef();
594
            if(typifiedNameRef != null){
595
                // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
596
                typifiedNameUuid = typifiedNameRef.getUuid();
597
            } else {
598
                // case of registrations with a name in the nomenclatural act.
599
                typifiedNameUuid = registrationDTO.getNameRef().getUuid();
600
            }
601

    
602
            identifierSet = new TypeDesignationWorkingsetEditorIdSet(
603
                    event.getRegistrationUuid(),
604
                    getView().getCitationUuid(), // FIXME This may pass the reference (e.g. Article) from RegistrationWorkingsetView
605
                    // to the TypeDesignationWorkingset even if the nomenclatural act is a Section !!! --> #9290
606
                    typifiedNameUuid
607
                    );
608
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
609
            popup.withDeleteButton(false);
610
            popup.loadInEditor(identifierSet);
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[]{"typeDesignations", "homotypicalGroup"}));
626
                    NameTypeDesignation nameTypeDesignation  = NameTypeDesignation.NewInstance();
627
                    nameTypeDesignation.getTypifiedNames().add(typifiedName);
628
                    return nameTypeDesignation;
629
                }
630
            });
631
            popup.withDeleteButton(false);
632
            popup.loadInEditor(null);
633
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
634
            if(event.hasSource()){
635
                // propagate readonly state from source component to popup
636
                popup.setReadOnly(event.getSource().isReadOnly());
637
            }
638
        }
639
    }
640

    
641
    /**
642
     * Performs final actions after a TypeDesignationEditor which has been
643
     * opened to add a TypeDesignation to a Registration object which was
644
     * created for an previously published name. Prior adding a typedesignation,
645
     * the according Registration object is dangling, that has no association to
646
     * any entity denoting an nomenclatural act which has a reference to a
647
     * publication. This means that the registration object is not in the
648
     * working set.
649
     *
650
     *
651
     * @param event
652
     * @throws RegistrationValidationException
653
     */
654
    @EventBusListenerMethod
655
    public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event) {
656

    
657
        if(!isFromOwnView(event)){
658
            return;
659
        }
660

    
661
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
662
            if(event.getReason().equals(Reason.SAVE)){
663
                // NOTE: adding the SpecimenTypeDesignations to the registration is done in the
664
                // SpecimenTypeDesignationWorkingSetServiceImpl.save(SpecimenTypeDesignationWorkingSetDTO dto) method
665
            }
666
            // always reload if the first editor is closed as the data might have been changed through any other sub-popupeditor
667
            refreshView(isAtContextRoot(event.getPopup()));
668
        } else if(event.getPopup() instanceof NameTypeDesignationPopupEditor){
669
            if(event.getReason().equals(Reason.SAVE)){
670

    
671
                Optional<Registration> registrationOpt = Optional.ofNullable(null);
672

    
673
                UUID typeDesignationUuid = ((NameTypeDesignationPopupEditor)event.getPopup()).getBean().getUuid();
674

    
675
                try {
676
                    clearSession();
677
                    registrationOpt = findRegistrationInContext(event.getPopup());
678
                    registrationOpt.ifPresent(reg -> {
679
                        registrationWorkflowService.addTypeDesignation(typeDesignationUuid, reg);
680
                        nameTypeDesignationPopupEditorRegistrationUUIDMap.remove(event.getPopup());
681
                        });
682

    
683
                } finally {
684
                    clearSession();
685
                }
686

    
687
                // Check if other names used in the context of the name are registered yet.
688
                NameTypeDesignationPopupEditor nameTypeDesignationEditor = (NameTypeDesignationPopupEditor)event.getPopup();
689
                Set<TaxonName> namesToCheck = new HashSet<>();
690

    
691
                namesToCheck.add(nameTypeDesignationEditor.getTypeNameField().getValue());
692

    
693
                for(TaxonName name : namesToCheck){
694
                    if(name != null){
695
                        assocciateOrQueueBlockingRegistration(registrationOpt, name.getUuid());
696
                    }
697

    
698
                }
699

    
700
            } else if(event.getReason().equals(Reason.CANCEL)){
701
                // noting to do
702
            }
703
            // always reload if the first editor is closed as the data might have been changed through any other sub-popupeditor
704
            refreshView(isAtContextRoot(event.getPopup()));
705

    
706
        }
707
        // ignore other editors
708
    }
709

    
710
    /**
711
     * @param registrationOpt
712
     * @param name
713
     */
714
    private void assocciateOrQueueBlockingRegistration(Optional<Registration> registrationOpt, UUID nameUuid) {
715
        registrationOpt.ifPresent(reg -> registrationWorkflowService.addBlockingRegistration(nameUuid, reg));
716
        if(!registrationOpt.isPresent()){
717
            // not present!
718
            Registration blockingRegistration = registrationWorkflowService.prepareBlockingRegistration(nameUuid);
719
            if(blockingRegistration != null){
720
                newNameBlockingRegistrations.add(blockingRegistration);
721
                logger.debug("Blocking registration created and queued for later association with the main registration.");
722
            }
723
        }
724
    }
725

    
726
    /**
727
     *
728
     */
729
    public void clearSession() {
730
        getRepo().clearSession();
731
    }
732

    
733

    
734
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationWorkingSet.class)
735
    public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent<RegistrationWorkingSet,?> event) {
736

    
737
        if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
738
            List<String> messages = new ArrayList<>();
739
            for(RegistrationDTO dto : workingset.getRegistrationDTOs()){
740
                dto.getValidationProblems().forEach(m -> messages.add(dto.getSummary() + ": " + m));
741
            }
742
            getView().openDetailsPopup("Validation Problems", messages);
743
        }
744
    }
745

    
746
    @EventBusListenerMethod
747
    public void onEntityChangeEvent(EntityChangeEvent event){
748

    
749
        if(!isFromOwnView(event)){
750
            return;
751
        }
752

    
753
        if(workingset == null){
754
            return;
755
        }
756
        if(Reference.class.isAssignableFrom(event.getEntityType())){
757

    
758
            if(workingset.getCitationUuid().equals(event.getEntityUuid())){
759
                if(event.isRemovedType()){
760
                    viewEventBus.publish(EventScope.UI, this, new NavigationEvent(StartRegistrationViewBean.NAME));
761
                } else {
762
                    refreshView(true);
763
                }
764
            }
765

    
766
        } else
767
        if(Registration.class.isAssignableFrom(event.getEntityType())){
768
            if(workingset.getRegistrations().stream().anyMatch(reg -> reg.getUuid() == event.getEntityUuid())){
769
                refreshView(true);
770
            }
771
        } else
772
        if(TaxonName.class.isAssignableFrom(event.getEntityType())){
773
            if(event.getType().equals(EntityChangeEvent.Type.CREATED)){
774
                Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getSourceView()).getEditorActionContext();
775
                EditorActionContext rootContext = context.get(0);
776
                if(rootContext.getParentView().equals(getView()) && event.getSourceView() != newNameForRegistrationPopupEditor){
777
                    try {
778
                        clearSession();
779
                        // create a blocking registration
780
                        UUID taxonNameUUID = event.getEntityUuid();
781
                        Optional<Registration> registrationOpt = findRegistrationInContext(context);
782
                        assocciateOrQueueBlockingRegistration(registrationOpt, taxonNameUUID);
783
                    } finally {
784
                        clearSession();
785
                    }
786

    
787
                } else {
788
                    // in case of creating a new name for a registration the parent view is the TaxonNamePopupEditor
789
                    // this is set
790
                    logger.debug("Non blocking registration, since a new name for a new registration has been created");
791
                }
792
            }
793
            if(workingset.getRegistrationDTOs().stream().anyMatch(reg ->
794
                reg.getTypifiedNameRef() != null
795
                && reg.getTypifiedNameRef().getUuid().equals(event.getEntityUuid()))){
796
                    //refreshView(true);
797
            }
798
        } else
799
        if(TypeDesignationBase.class.isAssignableFrom(event.getEntityType())){
800
            if(workingset.getRegistrationDTOs().stream().anyMatch(
801
                    reg -> reg.typeDesignations() != null && reg.typeDesignations().stream().anyMatch(
802
                            td -> td.getUuid() == event.getEntityUuid()
803
                            )
804
                        )
805
                    ){
806
                //refreshView(true);
807
            }
808
        }
809
    }
810

    
811

    
812

    
813
    public Optional<Registration> findRegistrationInContext(PopupView popupView) {
814
        Stack<EditorActionContext>context = ((AbstractPopupEditor)popupView).getEditorActionContext();
815
        return findRegistrationInContext(context);
816
    }
817

    
818
    /**
819
     * Finds the Registration in the EditorContext stack
820
     *
821
     * @param context
822
     * @return
823
     */
824
    public Optional<Registration> findRegistrationInContext(Stack<EditorActionContext> context) {
825
        EditorActionContext rootCtx = context.get(0);
826
        TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootCtx.getParentEntity();
827
        Optional<RegistrationDTO> registrationDTOOptional = workingset.getRegistrationDTO(regReference.getUuid());
828
        Optional<Registration> registrationOptional;
829
        if(!registrationDTOOptional.isPresent()){
830
            logger.debug("No RegistrationDTO in found rootCtx -> user is about to create a registration for a new name.");
831
            registrationOptional = Optional.ofNullable(null);
832
        }
833

    
834
        Optional<Registration> regOpt;
835
        if(registrationDTOOptional.isPresent()){
836
            regOpt = Optional.of(registrationDTOOptional.get().registration());
837
        } else {
838
            regOpt = Optional.ofNullable(null);
839
        }
840

    
841
        return regOpt;
842
    }
843

    
844
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
845
    public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
846

    
847
        // FIXME check from own view!!!
848
        if(getView() == null){
849
            return;
850
        }
851

    
852
        UUID registrationUuid = event.getIdentifier();
853

    
854
        RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
855
        if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
856

    
857
            Set<RegistrationDTO> blockingRegs;
858
            if(regDto.registration().isPersited()){
859
                blockingRegs = getWorkingSetService().loadBlockingRegistrations(registrationUuid);
860
            } else {
861
                blockingRegs = new HashSet<RegistrationDTO>(getWorkingSetService().makeDTOs(regDto.registration().getBlockedBy()));
862
            }
863
            getView().setBlockingRegistrations(registrationUuid, blockingRegs);
864
        } else if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
865
            getView().openDetailsPopup("Validation Problems", regDto.getValidationProblems());
866
        }
867
    }
868

    
869
    @Override
870
    public ICdmEntityUuidCacher getCache() {
871
        return cache;
872
    }
873

    
874
    @Override
875
    public void addRootEntity(CdmBase entity) {
876
        rootEntities.add(entity);
877
        cache.load(entity);
878
    }
879

    
880
    @Override
881
    public Collection<CdmBase> getRootEntities() {
882
        return rootEntities;
883
    }
884

    
885
    @Override
886
    public void destroy() throws Exception {
887
        super.destroy();
888
        disposeCache();
889
    }
890

    
891
    @Override
892
    public void disposeCache() {
893
        cache.dispose();
894
    }
895

    
896
    public boolean canCreateNameRegistrationFor(TaxonName name) {
897
        return registrationWorkflowService.canCreateNameRegistrationFor(workingset, name);
898
    }
899

    
900
    public boolean checkWokingsetContainsProtologe(TaxonName name) {
901
        return registrationWorkflowService.checkWokingsetContainsProtologe(workingset, name);
902
    }
903
}
(10-10/18)