ref #6805 Fix term dragging into feature tree editor
[taxeditor.git] / eu.etaxonomy.taxeditor.editor / src / main / java / eu / etaxonomy / taxeditor / editor / descriptiveDataSet / matrix / CharacterMatrix.java
index 93bd66270c549464e23dd3d9acc4bec9f71ac004..2135b176ed2e8be6b7f961e04ea50c7df30d426e 100644 (file)
@@ -24,19 +24,26 @@ import javax.inject.Inject;
 import org.apache.commons.collections4.map.LinkedMap;
 import org.eclipse.core.runtime.ICoreRunnable;
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
 import org.eclipse.core.runtime.jobs.IJobChangeEvent;
 import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.core.runtime.jobs.JobChangeAdapter;
 import org.eclipse.e4.ui.di.UISynchronize;
+import org.eclipse.e4.ui.services.EMenuService;
 import org.eclipse.jface.layout.GridDataFactory;
 import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.nebula.widgets.nattable.NatTable;
+import org.eclipse.nebula.widgets.nattable.config.AbstractUiBindingConfiguration;
 import org.eclipse.nebula.widgets.nattable.config.ConfigRegistry;
 import org.eclipse.nebula.widgets.nattable.config.DefaultNatTableStyleConfiguration;
 import org.eclipse.nebula.widgets.nattable.coordinate.PositionCoordinate;
+import org.eclipse.nebula.widgets.nattable.coordinate.Range;
 import org.eclipse.nebula.widgets.nattable.data.IDataProvider;
 import org.eclipse.nebula.widgets.nattable.data.ListDataProvider;
 import org.eclipse.nebula.widgets.nattable.export.command.ExportCommandHandler;
+import org.eclipse.nebula.widgets.nattable.extension.e4.selection.E4SelectionListener;
 import org.eclipse.nebula.widgets.nattable.extension.glazedlists.GlazedListsEventLayer;
 import org.eclipse.nebula.widgets.nattable.extension.glazedlists.GlazedListsSortModel;
 import org.eclipse.nebula.widgets.nattable.extension.glazedlists.tree.GlazedListTreeData;
@@ -69,34 +76,39 @@ import org.eclipse.nebula.widgets.nattable.summaryrow.FixedSummaryRowLayer;
 import org.eclipse.nebula.widgets.nattable.summaryrow.SummaryRowLayer;
 import org.eclipse.nebula.widgets.nattable.tree.ITreeRowModel;
 import org.eclipse.nebula.widgets.nattable.tree.TreeLayer;
+import org.eclipse.nebula.widgets.nattable.ui.binding.UiBindingRegistry;
+import org.eclipse.nebula.widgets.nattable.ui.matcher.MouseEventMatcher;
+import org.eclipse.nebula.widgets.nattable.ui.menu.PopupMenuAction;
+import org.eclipse.nebula.widgets.nattable.ui.menu.PopupMenuBuilder;
 import org.eclipse.nebula.widgets.nattable.util.GUIHelper;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Menu;
 
 import ca.odell.glazedlists.BasicEventList;
 import ca.odell.glazedlists.EventList;
 import ca.odell.glazedlists.SortedList;
 import ca.odell.glazedlists.TreeList;
 import eu.etaxonomy.cdm.api.application.CdmApplicationState;
-import eu.etaxonomy.cdm.api.service.IDescriptiveDataSetService;
-import eu.etaxonomy.cdm.api.service.IProgressMonitorService;
 import eu.etaxonomy.cdm.api.service.UpdateResult;
 import eu.etaxonomy.cdm.api.service.dto.RowWrapperDTO;
+import eu.etaxonomy.cdm.api.service.dto.SpecimenRowWrapperDTO;
 import eu.etaxonomy.cdm.common.monitor.IRemotingProgressMonitor;
+import eu.etaxonomy.cdm.model.description.DescriptionBase;
 import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
 import eu.etaxonomy.cdm.model.description.Feature;
 import eu.etaxonomy.cdm.model.description.FeatureNode;
 import eu.etaxonomy.cdm.model.description.FeatureTree;
 import eu.etaxonomy.cdm.model.description.MeasurementUnit;
