Project

General

Profile

Download (25.6 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 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.taxeditor.editor.view.derivate;
10

    
11
import java.util.ArrayList;
12
import java.util.Arrays;
13
import java.util.Collection;
14
import java.util.Collections;
15
import java.util.HashMap;
16
import java.util.HashSet;
17
import java.util.List;
18
import java.util.Map;
19
import java.util.Set;
20
import java.util.UUID;
21

    
22
import javax.annotation.PostConstruct;
23
import javax.annotation.PreDestroy;
24
import javax.inject.Inject;
25
import javax.inject.Named;
26

    
27
import org.eclipse.core.commands.ExecutionException;
28
import org.eclipse.core.commands.operations.IOperationHistory;
29
import org.eclipse.core.runtime.IAdaptable;
30
import org.eclipse.core.runtime.IProgressMonitor;
31
import org.eclipse.core.runtime.IStatus;
32
import org.eclipse.core.runtime.NullProgressMonitor;
33
import org.eclipse.core.runtime.Status;
34
import org.eclipse.e4.core.contexts.ContextInjectionFactory;
35
import org.eclipse.e4.core.contexts.IEclipseContext;
36
import org.eclipse.e4.core.di.annotations.Optional;
37
import org.eclipse.e4.core.services.events.IEventBroker;
38
import org.eclipse.e4.ui.di.Focus;
39
import org.eclipse.e4.ui.di.Persist;
40
import org.eclipse.e4.ui.model.application.ui.MDirtyable;
41
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
42
import org.eclipse.e4.ui.services.EMenuService;
43
import org.eclipse.e4.ui.services.IServiceConstants;
44
import org.eclipse.e4.ui.workbench.modeling.EPartService;
45
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
46
import org.eclipse.jface.util.LocalSelectionTransfer;
47
import org.eclipse.jface.viewers.ISelectionChangedListener;
48
import org.eclipse.jface.viewers.IStructuredSelection;
49
import org.eclipse.jface.viewers.StructuredSelection;
50
import org.eclipse.jface.viewers.TreeNode;
51
import org.eclipse.jface.viewers.TreeSelection;
52
import org.eclipse.jface.viewers.TreeViewer;
53
import org.eclipse.jface.viewers.Viewer;
54
import org.eclipse.jface.viewers.ViewerComparator;
55
import org.eclipse.swt.SWT;
56
import org.eclipse.swt.dnd.DND;
57
import org.eclipse.swt.dnd.Transfer;
58
import org.eclipse.swt.layout.GridData;
59
import org.eclipse.swt.layout.GridLayout;
60
import org.eclipse.swt.widgets.Composite;
61
import org.eclipse.swt.widgets.Tree;
62
import org.eclipse.ui.IMemento;
63
import org.eclipse.ui.ide.undo.WorkspaceUndoUtil;
64

    
65
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
66
import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
67
import eu.etaxonomy.cdm.api.service.IOccurrenceService;
68
import eu.etaxonomy.cdm.api.service.ITaxonService;
69
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
70
import eu.etaxonomy.cdm.model.molecular.SingleRead;
71
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
72
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
73
import eu.etaxonomy.cdm.model.taxon.Taxon;
74
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
75
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
76
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
77
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
78
import eu.etaxonomy.taxeditor.editor.EditorUtil;
79
import eu.etaxonomy.taxeditor.editor.l10n.Messages;
80
import eu.etaxonomy.taxeditor.editor.name.e4.TaxonNameEditorE4;
81
import eu.etaxonomy.taxeditor.editor.view.derivate.searchFilter.DerivateSearchCompositeController;
82
import eu.etaxonomy.taxeditor.event.WorkbenchEventConstants;
83
import eu.etaxonomy.taxeditor.model.AbstractUtility;
84
import eu.etaxonomy.taxeditor.model.IContextListener;
85
import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
86
import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
87
import eu.etaxonomy.taxeditor.model.IPartContentHasFactualData;
88
import eu.etaxonomy.taxeditor.model.IPartContentHasMedia;
89
import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
90
import eu.etaxonomy.taxeditor.model.MessagingUtils;
91
import eu.etaxonomy.taxeditor.operation.AbstractPostOperation;
92
import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
93
import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
94
import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
95
import eu.etaxonomy.taxeditor.store.CdmStore;
96
import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
97
import eu.etaxonomy.taxeditor.view.search.derivative.DerivateContentProvider;
98
import eu.etaxonomy.taxeditor.view.search.derivative.DerivateLabelProvider;
99
import eu.etaxonomy.taxeditor.workbench.part.ICollapsableExpandable;
100
import eu.etaxonomy.taxeditor.workbench.part.IE4SavablePart;
101

    
102
/**
103
 * Displays the derivate hierarchy of the specimen specified in the editor input.
104
 */
105
public class DerivateView implements IPartContentHasFactualData, IConversationEnabled,
106
        ICdmEntitySessionEnabled<SpecimenOrObservationBase<?>>, IDirtyMarkable, IPostOperationEnabled, IPartContentHasDetails, IPartContentHasSupplementalData, IPartContentHasMedia,
107
        IContextListener, IE4SavablePart, ICollapsableExpandable {
108

    
109
    private static final String SPECIMEN_EDITOR = Messages.DerivateView_SPECIMEN_EDITOR;
110

    
111
    public static final String ID = "eu.etaxonomy.taxeditor.editor.view.derivate.DerivateView"; //$NON-NLS-1$
112
    public static final String INPUT_ID = ID+".editorInput"; //$NON-NLS-1$
113

    
114
    public static final String YOU_NEED_TO_SAVE_BEFORE_PERFORMING_THIS_ACTION = Messages.DerivateView_YOU_NEED_TO_SAVE;
115
    public static final String VIEW_HAS_UNSAVED_CHANGES = Messages.DerivateView_UNSAVED_CHANGES;
116

    
117
    private static final List<String> SPECIMEN_INIT_STRATEGY = Arrays.asList(new String[] {
118
            "descriptions", //$NON-NLS-1$
119
            "annotations", //$NON-NLS-1$
120
            "markers", //$NON-NLS-1$
121
            "credits", //$NON-NLS-1$
122
            "extensions", //$NON-NLS-1$
123
            "rights", //$NON-NLS-1$
124
            "sources", //$NON-NLS-1$
125
            "derivationEvents.derivatives.annotations", //$NON-NLS-1$
126
            "derivationEvents.derivatives.markers", //$NON-NLS-1$
127
            "derivationEvents.derivatives.credits", //$NON-NLS-1$
128
            "derivationEvents.derivatives.extensions", //$NON-NLS-1$
129
            "derivationEvents.derivatives.rights", //$NON-NLS-1$
130
            "derivationEvents.derivatives.sources" //$NON-NLS-1$
131
    });
132

    
133
	private static final int WARN_THRESHOLD = 200;
134

    
135

    
136
	private ConversationHolder conversation;
137

    
138
	private TreeViewer viewer;
139

    
140
    private final int dndOperations = DND.DROP_MOVE;
141

    
142
    private DerivateLabelProvider labelProvider;
143

    
144
    private DerivateContentProvider contentProvider;
145

    
146
    private DerivateSearchCompositeController derivateSearchCompositeController;
147

    
148
    @Inject
149
    private IEventBroker eventBroker;
150

    
151
    /**
152
     * A map with keys being the derivative entities belonging to the {@link UUID}s passed to the constructor
153
     * and values being the root elements of the hierarchy (may be the same objects as the derivative entities)
154
     */
155
    private Map<SpecimenOrObservationBase<?>, SpecimenOrObservationBase<?>> derivateToRootEntityMap;
156

    
157
    /**
158
     * The set of root elements
159
     */
160
    private Set<SpecimenOrObservationBase<?>> rootElements;
161

    
162
    private ICdmEntitySession cdmEntitySession;
163

    
164
    /**
165
     * <code>true</code> if this view is listening to selection  changes
166
     */
167
    private boolean listenToSelectionChange;
168

    
169
    private Taxon selectedTaxon;
170

    
171
    @Inject
172
    private ESelectionService selService;
173

    
174
    @Inject
175
    private MDirtyable dirty;
176

    
177
    private ISelectionChangedListener selectionChangedListener;
178

    
179
    private Set<AbstractPostOperation> operations = new HashSet<>();
180

    
181
    @Inject
182
    private MPart thisPart;
183

    
184
    /**
185
     * Default constructor
186
     */
187
    @Inject
188
    public DerivateView() {
189
    }
190

    
191
    public void init(DerivateViewEditorInput editorInput){
192
        this.derivateToRootEntityMap = new HashMap<>();
193
        this.rootElements = new HashSet<>();
194

    
195
        //init tree
196
        Collection<UUID> derivativeUuids = editorInput.getDerivativeUuids();
197
        checkWarnThreshold(derivativeUuids);
198
        updateRootEntities(derivativeUuids);
199
        //set taxon filter
200
        derivateSearchCompositeController.setTaxonFilter(editorInput.getTaxonUuid());
201
        //reset status bar
202
        //TODO e4
203
//        getEditorSite().getActionBars().getStatusLineManager().setMessage(""); //$NON-NLS-1$
204
    }
205

    
206
    @PostConstruct
207
    public void createPartControl(Composite parent, EMenuService menuService,
208
            IEclipseContext context) {
209
        if (CdmStore.isActive()){
210
            if(conversation == null){
211
                conversation = CdmStore.createConversation();
212
            }
213
            if(cdmEntitySession == null){
214
                cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
215
            }
216
        }
217
        else{
218
            return;
219
        }
220
        //listen to context changes
221
        CdmStore.getContextManager().addContextListener(this);
222

    
223
        parent.setLayout(new GridLayout());
224

    
225
        //---search and filter---
226
        derivateSearchCompositeController = new DerivateSearchCompositeController(parent, this);
227
        GridData gridDataSearchBar = new GridData();
228
        gridDataSearchBar.horizontalAlignment = GridData.FILL;
229
        gridDataSearchBar.grabExcessHorizontalSpace = true;
230
        derivateSearchCompositeController.setLayoutData(gridDataSearchBar);
231
        derivateSearchCompositeController.setEnabled(CdmStore.isActive());
232

    
233
        //---tree viewer---
234
        viewer = new TreeViewer(new Tree(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION));
235
        GridData gridDataTree = new GridData();
236
        gridDataTree.horizontalAlignment = GridData.FILL;
237
        gridDataTree.verticalAlignment = GridData.FILL;
238
        gridDataTree.grabExcessVerticalSpace = true;
239
        gridDataTree.grabExcessHorizontalSpace = true;
240
        viewer.getTree().setLayoutData(gridDataTree);
241
        contentProvider = new DerivateContentProvider();
242
        viewer.setContentProvider(contentProvider);
243
        labelProvider = new DerivateLabelProvider();
244
        labelProvider.setConversation(conversation);
245
        viewer.setLabelProvider(labelProvider);
246
        viewer.getTree().setEnabled(CdmStore.isActive());
247

    
248
        //propagate selection
249
        selectionChangedListener = (event -> selService.setSelection(event.getSelection()));
250
        viewer.addSelectionChangedListener(selectionChangedListener);
251

    
252
        //create context menu
253
        menuService.registerContextMenu(viewer.getControl(), "eu.etaxonomy.taxeditor.editor.popupmenu.specimeneditor");
254

    
255
        //add drag'n'drop support
256
        Transfer[] transfers = new Transfer[] {LocalSelectionTransfer.getTransfer(),};
257
        viewer.addDragSupport(dndOperations, transfers, new DerivateDragListener(this));
258
        DerivateDropListener dropListener = new DerivateDropListener(this);
259
        ContextInjectionFactory.inject(dropListener, context);
260
        viewer.addDropSupport(dndOperations, transfers, dropListener);
261
    }
262

    
263
    public void updateRootEntities() {
264
        updateRootEntities((Collection)null);
265
    }
266

    
267
    public void updateRootEntities(Collection<UUID> derivativeUuids) {
268
        if(conversation!=null){
269
            if (!conversation.isBound()) {
270
                conversation.bind();
271
            }
272
            /*
273
             * If the active session is not the session of the Derivative Editor
274
             * then we will save the active session for later, bind temporarily
275
             * to our session and rebind to the original session when we are
276
             * done. This happens e.g. if a selection change happens in the
277
             * taxon editor and "Link with editor" is enabled. The selection
278
             * change event and thus the loading in updateRootEntities() happens
279
             * in the session of the taxon editor.
280
             */
281
            ICdmEntitySession previousCdmEntitySession = CdmStore.getCurrentSessionManager().getActiveSession();
282
            if(cdmEntitySession != null) {
283
                cdmEntitySession.bind();
284
            }
285
            eventBroker.post(WorkbenchEventConstants.CURRENT_ACTIVE_EDITOR, null);
286
            List<SpecimenOrObservationBase> derivates = null;
287
            if(derivativeUuids!=null){
288
                this.derivateToRootEntityMap = new HashMap<>();
289
                this.rootElements = new HashSet<>();
290
                derivates = CdmStore.getService(IOccurrenceService.class).load(new ArrayList(derivativeUuids), SPECIMEN_INIT_STRATEGY);
291
            }
292
            updateRootEntities(derivates);
293
            if(previousCdmEntitySession!=null){
294
                previousCdmEntitySession.bind();
295
            }
296
        }
297
    }
298

    
299
    public void updateRootEntities(List<SpecimenOrObservationBase> derivates) {
300
        if(derivates!=null){
301
            eventBroker.post(WorkbenchEventConstants.CURRENT_ACTIVE_EDITOR, null);
302
            this.derivateToRootEntityMap = new HashMap<>();
303
            this.rootElements = new HashSet<>();
304
            for (SpecimenOrObservationBase<?> derivate : derivates) {
305

    
306
                if(derivate instanceof FieldUnit){
307
                    derivateToRootEntityMap.put(derivate, derivate);
308
                }
309
                else {
310
                    SpecimenOrObservationBase<?> topMostDerivate = EditorUtil.getTopMostDerivate(derivate);
311
                    if(topMostDerivate!=null){
312
                        derivateToRootEntityMap.put(derivate, topMostDerivate);
313
                    }
314
                    else{
315
                        derivateToRootEntityMap.put(derivate, derivate);
316
                    }
317
                }
318
            }
319
            for (SpecimenOrObservationBase<?> specimen : derivateToRootEntityMap.values()) {
320
                rootElements.add(specimen);
321
            }
322
        }
323
        labelProvider.updateLabelCache(rootElements);
324
        viewer.setInput(rootElements);
325
        viewer.setComparator(new ViewerComparator() {
326
        	@Override
327
            public int compare(Viewer testViewer, Object e1, Object e2) {
328
	    		if (((TreeNode)e1).getValue() instanceof SpecimenOrObservationBase){
329
	    			return ((SpecimenOrObservationBase)((TreeNode)e1).getValue()).getTitleCache().compareTo(((SpecimenOrObservationBase)((TreeNode)e2).getValue()).getTitleCache());
330
	    		}else{
331
	    			return e1.toString().compareTo(e2.toString());
332
	    		}
333
	    		//return (((SpecimenOrObservationBase) e1).getTitleCache()).compareTo(((SpecimenOrObservationBase) e2).getTitleCache());
334
    		}
335
    	});
336

    
337
        //TODO e4
338
        //            getEditorSite().getActionBars().getStatusLineManager().setMessage(String.format(Messages.DerivateView_CNT_DERIVATIVES_FOUND, rootElements.size()));
339

    
340
        //set selection to derivatives if the filter criteria
341
        //taxon assignment or derivative type are set
342
        if(derivates!=null && !derivateSearchCompositeController.isDefaultSearch()){
343
            List<TreeNode> nodesToSelect = new ArrayList<>();
344
            for (SpecimenOrObservationBase<?> specimenOrObservationBase : derivates) {
345
                nodesToSelect.add(new TreeNode(specimenOrObservationBase));
346
            }
347
            setSelection(new StructuredSelection(nodesToSelect));
348
        }
349
        else{
350
            setSelection(null);
351
        }
352
    }
353

    
354
    private void setSelection(StructuredSelection selection){
355
        viewer.removeSelectionChangedListener(selectionChangedListener);
356
        viewer.setSelection(selection);
357
        viewer.addSelectionChangedListener(selectionChangedListener);
358
    }
359

    
360
    public void updateLabelCache(){
361
        labelProvider.updateLabelCache(rootElements);
362
    }
363

    
364
    @Persist
365
    @Override
366
    public void save(IProgressMonitor monitor) {
367
        String taskName = Messages.DerivateView_SAVING_HIERARCHY;
368
        monitor.beginTask(taskName, 3);
369
        if (!conversation.isBound()) {
370
            conversation.bind();
371
            if (!cdmEntitySession.isActive()){
372
                cdmEntitySession.bind();
373
            }
374
        }
375
        monitor.worked(1);
376

    
377
        // commit the conversation and start a new transaction immediately
378
        conversation.commit(true);
379

    
380
        for(AbstractPostOperation entry:operations){
381
            IStatus status = Status.CANCEL_STATUS;
382
            final IAdaptable uiInfoAdapter = WorkspaceUndoUtil
383
                    .getUIInfoAdapter(AbstractUtility.getShell());
384
            String operationlabel = entry.getLabel();
385
            try {
386
                entry.addContext(IOperationHistory.GLOBAL_UNDO_CONTEXT);
387
                status = entry.execute(new NullProgressMonitor(), uiInfoAdapter);
388
            } catch (ExecutionException e) {
389

    
390
                MessagingUtils.operationDialog(AbstractUtility.class, e, TaxeditorStorePlugin.PLUGIN_ID, operationlabel, null);
391

    
392
            }
393

    
394
            String statusString = status.equals(Status.OK_STATUS) ? "completed"
395
                    : "cancelled";
396

    
397
            IPostOperationEnabled postOperationEnabled = entry
398
                    .getPostOperationEnabled();
399
            if (postOperationEnabled != null) {
400
                postOperationEnabled.onComplete();
401
            }
402

    
403

    
404
            //AbstractUtility.executeOperation(entry,sync);
405
        }
406

    
407
        operations.clear();
408
        CdmStore.getService(IOccurrenceService.class).merge(new ArrayList<>(rootElements), true);
409

    
410
        monitor.worked(1);
411

    
412
        this.setDirty(false);
413
        monitor.worked(1);
414
        monitor.done();
415
        dirty.setDirty(false);
416
        refreshTree();
417
    }
418

    
419
    /**
420
     * @param isDirty the isDirty to set
421
     */
422
    public void setDirty(boolean isDirty) {
423
        dirty.setDirty(isDirty);
424
    }
425

    
426
    public Set<AbstractPostOperation> getOperations() {
427
        return operations;
428
    }
429

    
430
    public void addOperation(AbstractPostOperation operation) {
431
        this.operations.add(operation);
432
    }
433

    
434
    @Focus
435
    public void setFocus() {
436
        //make sure to bind again if maybe in another view the conversation was unbound
437
        if(conversation!=null && !conversation.isBound()){
438
            conversation.bind();
439
        }
440
        if(cdmEntitySession != null) {
441
            cdmEntitySession.bind();
442
        }
443
        if(viewer!=null && !viewer.getControl().isDisposed()) {
444
            viewer.getControl().setFocus();
445
            selService.setSelection(viewer.getSelection());
446
        }
447
    }
448

    
449
    @Override
450
    public void update(CdmDataChangeMap changeEvents) {
451
    }
452

    
453
    @Override
454
    public ConversationHolder getConversationHolder() {
455
        return conversation;
456
    }
457

    
458
    @Override
459
    public void changed(Object element) {
460
        setDirty(true);
461
        viewer.update(new TreeNode(element), null);
462
        viewer.refresh();
463
    }
464

    
465
    @Override
466
    public void forceDirty() {
467
        changed(null);
468
    }
469

    
470
    @Override
471
    public Map<Object, List<String>> getPropertyPathsMap() {
472
        List<String> specimenPropertyPaths = Arrays.asList(new String[] {
473
                "descriptions", //$NON-NLS-1$
474
                "derivationEvents.derivates", //$NON-NLS-1$
475
                "annotations", //$NON-NLS-1$
476
                "markers", //$NON-NLS-1$
477
                "credits", //$NON-NLS-1$
478
                "extensions", //$NON-NLS-1$
479
                "rights", //$NON-NLS-1$
480
                "sources" //$NON-NLS-1$
481
        });
482
        Map<Object, List<String>> specimenPropertyPathMap =
483
                new HashMap<>();
484
        specimenPropertyPathMap.put(SpecimenOrObservationBase.class,specimenPropertyPaths);
485
        return specimenPropertyPathMap;
486
    }
487

    
488
    /**
489
     * Refreshes the derivate hierarchy tree and expands the tree
490
     * to show and select the given object.
491
     *
492
     * @param expandTo the object to which the tree should be expanded
493
     */
494
    public void refreshTree(Object expandTo){
495
        refreshTree();
496
        TreeSelection selection = (TreeSelection) viewer.getSelection();
497
        viewer.expandToLevel(selection.getFirstElement(), 1);
498
        viewer.setSelection(new StructuredSelection(new TreeNode(expandTo)));
499
    }
500

    
501
    /**
502
     * Refreshes the derivate hierarchy tree
503
     */
504
    public void refreshTree(){
505
    	if(!viewer.getTree().isDisposed()){
506
    		viewer.refresh();
507
    	}
508
    }
509

    
510
    //FIXME:Remoting hack to make this work for remoting
511
    //This should actually be resolved using remoting post operations
512
    public void remove(Object obj) {
513
        if (obj instanceof TreeNode){
514
            obj = ((TreeNode)obj).getValue();
515
        }
516
        rootElements.remove(obj);
517
        this.derivateToRootEntityMap.remove(obj);
518
        viewer.setInput(rootElements);
519
    }
520

    
521
    /**
522
     * @return a set of {@link SingleRead}s that have multiple parents
523
     */
524
    public Set<SingleRead> getMultiLinkSingleReads() {
525
        return DerivateLabelProvider.getMultiLinkSingleReads();
526
    }
527

    
528
    public Object getSelectionInput() {
529
        return selectedTaxon;
530
    }
531

    
532
    public DerivateLabelProvider getLabelProvider() {
533
        return labelProvider;
534
    }
535

    
536
    @Override
537
    public boolean postOperation(Object objectAffectedByOperation) {
538
        refreshTree();
539
        if(objectAffectedByOperation!=null){
540
            changed(objectAffectedByOperation);
541
        }
542
        return true;
543
    }
544

    
545
    @Override
546
    public boolean onComplete() {
547
        return true;
548
    }
549

    
550

    
551
    @Override
552
    public boolean canAttachMedia() {
553
        return true;
554
    }
555

    
556
    public void addFieldUnit(FieldUnit fieldUnit) {
557
        rootElements.add(fieldUnit);
558
        derivateToRootEntityMap.put(fieldUnit, fieldUnit);
559
    }
560

    
561
    @Override
562
    public ICdmEntitySession getCdmEntitySession() {
563
        return cdmEntitySession;
564
    }
565

    
566
    @PreDestroy
567
    public void dispose() {
568
        if(conversation!=null){
569
            conversation.close();
570
            conversation = null;
571
        }
572
        if(cdmEntitySession != null) {
573
            cdmEntitySession.dispose();
574
            cdmEntitySession = null;
575
        }
576
        dirty.setDirty(false);
577
    }
578

    
579

    
580
    @Inject
581
    @Optional
582
    public void selectionChanged(@Optional @Named(IServiceConstants.ACTIVE_SELECTION) IStructuredSelection selection,
583
            @Named(IServiceConstants.ACTIVE_PART) MPart activePart, MPart thisPart){
584
        if(activePart == thisPart || viewer==null){
585
            return;
586
        }
587
        if(viewer.getTree().isDisposed()){
588
            return;
589
        }
590
        if(listenToSelectionChange){
591
            selectedTaxon = null;
592
            if(activePart.getObject() instanceof TaxonNameEditorE4){
593
                selectedTaxon = ((TaxonNameEditorE4) activePart.getObject()).getTaxon();
594
            }
595
            else if(selection != null){
596
                Object selectedElement = selection.getFirstElement();
597
                if(selectedElement instanceof TaxonNodeDto){
598
                    TaxonBase<?> taxonBase = CdmStore.getService(ITaxonService.class).load(((TaxonNodeDto)selectedElement).getTaxonUuid());
599
                    if(HibernateProxyHelper.isInstanceOf(taxonBase, Taxon.class)){
600
                        selectedTaxon = HibernateProxyHelper.deproxy(taxonBase, Taxon.class);
601
                    }
602
                    else if(selectedElement instanceof TaxonNode){
603
                        selectedTaxon = HibernateProxyHelper.deproxy(selectedElement, TaxonNode.class).getTaxon();
604
                    }
605
                    else if(selectedElement instanceof Taxon){
606
                        selectedTaxon = HibernateProxyHelper.deproxy(selectedElement, Taxon.class);
607
                    }
608
                }
609
            }
610
            if(selectedTaxon!=null){
611
                Collection<FieldUnit> fieldUnits = CdmStore.getService(IOccurrenceService.class).listRootUnitsByAssociatedTaxon(FieldUnit.class, selectedTaxon, null, null);
612
                Collection<UUID> uuids = new HashSet<>();
613
                for (SpecimenOrObservationBase<?> specimenOrObservationBase : fieldUnits) {
614
                    uuids.add(specimenOrObservationBase.getUuid());
615
                }
616
                checkWarnThreshold(uuids);
617
                updateRootEntities(uuids);
618

    
619
                thisPart.setLabel(SPECIMEN_EDITOR+": " + selectedTaxon.getName()); //$NON-NLS-1$
620
            }
621
            else{
622
                updateRootEntities((Collection<UUID>)Collections.EMPTY_LIST);
623
            }
624
        }
625
    }
626

    
627
	private void checkWarnThreshold(Collection<UUID> uuids) {
628
		if(uuids!=null && uuids.size()>WARN_THRESHOLD){
629
			MessagingUtils.warningDialog(Messages.DerivateView_PERF_WARNING, this.getClass(), String.format(Messages.DerivateView_PERF_WARNING_MESSAGE, uuids.size()));
630
			uuids.clear();
631
		}
632
	}
633

    
634
    public TreeViewer getViewer() {
635
        return viewer;
636
    }
637

    
638
    @Override
639
    public List<SpecimenOrObservationBase<?>> getRootEntities() {
640
        return new ArrayList<>(rootElements);
641
    }
642

    
643
    public void toggleListenToSelectionChange(MPart part) {
644
        listenToSelectionChange = !listenToSelectionChange;
645
        derivateSearchCompositeController.setEnabled(!listenToSelectionChange);
646
        if(!listenToSelectionChange){
647
            selectedTaxon = null;
648
            part.setLabel(SPECIMEN_EDITOR);
649
        }
650
        else if(selectedTaxon==null){
651
            part.setLabel(SPECIMEN_EDITOR+Messages.DerivateView_NO_TAXON_SELECTED);
652
        }
653
    }
654

    
655
    public boolean isListenToSelectionChange(){
656
        return listenToSelectionChange;
657
    }
658

    
659
    @Override
660
    public void contextAboutToStop(IMemento memento, IProgressMonitor monitor) {
661
    }
662

    
663
    @Override
664
    public void contextStop(IMemento memento, IProgressMonitor monitor) {
665
        //close view when workbench closes
666
        try{
667
            thisPart.getContext().get(EPartService.class).hidePart(thisPart);
668
        }
669
        catch(Exception e){
670
            //nothing
671
        }
672
    }
673

    
674
    @Override
675
    public void contextStart(IMemento memento, IProgressMonitor monitor) {
676
    }
677

    
678
    @Override
679
    public void contextRefresh(IProgressMonitor monitor) {
680
    }
681

    
682
    @Override
683
    public void workbenchShutdown(IMemento memento, IProgressMonitor monitor) {
684
    }
685

    
686
    @Override
687
    public boolean isDirty() {
688
        return dirty.isDirty();
689
    }
690

    
691
    @Override
692
    public void collapse() {
693
        viewer.collapseAll();
694
    }
695

    
696
    @Override
697
    public void expand() {
698
        viewer.expandAll();
699
    }
700
}
(3-3/6)