Project

General

Profile

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

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

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

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

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

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

    
132
	private static final int WARN_THRESHOLD = 200;
133
	
134
	private TreeViewer viewer;
135

    
136
    private final int dndOperations = DND.DROP_MOVE;
137

    
138
    private DerivateLabelProvider labelProvider;
139

    
140
    private DerivateContentProvider contentProvider;
141

    
142
    private DerivateSearchCompositeController derivateSearchCompositeController;
143

    
144
    @Inject
145
    private IEventBroker eventBroker;
146

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

    
153
    /**
154
     * The set of root elements
155
     */
156
    private Set<SpecimenOrObservationBase<?>> rootElements;
157

    
158
    private ICdmEntitySession cdmEntitySession;
159

    
160
    /**
161
     * <code>true</code> if this view is listening to selection  changes
162
     */
163
    private boolean listenToSelectionChange;
164

    
165
    private Taxon selectedTaxon;
166

    
167
    @Inject
168
    private ESelectionService selService;
169

    
170
    @Inject
171
    private MDirtyable dirty;
172

    
173
    private ISelectionChangedListener selectionChangedListener;
174

    
175
    private Set<AbstractPostOperation> operations = new HashSet<>();
176

    
177
    @Inject
178
    private MPart thisPart;
179

    
180
    /**
181
     * Default constructor
182
     */
183
    @Inject
184
    public DerivateView() {
185
    }
