Project

General

Profile

Download (37.2 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.Level;
26
import org.apache.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.spring.annotation.SpringComponent;
32
import com.vaadin.spring.annotation.ViewScope;
33
import com.vaadin.ui.AbstractField;
34
import com.vaadin.ui.Label;
35
import com.vaadin.ui.UI;
36
import com.vaadin.ui.VerticalLayout;
37
import com.vaadin.ui.Window;
38

    
39
import eu.etaxonomy.cdm.api.service.config.RegistrationStatusTransitions;
40
import eu.etaxonomy.cdm.api.service.dto.RegistrationDTO;
41
import eu.etaxonomy.cdm.api.service.dto.RegistrationWorkingSet;
42
import eu.etaxonomy.cdm.api.service.exception.RegistrationValidationException;
43
import eu.etaxonomy.cdm.api.service.name.TypeDesignationSetManager.TypeDesignationWorkingSetType;
44
import eu.etaxonomy.cdm.api.service.registration.IRegistrationWorkingSetService;
45
import eu.etaxonomy.cdm.api.utility.UserHelper;
46
import eu.etaxonomy.cdm.cache.CdmTransientEntityAndUuidCacher;
47
import eu.etaxonomy.cdm.database.PermissionDeniedException;
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.reference.Reference;
58
import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
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.permission.AccessRestrictedView;
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.SpecimenTypeDesignationWorkingsetPopupEditor;
87
import eu.etaxonomy.cdm.vaadin.view.name.TaxonNameEditorPresenter;
88
import eu.etaxonomy.cdm.vaadin.view.name.TaxonNamePopupEditor;
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
     *
161
     */
162
    public RegistrationWorkingsetPresenter() {
163
    }
164

    
165
    /**
166

    
167

    
168
    /**
169
     * @param doReload reload the workingset from the persistent storage.
170
     *  Workingsets which are not yet persisted are preserved.
171
     *
172
     */
173
    protected void refreshView(boolean doReload) {
174
        logger.setLevel(Level.DEBUG);
175
        if(workingset == null){
176
            return; // nothing to do
177
        }
178
        if(doReload){
179
            if(logger.isDebugEnabled()){
180
                logger.debug("refreshView() - workingset:\n" + workingset.toString());
181
            }
182
            List<RegistrationDTO> unpersisted = new ArrayList<>();
183
            for(RegistrationDTO regDto : workingset.getRegistrationDTOs()){
184
                if(!regDto.registration().isPersited()){
185
                    unpersisted.add(regDto);
186
                }
187
            }
188
            loadWorkingSet(workingset.getCitationUuid());
189
            for(RegistrationDTO regDtoUnpersisted : unpersisted){
190
                if(!workingset.getRegistrationDTOs().stream().anyMatch(dto -> dto.getUuid().equals(regDtoUnpersisted.getUuid()))){
191
                    // only add if the regDtoUnpersisted has not been persisted meanwhile
192
                    try {
193
                        workingset.add(regDtoUnpersisted);
194
                    } catch (RegistrationValidationException e) {
195
                        // would never happen here //
196
                    }
197
                }
198
            }
199
            if(logger.isDebugEnabled()){
200
                logger.debug("refreshView() - workingset reloaded:\n" + workingset.toString());
201
            }
202
        }
203
        applyWorkingset();
204
    }
205

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

    
216
            private static final long serialVersionUID = 7099181280977511048L;
217

    
218
            @Override
219
            public AbstractField<Object> create(RegistrationDTO regDto) {
220

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

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

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

    
246

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

    
251
    }
252

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

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

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

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

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

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

    
318

    
319
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
320
    public void onReferenceEditorActionAdd(ReferenceEditorAction event) {
321

    
322
        if(!checkFromOwnView(event)){
323
            return;
324
        }
325

    
326
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
327
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
328
        popup.loadInEditor(null);
329
    }
330

    
331
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
332
    public void onReferenceEditorActionEdit(ReferenceEditorAction event) {
333

    
334
        if(!checkFromOwnView(event)){
335
            return;
336
        }
337
        ReferencePopupEditor popup = openPopupEditor(ReferencePopupEditor.class, event);
338
        popup.withReferenceTypes(RegistrationUIDefaults.PRINTPUB_REFERENCE_TYPES);
339
        popup.withDeleteButton(true);
340
        popup.loadInEditor(event.getEntityUuid());
341
    }
342

    
343
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
344
    public void onRegistrationEditorAction(RegistrationEditorAction event) {
345

    
346
        if(!checkFromOwnView(event)){
347
            return;
348
        }
349

    
350
        RegistrationPopupEditor popup = openPopupEditor(RegistrationPopupEditor.class, event);
351
        popup.loadInEditor(event.getEntityUuid());
352
    }
353

    
354
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
355
    public void onTaxonNameEditorActionEdit(TaxonNameEditorAction event) {
356

    
357
        if(!checkFromOwnView(event)){
358
            return;
359
        }
360

    
361
        TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
362
        popup.setParentEditorActionContext(event.getContext(), event.getTarget());
363
        popup.withDeleteButton(true);
364
        TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
365
        popup.loadInEditor(event.getEntityUuid());
366
        if(event.hasSource() && event.getSource().isReadOnly()){
367
            // avoid resetting readonly to false
368
            popup.setReadOnly(true);
369
        }
370

    
371
    }
372

    
373

    
374
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
375
    public void onTaxonNameEditorActionAdd(TaxonNameEditorAction event) {
376

    
377
        if(!checkFromOwnView(event)){
378
            return;
379
        }
380

    
381
        getView().getAddNewNameRegistrationButton().setEnabled(false);
382
        if(newNameForRegistrationPopupEditor == null){
383
            TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
384
            newNameForRegistrationPopupEditor = popup;
385
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
386
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE,CRUD.DELETE));
387
            popup.withDeleteButton(true);
388
            popup.setCdmEntityInstantiator(new BeanInstantiator<TaxonName>() {
389

    
390
                @Override
391
                public TaxonName createNewBean() {
392
                    TaxonName newTaxonName = TaxonNameFactory.NewNameInstance(RegistrationUIDefaults.NOMENCLATURAL_CODE, Rank.SPECIES());
393
                    newTaxonName.setNomenclaturalReference(getRepo().getReferenceService().load(workingset.getCitationUuid(), TaxonNameEditorPresenter.REFERENCE_INIT_STRATEGY ));
394
                    return newTaxonName;
395
                }
396
            });
397
            TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
398
            popup.loadInEditor(null);
399
        }
