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.logging.log4j.LogManager;
26
import org.apache.logging.log4j.Logger;
27
import org.springframework.beans.factory.annotation.Autowired;
28
import org.vaadin.spring.events.EventScope;
29
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
30

    
31
import com.vaadin.server.ClientConnector.DetachEvent;
32
import com.vaadin.server.ClientConnector.DetachListener;
33
import com.vaadin.spring.annotation.SpringComponent;
34
import com.vaadin.spring.annotation.ViewScope;
35
import com.vaadin.ui.AbstractField;
36
import com.vaadin.ui.Label;
37
import com.vaadin.ui.UI;
38
import com.vaadin.ui.VerticalLayout;
39
import com.vaadin.ui.Window;
40

    
41
import eu.etaxonomy.cdm.api.service.config.RegistrationStatusTransitions;
42
import eu.etaxonomy.cdm.api.service.dto.RegistrationDTO;
43
import eu.etaxonomy.cdm.api.service.dto.RegistrationWorkingSet;
44
import eu.etaxonomy.cdm.api.service.exception.TypeDesignationSetException;
45
import eu.etaxonomy.cdm.api.service.name.TypeDesignationSet.TypeDesignationSetType;
46
import eu.etaxonomy.cdm.api.service.registration.IRegistrationWorkingSetService;
47
import eu.etaxonomy.cdm.api.util.UserHelper;
48
import eu.etaxonomy.cdm.cache.CdmTransientEntityWithUuidCacher;
49
import eu.etaxonomy.cdm.model.ICdmEntityUuidCacher;
50
import eu.etaxonomy.cdm.model.common.CdmBase;
51
import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
52
import eu.etaxonomy.cdm.model.name.Rank;
53
import eu.etaxonomy.cdm.model.name.Registration;
54
import eu.etaxonomy.cdm.model.name.RegistrationStatus;
55
import eu.etaxonomy.cdm.model.name.TaxonName;
56
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
57
import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
58
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
59
import eu.etaxonomy.cdm.model.permission.CRUD;
60
import eu.etaxonomy.cdm.model.reference.Reference;
61
import eu.etaxonomy.cdm.ref.TypedEntityReference;
62
import eu.etaxonomy.cdm.service.CdmBeanItemContainerFactory;
63
import eu.etaxonomy.cdm.service.CdmFilterablePagingProvider;
64
import eu.etaxonomy.cdm.service.CdmFilterablePagingProviderFactory;
65
import eu.etaxonomy.cdm.service.CdmStore;
66
import eu.etaxonomy.cdm.service.IRegistrationWorkflowService;
67
import eu.etaxonomy.cdm.service.UserHelperAccess;
68
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationItem;
69
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusFieldInstantiator;
70
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusSelect;
71
import eu.etaxonomy.cdm.vaadin.event.EditorActionContext;
72
import eu.etaxonomy.cdm.vaadin.event.EditorActionTypeFilter;
73
import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
74
import eu.etaxonomy.cdm.vaadin.event.ReferenceEditorAction;
75
import eu.etaxonomy.cdm.vaadin.event.RegistrationEditorAction;
76
import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEvent;
77
import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEventEntityTypeFilter;
78
import eu.etaxonomy.cdm.vaadin.event.TaxonNameEditorAction;
79
import eu.etaxonomy.cdm.vaadin.event.TypeDesignationSetEditorAction;
80
import eu.etaxonomy.cdm.vaadin.event.registration.RegistrationWorkingsetAction;
81
import eu.etaxonomy.cdm.vaadin.ui.RegistrationUIDefaults;
82
import eu.etaxonomy.cdm.vaadin.ui.config.TaxonNamePopupEditorConfig;
83
import eu.etaxonomy.cdm.vaadin.util.CdmTitleCacheCaptionGenerator;
84
import eu.etaxonomy.cdm.vaadin.view.name.CachingPresenter;
85
import eu.etaxonomy.cdm.vaadin.view.name.NameTypeDesignationPopupEditor;
86
import eu.etaxonomy.cdm.vaadin.view.name.NameTypeDesignationSetIds;
87
import eu.etaxonomy.cdm.vaadin.view.name.SpecimenTypeDesignationSetIds;
88
import eu.etaxonomy.cdm.vaadin.view.name.SpecimenTypeDesignationSetPopupEditor;
89
import eu.etaxonomy.cdm.vaadin.view.name.TaxonNameEditorPresenter;
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.reference.ReferencePopupEditor;
93
import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
94
import eu.etaxonomy.vaadin.mvp.AbstractPresenter;
95
import eu.etaxonomy.vaadin.mvp.AbstractView;
96
import eu.etaxonomy.vaadin.mvp.BeanInstantiator;
97
import eu.etaxonomy.vaadin.ui.navigation.NavigationEvent;
98
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent;
99
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent.Reason;
100
import eu.etaxonomy.vaadin.ui.view.PopupView;
101

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

    
110
    private static final long serialVersionUID = 2618456456539802265L;