186

    
187
    public void init(DerivateViewEditorInput editorInput){
188
        this.derivateToRootEntityMap = new HashMap<>();
189
        this.rootElements = new HashSet<>();
190

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

    
202
    @PostConstruct
203
    public void createPartControl(Composite parent, EMenuService menuService,
204
            IEclipseContext context) {
205
        if (CdmStore.isActive()){
206
            if(cdmEntitySession == null){
207
                cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
208
            }
209
        }
210
        else{
211
            return;
212
        }
213
        //listen to context changes
214
        CdmStore.getContextManager().addContextListener(this);
215

    
216
        parent.setLayout(new GridLayout());
217

    
218
        //---search and filter---
219
        derivateSearchCompositeController = new DerivateSearchCompositeController(parent, this);
220
        GridData gridDataSearchBar = new GridData();
221
        gridDataSearchBar.horizontalAlignment = GridData.FILL;
222
        gridDataSearchBar.grabExcessHorizontalSpace = true;
223
        derivateSearchCompositeController.setLayoutData(gridDataSearchBar);
224
        derivateSearchCompositeController.setEnabled(CdmStore.isActive());
225

    
226
        //---tree viewer---
227
        viewer = new TreeViewer(new Tree(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION));
228
        GridData gridDataTree = new GridData();
229
        gridDataTree.horizontalAlignment = GridData.FILL;
230
        gridDataTree.verticalAlignment = GridData.FILL;
231
        gridDataTree.grabExcessVerticalSpace = true;
232
        gridDataTree.grabExcessHorizontalSpace = true;
233
        viewer.getTree().setLayoutData(gridDataTree);
234
        contentProvider = new DerivateContentProvider();
235
        viewer.setContentProvider(contentProvider);
236
        labelProvider = new DerivateLabelProvider();
237
        
238
        viewer.setLabelProvider(labelProvider);
239
        viewer.getTree().setEnabled(CdmStore.isActive());
240

    
241
        //propagate selection
242
        selectionChangedListener = (event -> selService.setSelection(event.getSelection()));
243
        viewer.addSelectionChangedListener(selectionChangedListener);
244

    
245
        //create context menu
246
        menuService.registerContextMenu(viewer.getControl(), "eu.etaxonomy.taxeditor.editor.popupmenu.specimeneditor");
247

    
248
        //add drag'n'drop support
249
        Transfer[] transfers = new Transfer[] {LocalSelectionTransfer.getTransfer(),};
250
        viewer.addDragSupport(dndOperations, transfers, new DerivateDragListener(this));
251
        DerivateDropListener dropListener = new DerivateDropListener(this);
252
        ContextInjectionFactory.inject(dropListener, context);
253
        viewer.addDropSupport(dndOperations, transfers, dropListener);
254
    }
255

    
256
    public void updateRootEntities() {
257
        updateRootEntities((Collection)null);
258
    }
259

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

    
289
    public void updateRootEntities(List<SpecimenOrObservationBase> derivates) {
290
        if(derivates!=null){
291
            eventBroker.post(WorkbenchEventConstants.CURRENT_ACTIVE_EDITOR, null);
292
            this.derivateToRootEntityMap = new HashMap<>();
293
            this.rootElements = new HashSet<>();
294
            for (SpecimenOrObservationBase<?> derivate : derivates) {
295

    
296
                if(derivate instanceof FieldUnit){
297
                    derivateToRootEntityMap.put(derivate, derivate);
298
                }
299
                else {
300
                    SpecimenOrObservationBase<?> topMostDerivate = EditorUtil.getTopMostDerivate(derivate);
301
                    if(topMostDerivate!=null){
302
                        derivateToRootEntityMap.put(derivate, topMostDerivate);
303
                    }
304
                    else{
305
                        derivateToRootEntityMap.put(derivate, derivate);
306
                    }
307
                }
308
            }
309
            for (SpecimenOrObservationBase<?> specimen : derivateToRootEntityMap.values()) {
310
                rootElements.add(specimen);
311
            }
312
        }
313
        labelProvider.updateLabelCache(rootElements);
314
        viewer.setInput(rootElements);
315
        viewer.setComparator(new ViewerComparator() {
316
        	@Override
317
            public int compare(Viewer testViewer, Object e1, Object e2) {
318
	    		if (((TreeNode)e1).getValue() instanceof SpecimenOrObservationBase){
319
	    			return ((SpecimenOrObservationBase)((TreeNode)e1).getValue()).getTitleCache().compareTo(((SpecimenOrObservationBase)((TreeNode)e2).getValue()).getTitleCache());
320
	    		}else{
321
	    			return e1.toString().compareTo(e2.toString());
322
	    		}
323
	    		//return (((SpecimenOrObservationBase) e1).getTitleCache()).compareTo(((SpecimenOrObservationBase) e2).getTitleCache());
324
    		}
325
    	});
326

    
327
        //TODO e4
328
        //            getEditorSite().getActionBars().getStatusLineManager().setMessage(String.format(Messages.DerivateView_CNT_DERIVATIVES_FOUND, rootElements.size()));
329

    
330
        //set selection to derivatives if the filter criteria
331
        //taxon assignment or derivative type are set
332
        if(derivates!=null && !derivateSearchCompositeController.isDefaultSearch()){
333
            List<TreeNode> nodesToSelect = new ArrayList<>();
334
            for (SpecimenOrObservationBase<?> specimenOrObservationBase : derivates) {
335
                nodesToSelect.add(new TreeNode(specimenOrObservationBase));
336
            }
337
            setSelection(new StructuredSelection(nodesToSelect));
338
        }
339
        else{
340
            setSelection(null);
341
        }
342
    }
343

    
344
    private void setSelection(StructuredSelection selection){
345
        viewer.removeSelectionChangedListener(selectionChangedListener);
346
        viewer.setSelection(selection);
347
        viewer.addSelectionChangedListener(selectionChangedListener);
348
    }
349

    
350
    public void updateLabelCache(){
351
        labelProvider.updateLabelCache(rootElements);
352
    }
353

    
354
    @Persist
355
    @Override
356
    public void save(IProgressMonitor monitor) {
357
        String taskName = Messages.DerivateView_SAVING_HIERARCHY;
358
        monitor.beginTask(taskName, 3);
359
        
360
        if (!cdmEntitySession.isActive()){
361
        	cdmEntitySession.bind();
362
        }
363
        
364
        monitor.worked(1);
365

    
366
        for(AbstractPostOperation entry:operations){
367
            IStatus status = Status.CANCEL_STATUS;
368
            final IAdaptable uiInfoAdapter = WorkspaceUndoUtil
369
                    .getUIInfoAdapter(AbstractUtility.getShell());
370
            String operationlabel = entry.getLabel();
371
            try {
372
                entry.addContext(IOperationHistory.GLOBAL_UNDO_CONTEXT);
373
                status = entry.execute(new NullProgressMonitor(), uiInfoAdapter);
374
            } catch (ExecutionException e) {
375

    
376
                MessagingUtils.operationDialog(AbstractUtility.class, e, TaxeditorStorePlugin.PLUGIN_ID, operationlabel, null);
377

    
378
            }
379

    
380
            String statusString = status.equals(Status.OK_STATUS) ? "completed"
381
                    : "cancelled";
382

    
383
            IPostOperationEnabled postOperationEnabled = entry
384
                    .getPostOperationEnabled();
385
            if (postOperationEnabled != null) {
386
                postOperationEnabled.onComplete();
387
            }
388

    
389

    
390
            //AbstractUtility.executeOperation(entry,sync);
391
        }
392

    
393
        operations.clear();
394
        CdmStore.getService(IOccurrenceService.class).merge(new ArrayList<>(rootElements), true);
395

    
396
        monitor.worked(1);
397

    
398
        this.setDirty(false);
399
        monitor.worked(1);
400
        monitor.done();
401
        dirty.setDirty(false);
402
        refreshTree();
403
    }
404

    
405
    /**
406
     * @param isDirty the isDirty to set
407
     */
408
    public void setDirty(boolean isDirty) {
409
        dirty.setDirty(isDirty);
410
    }
411

    
412
    public Set<AbstractPostOperation> getOperations() {
413
        return operations;
414
    }
415

    
416
    public void addOperation(AbstractPostOperation operation) {
417
        this.operations.add(operation);
418
    }
419

    
420
    @Focus
421
    public void setFocus() {
422
        //make sure to bind again if maybe in another view the session was unbound
423
        
424
        if(cdmEntitySession != null) {
425
            cdmEntitySession.bind();
426
        }
427
        if(viewer!=null && !viewer.getControl().isDisposed()) {
428
            viewer.getControl().setFocus();
429
            selService.setSelection(viewer.getSelection());
430
        }
431
    }
432

    
433
    @Override
434
    public void changed(Object element) {
435
        setDirty(true);
436
        viewer.update(new TreeNode(element), null);
437
        viewer.refresh();
438
    }
439

    
440
    @Override
441
    public void forceDirty() {
442
        changed(null);
443
    }
444

    
445
    @Override
446
    public Map<Object, List<String>> getPropertyPathsMap() {
447
        List<String> specimenPropertyPaths = Arrays.asList(new String[] {
448
                "descriptions", //$NON-NLS-1$
449
                "derivationEvents.derivates", //$NON-NLS-1$
450
                "annotations", //$NON-NLS-1$
451
                "markers", //$NON-NLS-1$
452
                "credits", //$NON-NLS-1$
453
                "extensions", //$NON-NLS-1$
454
                "rights", //$NON-NLS-1$
455
                "sources" //$NON-NLS-1$
456
        });
457
        Map<Object, List<String>> specimenPropertyPathMap =
458
                new HashMap<>();
459
        specimenPropertyPathMap.put(SpecimenOrObservationBase.class,specimenPropertyPaths);
460
        return specimenPropertyPathMap;
461
    }
462

    
463
    /**
464
     * Refreshes the derivate hierarchy tree and expands the tree
465
     * to show and select the given object.
466
     *
467
     * @param expandTo the object to which the tree should be expanded
468
     */
469
    public void refreshTree(Object expandTo){
470
        refreshTree();
471
        TreeSelection selection = (TreeSelection) viewer.getSelection();
472
        viewer.expandToLevel(selection.getFirstElement(), 1);
473
        viewer.setSelection(new StructuredSelection(new TreeNode(expandTo)));
474
    }
475

    
476
    /**
477
     * Refreshes the derivate hierarchy tree
478
     */
479
    public void refreshTree(){
480
    	if(!viewer.getTree().isDisposed()){
481
    		viewer.refresh();
482
    	}
483
    }
484

    
485
    //FIXME:Remoting hack to make this work for remoting
486
    //This should actually be resolved using remoting post operations
487
    public void remove(Object obj) {
488
        if (obj instanceof TreeNode){
489
            obj = ((TreeNode)obj).getValue();
490
        }
491
        rootElements.remove(obj);
492
        this.derivateToRootEntityMap.remove(obj);
493
        viewer.setInput(rootElements);
494
    }
495

    
496
    /**
497
     * @return a set of {@link SingleRead}s that have multiple parents
498
     */
499
    public Set<SingleRead> getMultiLinkSingleReads() {
500
        return DerivateLabelProvider.getMultiLinkSingleReads();
501
    }
502

    
503
    public Object getSelectionInput() {
504
        return selectedTaxon;
505
    }
506

    
507
    public DerivateLabelProvider getLabelProvider() {
508
        return labelProvider;
509
    }
510

    
511
    @Override
512
    public boolean postOperation(Object objectAffectedByOperation) {
513
        refreshTree();
514
        if(objectAffectedByOperation!=null){
515
            changed(objectAffectedByOperation);
516
        }
517
        return true;
518
    }
519

    
520
    @Override
521
    public boolean onComplete() {
522
        return true;
523
    }
524

    
525

    
526
    @Override
527
    public boolean canAttachMedia() {
528
        return true;
529
    }
530

    
531
    public void addFieldUnit(FieldUnit fieldUnit) {
532
        rootElements.add(fieldUnit);
533
        derivateToRootEntityMap.put(fieldUnit, fieldUnit);
534
    }
535

    
536
    @Override
537
    public ICdmEntitySession getCdmEntitySession() {
538
        return cdmEntitySession;
539
    }
540

    
541
    @PreDestroy
542
    public void dispose() {
543
    	if(cdmEntitySession != null) {
544
            cdmEntitySession.dispose();
545
            cdmEntitySession = null;
546
        }
547
        dirty.setDirty(false);
548
    }
549

    
550

    
551
    @Inject
552
    @Optional
553
    public void selectionChanged(@Optional @Named(IServiceConstants.ACTIVE_SELECTION) IStructuredSelection selection,
554
            @Named(IServiceConstants.ACTIVE_PART) MPart activePart, MPart thisPart){
555
        if(activePart == thisPart || viewer==null){
556
            return;
557
        }
558
        if(viewer.getTree().isDisposed()){
559
            return;
560
        }
561
        if(listenToSelectionChange){
562
            selectedTaxon = null;
563
            if(activePart.getObject() instanceof TaxonNameEditorE4){
564
                selectedTaxon = ((TaxonNameEditorE4) activePart.getObject()).getTaxon();
565
            }
566
            else if(selection != null){
567
                Object selectedElement = selection.getFirstElement();
568
                if(selectedElement instanceof TaxonNodeDto){
569
                    TaxonBase<?> taxonBase = CdmStore.getService(ITaxonService.class).load(((TaxonNodeDto)selectedElement).getTaxonUuid());
570
                    if(HibernateProxyHelper.isInstanceOf(taxonBase, Taxon.class)){
571
                        selectedTaxon = HibernateProxyHelper.deproxy(taxonBase, Taxon.class);
572
                    }
573
                    else if(selectedElement instanceof TaxonNode){
574
                        selectedTaxon = HibernateProxyHelper.deproxy(selectedElement, TaxonNode.class).getTaxon();
575
                    }
576
                    else if(selectedElement instanceof Taxon){
577
                        selectedTaxon = HibernateProxyHelper.deproxy(selectedElement, Taxon.class);
578
                    }
579
                }
580
            }
581
            if(selectedTaxon!=null){
582
                Collection<FieldUnit> fieldUnits = CdmStore.getService(IOccurrenceService.class).listRootUnitsByAssociatedTaxon(FieldUnit.class, selectedTaxon, null, null);
583
                Collection<UUID> uuids = new HashSet<>();
584
                for (SpecimenOrObservationBase<?> specimenOrObservationBase : fieldUnits) {
585
                    uuids.add(specimenOrObservationBase.getUuid());
586
                }
587
                checkWarnThreshold(uuids);
588
                updateRootEntities(uuids);
589

    
590
                thisPart.setLabel(SPECIMEN_EDITOR+": " + selectedTaxon.getName()); //$NON-NLS-1$
591
            }
592
            else{
593
                updateRootEntities((Collection<UUID>)Collections.EMPTY_LIST);
594
            }
595
        }
596
    }
597

    
598
	private void checkWarnThreshold(Collection<UUID> uuids) {
599
		if(uuids!=null && uuids.size()>WARN_THRESHOLD){
600
			MessagingUtils.warningDialog(Messages.DerivateView_PERF_WARNING, this.getClass(), String.format(Messages.DerivateView_PERF_WARNING_MESSAGE, uuids.size()));
601
			uuids.clear();
602
		}
603
	}
604

    
605
    public TreeViewer getViewer() {
606
        return viewer;
607
    }
608

    
609
    @Override
610
    public List<SpecimenOrObservationBase<?>> getRootEntities() {
611
        return new ArrayList<>(rootElements);
612
    }
613

    
614
    public void toggleListenToSelectionChange(MPart part) {
615
        listenToSelectionChange = !listenToSelectionChange;
616
        derivateSearchCompositeController.setEnabled(!listenToSelectionChange);
617
        if(!listenToSelectionChange){
618
            selectedTaxon = null;
619
            part.setLabel(SPECIMEN_EDITOR);
620
        }
621
        else if(selectedTaxon==null){
622
            part.setLabel(SPECIMEN_EDITOR+Messages.DerivateView_NO_TAXON_SELECTED);
623
        }
624
    }
625
    
626
    public DerivateSearchCompositeController getSearchController() {
627
    	return derivateSearchCompositeController;
628
    }
629

    
630
    public boolean isListenToSelectionChange(){
631
        return listenToSelectionChange;
632
    }
633

    
634
    @Override
635
    public void contextAboutToStop(IMemento memento, IProgressMonitor monitor) {
636
    }
637

    
638
    @Override
639
    public void contextStop(IMemento memento, IProgressMonitor monitor) {
640
        //close view when workbench closes
641
        try{
642
            thisPart.getContext().get(EPartService.class).hidePart(thisPart);
643
        }
644
        catch(Exception e){
645
            //nothing
646
        }
647
    }
648

    
649
    @Override
650
    public void contextStart(IMemento memento, IProgressMonitor monitor) {
651
    }
652

    
653
    @Override
654
    public void contextRefresh(IProgressMonitor monitor) {
655
    }
656

    
657
    @Override
658
    public void workbenchShutdown(IMemento memento, IProgressMonitor monitor) {
659
    }
660

    
661
    @Override
662
    public boolean isDirty() {
663
        return dirty.isDirty();
664
    }
665

    
666
    @Override
667
    public void collapse() {
668
        viewer.collapseAll();
669
    }
670

    
671
    @Override
672
    public void expand() {
673
        viewer.expandAll();
674
    }
675
}
(3-3/6)