Merge branch 'release/4.3.0'
[taxeditor.git] / eu.etaxonomy.taxeditor.editor / src / main / java / eu / etaxonomy / taxeditor / editor / view / derivate / DerivateView.java
index ba2b3168117fa00724603b78ea2823dda7670a34..c5bcfb75a8c4e0d2bdca90719b15eb0220a50bd3 100644 (file)
@@ -27,6 +27,7 @@ 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.Display;
 import org.eclipse.swt.widgets.Menu;
 import org.eclipse.swt.widgets.Tree;
 import org.eclipse.ui.IEditorInput;
@@ -52,6 +53,7 @@ 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;
@@ -59,6 +61,7 @@ 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.model.MessagingUtils;
 import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
 import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
 import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
@@ -94,6 +97,50 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
             "derivationEvents.derivatives.sources"
     });
 
+       private static final int WARN_THRESHOLD = 200;
+
+    private DelaySelection delaySelection = null;
+    /**
+     * This is the monitor for the DelaySelection runnable.
+     * If it is <code>true</code> then it is currently delaying a selection.
+     */
+    private boolean isInDelay;
+
+
+    /**
+     * This class invokes internal_selectionChanged() in a separate thread.
+     * This allows an asynchronous and/or delayed handling of selection changes
+     */
+    private class DelaySelection implements Runnable{
+        private IWorkbenchPart part;
+        private ISelection selection;
+
+        public DelaySelection(IWorkbenchPart part, ISelection selection) {
+            super();
+            this.part = part;
+            this.selection = selection;
+        }
+
+        @Override
+        public void run() {
+            try{
+                selectionChanged_internal(part, selection);
+            }
+            finally{
+                isInDelay = false;
+            }
+        }
+
+        public synchronized void setSelection(ISelection selection) {
+            this.selection = selection;
+        }
+
+        public synchronized void setPart(IWorkbenchPart part) {
+            this.part = part;
+        }
+
+    }
+
        private ConversationHolder conversation;
 
        private TreeViewer viewer;
@@ -194,13 +241,20 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
 
         //create context menu
         MenuManager menuManager = new MenuManager();
+        menuManager.setRemoveAllWhenShown(true);
         getSite().registerContextMenu(menuManager, viewer);
         Control control = viewer.getControl();
         Menu menu = menuManager.createContextMenu(control);
         control.setMenu(menu);
 
         //init tree
-        updateRootEntities();
+        Collection<UUID> derivativeUuids = ((DerivateViewEditorInput)getEditorInput()).getDerivativeUuids();
+        checkWarnThreshold(derivativeUuids);
+               updateRootEntities(derivativeUuids);
+        //set taxon filter
+        derivateSearchCompositeController.setTaxonFilter(((DerivateViewEditorInput) getEditorInput()).getTaxonUuid());
+        //reset status bar
+        getEditorSite().getActionBars().getStatusLineManager().setMessage("");
 
         //add drag'n'drop support
         Transfer[] transfers = new Transfer[] {LocalSelectionTransfer.getTransfer(),};
@@ -209,7 +263,7 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
     }
 
     public void updateRootEntities() {
-        updateRootEntities(null);
+        updateRootEntities((Collection)null);
     }
 
     public void updateRootEntities(Collection<UUID> derivativeUuids) {
@@ -218,23 +272,37 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
                 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.
+             * If the active session is not the session of the Derivative Editor
+             * then we will save the active session for later, bind temporarily
+             * to our session and rebind to the original session when we are
+             * done. 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<?>>();
-                for (UUID uuid : derivativeUuids) {
-                    SpecimenOrObservationBase<?> derivate = CdmStore.getService(IOccurrenceService.class).load(uuid, SPECIMEN_INIT_STRATEGY);
+                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);
                     }
@@ -252,10 +320,28 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
                     rootElements.add(specimen);
                 }
             }
+            labelProvider.updateLabelCache(rootElements);
             viewer.setInput(rootElements);
-            refreshTree(false);
-            previousCdmEntitySession.bind();
-        }
+
+            getEditorSite().getActionBars().getStatusLineManager().setMessage(rootElements.size() +" derivative hierarchies found");
+
+            //set selection to derivatives if the filter criteria
+            //taxon assignment or derivative type are set
+            if(derivates!=null && !derivateSearchCompositeController.isDefaultSearch()){
+                List<TreeNode> nodesToSelect = new ArrayList<TreeNode>();
+                for (SpecimenOrObservationBase specimenOrObservationBase : derivates) {
+                    nodesToSelect.add(new TreeNode(specimenOrObservationBase));
+                }
+                viewer.setSelection(new StructuredSelection(nodesToSelect));
+            }
+            else{
+                viewer.setSelection(null);
+            }
+
+    }
+
+    public void updateLabelCache(){
+        labelProvider.updateLabelCache(rootElements);
     }
 
     @Override