111

    
112
    private static final Logger logger = LogManager.getLogger();
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 (TypeDesignationSetException 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().getExistingNameCombobox().setCaptionGenerator(titleCacheGenerator);
255
        CdmFilterablePagingProvider<TaxonName, TaxonName> pagingProvider = pagingProviderFactory.taxonNamesWithoutOrthophicIncorrect();
256
        getView().getExistingNameCombobox().loadFrom(pagingProvider, pagingProvider, pagingProvider.getPageSize());
257
    }
258

    
259
    protected void loadWorkingSet(UUID referenceUuid) {
260

    
261
        try {
262
            workingset = getWorkingSetService().loadWorkingSetByReferenceUuid(referenceUuid, true);
263
        } catch (TypeDesignationSetException error) {
264
            logger.error(error);
265
            showErrorDialog("Validation Error", error.getMessage());
266
        }
267
        cache = new CdmTransientEntityWithUuidCacher(this);
268
        for(Registration registration : workingset.getRegistrations()) {
269
            addRootEntity(registration);
270
        }
271
    }
272

    
273
    public void showErrorDialog(String errorDialogCaption, String errorMessage) {
274
        Window errorDialog = new Window(errorDialogCaption);
275
        errorDialog.setModal(true);
276
        VerticalLayout subContent = new VerticalLayout();
277
        subContent.setMargin(true);
278
        errorDialog.setContent(subContent);
279
        subContent.addComponent(new Label(errorMessage));
280
        UI.getCurrent().addWindow(errorDialog);
281
    }
282

    
283
    private void saveRegistrationStatusChange(UUID uuid, Object value) {
284
        Registration reg = getRepo().getRegistrationService().load(uuid);
285
        if(reg == null){
286
            // registration was not yet persisted, ignore
287
            return;
288
        }
289
        if(value != null && value instanceof RegistrationStatus){
290
            if(!Objects.equals(value, reg.getStatus())){
291
                reg.updateStatusAndDate((RegistrationStatus)value);
292
                cdmStore.saveBean(reg, (AbstractView)getView());
293
                refreshView(true);
294
            }
295
        } else {
296
            // only log here as error
297
            logger.error("Ivalid attempt to set RegistrationStatus to " + Objects.toString(value.toString(), "NULL"));
298
        }
299
    }
300

    
301
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
302
    public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
303

    
304
        if(!checkFromOwnView(event)){
305
            return;
306
        }
307

    
308
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
309
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
310
        popup.loadInEditor(null);
311
    }
312

    
313
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
314
    public void onReferenceEditorActionEdit(ReferenceEditorAction event) {
315

    
316
        if(!checkFromOwnView(event)){
317
            return;
318
        }
319
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
320
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
321
        popup.withDeleteButton(true);
322
        popup.loadInEditor(event.getEntityUuid());
323
    }
324

    
325
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
326
    public void onRegistrationEditorAction(RegistrationEditorAction event) {
327

    
328
        if(!checkFromOwnView(event)){
329
            return;
330
        }
331

    
332
        RegistrationPopupEditor popup = openPopupEditor(RegistrationPopupEditor.class, event);
333
        popup.loadInEditor(event.getEntityUuid());
334
    }