400
    }
401

    
402
    /**
403
     * Creates a new <code>Registration</code> for a new name that has just been edited
404
     * using a <code>TaxonNamePopupEditor</code>. The popup editor which has been opened to
405
     * edit the new name was remembered in <code>newNameForRegistrationPopupEditor</code>.
406
     * Any blocking registrations which have been created while editing the new name are
407
     * temporarily stored in <code>newNameBlockingRegistrations</code> until the registration
408
     * for the first name has been created. Additional new names are created for example
409
     * when a new name as basionym, replaced synonym, etc to the new name is created.
410
     * <p>
411
     * See also {@link #onTaxonNameEditorActionAdd(TaxonNameEditorAction)}).
412
     *
413
     * @param event
414
     * @throws RegistrationValidationException
415
     */
416
    @EventBusListenerMethod
417
    public void onDoneWithTaxonnameEditor(DoneWithPopupEvent event) {
418
        if(event.getPopup() instanceof TaxonNamePopupEditor){
419
            Registration registration = null;
420
            if(newNameForRegistrationPopupEditor != null && event.getPopup().equals(newNameForRegistrationPopupEditor)){
421
                if(event.getReason().equals(Reason.SAVE)){
422
                    try {
423
                        TaxonName taxonName = newNameForRegistrationPopupEditor.getBean().cdmEntity();
424
                        registration = registrationWorkflowService.createRegistration(taxonName, newNameBlockingRegistrations);
425
                        loadWorkingSet(workingset.getCitationUuid());
426
                    } finally {
427
                        clearSession();
428
                        getView().getAddNewNameRegistrationButton().setEnabled(true);
429
                    }
430
                }
431
                // nullify and clear the memory on this popup editor in any case (SAVE, CANCEL, DELETE)
432
                newNameForRegistrationPopupEditor = null;
433
                newNameBlockingRegistrations.clear();
434
                getView().getAddNewNameRegistrationButton().setEnabled(true);
435
            }
436

    
437
            if(registration == null){
438
                // no new registration has been created above, so there must be an existing one.
439
                registration = findRegistrationInContext(event.getPopup());
440
            }
441

    
442
            // Check if the other names used in the context of the name are registered yet.
443
            TaxonNamePopupEditor nameEditor = (TaxonNamePopupEditor)event.getPopup();
444
            Set<TaxonName> namesToCheck = new HashSet<>();
445

    
446
            namesToCheck.addAll(nameEditor.getBasionymComboboxSelect().getValue());
447
            namesToCheck.addAll(nameEditor.getReplacedSynonymsComboboxSelect().getValue());
448
            namesToCheck.add(nameEditor.getValidationField().getRelatedNameComboBox().getValue());
449
            namesToCheck.add(nameEditor.getOrthographicVariantField().getRelatedNameComboBox().getValue());
450

    
451
            for(TaxonName name : namesToCheck){
452
                if(name != null){
453
                    clearSession();
454
                    registrationWorkflowService.addBlockingRegistration(name.getUuid(), registration);
455
                }
456
            }
457

    
458
            // always reload if the first editor is closed as the data might have been changed through any other sub-popupeditor
459
            refreshView(isAtContextRoot(event.getPopup()));
460
        }
461
    }
