2 * Copyright (C) 2017 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
.descriptiveDataSet
.matrix
;
12 import java
.util
.ArrayList
;
13 import java
.util
.Collection
;
14 import java
.util
.HashMap
;
15 import java
.util
.List
;
17 import java
.util
.Properties
;
19 import java
.util
.UUID
;
20 import java
.util
.stream
.Collectors
;
22 import org
.apache
.commons
.collections4
.map
.LinkedMap
;
23 import org
.eclipse
.core
.runtime
.ICoreRunnable
;
24 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
25 import org
.eclipse
.core
.runtime
.jobs
.Job
;
26 import org
.eclipse
.jface
.layout
.GridDataFactory
;
27 import org
.eclipse
.jface
.viewers
.ComboViewer
;
28 import org
.eclipse
.nebula
.widgets
.nattable
.NatTable
;
29 import org
.eclipse
.nebula
.widgets
.nattable
.config
.ConfigRegistry
;
30 import org
.eclipse
.nebula
.widgets
.nattable
.config
.DefaultNatTableStyleConfiguration
;
31 import org
.eclipse
.nebula
.widgets
.nattable
.coordinate
.PositionCoordinate
;
32 import org
.eclipse
.nebula
.widgets
.nattable
.data
.IDataProvider
;
33 import org
.eclipse
.nebula
.widgets
.nattable
.data
.ListDataProvider
;
34 import org
.eclipse
.nebula
.widgets
.nattable
.export
.command
.ExportCommandHandler
;
35 import org
.eclipse
.nebula
.widgets
.nattable
.extension
.glazedlists
.GlazedListsEventLayer
;
36 import org
.eclipse
.nebula
.widgets
.nattable
.extension
.glazedlists
.GlazedListsSortModel
;
37 import org
.eclipse
.nebula
.widgets
.nattable
.extension
.glazedlists
.tree
.GlazedListTreeData
;
38 import org
.eclipse
.nebula
.widgets
.nattable
.extension
.glazedlists
.tree
.GlazedListTreeRowModel
;
39 import org
.eclipse
.nebula
.widgets
.nattable
.freeze
.CompositeFreezeLayer
;
40 import org
.eclipse
.nebula
.widgets
.nattable
.freeze
.FreezeHelper
;
41 import org
.eclipse
.nebula
.widgets
.nattable
.freeze
.FreezeLayer
;
42 import org
.eclipse
.nebula
.widgets
.nattable
.grid
.GridRegion
;
43 import org
.eclipse
.nebula
.widgets
.nattable
.grid
.command
.ClientAreaResizeCommand
;
44 import org
.eclipse
.nebula
.widgets
.nattable
.grid
.data
.DefaultColumnHeaderDataProvider
;
45 import org
.eclipse
.nebula
.widgets
.nattable
.grid
.data
.DefaultCornerDataProvider
;
46 import org
.eclipse
.nebula
.widgets
.nattable
.grid
.data
.DefaultRowHeaderDataProvider
;
47 import org
.eclipse
.nebula
.widgets
.nattable
.grid
.data
.FixedSummaryRowHeaderLayer
;
48 import org
.eclipse
.nebula
.widgets
.nattable
.grid
.layer
.ColumnHeaderLayer
;
49 import org
.eclipse
.nebula
.widgets
.nattable
.grid
.layer
.CornerLayer
;
50 import org
.eclipse
.nebula
.widgets
.nattable
.grid
.layer
.DefaultRowHeaderDataLayer
;
51 import org
.eclipse
.nebula
.widgets
.nattable
.grid
.layer
.GridLayer
;
52 import org
.eclipse
.nebula
.widgets
.nattable
.layer
.AbstractLayer
;
53 import org
.eclipse
.nebula
.widgets
.nattable
.layer
.CompositeLayer
;
54 import org
.eclipse
.nebula
.widgets
.nattable
.layer
.DataLayer
;
55 import org
.eclipse
.nebula
.widgets
.nattable
.layer
.ILayer
;
56 import org
.eclipse
.nebula
.widgets
.nattable
.layer
.cell
.ColumnOverrideLabelAccumulator
;
57 import org
.eclipse
.nebula
.widgets
.nattable
.layer
.stack
.DefaultBodyLayerStack
;
58 import org
.eclipse
.nebula
.widgets
.nattable
.selection
.SelectionLayer
;
59 import org
.eclipse
.nebula
.widgets
.nattable
.sort
.SortHeaderLayer
;
60 import org
.eclipse
.nebula
.widgets
.nattable
.sort
.config
.SingleClickSortConfiguration
;
61 import org
.eclipse
.nebula
.widgets
.nattable
.style
.HorizontalAlignmentEnum
;
62 import org
.eclipse
.nebula
.widgets
.nattable
.style
.theme
.ModernNatTableThemeConfiguration
;
63 import org
.eclipse
.nebula
.widgets
.nattable
.summaryrow
.FixedSummaryRowLayer
;
64 import org
.eclipse
.nebula
.widgets
.nattable
.summaryrow
.SummaryRowLayer
;
65 import org
.eclipse
.nebula
.widgets
.nattable
.tree
.ITreeRowModel
;
66 import org
.eclipse
.nebula
.widgets
.nattable
.tree
.TreeLayer
;
67 import org
.eclipse
.nebula
.widgets
.nattable
.util
.GUIHelper
;
68 import org
.eclipse
.swt
.SWT
;
69 import org
.eclipse
.swt
.layout
.GridData
;
70 import org
.eclipse
.swt
.layout
.GridLayout
;
71 import org
.eclipse
.swt
.widgets
.Button
;
72 import org
.eclipse
.swt
.widgets
.Composite
;
74 import ca
.odell
.glazedlists
.BasicEventList
;
75 import ca
.odell
.glazedlists
.EventList
;
76 import ca
.odell
.glazedlists
.SortedList
;
77 import ca
.odell
.glazedlists
.TreeList
;
78 import eu
.etaxonomy
.cdm
.api
.application
.CdmApplicationState
;
79 import eu
.etaxonomy
.cdm
.api
.service
.IDescriptiveDataSetService
;
80 import eu
.etaxonomy
.cdm
.api
.service
.IProgressMonitorService
;
81 import eu
.etaxonomy
.cdm
.api
.service
.UpdateResult
;
82 import eu
.etaxonomy
.cdm
.api
.service
.dto
.RowWrapperDTO
;
83 import eu
.etaxonomy
.cdm
.common
.monitor
.IRemotingProgressMonitor
;
84 import eu
.etaxonomy
.cdm
.model
.description
.DescriptiveDataSet
;
85 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
86 import eu
.etaxonomy
.cdm
.model
.description
.FeatureNode
;
87 import eu
.etaxonomy
.cdm
.model
.description
.FeatureTree
;
88 import eu
.etaxonomy
.cdm
.model
.description
.MeasurementUnit
;
89 import eu
.etaxonomy
.cdm
.model
.description
.SpecimenDescription
;
90 import eu
.etaxonomy
.cdm
.model
.description
.State
;
91 import eu
.etaxonomy
.cdm
.persistence
.dto
.SpecimenNodeWrapper
;
92 import eu
.etaxonomy
.taxeditor
.editor
.l10n
.Messages
;
93 import eu
.etaxonomy
.taxeditor
.model
.MessagingUtils
;
94 import eu
.etaxonomy
.taxeditor
.store
.CdmStore
;
95 import eu
.etaxonomy
.taxeditor
.workbench
.WorkbenchUtility
;
98 * Character matrix editor for editing specimen/taxon descriptions in a table
100 * @since Nov 26, 2017
103 public class CharacterMatrix
extends Composite
{
105 private static final String CHARACTER_MATRIX_STATE_PROPERTIES
= "characterMatrixState.properties"; //$NON-NLS-1$
107 static final int LEADING_COLUMN_COUNT
= 4;
108 static final String TAXON_COLUMN
= "taxon_column"; //$NON-NLS-1$
109 static final String COLLECTOR_COLUMN
= "collector_column"; //$NON-NLS-1$
110 static final String IDENTIFIER_COLUMN
= "identifier_column"; //$NON-NLS-1$
111 static final String COUNTRY_COLUMN
= "country_column"; //$NON-NLS-1$
113 static final String LABEL_TAXON_ROW
= "TAXON_ROW"; //$NON-NLS-1$
115 private DescriptiveDataSet descriptiveDataSet
;
117 private NatTable natTable
;
119 private Map
<Integer
, Feature
> indexToFeatureMap
= new HashMap
<>();
121 private Map
<Feature
, List
<State
>> categoricalFeatureToStateMap
= new HashMap
<>();
123 private LinkedMap
<String
, String
> propertyToLabelMap
= new LinkedMap
<>();
125 //FIXME use more concrete generic
126 private EventList
<Object
> descriptions
;
128 private Collection
<SpecimenNodeWrapper
> specimenCache
= null;
130 private Map
<Feature
, CategoricalDataHistogram
> featureToHistogramMap
= new HashMap
<>();
132 private ListDataProvider
<Object
> bodyDataProvider
;
134 private FreezeLayer freezeLayer
;
136 private List
<Feature
> features
;
138 private CharacterMatrixPart part
;
140 private AbstractLayer topMostLayer
;
142 private FixedSummaryRowLayer summaryRowLayer
;
144 private ConfigRegistry configRegistry
;
146 private DefaultBodyLayerStack bodyLayer
;
148 private boolean isTreeView
= true;
150 private CharacterMatrixToolbar toolbar
;
153 public CharacterMatrix(Composite parent
, CharacterMatrixPart part
) {
154 super(parent
, SWT
.NONE
);
156 this.setLayout(new GridLayout());
160 natTable
= new NatTable(this, false);
162 createBottomToolbar();
166 private void createToolBar(){
167 toolbar
= new CharacterMatrixToolbar(this, SWT
.NONE
);
170 @SuppressWarnings("unused")
171 private void createBottomToolbar() {
172 new CharacterMatrixBottomToolbar(this, SWT
.NONE
);
176 private void applyStyles(){
177 ModernNatTableThemeConfiguration configuration
= new ModernNatTableThemeConfiguration();
178 configuration
.summaryRowHAlign
= HorizontalAlignmentEnum
.CENTER
;
179 // NOTE: Getting the colors and fonts from the GUIHelper ensures that
180 // they are disposed properly (required by SWT)
181 configuration
.summaryRowBgColor
= GUIHelper
.getColor(255, 255, 153);
182 configuration
.cHeaderBgColor
= GUIHelper
.getColor(211, 211, 211);
183 configuration
.rHeaderBgColor
= GUIHelper
.getColor(211, 211, 211);
184 natTable
.addConfiguration(configuration
);
188 void toggleTreeFlat(boolean isTree
, Button btnToggleFlat
, Button btnToggleTree
, Button btnCollapseAll
, Button btnExpandAll
, Button btnFreezeSuppInfo
) {
191 btnToggleFlat
.setEnabled(isTree
);
192 btnToggleTree
.setEnabled(!isTree
);
193 btnCollapseAll
.setEnabled(isTree
);
194 btnExpandAll
.setEnabled(isTree
);
197 public boolean isTreeView() {
201 public void createTable(boolean treeView
){
205 createLayers(treeView
);
210 configureNatTable(treeView
, configRegistry
, topMostLayer
, summaryRowLayer
);
213 * handlers and listeners
215 registerHandlersAndListeners(topMostLayer
);
218 GridDataFactory
.fillDefaults().grab(true, true).applyTo(natTable
);
220 //update label to current data set
221 toolbar
.getWsLabel().setText(descriptiveDataSet
.getLabel());
222 toolbar
.getWsLabel().setLayoutData(new GridData(SWT
.FILL
, SWT
.CENTER
, true, false));
223 toolbar
.getWsLabel().getParent().layout();
225 //initial freeze of supplemental columns
226 freezeSupplementalColumns(true);
229 //add tooltip to table
230 new ChartTooltip(this);
233 natTable
.doCommand(new ClientAreaResizeCommand(natTable
));
236 private List
<Feature
> initFeatureList(FeatureNode node
){
237 List
<Feature
> features
= new ArrayList
<>();
238 node
.getChildNodes().forEach(childNode
->
240 features
.add(childNode
.getFeature());
241 features
.addAll(initFeatureList(childNode
));
246 public void initDescriptiveDataSet(DescriptiveDataSet descriptiveDataSet
){
247 this.descriptiveDataSet
= descriptiveDataSet
;
248 //get features/columns stored in descriptive data set
249 FeatureTree tree
= descriptiveDataSet
.getDescriptiveSystem();
250 features
= initFeatureList(tree
.getRoot());
252 //init state data for categorical features
253 features
.forEach(feature
->
255 if(feature
.isSupportsCategoricalData()){
256 List
<State
> supportedStates
= new ArrayList
<>();
257 feature
.getSupportedCategoricalEnumerations().forEach(voc
->supportedStates
.addAll(voc
.getTerms()));
258 categoricalFeatureToStateMap
.put(feature
, supportedStates
);
261 descriptions
= new BasicEventList
<>();
265 private void createLayers(boolean treeView
) {
266 // use the SortedList constructor with 'null' for the Comparator
267 // because the Comparator will be set by configuration
268 SortedList
<Object
> sortedList
= new SortedList
<>(descriptions
, new MatrixRowComparator());
269 // wrap the SortedList with the TreeList
270 TreeList
<Object
> treeList
= new TreeList(sortedList
, new DescriptionTreeFormat(descriptiveDataSet
), TreeList
.NODES_START_EXPANDED
);
274 SpecimenColumnPropertyAccessor columnPropertyAccessor
= new SpecimenColumnPropertyAccessor(this);
275 bodyDataProvider
= treeView?
new ListDataProvider
<>(treeList
, columnPropertyAccessor
):new ListDataProvider
<>(sortedList
, columnPropertyAccessor
);
277 configRegistry
= new ConfigRegistry();
286 - (top) SummaryRowLayer
287 - (bottom) ViewportLayer
293 TreeLayer (default visible)
319 DataLayer bodyDataLayer
= new DataLayer(bodyDataProvider
);
322 CharacterMatrixConfigLabelAccumulator labelAccumulator
= new CharacterMatrixConfigLabelAccumulator(this);
323 bodyDataLayer
.setConfigLabelAccumulator(labelAccumulator
);
326 propertyToLabelMap
.put(TAXON_COLUMN
, Messages
.CharacterMatrix_TAXON
);
327 propertyToLabelMap
.put(COLLECTOR_COLUMN
, Messages
.CharacterMatrix_COLLECTOR_NO
);
328 propertyToLabelMap
.put(IDENTIFIER_COLUMN
, Messages
.CharacterMatrix_IDENTIFIER
);
329 propertyToLabelMap
.put(COUNTRY_COLUMN
, Messages
.CharacterMatrix_COUNTRY
);
330 for(int i
=0;i
<features
.size();i
++){
331 Feature feature
= features
.get(i
);
332 initLabels(i
, feature
);
335 // layer for event handling of GlazedLists and PropertyChanges
336 GlazedListsEventLayer eventLayer
= new GlazedListsEventLayer
<>(bodyDataLayer
, treeList
);
337 GlazedListTreeData treeData
= new GlazedListTreeData
<>(treeList
);
338 ITreeRowModel treeRowModel
= new GlazedListTreeRowModel
<>(treeData
);
340 bodyLayer
= new DefaultBodyLayerStack(eventLayer
);
341 final SelectionLayer selectionLayer
= bodyLayer
.getSelectionLayer();
342 freezeLayer
= new FreezeLayer(selectionLayer
);
343 final CompositeFreezeLayer compositeFreezeLayer
= new CompositeFreezeLayer(
344 freezeLayer
, bodyLayer
.getViewportLayer(), selectionLayer
);
345 TreeLayer treeLayer
= new TreeLayer(compositeFreezeLayer
, treeRowModel
);
347 topMostLayer
= treeView?treeLayer
:compositeFreezeLayer
;
349 summaryRowLayer
= new FixedSummaryRowLayer(bodyDataLayer
, topMostLayer
, configRegistry
, false);
350 //regoster labels with summary prefix for summary layer
351 ColumnOverrideLabelAccumulator summaryColumnLabelAccumulator
=new ColumnOverrideLabelAccumulator(bodyDataLayer
);
352 summaryRowLayer
.setConfigLabelAccumulator(summaryColumnLabelAccumulator
);
353 for(int i
=0;i
<features
.size();i
++){
354 Feature feature
= features
.get(i
);
355 summaryColumnLabelAccumulator
.registerColumnOverrides(
356 i
+LEADING_COLUMN_COUNT
,
357 SummaryRowLayer
.DEFAULT_SUMMARY_COLUMN_CONFIG_LABEL_PREFIX
+MatrixUtility
.getProperty(feature
));
359 // because the horizontal dependency is the ViewportLayer
360 // we need to set the composite dependency to false
361 summaryRowLayer
.setHorizontalCompositeDependency(false);
363 CompositeLayer composite
= new CompositeLayer(1, 2);
364 composite
.setChildLayer("SUMMARY", summaryRowLayer
, 0, 0); //$NON-NLS-1$
365 composite
.setChildLayer(GridRegion
.BODY
, topMostLayer
, 0, 1);
369 * column header layer
371 IDataProvider columnHeaderDataProvider
= new DefaultColumnHeaderDataProvider(
372 propertyToLabelMap
.values().toArray(new String
[] {}), propertyToLabelMap
);
373 DataLayer columnHeaderDataLayer
= new DataLayer(columnHeaderDataProvider
);
374 ColumnHeaderLayer columnHeaderLayer
= new ColumnHeaderLayer(columnHeaderDataLayer
, topMostLayer
, selectionLayer
);
376 // add the SortHeaderLayer to the column header layer stack
377 // as we use GlazedLists, we use the GlazedListsSortModel which
378 // delegates the sorting to the SortedList
379 final SortHeaderLayer
<SpecimenDescription
> sortHeaderLayer
= new SortHeaderLayer
<>(
381 new GlazedListsSortModel
<>(
383 columnPropertyAccessor
,
385 columnHeaderDataLayer
));
391 IDataProvider rowHeaderDataProvider
= new DefaultRowHeaderDataProvider(bodyDataProvider
);
392 DefaultRowHeaderDataLayer rowHeaderDataLayer
= new DefaultRowHeaderDataLayer(rowHeaderDataProvider
);
393 FixedSummaryRowHeaderLayer fixedSummaryRowHeaderLayer
= new FixedSummaryRowHeaderLayer(rowHeaderDataLayer
,
394 composite
, selectionLayer
);
395 fixedSummaryRowHeaderLayer
.setSummaryRowLabel("\u2211"); //$NON-NLS-1$
401 ILayer cornerLayer
= new CornerLayer(
402 new DataLayer(new DefaultCornerDataProvider(columnHeaderDataProvider
, rowHeaderDataProvider
)),
403 fixedSummaryRowHeaderLayer
, sortHeaderLayer
);
407 * GRID layer (composition of all other layers)
409 GridLayer gridLayer
= new GridLayer(composite
, sortHeaderLayer
, fixedSummaryRowHeaderLayer
, cornerLayer
);
411 natTable
.setLayer(gridLayer
);
415 private void registerHandlersAndListeners(AbstractLayer topMostLayer
) {
416 // add the ExportCommandHandler to the ViewportLayer in order to make
418 topMostLayer
.registerCommandHandler(new ExportCommandHandler(topMostLayer
));
420 //propagate single cell selection
421 natTable
.addLayerListener(new CellSelectionListener(part
));
423 //register handler for view configuration menu
424 natTable
.registerCommandHandler(toolbar
.getDisplayPersistenceDialogCommandHandler());
427 private void configureNatTable(boolean treeView
,
428 ConfigRegistry configRegistry
,
429 AbstractLayer topMostLayer
,
430 FixedSummaryRowLayer summaryRowLayer
) {
434 natTable
.setConfigRegistry(configRegistry
);
438 //add default configuration because autoconfigure is set to false in constructor
439 natTable
.addConfiguration(new DefaultNatTableStyleConfiguration());
441 //FIXME: this is for DEBUG ONLY
442 // natTable.addConfiguration(new DebugMenuConfiguration(natTable));
444 // override the default sort configuration and change the mouse bindings
445 // to sort on a single click
447 natTable
.addConfiguration(new SingleClickSortConfiguration());
450 natTable
.addConfiguration(new CharacterMatrixLabelStyleConfiguration());
452 // add the header menu configuration for adding the column header menu
453 // with hide/show actions
454 natTable
.addConfiguration(new CharacterMatrixHeaderMenuConfiguration(natTable
));
456 // add custom configuration for data conversion and add column labels to viewport layer
457 topMostLayer
.addConfiguration(new DataConversionConfiguration(this));
459 //register aggregation configuration
460 summaryRowLayer
.addConfiguration(new AggregationConfiguration(this));
462 natTable
.configure();
465 void freezeSupplementalColumns(boolean freeze
){
467 FreezeHelper
.freeze(freezeLayer
, bodyLayer
.getViewportLayer(),
468 new PositionCoordinate(bodyLayer
.getViewportLayer(), 0, 0),
469 new PositionCoordinate(bodyLayer
.getViewportLayer(), LEADING_COLUMN_COUNT
-1, -1));
472 FreezeHelper
.unfreeze(freezeLayer
, bodyLayer
.getViewportLayer());
476 void selectStateItem(ComboViewer comboStates
, String stateName
){
477 String
[] items
= comboStates
.getCombo().getItems();
478 for(int i
=0;i
<items
.length
;i
++){
479 if(items
[i
].equals(stateName
)){
480 comboStates
.getCombo().select(i
);
486 private void initLabels(int index
, Feature feature
) {
487 indexToFeatureMap
.put(index
+LEADING_COLUMN_COUNT
, feature
);
489 String featureLabel
= feature
.getLabel();
490 String property
= featureLabel
;
491 //show unit for quantitative data
492 if(feature
.isSupportsQuantitativeData()){
493 Set
<MeasurementUnit
> recommendedMeasurementUnits
= feature
.getRecommendedMeasurementUnits();
494 if(recommendedMeasurementUnits
.size()>1){
495 MessagingUtils
.warningDialog(Messages
.CharacterMatrix_INIT_PROBLEM
, CharacterMatrix
.class,
496 String
.format(Messages
.CharacterMatrix_INIT_PROBLEM_MESSAGE
, feature
.getLabel()));
498 if(recommendedMeasurementUnits
.size()==1){
499 MeasurementUnit unit
= recommendedMeasurementUnits
.iterator().next();
500 featureLabel
+= " ["+unit
.getIdInVocabulary()+"]"; //$NON-NLS-1$ //$NON-NLS-2$
503 propertyToLabelMap
.put(property
, featureLabel
);
506 public void loadDescriptions(DescriptiveDataSet descriptiveDataSet
) {
507 UUID monitorUuid
= CdmStore
.getService(IDescriptiveDataSetService
.class).monitGetRowWrapper(descriptiveDataSet
);
508 IProgressMonitorService progressMonitorService
= CdmApplicationState
.getCurrentAppConfig().getProgressMonitorService();
511 String jobLabel
= "Load character data";
512 Job job
= Job
.create(jobLabel
, (ICoreRunnable
) monitor
-> {
513 monitor
.beginTask(jobLabel
, IProgressMonitor
.UNKNOWN
);
514 while(progressMonitorService
.isMonitorThreadRunning(monitorUuid
)){
515 if(monitor
.isCanceled()){
516 progressMonitorService
.interrupt(monitorUuid
);
519 IRemotingProgressMonitor remotingMonitor
= progressMonitorService
.getRemotingMonitor(monitorUuid
);
520 Object result
= remotingMonitor
.getResult();
521 if(result
instanceof Collection
){
522 Collection
<RowWrapperDTO
> wrappers
= (Collection
<RowWrapperDTO
>) result
;
523 wrappers
.forEach(wrapper
->CharacterMatrix
.this.descriptions
.add(wrapper
));
530 public List
<State
> getSupportedStatesForCategoricalFeature(Feature feature
){
531 return categoricalFeatureToStateMap
.get(feature
);
534 public Map
<Integer
, Feature
> getIndexToFeatureMap() {
535 return indexToFeatureMap
;
538 public LinkedMap
<String
, String
> getPropertyToLabelMap() {
539 return propertyToLabelMap
;
542 public void setDirty() {
546 public NatTable
getNatTable() {
550 public EventList
<Object
> getDescriptions() {
554 public DescriptiveDataSet
getDescriptiveDataSet() {
555 return descriptiveDataSet
;
558 public Collection
<SpecimenNodeWrapper
> getSpecimenCache() {
559 return specimenCache
;
562 public void setSpecimenCache(Collection
<SpecimenNodeWrapper
> specimenCache
) {
563 this.specimenCache
= specimenCache
.stream()
565 //map descriptions on a list of uuids of the described specimen
566 !this.descriptions
.stream()
567 .map(o
->((RowWrapperDTO
)o
).getSpecimen().getUuid())
568 .collect(Collectors
.toList())
569 //an check if the specimen to add is already contained
570 .contains(wrapper
.getUuidAndTitleCache().getUuid())
572 .collect(Collectors
.toList());
575 public Properties
getNatTableState() {
576 return toolbar
.getNatTableState();
579 public ListDataProvider
<Object
> getBodyDataProvider() {
580 return bodyDataProvider
;
583 DefaultBodyLayerStack
getBodyLayer() {
587 File
getStatePropertiesFile() {
588 return new File(WorkbenchUtility
.getBaseLocation(), CHARACTER_MATRIX_STATE_PROPERTIES
);
591 public List
<Feature
> getFeatures() {
595 public void addUpdateResult(UpdateResult result
){
596 part
.addUpdateResult(result
);
599 public Map
<Feature
, CategoricalDataHistogram
> getFeatureToHistogramMap() {
600 return featureToHistogramMap
;