335

    
336
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
337
    public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
338

    
339
        if(!checkFromOwnView(event)){
340
            return;
341
        }
342

    
343
        boolean isAddExistingNameRegistration = event.getTarget() != null && event.getTarget().equals(getView().getExistingNameCombobox());
344

    
345
        TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
346

    
347
        popup.setParentEditorActionContext(event.getContext(), event.getTarget());
348
        popup.withDeleteButton(!isAddExistingNameRegistration);
349
        TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
350
        if(isAddExistingNameRegistration){
351
            // allow saving even if the name parts are not valid
352
            // the user will need to fix this in a later step
353
            popup.disableMode(TaxonNamePopupEditorMode.VALIDATE_AGAINST_HIGHER_NAME_PART);
354
            getView().getAddExistingNameRegistrationButton().setEnabled(false);
355
            popup.addDetachListener(new DetachListener() {
356
                private static final long serialVersionUID = 836224587615950302L;
357

    
358
                @Override
359
                public void detach(DetachEvent event) {
360
                    getView().getAddExistingNameRegistrationButton().setEnabled(true);
361

    
362
                }
363
            });
364
        }
365
        popup.loadInEditor(event.getEntityUuid());
366
        if(event.hasSource() && event.getSource().isReadOnly()){
367
            // avoid resetting readonly to false
368
            logger.error("Set popup to readonly as event source is read only");
369
            popup.setReadOnly(true);
370
        }
371

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

    
393
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
394
    public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
395

    
396
        if(!checkFromOwnView(event)){
397
            return;
398
        }
399

    
400
        getView().getAddNewNameRegistrationButton().setEnabled(false);
401
        if(newNameForRegistrationPopupEditor == null){
402
            TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
403
            newNameForRegistrationPopupEditor = popup;
404
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
405
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE,CRUD.DELETE));
406
            popup.withDeleteButton(true);
407
            popup.setCdmEntityInstantiator(new BeanInstantiator<TaxonName>() {
408

    
409
                @Override
410
                public TaxonName createNewBean() {
411
                    TaxonName newTaxonName = TaxonNameFactory.NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
412
                    newTaxonName.setNomenclaturalReference(getRepo().getReferenceService().load(workingset.getCitationUuid(), TaxonNameEditorPresenter.REFERENCE_INIT_STRATEGY ));
413
                    return newTaxonName;
414
                }
415
            });
416
            TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
417
            popup.loadInEditor(null);
418
        }
419
    }
420

    
421
    /**
422
     * Creates a new <code>Registration</code> for a new name that has just been edited
423
     * using a <code>TaxonNamePopupEditor</code>. The popup editor which has been opened to
424
     * edit the new name was remembered in <code>newNameForRegistrationPopupEditor</code>.
425
     * Any blocking registrations which have been created while editing the new name are
426
     * temporarily stored in <code>newNameBlockingRegistrations</code> until the registration
427
     * for the first name has been created. Additional new names are created for example
428
     * when a new name as basionym, replaced synonym, etc to the new name is created.
429
     * <p>
430
     * See also {@link #onTaxonNameEditorActionAdd(TaxonNameEditorAction)}).
431
     *
432
     * @param event
433
     * @throws TypeDesignationSetException
434
     *      passes on the Exception which may come from onRegistrationWorkflowEventActionStart()
435
     */
436
    @EventBusListenerMethod