462

    
463

    
464
    /**
465
     * Creates a new Registration for an exiting (previously published) name.
466
     *
467
     * @param event
468
     * @throws RegistrationValidationException
469
     */
470
    @EventBusListenerMethod
471
    public void onRegistrationWorkflowEventActionStart(RegistrationWorkingsetAction event) throws RegistrationValidationException {
472

    
473
        if(!event.isStart()){
474
            return;
475
        }
476

    
477
        getView().getAddExistingNameCombobox().commit(); // update the chosen value in the datasource
478
        TaxonName typifiedName = getView().getAddExistingNameCombobox().getValue();
479
        if(typifiedName != null){
480
            boolean doReloadWorkingSet = false;
481
            try {
482
                doReloadWorkingSet = registrationWorkflowService.createRegistrationforExistingName(workingset, typifiedName);
483
            } finally {
484
                clearSession();
485
                refreshView(doReloadWorkingSet);
486
                getView().getAddExistingNameRegistrationButton().setEnabled(false);
487
            }
488
        } else {
489
            logger.error("Seletced name is NULL");
490
        }
491

    
492
    }
493

    
494
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Edit.class)
495
    public void onTypeDesignationsEditorActionEdit(TypeDesignationWorkingsetEditorAction event) {
496

    
497
        if(!checkFromOwnView(event)){
498
            return;
499
        }
500

    
501
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET ){
502
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
503
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
504
            popup.withDeleteButton(true);
505
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
506
            if(event.hasSource()){
507
                // propagate readonly state from source button to popup
508
                popup.setReadOnly(event.getSource().isReadOnly());
509
            }
510
        } else {
511
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
512
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
513
            popup.withDeleteButton(true);
514
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
515

    
516
            popup.getCitationCombobox().setEnabled(false);
517
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
518

    
519
            if(event.hasSource()){
520
                // propagate readonly state from source button to popup
521
                popup.setReadOnly(event.getSource().isReadOnly());
522
            }
523
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
524
        }
525
    }
526

    
527
    @EventBusListenerMethod(filter = EditorActionTypeFilter.Add.class)
528
    public void onTypeDesignationWorkingsetAdd(TypeDesignationWorkingsetEditorAction event) {
529

    
530
        if(!event.hasSource()){
531
            return;
532
        }
533

    
534
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
535
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
536
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
537
            TypeDesignationWorkingsetEditorIdSet identifierSet;
538
            UUID typifiedNameUuid;
539

    
540
            RegistrationDTO registrationDTO = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
541
            EntityReference typifiedNameRef = registrationDTO.getTypifiedNameRef();
542
            if(typifiedNameRef != null){
543
                // case for registrations without name, in which case the typifiedName is only defined via the typedesignations
544
                typifiedNameUuid = typifiedNameRef.getUuid();
545
            } else {
546
                // case of registrations with a name in the nomenclatural act.
547
                typifiedNameUuid = registrationDTO.getNameRef().getUuid();
548
            }
549

    
550
            identifierSet = new TypeDesignationWorkingsetEditorIdSet(
551
                    event.getRegistrationUuid(),
552
                    getView().getCitationUuid(),
553
                    typifiedNameUuid
554
                    );
555
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
556
            popup.loadInEditor(identifierSet);
557
            popup.withDeleteButton(true);
558
            if(event.hasSource()){
559
                // propagate readonly state from source component to popup
560
                popup.setReadOnly(event.getSource().isReadOnly());
561
            }
562
        } else {
563
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
564
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
565
            popup.withDeleteButton(true);
566
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
567
            RegistrationDTO regDto = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
568
            Reference citation = regDto.getCitation();
569
            nameTypeDesignationPopupEditorRegistrationUUIDMap.put(popup, event.getRegistrationUuid());
570
            popup.setBeanInstantiator(new BeanInstantiator<NameTypeDesignation>() {
571

    
572
                @Override
573
                public NameTypeDesignation createNewBean() {
574

    
575
                    TaxonName typifiedName = getRepo().getNameService().load(event.getTypifiedNameUuid(), Arrays.asList(new String[]{"typeDesignations", "homotypicalGroup"}));
576
                    NameTypeDesignation nameTypeDesignation  = NameTypeDesignation.NewInstance();
577
                    nameTypeDesignation.setCitation(citation);
578
                    nameTypeDesignation.getTypifiedNames().add(typifiedName);
579
                    return nameTypeDesignation;
580
                }
581
            });
582
            popup.loadInEditor(null);
583
            popup.getCitationCombobox().setEnabled(false);
584
            popup.getTypifiedNamesComboboxSelect().setEnabled(false);
585
            if(event.hasSource()){
586
                // propagate readonly state from source component to popup
587
                popup.setReadOnly(event.getSource().isReadOnly());
588
            }
589
        }
