Add status bar info for hierarchies found
[taxeditor.git] / eu.etaxonomy.taxeditor.editor / src / main / java / eu / etaxonomy / taxeditor / editor / view / derivate / DerivateView.java
index 68445078d0e23e189d5822ff05a32bc6e8b67e7e..a6504a980626b40a4448e55fae4ee02630f7b8fb 100644 (file)
@@ -1,8 +1,12 @@
 package eu.etaxonomy.taxeditor.editor.view.derivate;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Map.Entry;
+import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 
@@ -11,8 +15,7 @@ import org.eclipse.jface.action.MenuManager;
 import org.eclipse.jface.util.LocalSelectionTransfer;
 import org.eclipse.jface.viewers.AbstractTreeViewer;
 import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.jface.viewers.TreeNode;
 import org.eclipse.jface.viewers.TreeSelection;
@@ -20,6 +23,8 @@ import org.eclipse.jface.viewers.TreeViewer;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.dnd.DND;
 import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Menu;
@@ -27,36 +32,68 @@ import org.eclipse.swt.widgets.Tree;
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.IEditorPart;
 import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.ISelectionService;
+import org.eclipse.ui.IWorkbenchPart;
 import org.eclipse.ui.PartInitException;
 import org.eclipse.ui.part.EditorPart;
 
 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
 import eu.etaxonomy.cdm.api.service.IOccurrenceService;
-import eu.etaxonomy.cdm.api.service.molecular.ISequenceService;
+import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
 import eu.etaxonomy.cdm.model.common.CdmBase;
-import eu.etaxonomy.cdm.model.molecular.Sequence;
 import eu.etaxonomy.cdm.model.molecular.SingleRead;
+import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
+import eu.etaxonomy.cdm.model.taxon.Taxon;
+import eu.etaxonomy.cdm.model.taxon.TaxonNode;
 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
+import eu.etaxonomy.taxeditor.editor.EditorUtil;
+import eu.etaxonomy.taxeditor.editor.Messages;
+import eu.etaxonomy.taxeditor.editor.MultiPageTaxonEditor;
+import eu.etaxonomy.taxeditor.editor.view.derivate.searchFilter.DerivateSearchCompositeController;
+import eu.etaxonomy.taxeditor.model.IContextListener;
 import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
 import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
 import eu.etaxonomy.taxeditor.model.IPartContentHasFactualData;
 import eu.etaxonomy.taxeditor.model.IPartContentHasMedia;
 import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
 import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
+import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
+import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
 import eu.etaxonomy.taxeditor.store.CdmStore;
+import eu.etaxonomy.taxeditor.view.derivateSearch.DerivateContentProvider;
 import eu.etaxonomy.taxeditor.view.derivateSearch.DerivateLabelProvider;
 
 /**
  * Displays the derivate hierarchy of the specimen specified in the editor input.
  *
  */
