Project

General

Profile

Download (25.7 KB) Statistics
| Branch: | Tag: | Revision:
1
package eu.etaxonomy.taxeditor.editor.view.derivate;
2

    
3
import java.util.ArrayList;
4
import java.util.Arrays;
5
import java.util.Collection;
6
import java.util.Collections;
7
import java.util.HashMap;
8
import java.util.HashSet;
9
import java.util.List;
10
import java.util.Map;
11
import java.util.Set;
12
import java.util.UUID;
13

    
14
import javax.annotation.PostConstruct;
15
import javax.annotation.PreDestroy;
16
import javax.inject.Inject;
17
import javax.inject.Named;
18

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

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

    
94
/**
95
 * Displays the derivate hierarchy of the specimen specified in the editor input.
96
 *
97
 */
98
public class DerivateView implements IPartContentHasFactualData, IConversationEnabled,
99
        ICdmEntitySessionEnabled, IDirtyMarkable, IPostOperationEnabled, IPartContentHasDetails, IPartContentHasSupplementalData, IPartContentHasMedia,
100
        IContextListener, IE4SavablePart, ICollapsableExpandable {
101

    
102
    private static final String SPECIMEN_EDITOR = Messages.DerivateView_SPECIMEN_EDITOR;
103

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

    
107
    public static final String YOU_NEED_TO_SAVE_BEFORE_PERFORMING_THIS_ACTION = Messages.DerivateView_YOU_NEED_TO_SAVE;
108
    public static final String VIEW_HAS_UNSAVED_CHANGES = Messages.DerivateView_UNSAVED_CHANGES;
109

    
110
    private static final List<String> SPECIMEN_INIT_STRATEGY = Arrays.asList(new String[] {
111
            "descriptions", //$NON-NLS-1$
112
            "annotations", //$NON-NLS-1$
113
            "markers", //$NON-NLS-1$
114
            "credits", //$NON-NLS-1$
115
            "extensions", //$NON-NLS-1$
116
            "rights", //$NON-NLS-1$
117
            "sources", //$NON-NLS-1$
118
            "derivationEvents.derivatives.annotations", //$NON-NLS-1$
119
            "derivationEvents.derivatives.markers", //$NON-NLS-1$
120
            "derivationEvents.derivatives.credits", //$NON-NLS-1$
121
            "derivationEvents.derivatives.extensions", //$NON-NLS-1$
122
            "derivationEvents.derivatives.rights", //$NON-NLS-1$
123
            "derivationEvents.derivatives.sources" //$NON-NLS-1$
124
    });
125

    
126
	private static final int WARN_THRESHOLD = 200;
127

    
128

    
129
	private ConversationHolder conversation;
130

    
131
	private TreeViewer viewer;
132

    
133
    private final int dndOperations = DND.DROP_MOVE;
134

    
135
    private DerivateLabelProvider labelProvider;
136

    
137
    private DerivateContentProvider contentProvider;
138

    
139
    private DerivateSearchCompositeController derivateSearchCompositeController;
140

    
141
    @Inject
142
    private IEventBroker eventBroker;
143

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

    
150
    /**
151
     * The set of root elements
152
     */
153
    private Set<SpecimenOrObservationBase<?>> rootElements;
154

    
155
    private ICdmEntitySession cdmEntitySession;
156

    
157
    /**
158
     * <code>true</code> if this view is listening to selection  changes
159
     */
160
    private boolean listenToSelectionChange;
161

    
162
    private Taxon selectedTaxon;
163

    
164
    @Inject
165
    private ESelectionService selService;
166

    
167
    @Inject
168
    private MDirtyable dirty;
169

    
170
    private ISelectionChangedListener selectionChangedListener;
171

    
172
    private Set<AbstractPostOperation> operations = new HashSet<>();
173

    
174
    @Inject
175
    private MPart thisPart;
176

    
177
    /**
178
     * Default constructor
179
     */
180
    @Inject
181
    public DerivateView() {
182
    }
183

    
184
    /**
185
     * {@inheritDoc}
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(conversation == null){
207
                conversation = CdmStore.createConversation();
208
            }
209
            if(cdmEntitySession == null){
210
                cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
211
            }
212
        }
213
        else{
214
            return;
215
        }
216
        //listen to context changes
217
        CdmStore.getContextManager().addContextListener(this);
218

    
219
        parent.setLayout(new GridLayout());
220

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

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

    
244
        //propagate selection
245
        selectionChangedListener = (event -> selService.setSelection(event.getSelection()));
246
        viewer.addSelectionChangedListener(selectionChangedListener);
247

    
248
        //create context menu
249
        menuService.registerContextMenu(viewer.getControl(), "eu.etaxonomy.taxeditor.editor.popupmenu.specimeneditor");
250

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

    
259
    public void updateRootEntities() {
260
        updateRootEntities((Collection)null);
261
    }
262

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

    
295

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

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

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

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

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

    
358
    public void updateLabelCache(){
359
        labelProvider.updateLabelCache(rootElements);
360
    }
361

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

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

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

    
388
                MessagingUtils.operationDialog(AbstractUtility.class, e, TaxeditorStorePlugin.PLUGIN_ID, operationlabel, null);
389

    
390
            }
391

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

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

    
401

    
402
            //AbstractUtility.executeOperation(entry,sync);
403
        }
404

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

    
408
        monitor.worked(1);
409

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

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

    
424
    public Set<AbstractPostOperation> getOperations() {
425
        return operations;
426
    }
427

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

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

    
447
    @Override
448
    public void update(CdmDataChangeMap changeEvents) {
449
    }
450

    
451
    @Override
452
    public ConversationHolder getConversationHolder() {
453
        return conversation;
454
    }
455

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

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

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

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

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

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

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

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

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

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

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

    
549

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

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

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

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

    
578

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

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

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

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

    
637
    /**
638
     * {@inheritDoc}
639
     */
640
    @Override
641
    public List<SpecimenOrObservationBase<?>> getRootEntities() {
642
        return new ArrayList<>(rootElements);
643
    }
644

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

    
657
    public boolean isListenToSelectionChange(){
658
        return listenToSelectionChange;
659
    }
660

    
661
    /**
662
     * {@inheritDoc}
663
     */
664
    @Override
665
    public void contextAboutToStop(IMemento memento, IProgressMonitor monitor) {
666
    }
667

    
668
    /**
669
     * {@inheritDoc}
670
     */
671
    @Override
672
    public void contextStop(IMemento memento, IProgressMonitor monitor) {
673
        //close view when workbench closes
674
        try{
675
            thisPart.getContext().get(EPartService.class).hidePart(thisPart);
676
        }
677
        catch(Exception e){
678
            //nothing
679
        }
680
    }
681

    
682
    /**
683
     * {@inheritDoc}
684
     */
685
    @Override
686
    public void contextStart(IMemento memento, IProgressMonitor monitor) {
687
    }
688

    
689
    /**
690
     * {@inheritDoc}
691
     */
692
    @Override
693
    public void contextRefresh(IProgressMonitor monitor) {
694
    }
695

    
696
    /**
697
     * {@inheritDoc}
698
     */
699
    @Override
700
    public void workbenchShutdown(IMemento memento, IProgressMonitor monitor) {
701
    }
702

    
703

    
704
    @Override
705
    public boolean isDirty() {
706
        return dirty.isDirty();
707
    }
708

    
709
    @Override
710
    public void collapse() {
711
        viewer.collapseAll();
712
    }
713

    
714
    @Override
715
    public void expand() {
716
        viewer.expandAll();
717
    }
718

    
719
}
(3-3/6)