590
    }
591

    
592
    /**
593
     * Performs final actions after a TypeDesignationEditor which has been
594
     * opened to add a TypeDesignation to a Registration object which was
595
     * created for an previously published name. Prior adding a typedesignation,
596
     * the according Registration object is dangling, that has no association to
597
     * any entity denoting an nomenclatural act which has a reference to a
598
     * publication. This means that the registration object is not in the
599
     * working set.
600
     *
601
     *
602
     * @param event
603
     * @throws RegistrationValidationException
604
     */
605
    @EventBusListenerMethod
606
    public void onDoneWithTypeDesignationEditor(DoneWithPopupEvent event) {
607
        if(event.getPopup() instanceof SpecimenTypeDesignationWorkingsetPopupEditor){
608
            if(event.getReason().equals(Reason.SAVE)){
609
                // NOTE: adding the SpecimenTypeDesignations to the registration is done in the
610
                // SpecimenTypeDesignationWorkingSetServiceImpl.save(SpecimenTypeDesignationWorkingSetDTO dto) method
611
            }
612
            // always reload if the first editor is closed as the data might have been changed through any other sub-popupeditor
613
            refreshView(isAtContextRoot(event.getPopup()));
614
        } else if(event.getPopup() instanceof NameTypeDesignationPopupEditor){
615
            if(event.getReason().equals(Reason.SAVE)){
616

    
617
                Registration registration = null;
618

    
619
                UUID typeDesignationUuid = ((NameTypeDesignationPopupEditor)event.getPopup()).getBean().getUuid();
620

    
621
                try {
622
                    clearSession();
623
                    Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getPopup()).getEditorActionContext();
624
                    registration = findRegistrationInContext(context);
625
                    registrationWorkflowService.addTypeDesignation(typeDesignationUuid, registration);
626
                    nameTypeDesignationPopupEditorRegistrationUUIDMap.remove(event.getPopup());
627
                } finally {
628
                    clearSession();
629
                }
630

    
631
                if(registration == null){
632
                    // no new registration has been created above, so there must be an existing one.
633
                    registration = findRegistrationInContext(event.getPopup());
634
                }
635

    
636
                // Check if the other names used in the context of the name are registered yet.
637
                NameTypeDesignationPopupEditor nameEditor = (NameTypeDesignationPopupEditor)event.getPopup();
638
                Set<TaxonName> namesToCheck = new HashSet<>();
639

    
640
                namesToCheck.add(nameEditor.getTypeNameField().getValue());
641

    
642
                for(TaxonName name : namesToCheck){
643
                    if(name != null){
644
                        registrationWorkflowService.addBlockingRegistration(name.getUuid(), registration);
645
                    }
646

    
647
                }
648

    
649
            } else if(event.getReason().equals(Reason.CANCEL)){
650
                // noting to do
651
            }
652
            // always reload if the first editor is closed as the data might have been changed through any other sub-popupeditor
653
            refreshView(isAtContextRoot(event.getPopup()));
654

    
655
        }
656
        // ignore other editors
657
    }
658

    
659
    /**
660
     *
661
     */