437
    public void onDoneWithTaxonnameEditor(DoneWithPopupEvent event) throws TypeDesignationSetException {
438

    
439
        if(!isFromOwnView(event)){
440
            return;
441
        }
442

    
443
        if(event.getPopup() instanceof TaxonNamePopupEditor){
444

    
445
            EditorActionContext rootContext = editorActionContextRoot(event.getPopup());
446
            boolean isAddExistingNameRegistration = rootContext.getTargetField() != null && rootContext.getTargetField().equals(getView().getExistingNameCombobox());
447

    
448
            if(isAddExistingNameRegistration){
449
                if(event.getReason().equals(Reason.SAVE)){
450
                onRegistrationWorkflowEventActionStart(new RegistrationWorkingsetAction(workingset.getCitationUuid(),
451
                        RegistrationWorkingsetAction.Action.start));
452
                }
453
                // just ignore on CANCEL
454
            } else {
455
                Optional<Registration> registrationOpt = Optional.ofNullable(null);
456
                if(newNameForRegistrationPopupEditor != null && event.getPopup().equals(newNameForRegistrationPopupEditor)){
457
                    if(event.getReason().equals(Reason.SAVE)){
458
                        try {
459
                            TaxonName taxonName = newNameForRegistrationPopupEditor.getBean().cdmEntity();
460
                            registrationOpt = Optional.of(registrationWorkflowService.createRegistration(taxonName, newNameBlockingRegistrations));
461
                            loadWorkingSet(workingset.getCitationUuid());
462
                        } finally {
463
                            clearSession();
464
                            getView().getAddNewNameRegistrationButton().setEnabled(true);
465
                        }
466
                    }
467
                    // nullify and clear the memory on this popup editor in any case (SAVE, DELETE, CANCEL)
468
                    newNameForRegistrationPopupEditor = null;
469
                    newNameBlockingRegistrations.clear();
470
                    getView().getAddNewNameRegistrationButton().setEnabled(true);
471
                }
472

    
473
                if(event.getReason().equals(Reason.SAVE)){
474
                    if(!registrationOpt.isPresent()){
475
                        // no new registration has been created above, so there must be an existing one.
476
                        registrationOpt = findRegistrationInContext(event.getPopup());
477
                    }
478

    
479
                    // Check if the other names used in the context of the name are registered yet.
480
                    TaxonNamePopupEditor nameEditor = (TaxonNamePopupEditor)event.getPopup();
481
                    Set<TaxonName> namesToCheck = new HashSet<>();
482

    
483
                    namesToCheck.addAll(nameEditor.getBasionymComboboxSelect().getValue());
484
                    namesToCheck.addAll(nameEditor.getReplacedSynonymsComboboxSelect().getValue());
485
                    namesToCheck.add(nameEditor.getValidationField().getRelatedNameComboBox().getValue());
486
                    namesToCheck.add(nameEditor.getOrthographicVariantField().getRelatedNameComboBox().getValue());
487
                    // NOTE: according to https://dev.e-taxonomy.eu/redmine/issues/8049#note-2 we will not create blocking
488
                    // registrations for names in WeaklyRelatedEntityFields
489

    
490
                    for(TaxonName name : namesToCheck){
491
                        if(name != null){
492
                            clearSession();
493
                            assocciateOrQueueBlockingRegistration(registrationOpt, name.getUuid());
494
                        }
495
                    }
496
                } else if (event.getReason().equals(Reason.DELETE)){
497
                    //FIXME handle delete: need to remove blocking registrations?
498
                }
499
                // always reload if the first editor is closed as the data might have been changed through any other sub-popupeditor
500
                refreshView(isAtContextRoot(event.getPopup()));
501
            }
502
        }
503
    }
504

    
505
    /**
506
     * Creates a new Registration for an exiting (previously published) name.
507
     */
508
    @EventBusListenerMethod
509
    public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event) throws TypeDesignationSetException {
510

    
511
        if(!event.isStart()){
512
            return;
513
        }
514

    
515
        getView().getExistingNameCombobox().commit(); // update the chosen value in the datasource
516
        TaxonName typifiedName = getView().getExistingNameCombobox().getValue();
517
        if(typifiedName != null){
518
            boolean doReloadWorkingSet = false;
519
            try {
520
                doReloadWorkingSet = registrationWorkflowService.createRegistrationforExistingName(workingset, typifiedName);
521
            } finally {
522
                clearSession();
523
                refreshView(doReloadWorkingSet);
524
                getView().getAddExistingNameRegistrationButton().setEnabled(false);
525
            }
526
        } else {
527
            logger.error("Seletced name is NULL");
528
        }
529

    
530
    }