@@ -270,9 +356,8 @@ 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);
-        }
+        CdmStore.getService(IOccurrenceService.class).merge(new ArrayList<SpecimenOrObservationBase>(rootElements), true);
+        
         monitor.worked(1);
 
         this.setDirty(false);
@@ -310,7 +395,6 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
 
     @Override
     public void setFocus() {
-        viewer.getControl().setFocus();
         //make sure to bind again if maybe in another view the conversation was unbound
         if(conversation!=null && !conversation.isBound()){
             conversation.bind();
@@ -318,6 +402,7 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
         if(cdmEntitySession != null) {
             cdmEntitySession.bind();
         }
+        derivateSearchCompositeController.setFocusOnSearchField();
     }
 
     @Override
@@ -333,7 +418,7 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
     public void changed(Object element) {
         setDirty(true);
         firePropertyChange(IEditorPart.PROP_DIRTY);
-        viewer.refresh();
+        viewer.update(new TreeNode(element), null);
     }
 
     @Override
@@ -376,22 +461,9 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
      * Refreshes the derivate hierarchy tree
      */
     public void refreshTree(){
-        refreshTree(true);
-    }
-
-    /**
-     * Refreshes the derivate hierarchy tree
-     * @param refreshViewer if <code>true</code> then also the
-     * viewer will be refreshed. This was implemented due to
-     * performance reasons. If passing <code>false</code>
-     * does what was expected use <code>false</code> preferably.
-     */
-    public void refreshTree(boolean refreshViewer){
-        //refresh typedesignations
-        labelProvider.refresh();
-        if(refreshViewer){
-            viewer.refresh();
-        }
+       if(!viewer.getTree().isDisposed()){
+               viewer.refresh();
+       }
     }
 
     //FIXME:Remoting hack to make this work for remoting
@@ -456,32 +528,65 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
             cdmEntitySession.dispose();
         }
     }
-
-    @Override
-    public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+    public void selectionChanged_internal(IWorkbenchPart part, ISelection selection) {
+       if(part == this){
+            return;
+        }
         if(viewer.getTree().isDisposed()){
             return;
         }
-        if(listenToSelectionChange && 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(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());
                 }
+                checkWarnThreshold(uuids);
                 updateRootEntities(uuids);
                 setPartName("Derivative Editor: " + selectedTaxon.getName());
             }
         }
     }
 
+    @Override
+    public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+       if(delaySelection==null){
+            delaySelection = new DelaySelection(part, selection);
+        }
+        delaySelection.setPart(part);
+        delaySelection.setSelection(selection);
+        if(!isInDelay){
+            isInDelay = true;
+            Display.getCurrent().asyncExec(delaySelection);
+        }
+    }
+
+
+       private void checkWarnThreshold(Collection<UUID> uuids) {
+               if(uuids!=null && uuids.size()>WARN_THRESHOLD){
+                       MessagingUtils.warningDialog("Performance warning", this.getClass(), String.format("Specimens will not be loaded!\n"
+                                       + "There are %d specimens associated with the current "
+                                       + "selection. If you really want to show all of them in the specimen editor please "
+                                       + "use the taxon filter in the search bar.", uuids.size()));
+                       uuids.clear();
+               }
+       }
+
     public TreeViewer getViewer() {
         return viewer;
     }
@@ -523,8 +628,10 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
     @Override
     public void contextStop(IMemento memento, IProgressMonitor monitor) {
         derivateSearchCompositeController.setEnabled(false);
-        viewer.getTree().setEnabled(false);
-        viewer.setInput(null);
+        if(!viewer.getTree().isDisposed()) {
+            viewer.getTree().setEnabled(false);
+            viewer.setInput(null);
+        }
     }
 
     /**
@@ -533,7 +640,9 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
     @Override
     public void contextStart(IMemento memento, IProgressMonitor monitor) {
         derivateSearchCompositeController.setEnabled(!listenToSelectionChange);
-        viewer.getTree().setEnabled(true);
+        if(!viewer.getTree().isDisposed()){
+            viewer.getTree().setEnabled(true);
+        }
         refreshTree();
     }