662
    public void clearSession() {
663
        getRepo().clearSession();
664
    }
665

    
666

    
667
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationWorkingSet.class)
668
    public void onShowDetailsEventForRegistrationWorkingSet(ShowDetailsEvent<RegistrationWorkingSet,?> event) {
669

    
670
        if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
671
            List<String> messages = new ArrayList<>();
672
            for(RegistrationDTO dto : workingset.getRegistrationDTOs()){
673
                dto.getValidationProblems().forEach(m -> messages.add(dto.getSummary() + ": " + m));
674
            }
675
            getView().openDetailsPopup("Validation Problems", messages);
676
        }
677
    }
678

    
679
    @EventBusListenerMethod
680
    public void onEntityChangeEvent(EntityChangeEvent event){
681

    
682
        if(workingset == null){
683
            return;
684
        }
685
        if(Reference.class.isAssignableFrom(event.getEntityType())){
686

    
687
            if(workingset.getCitationUuid().equals(event.getEntityUuid())){
688
                if(event.isRemovedType()){
689
                    viewEventBus.publish(EventScope.UI, this, new NavigationEvent(StartRegistrationViewBean.NAME));
690
                } else {
691
                    refreshView(true);
692
                }
693
            }
694

    
695
        } else
696
        if(Registration.class.isAssignableFrom(event.getEntityType())){
697
            if(workingset.getRegistrations().stream().anyMatch(reg -> reg.getUuid() == event.getEntityUuid())){
698
                refreshView(true);
699
            }
700
        } else
701
        if(TaxonName.class.isAssignableFrom(event.getEntityType())){
702
            if(event.getType().equals(EntityChangeEvent.Type.CREATED)){
703
                Stack<EditorActionContext>context = ((AbstractPopupEditor)event.getSourceView()).getEditorActionContext();
704
                EditorActionContext rootContext = context.get(0);
705
                if(rootContext.getParentView().equals(getView()) && event.getSourceView() != newNameForRegistrationPopupEditor){
706
                    try {
707
                        clearSession();
708
                        // create a blocking registration, the new Registration will be persisted
709
                        UUID taxonNameUUID = event.getEntityUuid();
710

    
711
                        if(context.get(1).getParentView() instanceof TaxonNamePopupEditor && !((TaxonNamePopupEditor)context.get(1).getParentView()).getBean().cdmEntity().isPersited()){
712
                            // Oha!! The event came from a popup editor and the
713
                            // first popup in the context is a TaxonNameEditor with un-persisted name
714
                            // This is a name for a new registration which has not yet been created.
715
                            // It is necessary to store blocking registrations in the newNameBlockingRegistrations
716
                            Registration blockingRegistration = getRepo().getRegistrationService().createRegistrationForName(taxonNameUUID);
717
                            newNameBlockingRegistrations.add(blockingRegistration);
718
                            logger.debug("Blocking registration created and memorized");
719
                        } else {
720
                            Registration registration = findRegistrationInContext(context);
721
                            // some new name somehow related to an existing registration
722
                            registrationWorkflowService.addBlockingRegistration(taxonNameUUID, registration);
723
                        }
724
                    } finally {
725
                        clearSession();
726
                    }
727

    
728
                } else {
729
                    // in case of creating a new name for a registration the parent view is the TaxonNamePopupEditor
730
                    // this is set
731
                    logger.debug("Non blocking registration, since a new name for a new registration has been created");
732
                }
733
            }
734
            if(workingset.getRegistrationDTOs().stream().anyMatch(reg ->
735
                reg.getTypifiedNameRef() != null
736
                && reg.getTypifiedNameRef().getUuid().equals(event.getEntityUuid()))){
737
                    //refreshView(true);
738
            }
739
        } else
740
        if(TypeDesignationBase.class.isAssignableFrom(event.getEntityType())){
741
            if(workingset.getRegistrationDTOs().stream().anyMatch(
742
                    reg -> reg.typeDesignations() != null && reg.typeDesignations().stream().anyMatch(
743
                            td -> td.getUuid() == event.getEntityUuid()
744
                            )
745
                        )
746
                    ){
747
                //refreshView(true);
748
            }
749
        }
750
    }