531

    
532
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
533
    public void onTypeDesignationsEditorActionEdit(TypeDesignationSetEditorAction event) {
534

    
535
        if(!checkFromOwnView(event)){
536
            return;
537
        }
538

    
539
        RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
540

    
541
        if(event.getWorkingSetType() == TypeDesignationSetType.SPECIMEN_TYPE_DESIGNATION_SET ){
542
            SpecimenTypeDesignationSetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationSetPopupEditor.class, event);
543
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
544
            popup.withDeleteButton(true);
545
            popup.loadInEditor(new SpecimenTypeDesignationSetIds(
546
                    workingset.getCitationUuid(),
547
                    event.getRegistrationUuid(),
548
                    CdmBase.deproxy(event.getBaseEntity(), FieldUnit.class), null));
549
            if(event.hasSource()){
550
                // propagate readonly state from source button to popup
551
                popup.setReadOnly(event.getSource().isReadOnly());
552
            }
553
        } else {
554
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
555
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
556
            popup.withDeleteButton(true);
557
            popup.loadInEditor(NameTypeDesignationSetIds.forExistingTypeDesignation(
558
                    registrationDTO.getCitationUuid(),
559
                    CdmBase.deproxy(event.getBaseEntity(), NameTypeDesignation.class))
560
                    );
561
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
562
            if(event.hasSource()){
563
                // propagate readonly state from source button to popup
564
                popup.setReadOnly(event.getSource().isReadOnly());
565
            }
566
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
567
        }
568
    }
569

    
570
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
571
    public void onTypeDesignationSetAdd(TypeDesignationSetEditorAction event) {
572

    
573
        if(!event.hasSource()){
574
            return;
575
        }
576

    
577
        RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
578

    
579
        if(event.getWorkingSetType() == TypeDesignationSetType.SPECIMEN_TYPE_DESIGNATION_SET){
580
            SpecimenTypeDesignationSetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationSetPopupEditor.class, event);
581
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
582
            TypedEntityReference<TaxonName> typifiedNameRef;
583
            if(registrationDTO.getTypifiedNameRef() != null){
584
                // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
585
                typifiedNameRef = new TypedEntityReference(TaxonName.class, registrationDTO.getTypifiedNameRef().getUuid());
586
            } else {
587
                // case of registrations with a name in the nomenclatural act.
588
                typifiedNameRef = new TypedEntityReference(TaxonName.class, registrationDTO.getNameRef().getUuid());
589
            }
590

    
591
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
592
            popup.withDeleteButton(false);
593
            popup.loadInEditor(new SpecimenTypeDesignationSetIds(
594
                        workingset.getCitationUuid(),
595
                        event.getRegistrationUuid(),
596
                        null,
597
                        typifiedNameRef.getUuid()
598
                        )
599
                    );
600
            if(event.hasSource()){
601
                // propagate readonly state from source component to popup
602
                popup.setReadOnly(event.getSource().isReadOnly());
603
            }
604
        } else {
605
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
606
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
607
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
608
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
609
            popup.setBeanInstantiator(new BeanInstantiator<NameTypeDesignation>() {
610

    
611
                @Override
612
                public NameTypeDesignation createNewBean() {
613

    
614
                    TaxonName typifiedName = getRepo().getNameService().load(event.getTypifiedNameUuid(), Arrays.asList(new String[]{
615
                            "typeDesignations",
616
                            "homotypicalGroup",
617
                            "nomenclaturalSource.citation"
618
                            }));
619
                    NameTypeDesignation nameTypeDesignation  = NameTypeDesignation.NewInstance();
620
                    nameTypeDesignation.getTypifiedNames().add(typifiedName);
621
                    return nameTypeDesignation;
622
                }
623
            });
624
            popup.withDeleteButton(false);
625
            popup.loadInEditor(NameTypeDesignationSetIds.forNewTypeDesignation(
626
                    registrationDTO.getCitationUuid(),
627
                    event.getTypifiedNameUuid()
628
                    )
629
                );
630
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
631
            if(event.hasSource()){
632
                // propagate readonly state from source component to popup
633
                popup.setReadOnly(event.getSource().isReadOnly());
634
            }
635
        }
