2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
9 package eu
.etaxonomy
.taxeditor
.editor
.view
.derivate
;
11 import java
.util
.ArrayList
;
12 import java
.util
.Arrays
;
13 import java
.util
.Collection
;
14 import java
.util
.Collections
;
15 import java
.util
.EnumSet
;
16 import java
.util
.HashMap
;
17 import java
.util
.HashSet
;
18 import java
.util
.List
;
21 import java
.util
.UUID
;
23 import javax
.annotation
.PostConstruct
;
24 import javax
.annotation
.PreDestroy
;
25 import javax
.inject
.Inject
;
26 import javax
.inject
.Named
;
28 import org
.eclipse
.core
.commands
.ExecutionException
;
29 import org
.eclipse
.core
.commands
.operations
.IOperationHistory
;
30 import org
.eclipse
.core
.runtime
.IAdaptable
;
31 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
32 import org
.eclipse
.core
.runtime
.IStatus
;
33 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
34 import org
.eclipse
.core
.runtime
.Status
;
35 import org
.eclipse
.e4
.core
.contexts
.ContextInjectionFactory
;
36 import org
.eclipse
.e4
.core
.contexts
.IEclipseContext
;
37 import org
.eclipse
.e4
.core
.di
.annotations
.Optional
;
38 import org
.eclipse
.e4
.core
.services
.events
.IEventBroker
;
39 import org
.eclipse
.e4
.ui
.di
.Focus
;
40 import org
.eclipse
.e4
.ui
.di
.Persist
;
41 import org
.eclipse
.e4
.ui
.model
.application
.ui
.MDirtyable
;
42 import org
.eclipse
.e4
.ui
.model
.application
.ui
.basic
.MPart
;
43 import org
.eclipse
.e4
.ui
.services
.EMenuService
;
44 import org
.eclipse
.e4
.ui
.services
.IServiceConstants
;
45 import org
.eclipse
.e4
.ui
.workbench
.modeling
.EPartService
;
46 import org
.eclipse
.e4
.ui
.workbench
.modeling
.ESelectionService
;
47 import org
.eclipse
.jface
.util
.LocalSelectionTransfer
;
48 import org
.eclipse
.jface
.viewers
.ISelectionChangedListener
;
49 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
50 import org
.eclipse
.jface
.viewers
.StructuredSelection
;
51 import org
.eclipse
.jface
.viewers
.TreeNode
;
52 import org
.eclipse
.jface
.viewers
.TreeSelection
;
53 import org
.eclipse
.jface
.viewers
.TreeViewer
;
54 import org
.eclipse
.jface
.viewers
.Viewer
;
55 import org
.eclipse
.jface
.viewers
.ViewerComparator
;
56 import org
.eclipse
.swt
.SWT
;
57 import org
.eclipse
.swt
.dnd
.DND
;
58 import org
.eclipse
.swt
.dnd
.Transfer
;
59 import org
.eclipse
.swt
.layout
.GridData
;
60 import org
.eclipse
.swt
.layout
.GridLayout
;
61 import org
.eclipse
.swt
.widgets
.Composite
;
62 import org
.eclipse
.swt
.widgets
.Tree
;
63 import org
.eclipse
.ui
.IMemento
;
64 import org
.eclipse
.ui
.ide
.undo
.WorkspaceUndoUtil
;
66 import eu
.etaxonomy
.cdm
.api
.filter
.TaxonOccurrenceRelationType
;
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
.taxeditor
.editor
.EditorUtil
;
78 import eu
.etaxonomy
.taxeditor
.editor
.l10n
.Messages
;
79 import eu
.etaxonomy
.taxeditor
.editor
.name
.e4
.TaxonEditor
;
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
;
102 * Displays the derivate hierarchy of the specimen specified in the editor input.
104 public class DerivateView
implements IPartContentHasFactualData
,
105 ICdmEntitySessionEnabled
<SpecimenOrObservationBase
<?
>>, IDirtyMarkable
, IPostOperationEnabled
, IPartContentHasDetails
, IPartContentHasSupplementalData
, IPartContentHasMedia
,
106 IContextListener
, IE4SavablePart
, ICollapsableExpandable
{
108 private static final String SPECIMEN_EDITOR
= Messages
.DerivateView_SPECIMEN_EDITOR
;
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$
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
;
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$
132 private static final int WARN_THRESHOLD
= 200;
134 private TreeViewer viewer
;
136 private final int dndOperations
= DND
.DROP_MOVE
;
138 private DerivateLabelProvider labelProvider
;
140 private DerivateContentProvider contentProvider
;
142 private DerivateSearchCompositeController derivateSearchCompositeController
;
145 private IEventBroker eventBroker
;
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)
151 private Map
<SpecimenOrObservationBase
<?
>, SpecimenOrObservationBase
<?
>> derivateToRootEntityMap
;
154 * The set of root elements
156 private Set
<SpecimenOrObservationBase
<?
>> rootElements
;
158 private ICdmEntitySession cdmEntitySession
;
161 * <code>true</code> if this view is listening to selection changes
163 private boolean listenToSelectionChange
;
165 private Taxon selectedTaxon
;
168 private ESelectionService selService
;
171 private MDirtyable dirty
;
173 private ISelectionChangedListener selectionChangedListener
;
175 private Set
<AbstractPostOperation
> operations
= new HashSet
<>();
178 private MPart thisPart
;
181 * Default constructor
184 public DerivateView() {
187 public void init(DerivateViewEditorInput editorInput
){
188 this.derivateToRootEntityMap
= new HashMap
<>();
189 this.rootElements
= new HashSet
<>();
192 Collection
<UUID
> derivativeUuids
= editorInput
.getDerivativeUuids();
193 checkWarnThreshold(derivativeUuids
);
194 updateRootEntities(derivativeUuids
);
196 derivateSearchCompositeController
.setTaxonFilter(editorInput
.getTaxonUuid());
199 // getEditorSite().getActionBars().getStatusLineManager().setMessage(""); //$NON-NLS-1$
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);
213 //listen to context changes
214 CdmStore
.getContextManager().addContextListener(this);
216 parent
.setLayout(new GridLayout());
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());
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();
238 viewer
.setLabelProvider(labelProvider
);
239 viewer
.getTree().setEnabled(CdmStore
.isActive());
241 //propagate selection
242 selectionChangedListener
= (event
-> selService
.setSelection(event
.getSelection()));
243 viewer
.addSelectionChangedListener(selectionChangedListener
);
245 //create context menu
246 menuService
.registerContextMenu(viewer
.getControl(), "eu.etaxonomy.taxeditor.editor.popupmenu.specimeneditor");
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
);
256 public void updateRootEntities() {
257 updateRootEntities((Collection
)null);
260 public void updateRootEntities(Collection
<UUID
> derivativeUuids
) {
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.
271 ICdmEntitySession previousCdmEntitySession
= CdmStore
.getCurrentSessionManager().getActiveSession();
272 if(cdmEntitySession
!= null) {
273 cdmEntitySession
.bind();
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
);
282 updateRootEntities(derivates
);
283 if(previousCdmEntitySession
!=null){
284 previousCdmEntitySession
.bind();
289 public void updateRootEntities(List
<SpecimenOrObservationBase
> derivates
) {
291 eventBroker
.post(WorkbenchEventConstants
.CURRENT_ACTIVE_EDITOR
, null);
292 this.derivateToRootEntityMap
= new HashMap
<>();
293 this.rootElements
= new HashSet
<>();
294 for (SpecimenOrObservationBase
<?
> derivate
: derivates
) {
296 if(derivate
instanceof FieldUnit
){
297 derivateToRootEntityMap
.put(derivate
, derivate
);
300 SpecimenOrObservationBase
<?
> topMostDerivate
= EditorUtil
.getTopMostDerivate(derivate
);
301 if(topMostDerivate
!=null){
302 derivateToRootEntityMap
.put(derivate
, topMostDerivate
);
305 derivateToRootEntityMap
.put(derivate
, derivate
);
309 for (SpecimenOrObservationBase
<?
> specimen
: derivateToRootEntityMap
.values()) {
310 rootElements
.add(specimen
);
313 labelProvider
.updateLabelCache(rootElements
);
314 viewer
.setInput(rootElements
);
315 viewer
.setComparator(new ViewerComparator() {
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());
321 return e1
.toString().compareTo(e2
.toString());
323 //return (((SpecimenOrObservationBase) e1).getTitleCache()).compareTo(((SpecimenOrObservationBase) e2).getTitleCache());
328 // getEditorSite().getActionBars().getStatusLineManager().setMessage(String.format(Messages.DerivateView_CNT_DERIVATIVES_FOUND, rootElements.size()));
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
));
337 setSelection(new StructuredSelection(nodesToSelect
));
344 private void setSelection(StructuredSelection selection
){
345 viewer
.removeSelectionChangedListener(selectionChangedListener
);
346 viewer
.setSelection(selection
);
347 viewer
.addSelectionChangedListener(selectionChangedListener
);
350 public void updateLabelCache(){
351 labelProvider
.updateLabelCache(rootElements
);
356 public void save(IProgressMonitor monitor
) {
357 String taskName
= Messages
.DerivateView_SAVING_HIERARCHY
;
358 monitor
.beginTask(taskName
, 3);
360 if (!cdmEntitySession
.isActive()){
361 cdmEntitySession
.bind();
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();
372 entry
.addContext(IOperationHistory
.GLOBAL_UNDO_CONTEXT
);
373 status
= entry
.execute(new NullProgressMonitor(), uiInfoAdapter
);
374 } catch (ExecutionException e
) {
376 MessagingUtils
.operationDialog(AbstractUtility
.class, e
, TaxeditorStorePlugin
.PLUGIN_ID
, operationlabel
, null);
380 String statusString
= status
.equals(Status
.OK_STATUS
) ?
"completed"
383 IPostOperationEnabled postOperationEnabled
= entry
384 .getPostOperationEnabled();
385 if (postOperationEnabled
!= null) {
386 postOperationEnabled
.onComplete();
390 //AbstractUtility.executeOperation(entry,sync);
394 CdmStore
.getService(IOccurrenceService
.class).merge(new ArrayList
<>(rootElements
), true);
398 this.setDirty(false);
401 dirty
.setDirty(false);
406 * @param isDirty the isDirty to set
408 public void setDirty(boolean isDirty
) {
409 dirty
.setDirty(isDirty
);
412 public Set
<AbstractPostOperation
> getOperations() {
416 public void addOperation(AbstractPostOperation operation
) {
417 this.operations
.add(operation
);
421 public void setFocus() {
422 //make sure to bind again if maybe in another view the session was unbound
424 if(cdmEntitySession
!= null) {
425 cdmEntitySession
.bind();
427 if(viewer
!=null && !viewer
.getControl().isDisposed()) {
428 viewer
.getControl().setFocus();
429 selService
.setSelection(viewer
.getSelection());
434 public void changed(Object element
) {
436 viewer
.update(new TreeNode(element
), null);
441 public void forceDirty() {
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$
457 Map
<Object
, List
<String
>> specimenPropertyPathMap
=
459 specimenPropertyPathMap
.put(SpecimenOrObservationBase
.class,specimenPropertyPaths
);
460 return specimenPropertyPathMap
;
464 * Refreshes the derivate hierarchy tree and expands the tree
465 * to show and select the given object.
467 * @param expandTo the object to which the tree should be expanded
469 public void refreshTree(Object expandTo
){
471 TreeSelection selection
= (TreeSelection
) viewer
.getSelection();
472 viewer
.expandToLevel(selection
.getFirstElement(), 1);
473 viewer
.setSelection(new StructuredSelection(new TreeNode(expandTo
)));
477 * Refreshes the derivate hierarchy tree
479 public void refreshTree(){
480 if(!viewer
.getTree().isDisposed()){
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();
491 rootElements
.remove(obj
);
492 this.derivateToRootEntityMap
.remove(obj
);
493 viewer
.setInput(rootElements
);
497 * @return a set of {@link SingleRead}s that have multiple parents
499 public Set
<SingleRead
> getMultiLinkSingleReads() {
500 return DerivateLabelProvider
.getMultiLinkSingleReads();
503 public Object
getSelectionInput() {
504 return selectedTaxon
;
507 public DerivateLabelProvider
getLabelProvider() {
508 return labelProvider
;
512 public boolean postOperation(Object objectAffectedByOperation
) {
514 if(objectAffectedByOperation
!=null){
515 changed(objectAffectedByOperation
);
521 public boolean onComplete() {
527 public boolean canAttachMedia() {
531 public void addFieldUnit(FieldUnit fieldUnit
) {
532 rootElements
.add(fieldUnit
);
533 derivateToRootEntityMap
.put(fieldUnit
, fieldUnit
);
537 public ICdmEntitySession
getCdmEntitySession() {
538 return cdmEntitySession
;
542 public void dispose() {
543 if(cdmEntitySession
!= null) {
544 cdmEntitySession
.dispose();
545 cdmEntitySession
= null;
547 dirty
.setDirty(false);
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){
558 if(viewer
.getTree().isDisposed()){
561 if(listenToSelectionChange
){
562 selectedTaxon
= null;
563 if(activePart
.getObject() instanceof TaxonEditor
){
564 selectedTaxon
= ((TaxonEditor
) activePart
.getObject()).getTaxon();
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);
573 else if(selectedElement
instanceof TaxonNode
){
574 selectedTaxon
= HibernateProxyHelper
.deproxy(selectedElement
, TaxonNode
.class).getTaxon();
576 else if(selectedElement
instanceof Taxon
){
577 selectedTaxon
= HibernateProxyHelper
.deproxy(selectedElement
, Taxon
.class);
581 if(selectedTaxon
!=null){
582 boolean includeUnpublished
= true;
583 EnumSet
<TaxonOccurrenceRelationType
> associationFilter
= TaxonOccurrenceRelationType
.All();
584 Collection
<FieldUnit
> fieldUnits
= CdmStore
.getService(IOccurrenceService
.class)
585 .listRootUnitsByAssociatedTaxon(FieldUnit
.class, selectedTaxon
, includeUnpublished
, associationFilter
, null, null);
586 Collection
<UUID
> uuids
= new HashSet
<>();
587 for (SpecimenOrObservationBase
<?
> specimenOrObservationBase
: fieldUnits
) {
588 uuids
.add(specimenOrObservationBase
.getUuid());
590 checkWarnThreshold(uuids
);
591 updateRootEntities(uuids
);
593 thisPart
.setLabel(SPECIMEN_EDITOR
+": " + selectedTaxon
.getName()); //$NON-NLS-1$
596 updateRootEntities((Collection
<UUID
>)Collections
.EMPTY_LIST
);
601 private void checkWarnThreshold(Collection
<UUID
> uuids
) {
602 if(uuids
!=null && uuids
.size()>WARN_THRESHOLD
){
603 MessagingUtils
.warningDialog(Messages
.DerivateView_PERF_WARNING
, this.getClass(), String
.format(Messages
.DerivateView_PERF_WARNING_MESSAGE
, uuids
.size()));
608 public TreeViewer
getViewer() {
613 public List
<SpecimenOrObservationBase
<?
>> getRootEntities() {
614 return new ArrayList
<>(rootElements
);
617 public void toggleListenToSelectionChange(MPart part
) {
618 listenToSelectionChange
= !listenToSelectionChange
;
619 derivateSearchCompositeController
.setEnabled(!listenToSelectionChange
);
620 if(!listenToSelectionChange
){
621 selectedTaxon
= null;
622 part
.setLabel(SPECIMEN_EDITOR
);
624 else if(selectedTaxon
==null){
625 part
.setLabel(SPECIMEN_EDITOR
+Messages
.DerivateView_NO_TAXON_SELECTED
);
629 public DerivateSearchCompositeController
getSearchController() {
630 return derivateSearchCompositeController
;
633 public boolean isListenToSelectionChange(){
634 return listenToSelectionChange
;
638 public void contextAboutToStop(IMemento memento
, IProgressMonitor monitor
) {
642 public void contextStop(IMemento memento
, IProgressMonitor monitor
) {
643 //close view when workbench closes
645 thisPart
.getContext().get(EPartService
.class).hidePart(thisPart
);
653 public void contextStart(IMemento memento
, IProgressMonitor monitor
) {
657 public void contextRefresh(IProgressMonitor monitor
) {
661 public void workbenchShutdown(IMemento memento
, IProgressMonitor monitor
) {
665 public boolean isDirty() {
666 return dirty
.isDirty();
670 public void collapse() {
671 viewer
.collapseAll();
675 public void expand() {