751

    
752
    public boolean isAtContextRoot(PopupView popupView) {
753
        AbstractPopupEditor popupEditor = ((AbstractPopupEditor)popupView);
754
        if(popupEditor.getEditorActionContext().size() > 1){
755
            EditorActionContext topContext = (EditorActionContext) popupEditor.getEditorActionContext().get(popupEditor.getEditorActionContext().size() - 2);
756
            return getView().equals(topContext.getParentView());
757
        } else {
758
            logger.error("Invalid EditorActionContext size. A popupeditor should at leaset have the workingset as root");
759
            return false;
760
        }
761
    }
762

    
763
    public EditorActionContext editorActionContextRoot(PopupView popupView) {
764
        Stack<EditorActionContext>context = ((AbstractPopupEditor)popupView).getEditorActionContext();
765
        return context.get(0);
766
    }
767

    
768
    public Registration findRegistrationInContext(PopupView popupView) {
769
        Stack<EditorActionContext>context = ((AbstractPopupEditor)popupView).getEditorActionContext();
770
        return findRegistrationInContext(context);
771
    }
772
    /**
773
     * Finds the Registration in the EditorContext stack
774
     *
775
     * @param context
776
     * @return
777
     */
778
    public Registration findRegistrationInContext(Stack<EditorActionContext> context) {
779
        EditorActionContext rootCtx = context.get(0);
780
        TypedEntityReference<Registration> regReference = (TypedEntityReference<Registration>)rootCtx.getParentEntity();
781
        Optional<RegistrationDTO> registrationDTOOptional = workingset.getRegistrationDTO(regReference.getUuid());
782
        if(!registrationDTOOptional.isPresent()){
783
            logger.error("RegistrationDTO missing in rootCtx.");
784
        }
785
        Registration registration = registrationDTOOptional.get().registration();
786

    
787
        // registration = reloadRegistration(registration);
788
        return registration;
789
    }
790

    
791

    
792

    
793
    @EventBusListenerMethod(filter = ShowDetailsEventEntityTypeFilter.RegistrationDTO.class)
794
    public void onShowDetailsEventForRegistrationDTO(ShowDetailsEvent<RegistrationDTO, UUID> event) {
795

    
796
        // FIXME check from own view!!!
797
        if(getView() == null){
798
            return;
799
        }
800

    
801
        UUID registrationUuid = event.getIdentifier();
802

    
803
        RegistrationDTO regDto = workingset.getRegistrationDTO(registrationUuid).get();
804
        if(event.getProperty().equals(RegistrationItem.BLOCKED_BY)){
805

    
806
            Set<RegistrationDTO> blockingRegs;
807
            if(regDto.registration().isPersited()){
808
                blockingRegs = getWorkingSetService().loadBlockingRegistrations(registrationUuid);
809
            } else {
810
                blockingRegs = new HashSet<RegistrationDTO>(getWorkingSetService().makeDTOs(regDto.registration().getBlockedBy()));
811
            }
812
            getView().setBlockingRegistrations(registrationUuid, blockingRegs);
813
        } else if(event.getProperty().equals(RegistrationItem.VALIDATION_PROBLEMS)){
814
            getView().openDetailsPopup("Validation Problems", regDto.getValidationProblems());
815
        }
816
    }
817

    
818
    /**
819
     * {@inheritDoc}
820
     */
821
    @Override
822
    public ICdmEntityUuidCacher getCache() {
823
        return cache;
824
    }
825

    
826
    /**
827
     * {@inheritDoc}
828
     */
829
    @Override
830
    public void addRootEntity(CdmBase entity) {
831
        rootEntities.add(entity);
832
        cache.load(entity);
833
    }
834

    
835

    
836
    /**
837
     * {@inheritDoc}
838
     */
839
    @Override
840
    public Collection<CdmBase> getRootEntities() {
841
        return rootEntities;
842
    }
843

    
844
    @Override
845
    public void destroy() throws Exception {
846
        super.destroy();
847
        disposeCache();
848
    }
849

    
850
    /**
851
     * {@inheritDoc}
852
     */
853
    @Override
854
    public void disposeCache() {
855
        cache.dispose();
856
    }
857

    
858
    /**
859
     * @param name
860
     * @return
861
     */
862
    public boolean canCreateNameRegistrationFor(TaxonName name) {
863
        return registrationWorkflowService.canCreateNameRegistrationFor(workingset, name);
864
    }
865

    
866
    /**
867
     * @param name
868
     * @return
869
     */
870
    public boolean checkWokingsetContainsProtologe(TaxonName name) {
871
        return registrationWorkflowService.checkWokingsetContainsProtologe(workingset, name);
872
    }
873

    
874
}
(10-10/18)