2 * Copyright (C) 2018 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
;
11 import java
.util
.ArrayList
;
12 import java
.util
.Collection
;
13 import java
.util
.HashMap
;
14 import java
.util
.HashSet
;
15 import java
.util
.List
;
18 import java
.util
.UUID
;
19 import java
.util
.stream
.Collectors
;
21 import org
.eclipse
.jface
.layout
.GridDataFactory
;
22 import org
.eclipse
.jface
.window
.Window
;
23 import org
.eclipse
.swt
.SWT
;
24 import org
.eclipse
.swt
.events
.SelectionAdapter
;
25 import org
.eclipse
.swt
.events
.SelectionEvent
;
26 import org
.eclipse
.swt
.layout
.RowLayout
;
27 import org
.eclipse
.swt
.widgets
.Button
;
28 import org
.eclipse
.swt
.widgets
.Composite
;
30 import eu
.etaxonomy
.cdm
.api
.service
.IDescriptionService
;
31 import eu
.etaxonomy
.cdm
.api
.service
.IDescriptiveDataSetService
;
32 import eu
.etaxonomy
.cdm
.api
.service
.IOccurrenceService
;
33 import eu
.etaxonomy
.cdm
.api
.service
.ITaxonNodeService
;
34 import eu
.etaxonomy
.cdm
.api
.service
.UpdateResult
;
35 import eu
.etaxonomy
.cdm
.api
.service
.dto
.RowWrapperDTO
;
36 import eu
.etaxonomy
.cdm
.model
.description
.CategoricalData
;
37 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
38 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
39 import eu
.etaxonomy
.cdm
.model
.description
.QuantitativeData
;
40 import eu
.etaxonomy
.cdm
.model
.description
.SpecimenDescription
;
41 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
42 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
43 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
44 import eu
.etaxonomy
.cdm
.persistence
.dto
.SpecimenNodeWrapper
;
45 import eu
.etaxonomy
.cdm
.persistence
.dto
.TaxonNodeDto
;
46 import eu
.etaxonomy
.taxeditor
.editor
.l10n
.Messages
;
47 import eu
.etaxonomy
.taxeditor
.model
.DescriptionHelper
;
48 import eu
.etaxonomy
.taxeditor
.model
.ImageResources
;
49 import eu
.etaxonomy
.taxeditor
.model
.MessagingUtils
;
50 import eu
.etaxonomy
.taxeditor
.store
.CdmStore
;
51 import eu
.etaxonomy
.taxeditor
.ui
.dialog
.selection
.TaxonSelectionDialog
;
58 public class CharacterMatrixBottomToolbar
extends Composite
{
60 private CharacterMatrix matrix
;
62 public CharacterMatrixBottomToolbar(CharacterMatrix matrix
, int style
) {
71 setLayout(new RowLayout());
72 GridDataFactory
.fillDefaults().grab(true, false).applyTo(this);
75 * Add description button
77 Button btnAddDescription
= new Button(this, SWT
.PUSH
);
78 btnAddDescription
.setImage(ImageResources
.getImage(ImageResources
.ADD_ICON_GREEN
));
79 btnAddDescription
.addSelectionListener(new SelectionAdapter() {
81 public void widgetSelected(SelectionEvent e
) {
82 SpecimenSelectionDialog dialog
= new SpecimenSelectionDialog(matrix
.getShell(), matrix
);
83 if(dialog
.open()==Window
.OK
){
84 Collection
<SpecimenNodeWrapper
> wrappers
= dialog
.getSpecimen();
85 for (SpecimenNodeWrapper wrapper
: wrappers
) {
86 SpecimenOrObservationBase specimen
= CdmStore
.getService(IOccurrenceService
.class).load(wrapper
.getUuidAndTitleCache().getUuid());
87 SpecimenDescription description
= getDescriptionForDescriptiveDataSet(specimen
);
88 //description elements
89 Map
<Feature
, DescriptionElementBase
> featureToElementMap
= new HashMap
<>();
90 Set
<DescriptionElementBase
> elements
= description
.getElements();
91 for (DescriptionElementBase descriptionElementBase
: elements
) {
92 Feature feature
= descriptionElementBase
.getFeature();
93 featureToElementMap
.put(feature
, descriptionElementBase
);
95 RowWrapperDTO rowWrapper
= CdmStore
.getService(IDescriptiveDataSetService
.class).createRowWrapper(description
, matrix
.getDescriptiveDataSet());
96 matrix
.getDescriptions().add(rowWrapper
);
97 matrix
.getDescriptiveDataSet().addDescription(description
);
99 matrix
.getSpecimenCache().remove(wrapper
);
105 * Remove description button
107 Button btnRemoveDescription
= new Button(this, SWT
.PUSH
);
108 btnRemoveDescription
.setImage(ImageResources
.getImage(ImageResources
.ACTIVE_DELETE_ICON
));
109 btnRemoveDescription
.addSelectionListener(new SelectionAdapter() {
111 public void widgetSelected(SelectionEvent e
) {
112 int[] fullySelectedRowPositions
= matrix
.getBodyLayer().getSelectionLayer().getFullySelectedRowPositions();
113 List
<RowWrapperDTO
> toRemove
= new ArrayList
<>();
114 for (int i
: fullySelectedRowPositions
) {
115 Object rowObject
= matrix
.getBodyDataProvider().getRowObject(i
);
116 if(rowObject
instanceof RowWrapperDTO
){
117 toRemove
.add((RowWrapperDTO
) rowObject
);
120 toRemove
.forEach(rowToRemove
->{
121 matrix
.getDescriptions().remove(rowToRemove
);
122 matrix
.getDescriptiveDataSet().removeDescription(rowToRemove
.getSpecimenDescription());
130 Button btnAggregate
= new Button(this, SWT
.PUSH
);
131 btnAggregate
.setText("Aggregate");
132 btnAggregate
.addSelectionListener(new SelectionAdapter() {
133 @SuppressWarnings("unchecked")
135 public void widgetSelected(SelectionEvent e
) {
136 Set
<TaxonNode
> taxonSubtreeFilter
= matrix
.getDescriptiveDataSet().getTaxonSubtreeFilter();
137 List
<TaxonNodeDto
> nodeDtos
= taxonSubtreeFilter
.stream()
138 .map(node
-> new TaxonNodeDto(node
)).collect(Collectors
.toList());
139 TaxonNodeDto parentDto
= CdmStore
.getService(ITaxonNodeService
.class).findCommonParentDto(nodeDtos
);
140 UUID taxonUuid
= parentDto
.getTaxonUuid();
141 int response
= MessagingUtils
.confirmDialog(
142 "Choose location for the aggregated description",
143 String
.format("The aggregated description will be stored at "
144 + "the common parent taxon of this data set:\n%s\n\n"
145 + "Do you want to use this taxon?"
146 , parentDto
.getTaxonTitleCache()), "Yes", "Choose taxon", "Cancel");
150 else if(response
==1){
151 Taxon taxon
= TaxonSelectionDialog
.selectTaxon(getShell(), null);
155 taxonUuid
= taxon
.getUuid();
157 UpdateResult result
= CdmStore
.getService(IDescriptionService
.class).aggregateDescription(taxonUuid
, null, matrix
.getDescriptiveDataSet().getUuid());
158 matrix
.addUpdateResult(result
);
161 //aggregate histogram for categorical tooltip
162 Map
<Feature
, CategoricalDataHistogram
> featureToHistogramMap
= matrix
.getFeatureToHistogramMap();
163 featureToHistogramMap
.clear();
164 // matrix.getFeatures().forEach(feature->{
165 matrix
.getDescriptions()
166 .forEach(o
-> ((RowWrapperDTO
) o
).getSpecimenDescription().getElements().stream()
167 .filter(descriptionElement
-> descriptionElement
instanceof CategoricalData
)
168 .forEach(categoricalData
-> {
169 Feature feature
= ((CategoricalData
) categoricalData
).getFeature();
170 CategoricalDataHistogram dataHistogram
= featureToHistogramMap
.get(feature
);
171 if(dataHistogram
==null){
172 dataHistogram
= new CategoricalDataHistogram(feature
);
174 featureToHistogramMap
.put(feature
, dataHistogram
);
175 ((CategoricalData
) categoricalData
).getStateData()
176 .forEach(stateData
-> featureToHistogramMap
.get(feature
).addState(stateData
.getState()));
181 private SpecimenDescription
getDescriptionForDescriptiveDataSet(SpecimenOrObservationBase specimen
){
182 Set
<Feature
> wsFeatures
= matrix
.getDescriptiveDataSet().getDescriptiveSystem().getDistinctFeatures();
183 List
<DescriptionElementBase
> matchingDescriptionElements
= new ArrayList
<>();
185 for (SpecimenDescription specimenDescription
: (Set
<SpecimenDescription
>) specimen
.getDescriptions()) {
186 specimenDescription
= (SpecimenDescription
) CdmStore
.getService(IDescriptionService
.class).load(specimenDescription
.getUuid());
187 Set
<Feature
> specimenDescriptionFeatures
= new HashSet
<>();
188 //gather specimen description features and check for match with WS features
189 for (DescriptionElementBase specimenDescriptionElement
: specimenDescription
.getElements()) {
190 Feature feature
= specimenDescriptionElement
.getFeature();
191 specimenDescriptionFeatures
.add(feature
);
192 if(wsFeatures
.contains(feature
)){
193 matchingDescriptionElements
.add(specimenDescriptionElement
);
196 //if description with the exact same features is found return the description
197 if(specimenDescriptionFeatures
.equals(wsFeatures
)){
198 return specimenDescription
;
201 //Create new specimen description if no match was found
203 SpecimenDescription newDesription
= SpecimenDescription
.NewInstance(specimen
);
204 newDesription
.setTitleCache(Messages
.CharacterMatrix_DESCRIPTIVE_DATA_SET
+matrix
.getDescriptiveDataSet().getLabel()+": "+newDesription
.generateTitle(), true); //$NON-NLS-2$
206 //check for equals description element (same feature and same values)
207 Map
<Feature
, List
<DescriptionElementBase
>> featureToElementMap
= new HashMap
<>();
208 for(DescriptionElementBase element
:matchingDescriptionElements
){
209 List
<DescriptionElementBase
> list
= featureToElementMap
.get(element
.getFeature());
211 list
= new ArrayList
<>();
214 featureToElementMap
.put(element
.getFeature(), list
);
216 Set
<DescriptionElementBase
> descriptionElementsToClone
= new HashSet
<>();
217 for(Feature feature
:featureToElementMap
.keySet()){
218 List
<DescriptionElementBase
> elements
= featureToElementMap
.get(feature
);
219 //no duplicate description elements found for this feature
220 if(elements
.size()==1){
221 descriptionElementsToClone
.add(elements
.get(0));
223 //duplicates found -> check if all are equal
225 DescriptionElementBase match
= null;
226 for (DescriptionElementBase descriptionElementBase
: elements
) {
228 match
= descriptionElementBase
;
230 else if(!new DescriptionElementCompareWrapper(match
).equals(new DescriptionElementCompareWrapper(descriptionElementBase
))){
232 MessagingUtils
.informationDialog(Messages
.CharacterMatrix_MULTIPLE_DATA
,
233 String
.format(Messages
.CharacterMatrix_MULTIPLE_DATA_MESSAGE
, feature
.getLabel()));
238 descriptionElementsToClone
.add(match
);
242 //clone matching descriptionElements
243 for (DescriptionElementBase descriptionElementBase
: descriptionElementsToClone
) {
244 DescriptionElementBase clone
;
246 clone
= descriptionElementBase
.clone(newDesription
);
247 clone
.getSources().forEach(source
-> source
.setOriginalNameString(DescriptionHelper
.getLabel(descriptionElementBase
)));
248 } catch (CloneNotSupportedException e
) {
249 MessagingUtils
.error(CharacterMatrix
.class, e
);
253 //add all remaining description elements to the new description
254 for(Feature wsFeature
:wsFeatures
){
255 boolean featureFound
= false;
256 for(DescriptionElementBase element
:newDesription
.getElements()){
257 if(element
.getFeature().equals(wsFeature
)){
263 if(wsFeature
.isSupportsCategoricalData()){
264 newDesription
.addElement(CategoricalData
.NewInstance(wsFeature
));
266 else if(wsFeature
.isSupportsQuantitativeData()){
267 newDesription
.addElement(QuantitativeData
.NewInstance(wsFeature
));
271 return newDesription
;