-public class DerivateView extends EditorPart implements IPartContentHasFactualData, IDirtyMarkable,
-        IConversationEnabled, IPartContentHasDetails, IPartContentHasSupplementalData, IPartContentHasMedia,
-        ISelectionChangedListener, IPostOperationEnabled {
-
-    public static final String ID = "eu.etaxonomy.taxeditor.editor.view.derivate.DerivateView";
+public class DerivateView extends EditorPart implements IPartContentHasFactualData, IConversationEnabled,
+        ICdmEntitySessionEnabled, IDirtyMarkable, IPostOperationEnabled, IPartContentHasDetails, IPartContentHasSupplementalData, IPartContentHasMedia,
+        IContextListener, ISelectionListener {
+    public static final String ID = "eu.etaxonomy.taxeditor.editor.view.derivate.DerivateView"; //$NON-NLS-1$
+
+    public static final String YOU_NEED_TO_SAVE_BEFORE_PERFORMING_THIS_ACTION = Messages.DerivateView_YOU_NEED_TO_SAVE;
+    public static final String VIEW_HAS_UNSAVED_CHANGES = Messages.DerivateView_UNSAVED_CHANGES;
+
+    private static final List<String> SPECIMEN_INIT_STRATEGY = Arrays.asList(new String[] {
+            "descriptions",
+            "annotations",
+            "markers",
+            "credits",
+            "extensions",
+            "rights",
+            "sources",
+            "derivationEvents.derivatives.annotations",
+            "derivationEvents.derivatives.markers",
+            "derivationEvents.derivatives.credits",
+            "derivationEvents.derivatives.extensions",
+            "derivationEvents.derivatives.rights",
+            "derivationEvents.derivatives.sources"
+    });
 
        private ConversationHolder conversation;
 
@@ -68,9 +105,31 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
 
     private DerivateLabelProvider labelProvider;
 
-    private Set<SingleRead> multiLinkSingleReads;
+    private DerivateContentProvider contentProvider;
+
+    private DerivateSearchCompositeController derivateSearchCompositeController;
+
+    /**
+     * A map with keys being the derivative entities belonging to the {@link UUID}s passed to the constructor
+     * and values being the root elements of the hierarchy (may be the same objects as the derivative entities)
+     */
+    private Map<SpecimenOrObservationBase<?>, SpecimenOrObservationBase<?>> derivateToRootEntityMap;
+
+    /**
+     * The set of root elements
+     */
+    private Set<SpecimenOrObservationBase<?>> rootElements;
+
+    private ICdmEntitySession cdmEntitySession;
+
+    /**
+     * <code>true</code> if this view is listening to selection  changes
+     */
+    private boolean listenToSelectionChange;
+
+    private Taxon selectedTaxon;
 
-    private ISelection selection = null;
+    private ISelectionService selectionService;
 
     /**
      * Default constructor
@@ -78,21 +137,61 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
     public DerivateView() {
     }
 
-    /* (non-Javadoc)
-     * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
+
+    /**
+     * {@inheritDoc}
      */
+    @Override
+    public void init(IEditorSite site, IEditorInput input) throws PartInitException {
+        this.setSite(site);
+        this.setInput(input);
+        this.derivateToRootEntityMap = new HashMap<SpecimenOrObservationBase<?>, SpecimenOrObservationBase<?>>();
+        this.rootElements = new HashSet<SpecimenOrObservationBase<?>>();
+
+        if (CdmStore.isActive() && conversation == null) {
+            conversation = CdmStore.createConversation();
+        }
+        if (CdmStore.isActive()) {
+            cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
+        }
+        //listen to context changes
+        CdmStore.getContextManager().addContextListener(this);
+    }
+
     @Override
     public void createPartControl(Composite parent) {
+
+        parent.setLayout(new GridLayout());
+
+        //---search and filter---
+        derivateSearchCompositeController = new DerivateSearchCompositeController(parent, this);
+        GridData gridDataSearchBar = new GridData();
+        gridDataSearchBar.horizontalAlignment = GridData.FILL;
+        gridDataSearchBar.grabExcessHorizontalSpace = true;
+        derivateSearchCompositeController.setLayoutData(gridDataSearchBar);
+        derivateSearchCompositeController.setEnabled(CdmStore.isActive());
+
+        //---tree viewer---
         viewer = new TreeViewer(new Tree(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION));
-        viewer.setContentProvider(new DerivateContentProvider());
+        GridData gridDataTree = new GridData();
+        gridDataTree.horizontalAlignment = GridData.FILL;
+        gridDataTree.verticalAlignment = GridData.FILL;
+        gridDataTree.grabExcessVerticalSpace = true;
+        gridDataTree.grabExcessHorizontalSpace = true;
+        viewer.getTree().setLayoutData(gridDataTree);
+        contentProvider = new DerivateContentProvider();
+        viewer.setContentProvider(contentProvider);
         labelProvider = new DerivateLabelProvider();
         labelProvider.setConversation(conversation);
         viewer.setLabelProvider(labelProvider);
         viewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
+        viewer.getTree().setEnabled(CdmStore.isActive());
         // Propagate selection from viewer
         getSite().setSelectionProvider(viewer);
+
         //listen to selection changes
-        viewer.addSelectionChangedListener(this);
+        selectionService = getSite().getWorkbenchWindow().getSelectionService();
+        selectionService.addSelectionListener(this);
 
         //create context menu
         MenuManager menuManager = new MenuManager();
@@ -101,20 +200,8 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
         Menu menu = menuManager.createContextMenu(control);
         control.setMenu(menu);
 
-        generateMultiLinkSingleReads();
-        labelProvider.setMultiLinkSingleReads(multiLinkSingleReads);
-        IEditorInput editorInput = getEditorInput();
-        viewer.setInput(editorInput);
-        //set selection to selected derivate if only one was selected
-        if(editorInput instanceof DerivateViewEditorInput){
-            Set<UUID> derivateUUIDs = ((DerivateViewEditorInput) editorInput).getDerivateUUIDs();
-            if(derivateUUIDs.size()==1){
-                SpecimenOrObservationBase<?> specimen = CdmStore.getService(IOccurrenceService.class).load(derivateUUIDs.iterator().next());
-                if(specimen!=null){
-                    viewer.setSelection(new StructuredSelection(new TreeNode(specimen)));
-                }
-            }
-        }
+        //init tree
+        updateRootEntities();
 
         //add drag'n'drop support
         Transfer[] transfers = new Transfer[] {LocalSelectionTransfer.getTransfer(),};
@@ -122,16 +209,74 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
         viewer.addDropSupport(dndOperations, transfers, new DerivateDropListener(this));
     }
 
-    /* (non-Javadoc)
-     * @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
-     */
+    public void updateRootEntities() {
+        updateRootEntities((Collection)null);
+    }
+
+    public void updateRootEntities(Collection<UUID> derivativeUuids) {
+        if(conversation!=null){
+            if (!conversation.isBound()) {
+                conversation.bind();
+            }
+            /*
+             * If the active session is not the session of the Derivate Editor then we will
+             * save it, bind temporarily to our session and rebind to the original session.
+             * This happens e.g. if a selection change happens in the taxon editor and
+             * "Link with editor" is enabled. The selection change event and thus the
+             * loading in updateRootEntities() happens in the session of the taxon
+             * editor.
+             */
+            ICdmEntitySession previousCdmEntitySession = CdmStore.getCurrentSessionManager().getActiveSession();
+            if(cdmEntitySession != null) {
+                cdmEntitySession.bind();
+            }
+
+            List<SpecimenOrObservationBase> derivates = null;
+            if(derivativeUuids!=null){
+                this.derivateToRootEntityMap = new HashMap<SpecimenOrObservationBase<?>, SpecimenOrObservationBase<?>>();
+                this.rootElements = new HashSet<SpecimenOrObservationBase<?>>();
+                derivates = CdmStore.getService(IOccurrenceService.class).load(new ArrayList(derivativeUuids), SPECIMEN_INIT_STRATEGY);
+            }
+            updateRootEntities(derivates);
+            previousCdmEntitySession.bind();
+        }
+    }
+
+
+    public void updateRootEntities(List<SpecimenOrObservationBase> derivates) {
+
+            if(derivates!=null){
+                this.derivateToRootEntityMap = new HashMap<SpecimenOrObservationBase<?>, SpecimenOrObservationBase<?>>();
+                this.rootElements = new HashSet<SpecimenOrObservationBase<?>>();
+                for (SpecimenOrObservationBase derivate : derivates) {
+
+                    if(derivate instanceof FieldUnit){
+                        derivateToRootEntityMap.put(derivate, derivate);
+                    }
+                    else {
+                        SpecimenOrObservationBase<?> topMostDerivate = EditorUtil.getTopMostDerivate(derivate);
+                        if(topMostDerivate!=null){
+                            derivateToRootEntityMap.put(derivate, topMostDerivate);
+                        }
+                        else{
+                            derivateToRootEntityMap.put(derivate, derivate);
+                        }
+                    }
+                }
+                for (SpecimenOrObservationBase<?> specimen : derivateToRootEntityMap.values()) {
+                    rootElements.add(specimen);
+                }
+            }
+            labelProvider.initCache(rootElements);
+            viewer.setInput(rootElements);
+
+            getEditorSite().getActionBars().getStatusLineManager().setMessage(rootElements.size() +" derivative hierarchies found");
+
+    }
+
     @Override
     public void doSave(IProgressMonitor monitor) {
-        String taskName = "Saving hierarchy";
-        if(getEditorInput() instanceof DerivateViewEditorInput){
-            DerivateViewEditorInput derivateViewEditorInput = (DerivateViewEditorInput) getEditorInput();
-            taskName += " "+derivateViewEditorInput.getName();
-        }
+        String taskName = Messages.DerivateView_SAVING_HIERARCHY;
         monitor.beginTask(taskName, 3);
         if (!conversation.isBound()) {
             conversation.bind();
@@ -140,6 +285,10 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
 
         // commit the conversation and start a new transaction immediately
         conversation.commit(true);
+
+        if(CdmStore.getCurrentSessionManager().isRemoting()) {
+            CdmStore.getService(IOccurrenceService.class).merge(new ArrayList<SpecimenOrObservationBase>(rootElements), true);
+        }
         monitor.worked(1);
 
         this.setDirty(false);
@@ -149,42 +298,15 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
         refreshTree();
     }
 
-    /* (non-Javadoc)
-     * @see org.eclipse.ui.part.EditorPart#doSaveAs()
-     */
     @Override
     public void doSaveAs() {
     }
 
-    /* (non-Javadoc)
-     * @see org.eclipse.ui.part.EditorPart#getTitleToolTip()
-     */
     @Override
     public String getTitleToolTip() {
-        if(getEditorInput() instanceof DerivateViewEditorInput){
-            DerivateViewEditorInput derivateViewEditorInput = (DerivateViewEditorInput) getEditorInput();
-            return derivateViewEditorInput.getName();
-        }
-        return "Derivate View";
-    }
-
-    /* (non-Javadoc)
-     * @see org.eclipse.ui.part.EditorPart#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
-     */
-    @Override
-    public void init(IEditorSite site, IEditorInput input) throws PartInitException {
-        setSite(site);
-        setInput(input);
-        if(input instanceof DerivateViewEditorInput){
-            DerivateViewEditorInput derivateViewEditorInput = (DerivateViewEditorInput) input;
-            conversation = derivateViewEditorInput.getConversationHolder();
-            setPartName(derivateViewEditorInput.getName());
-        }
+        return Messages.DerivateView_DERIVATIVE_EDITOR;
     }
 
-    /* (non-Javadoc)
-     * @see org.eclipse.ui.part.EditorPart#isDirty()
-     */
     @Override
     public boolean isDirty() {
         return isDirty;
@@ -197,67 +319,62 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
         this.isDirty = isDirty;
     }
 
-    /* (non-Javadoc)
-     * @see org.eclipse.ui.part.EditorPart#isSaveAsAllowed()
-     */
     @Override
     public boolean isSaveAsAllowed() {
         return false;
     }
 
-
-    /* (non-Javadoc)
-     * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
-     */
     @Override
     public void setFocus() {
         viewer.getControl().setFocus();
         //make sure to bind again if maybe in another view the conversation was unbound
-        if(!conversation.isBound()){
+        if(conversation!=null && !conversation.isBound()){
             conversation.bind();
         }
+        if(cdmEntitySession != null) {
+            cdmEntitySession.bind();
+        }
     }
 
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.persistence.hibernate.ICdmPostDataChangeObserver#update(eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap)
-     */
     @Override
     public void update(CdmDataChangeMap changeEvents) {
     }
 
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.api.conversation.IConversationEnabled#getConversationHolder()
-     */
     @Override
     public ConversationHolder getConversationHolder() {
         return conversation;
     }
 
-    /**
-     * @return the viewer
-     */
-    public TreeViewer getViewer() {
-        return viewer;
-    }
-
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.taxeditor.model.IDirtyMarkableSelectionProvider#changed(java.lang.Object)
-     */
     @Override
     public void changed(Object element) {
         setDirty(true);
         firePropertyChange(IEditorPart.PROP_DIRTY);
-        viewer.refresh();
+        viewer.update(new TreeNode(element), null);
     }
 
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.taxeditor.model.IDirtyMarkableSelectionProvider#forceDirty()
-     */
     @Override
     public void forceDirty() {
         changed(null);
     }
 
+    @Override
+    public Map<Object, List<String>> getPropertyPathsMap() {
+        List<String> specimenPropertyPaths = Arrays.asList(new String[] {
+                "descriptions",
+                "derivationEvents.derivates",
+                "annotations",
+                "markers",
+                "credits",
+                "extensions",
+                "rights",
+                "sources"
+        });
+        Map<Object, List<String>> specimenPropertyPathMap =
+                new HashMap<Object, List<String>>();
+        specimenPropertyPathMap.put(SpecimenOrObservationBase.class,specimenPropertyPaths);
+        return specimenPropertyPathMap;
+    }
+
     /**
      * Refreshes the derivate hierarchy tree and expands the tree
      * to show and select the given object.
@@ -275,48 +392,31 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
      * Refreshes the derivate hierarchy tree
      */
     public void refreshTree(){
-        generateMultiLinkSingleReads();
-        labelProvider.setMultiLinkSingleReads(multiLinkSingleReads);
         viewer.refresh();
     }
 
-
-    private void generateMultiLinkSingleReads() {
-        Set<SingleRead> multiLinkSingleReads = new HashSet<SingleRead>();
-        for(Entry<SingleRead, Collection<Sequence>> entry:CdmStore.getService(ISequenceService.class).getSingleReadSequencesMap().entrySet()){
-            if(entry.getValue().size()>1){
-                multiLinkSingleReads.add(entry.getKey());
-            }
-        }
-        this.multiLinkSingleReads = multiLinkSingleReads;
+    //FIXME:Remoting hack to make this work for remoting
+    //This should actually be resolved using remoting post operations
+    public void remove(Object obj) {
+        rootElements.remove(obj);
+        viewer.setInput(rootElements);
     }
 
     /**
      * @return a set of {@link SingleRead}s that have multiple parents
      */
     public Set<SingleRead> getMultiLinkSingleReads() {
-        return this.multiLinkSingleReads;
-    }
-
-    /* (non-Javadoc)
-     * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
-     */
-    @Override
-    public void selectionChanged(SelectionChangedEvent event) {
-        this.selection  = event.getSelection();
+        return DerivateLabelProvider.getMultiLinkSingleReads();
     }
 
-    public ISelection getSelection() {
-        return selection;
+    public Object getSelectionInput() {
+        return selectedTaxon;
     }
 
     public DerivateLabelProvider getLabelProvider() {
         return labelProvider;
     }
 
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.taxeditor.operation.IPostOperationEnabled#postOperation(eu.etaxonomy.cdm.model.common.CdmBase)
-     */
     @Override
     public boolean postOperation(CdmBase objectAffectedByOperation) {
         refreshTree();
@@ -326,12 +426,137 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
         return true;
     }
 
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.taxeditor.operation.IPostOperationEnabled#onComplete()
-     */
     @Override
     public boolean onComplete() {
         return true;
     }
 
+
+    @Override
+    public boolean canAttachMedia() {
+        return true;
+    }
+
+    public void addFieldUnit(FieldUnit fieldUnit) {
+        rootElements.add(fieldUnit);
+        derivateToRootEntityMap.put(fieldUnit, fieldUnit);
+    }
+
+    @Override
+    public ICdmEntitySession getCdmEntitySession() {
+        return cdmEntitySession;
+    }
+
+    @Override
+    public void dispose() {
+        super.dispose();
+        if(conversation!=null){
+            conversation.close();
+        }
+        if(cdmEntitySession != null) {
+            cdmEntitySession.dispose();
+        }
+    }
+
+    @Override
+    public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+        if(viewer.getTree().isDisposed()){
+            return;
+        }
+        if(listenToSelectionChange){
+            if(part instanceof MultiPageTaxonEditor){
+                selectedTaxon = ((MultiPageTaxonEditor) part).getTaxon();
+            }
+            else if(selection instanceof IStructuredSelection){
+                Object selectedElement = ((IStructuredSelection) selection).getFirstElement();
+                if(selectedElement instanceof CdmBase){
+                    if(((CdmBase) selectedElement).isInstanceOf(TaxonNode.class)){
+                        selectedTaxon = HibernateProxyHelper.deproxy(selectedElement, TaxonNode.class).getTaxon();
+                    }
+                    else if(((CdmBase) selectedElement).isInstanceOf(Taxon.class)){
+                        selectedTaxon = HibernateProxyHelper.deproxy(selectedElement, Taxon.class);
+                    }
+                }
+            }
+            if(selectedTaxon!=null){
+                Collection<SpecimenOrObservationBase> fieldUnits = CdmStore.getService(IOccurrenceService.class).listFieldUnitsByAssociatedTaxon(selectedTaxon, null, null);
+                Collection<UUID> uuids = new HashSet<UUID>();
+                for (SpecimenOrObservationBase specimenOrObservationBase : fieldUnits) {
+                    uuids.add(specimenOrObservationBase.getUuid());
+                }
+                updateRootEntities(uuids);
+                setPartName("Derivative Editor: " + selectedTaxon.getName());
+            }
+        }
+    }
+
+    public TreeViewer getViewer() {
+        return viewer;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<SpecimenOrObservationBase<?>> getRootEntities() {
+        return new ArrayList<SpecimenOrObservationBase<?>>(rootElements);
+    }
+
+    public void toggleListenToSelectionChange() {
+        listenToSelectionChange = !listenToSelectionChange;
+        derivateSearchCompositeController.setEnabled(!listenToSelectionChange);
+        if(!listenToSelectionChange){
+            selectedTaxon = null;
+            setPartName("Derivative Editor");
+        }
+        else if(selectedTaxon==null){
+            setPartName("Derivative Editor [no taxon selected]");
+        }
+    }
+
+    public boolean isListenToSelectionChange(){
+        return listenToSelectionChange;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void contextAboutToStop(IMemento memento, IProgressMonitor monitor) {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void contextStop(IMemento memento, IProgressMonitor monitor) {
+        derivateSearchCompositeController.setEnabled(false);
+        viewer.getTree().setEnabled(false);
+        viewer.setInput(null);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void contextStart(IMemento memento, IProgressMonitor monitor) {
+        derivateSearchCompositeController.setEnabled(!listenToSelectionChange);
+        viewer.getTree().setEnabled(true);
+        refreshTree();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void contextRefresh(IProgressMonitor monitor) {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void workbenchShutdown(IMemento memento, IProgressMonitor monitor) {
+    }
+
 }