-import eu.etaxonomy.cdm.model.description.SpecimenDescription;
 import eu.etaxonomy.cdm.model.description.State;
 import eu.etaxonomy.cdm.persistence.dto.SpecimenNodeWrapper;
 import eu.etaxonomy.taxeditor.editor.internal.TaxeditorEditorPlugin;
 import eu.etaxonomy.taxeditor.editor.l10n.Messages;
 import eu.etaxonomy.taxeditor.model.MessagingUtils;
+import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
 import eu.etaxonomy.taxeditor.store.CdmStore;
 import eu.etaxonomy.taxeditor.workbench.WorkbenchUtility;
 
@@ -117,10 +129,21 @@ public class CharacterMatrix extends Composite {
     static final String COUNTRY_COLUMN = "country_column"; //$NON-NLS-1$
 
     static final String LABEL_TAXON_ROW = "TAXON_ROW"; //$NON-NLS-1$
+    static final String LABEL_TAXON_AGGREGATED_DESCRIPTION = "TAXON_AGGREGATED_DESCRIPTION"; //$NON-NLS-1$
+    static final String LABEL_TAXON_AGGREGATED_DESCRIPTION_ICON = "TAXON_AGGREGATED_DESCRIPTION_ICON"; //$NON-NLS-1$
+    static final String LABEL_TAXON_DEFAULT_DESCRIPTION = "TAXON_DEFAULT_DESCRIPTION"; //$NON-NLS-1$
+    static final String LABEL_TAXON_DEFAULT_DESCRIPTION_ICON = "TAXON_DEFAULT_DESCRIPTION_ICON"; //$NON-NLS-1$
+    static final String LABEL_TAXON_LITERATURE_DESCRIPTION = "TAXON_LITERATURE_DESCRIPTION"; //$NON-NLS-1$
+    static final String LABEL_TAXON_LITERATURE_DESCRIPTION_ICON = "TAXON_LITERATURE_DESCRIPTION_ICON"; //$NON-NLS-1$
+    static final String LABEL_TAXON_DESCRIPTION = "LABEL_TAXON_DESCRIPTION"; //$NON-NLS-1$
+    static final String LABEL_DESCRIPTION_HAS_SUPPLEMENTAL_DATA = "LABEL_DESCRIPTION_HAS_SUPPLEMENTAL_DATA"; //$NON-NLS-1$
 
     @Inject
     private UISynchronize sync;
 
+    @Inject
+    private EMenuService menuService;
+
     private DescriptiveDataSet descriptiveDataSet;
 
     private NatTable natTable;
@@ -131,7 +154,6 @@ public class CharacterMatrix extends Composite {
 
     private LinkedMap<String, String> propertyToLabelMap = new LinkedMap<>();
 
-    //FIXME use more concrete generic
     private EventList<Object> descriptions;
 
     private Collection<SpecimenNodeWrapper> specimenCache = null;
@@ -162,8 +184,6 @@ public class CharacterMatrix extends Composite {
 
     private boolean isShowTooltips = true;
 
-    private boolean isExactQuantitativeValue = true;
-
     public CharacterMatrix(Composite parent, CharacterMatrixPart part) {
         super(parent, SWT.NONE);
         this.part = part;
@@ -192,7 +212,6 @@ public class CharacterMatrix extends Composite {
         configuration.summaryRowHAlign = HorizontalAlignmentEnum.CENTER;
         // NOTE: Getting the colors and fonts from the GUIHelper ensures that
         // they are disposed properly (required by SWT)
-        configuration.summaryRowBgColor = GUIHelper.getColor(255, 255, 153);
         configuration.cHeaderBgColor = GUIHelper.getColor(211, 211, 211);
         configuration.rHeaderBgColor = GUIHelper.getColor(211, 211, 211);
         natTable.addConfiguration(configuration);
@@ -391,7 +410,7 @@ public class CharacterMatrix extends Composite {
         // add the SortHeaderLayer to the column header layer stack
         // as we use GlazedLists, we use the GlazedListsSortModel which
         // delegates the sorting to the SortedList
-        final SortHeaderLayer<SpecimenDescription> sortHeaderLayer = new SortHeaderLayer<>(
+        final SortHeaderLayer<DescriptionBase> sortHeaderLayer = new SortHeaderLayer<>(
                 columnHeaderLayer,
                 new GlazedListsSortModel<>(
                         sortedList,
@@ -432,8 +451,11 @@ public class CharacterMatrix extends Composite {
         // exporting work
         topMostLayer.registerCommandHandler(new ExportCommandHandler(topMostLayer));
 
-        //propagate single cell selection
-        natTable.addLayerListener(new CellSelectionListener(part));
+        //selection listener
+        E4SelectionListener selectionListener = new CellSelectionListener(part.getSelectionService(),
+                bodyLayer.getSelectionLayer(), bodyDataProvider, part);
+        bodyLayer.getSelectionLayer().addLayerListener(selectionListener);
+        selectionListener.setFullySelectedRowsOnly(false);
 
         //register handler for view configuration menu
         natTable.registerCommandHandler(toolbar.getDisplayPersistenceDialogCommandHandler());
@@ -474,6 +496,31 @@ public class CharacterMatrix extends Composite {
         //register aggregation configuration
         summaryRowLayer.addConfiguration(new AggregationConfiguration(this));
 
+      //+++CONTEXT MENU+++
+        menuService.registerContextMenu(natTable, "eu.etaxonomy.taxeditor.editor.popupmenu.charactermatrix"); //$NON-NLS-1$
+        // get the menu registered by EMenuService
+        final Menu e4Menu = natTable.getMenu();
+        // remove the menu reference from NatTable instance
+        natTable.setMenu(null);
+        natTable.addConfiguration(
+                new AbstractUiBindingConfiguration() {
+            @Override
+            public void configureUiBindings(
+                    UiBindingRegistry uiBindingRegistry) {
+                // add e4 menu to NatTable
+                new PopupMenuBuilder(natTable, e4Menu)
+                    .build();
+
+                // register the UI binding for header, corner and body region
+                uiBindingRegistry.registerMouseDownBinding(
+                        new MouseEventMatcher(
+                                SWT.NONE,
+                                null,
+                                MouseEventMatcher.RIGHT_BUTTON),
+                        new PopupMenuAction(e4Menu));
+            }
+        });
+
         natTable.configure();
     }
 
@@ -519,23 +566,38 @@ public class CharacterMatrix extends Composite {
     }
 
     public void loadDescriptions(DescriptiveDataSet descriptiveDataSet) {
-        UUID monitorUuid = CdmStore.getService(IDescriptiveDataSetService.class).monitGetRowWrapper(descriptiveDataSet);
-        IProgressMonitorService progressMonitorService = CdmApplicationState.getCurrentAppConfig().getProgressMonitorService();
+        UUID monitorUuid =  CdmApplicationState.getLongRunningTasksService().monitGetRowWrapper(descriptiveDataSet);
 
         final Collection<RowWrapperDTO> wrappers = new ArrayList<>();
         String jobLabel = Messages.CharacterMatrix_LOAD_CHARACTER_DATA;
         Job job = Job.create(jobLabel, (ICoreRunnable) monitor -> {
-            monitor.beginTask(jobLabel, IProgressMonitor.UNKNOWN);
-            while(progressMonitorService.isMonitorThreadRunning(monitorUuid)){
-                if(monitor.isCanceled()){
-                    progressMonitorService.interrupt(monitorUuid);
-                }
+            SubMonitor subMonitor = SubMonitor.convert(monitor);
+            subMonitor.beginTask(jobLabel, IProgressMonitor.UNKNOWN);
+            IRemotingProgressMonitor remotingMonitor;
+            try {
+                 remotingMonitor = CdmStore.getProgressMonitorClientManager()
+                .pollMonitor(jobLabel,
+                        monitorUuid,
+                        50,
+                        null,
+                        (List)null,
+                        subMonitor);
+            } catch (InterruptedException e) {
+                MessagingUtils.informationDialog(Messages.CharacterMatrix_LOADING_FAILED_TITLE,
+                        Messages.CharacterMatrix_LOADING_FAILED_MESSAGE);
+                return;
             }
-            IRemotingProgressMonitor remotingMonitor = progressMonitorService.getRemotingMonitor(monitorUuid);
             Object result = remotingMonitor.getResult();
             if(result instanceof Collection){
                 wrappers.addAll((Collection<RowWrapperDTO>) result);
             }
+            if(result instanceof Exception){
+                MessagingUtils.errorDialog("Exception during description loading", this.getClass(), "An exception occured during loading", TaxeditorEditorPlugin.PLUGIN_ID, (Throwable) result, true);
+            }
+            else if(wrappers.isEmpty()){
+                MessagingUtils.informationDialog(Messages.CharacterMatrix_NO_DESCRIPTION_TITLE,
+                        Messages.CharacterMatrix_NO_DESCRIPTION_MESSAGE);
+            }
             monitor.done();
         });
         job.addJobChangeListener(new JobChangeAdapter(){
@@ -545,16 +607,31 @@ public class CharacterMatrix extends Composite {
                     List<RowWrapperDTO> rowsWithoutTaxonNode = wrappers.stream().filter(row->row.getTaxonNode()==null).collect(Collectors.toList());
                     if(!rowsWithoutTaxonNode.isEmpty()){
                         String collect = rowsWithoutTaxonNode.stream().
-                        map(row->row.getSpecimenDescription().toString())
+                        map(row->row.getDescription().toString())
                         .collect(Collectors.joining("\n\n - ")); //$NON-NLS-1$
-                        MessagingUtils.errorDialog(Messages.CharacterMatrix_NO_NODE_FOUND_TITLE, this.getClass(), Messages.CharacterMatrix_NO_NODE_FOUND_MESSAGE+collect+"\n\n", TaxeditorEditorPlugin.PLUGIN_ID, null, false); //$NON-NLS-3$
+                        MessagingUtils.warningDialog(
+                                Messages.CharacterMatrix_NO_NODE_FOUND_TITLE,
+                                this.getClass(),
+                                String.format(Messages.CharacterMatrix_NO_NODE_FOUND_MESSAGE, collect)
+                                );
                     }
                     wrappers.stream().filter(row->row.getTaxonNode()!=null).forEach(wrapper->CharacterMatrix.this.descriptions.add(wrapper));
                     loadingDone();
                 });
             }
         });
-        job.schedule(1000);
+        job.schedule();
+    }
+
+    public IStructuredSelection getSelection(){
+        Set<Range> selectedRowPositions = bodyLayer.getSelectionLayer().getSelectedRowPositions();
+        List<Object> selectedObjects = new ArrayList<>();
+        for (Range range : selectedRowPositions) {
+            for(int i=range.start;i<range.end;i++){
+                selectedObjects.add(bodyDataProvider.getRowObject(i));
+            }
+        }
+        return new StructuredSelection(selectedObjects);
     }
 
     private void loadingDone() {
@@ -598,7 +675,8 @@ public class CharacterMatrix extends Composite {
                 .filter(wrapper ->
         //map descriptions on a list of uuids of the described specimen
         !this.descriptions.stream()
-        .map(o->((RowWrapperDTO)o).getSpecimen().getUuid())
+        .filter(rowWrapper->rowWrapper instanceof SpecimenRowWrapperDTO)
+        .map(specimenRowWrapper->((SpecimenRowWrapperDTO) specimenRowWrapper).getSpecimen().getUuid())
         .collect(Collectors.toList())
         //an check if the specimen to add is already contained
         .contains(wrapper.getUuidAndTitleCache().getUuid())
@@ -646,12 +724,8 @@ public class CharacterMatrix extends Composite {
         return isShowTooltips;
     }
 
-    public void toogleExactQuantitativeValue() {
-        this.isExactQuantitativeValue = !this.isExactQuantitativeValue;
-    }
-
-    public boolean isExactQuantitativeValue() {
-        return isExactQuantitativeValue;
+    public ICdmEntitySession getCdmEntitiySession(){
+        return part.getCdmEntitySession();
     }
 
 }