636
    }
637

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

    
654
        if(!isFromOwnView(event)){
655
            return;
656
        }
657

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

    
668
                Optional<Registration> registrationOpt = Optional.ofNullable(null);
669
                UUID typeDesignationUuid = ((NameTypeDesignationPopupEditor)event.getPopup()).getBean().getUuid();
670
                try {
671
                    clearSession();
672
                    registrationOpt = findRegistrationInContext(event.getPopup());
673
                    registrationOpt.ifPresent(reg -> {
674
                        registrationWorkflowService.addTypeDesignation(typeDesignationUuid, reg);
675
                        nameTypeDesignationPopupEditorRegistrationUUIDMap.remove(event.getPopup());
676
                        });
677

    
678
                } finally {
679
                    clearSession();
680
                }
681

    
682
                // Check if other names used in the context of the name are registered yet.
683
                NameTypeDesignationPopupEditor nameTypeDesignationEditor = (NameTypeDesignationPopupEditor)event.getPopup();
684
                Set<TaxonName> namesToCheck = new HashSet<>();
685

    
686
                namesToCheck.add(nameTypeDesignationEditor.getTypeNameField().getValue());
687

    
688
                for(TaxonName name : namesToCheck){
689
                    if(name != null){
690
                        assocciateOrQueueBlockingRegistration(registrationOpt, name.getUuid());
691
                    }
692

    
693
                }
694

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

    
701
        }
702
        // ignore other editors
703
    }
704

    
705
    private void assocciateOrQueueBlockingRegistration(Optional<Registration> registrationOpt, UUID nameUuid) {
706
        registrationOpt.ifPresent(reg -> registrationWorkflowService.addBlockingRegistration(nameUuid, reg));
707
        if(!registrationOpt.isPresent()){
708
            // not present!
709
            Registration blockingRegistration = registrationWorkflowService.prepareBlockingRegistration(nameUuid);
710
            if(blockingRegistration != null){
711
                newNameBlockingRegistrations.add(blockingRegistration);
712
                logger.debug("Blocking registration created and queued for later association with the main registration.");
713
            }
714
        }
715
    }
716

    
717

    
718
    public void clearSession() {
719
        getRepo().clearSession();
720
    }
721

    
722
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationWorkingSet.class)
723
    public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent<RegistrationWorkingSet,?> event) {
724

    
725
        if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
726
            List<String> messages = new ArrayList<>();
727
            for(RegistrationDTO dto : workingset.getRegistrationDTOs()){
728
                dto.getValidationProblems().forEach(m -> messages.add(dto.getSummary() + ": " + m));
729
            }
730
            getView().openDetailsPopup("Validation Problems", messages);
731
        }
732
    }
733

    
734
    @EventBusListenerMethod
735
    public void onEntityChangeEvent(EntityChangeEvent event){
736

    
737
        if(!isFromOwnView(event)){
738
            return;
739
        }
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())){
761
            if(event.getType().equals(EntityChangeEvent.Type.CREATED)){
762
                Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getSourceView()).getEditorActionContext();
763
                EditorActionContext rootContext = context.get(0);
764
                if(rootContext.getParentView().equals(getView()) && event.getSourceView() != newNameForRegistrationPopupEditor){
765
                    try {
766
                        clearSession();
767
                        // create a blocking registration
768
                        UUID taxonNameUUID = event.getEntityUuid();
769
                        Optional<Registration> registrationOpt = findRegistrationInContext(context);
770
                        assocciateOrQueueBlockingRegistration(registrationOpt, taxonNameUUID);
771
                    } finally {
772
                        clearSession();
773
                    }
774

    
775
                } else {
776
                    // in case of creating a new name for a registration the parent view is the TaxonNamePopupEditor
777
                    // this is set
778
                    logger.debug("Non blocking registration, since a new name for a new registration has been created");
779
                }
780
            }
781
            if(workingset.getRegistrationDTOs().stream().anyMatch(reg ->
782
                reg.getTypifiedNameRef() != null
783
                && reg.getTypifiedNameRef().getUuid().equals(event.getEntityUuid()))){
784
                    //refreshView(true);
785
            }
786
        } else
787
        if(TypeDesignationBase.class.isAssignableFrom(event.getEntityType())){
788
            if(workingset.getRegistrationDTOs().stream().anyMatch(
789
                    reg -> reg.typeDesignations() != null && reg.typeDesignations().stream().anyMatch(
790
                            td -> td.getUuid() == event.getEntityUuid()
791
                            )
792
                        )
793
                    ){
794
                //refreshView(true);
795
            }
796
        }
797
    }
798

    
799
    public Optional<Registration> findRegistrationInContext(PopupView popupView) {
800
        Stack<EditorActionContext>context = ((AbstractPopupEditor)popupView).getEditorActionContext();
801
        return findRegistrationInContext(context);
802
    }
803

    
804
    /**
805
     * Finds the Registration in the EditorContext stack
806
     */
807
    public Optional<Registration> findRegistrationInContext(Stack<EditorActionContext> context) {
808
        EditorActionContext rootCtx = context.get(0);
809
        TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootCtx.getParentEntity();
810
        Optional<RegistrationDTO> registrationDTOOptional = workingset.getRegistrationDTO(regReference.getUuid());
811
        Optional<Registration> registrationOptional;
812
        if(!registrationDTOOptional.isPresent()){
813
            logger.debug("No RegistrationDTO in found rootCtx -> user is about to create a registration for a new name.");
814
            registrationOptional = Optional.ofNullable(null);
815
        }
816

    
817
        Optional<Registration> regOpt;
818
        if(registrationDTOOptional.isPresent()){
819
            regOpt = Optional.of(registrationDTOOptional.get().registration());
820
        } else {
821
            regOpt = Optional.ofNullable(null);
822
        }
823

    
824
        return regOpt;
825
    }
826

    
827
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
828
    public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
829

    
830
        // FIXME check from own view!!!
831
        if(getView() == null){
832
            return;
833
        }
834

    
835
        UUID registrationUuid = event.getIdentifier();
836

    
837
        RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
838
        if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
839

    
840
            Set<RegistrationDTO> blockingRegs;
841
            if(regDto.registration().isPersited()){
842
                blockingRegs = getWorkingSetService().loadBlockingRegistrations(registrationUuid);
843
            } else {
844
                blockingRegs = new HashSet<RegistrationDTO>(getWorkingSetService().makeDTOs(regDto.registration().getBlockedBy()));
845
            }
846
            getView().setBlockingRegistrations(registrationUuid, blockingRegs);
847
        } else if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
848
            getView().openDetailsPopup("Validation Problems", regDto.getValidationProblems());
849
        }
850
    }
851

    
852
    @Override
853
    public ICdmEntityUuidCacher getCache() {
854
        return cache;
855
    }
856

    
857
    @Override
858
    public void addRootEntity(CdmBase entity) {
859
        rootEntities.add(entity);
860
        cache.load(entity);
861
    }
862

    
863
    @Override
864
    public Collection<CdmBase> getRootEntities() {
865
        return rootEntities;
866
    }
867

    
868
    @Override
869
    public void destroy() throws Exception {
870
        super.destroy();
871
        disposeCache();
872
    }
873

    
874
    @Override
875
    public void disposeCache() {
876
        cache.dispose();
877
    }
878

    
879
    public boolean canCreateNameRegistrationFor(TaxonName name) {
880
        return registrationWorkflowService.canCreateNameRegistrationFor(workingset, name);
881
    }
882

    
883
    public boolean checkWokingsetContainsProtologe(TaxonName name) {
884
        return registrationWorkflowService.checkWokingsetContainsProtologe(workingset, name);
885
    }
886
}
(10-10/18)