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() {
134 public void widgetSelected(SelectionEvent e
) {
135 Set
<TaxonNode
> taxonSubtreeFilter
= matrix
.getDescriptiveDataSet().getTaxonSubtreeFilter();
136 List
<TaxonNodeDto
> nodeDtos
= taxonSubtreeFilter
.stream()
137 .map(node
-> new TaxonNodeDto(node
)).collect(Collectors
.toList());
138 TaxonNodeDto parentDto
= CdmStore
.getService(ITaxonNodeService
.class).findCommonParentDto(nodeDtos
);
139 UUID taxonUuid
= parentDto
.getTaxonUuid();
140 int response
= MessagingUtils
.confirmDialog(
141 "Choose location for the aggregated description",
142 String
.format("The aggregated description will be stored at "
143 + "the common parent taxon of this data set:\n%s\n\n"
144 + "Do you want to use this taxon?"
145 , parentDto
.getTaxonTitleCache()), "Yes", "Choose taxon", "Cancel");
149 else if(response
==1){
150 Taxon taxon
= TaxonSelectionDialog
.selectTaxon(getShell(), null);
154 taxonUuid
= taxon
.getUuid();
156 UpdateResult result
= CdmStore
.getService(IDescriptionService
.class).aggregateDescription(taxonUuid
, null, matrix
.getDescriptiveDataSet().getUuid());
157 matrix
.addUpdateResult(result
);
164 private SpecimenDescription
getDescriptionForDescriptiveDataSet(SpecimenOrObservationBase specimen
){
165 Set
<Feature
> wsFeatures
= matrix
.getDescriptiveDataSet().getDescriptiveSystem().getDistinctFeatures();
166 List
<DescriptionElementBase
> matchingDescriptionElements
= new ArrayList
<>();
168 for (SpecimenDescription specimenDescription
: (Set
<SpecimenDescription
>) specimen
.getDescriptions()) {
169 specimenDescription
= (SpecimenDescription
) CdmStore
.getService(IDescriptionService
.class).load(specimenDescription
.getUuid());
170 Set
<Feature
> specimenDescriptionFeatures
= new HashSet
<>();
171 //gather specimen description features and check for match with WS features
172 for (DescriptionElementBase specimenDescriptionElement
: specimenDescription
.getElements()) {
173 Feature feature
= specimenDescriptionElement
.getFeature();
174 specimenDescriptionFeatures
.add(feature
);
175 if(wsFeatures
.contains(feature
)){
176 matchingDescriptionElements
.add(specimenDescriptionElement
);
179 //if description with the exact same features is found return the description
180 if(specimenDescriptionFeatures
.equals(wsFeatures
)){
181 return specimenDescription
;
184 //Create new specimen description if no match was found
186 SpecimenDescription newDesription
= SpecimenDescription
.NewInstance(specimen
);
187 newDesription
.setTitleCache(Messages
.CharacterMatrix_DESCRIPTIVE_DATA_SET
+matrix
.getDescriptiveDataSet().getLabel()+": "+newDesription
.generateTitle(), true); //$NON-NLS-2$
189 //check for equals description element (same feature and same values)
190 Map
<Feature
, List
<DescriptionElementBase
>> featureToElementMap
= new HashMap
<>();
191 for(DescriptionElementBase element
:matchingDescriptionElements
){
192 List
<DescriptionElementBase
> list
= featureToElementMap
.get(element
.getFeature());
194 list
= new ArrayList
<>();
197 featureToElementMap
.put(element
.getFeature(), list
);
199 Set
<DescriptionElementBase
> descriptionElementsToClone
= new HashSet
<>();
200 for(Feature feature
:featureToElementMap
.keySet()){
201 List
<DescriptionElementBase
> elements
= featureToElementMap
.get(feature
);
202 //no duplicate description elements found for this feature
203 if(elements
.size()==1){
204 descriptionElementsToClone
.add(elements
.get(0));
206 //duplicates found -> check if all are equal
208 DescriptionElementBase match
= null;
209 for (DescriptionElementBase descriptionElementBase
: elements
) {
211 match
= descriptionElementBase
;
213 else if(!new DescriptionElementCompareWrapper(match
).equals(new DescriptionElementCompareWrapper(descriptionElementBase
))){
215 MessagingUtils
.informationDialog(Messages
.CharacterMatrix_MULTIPLE_DATA
,
216 String
.format(Messages
.CharacterMatrix_MULTIPLE_DATA_MESSAGE
, feature
.getLabel()));
221 descriptionElementsToClone
.add(match
);
225 //clone matching descriptionElements
226 for (DescriptionElementBase descriptionElementBase
: descriptionElementsToClone
) {
227 DescriptionElementBase clone
;
229 clone
= descriptionElementBase
.clone(newDesription
);
230 clone
.getSources().forEach(source
-> source
.setOriginalNameString(DescriptionHelper
.getLabel(descriptionElementBase
)));
231 } catch (CloneNotSupportedException e
) {
232 MessagingUtils
.error(CharacterMatrix
.class, e
);
236 //add all remaining description elements to the new description
237 for(Feature wsFeature
:wsFeatures
){
238 boolean featureFound
= false;
239 for(DescriptionElementBase element
:newDesription
.getElements()){
240 if(element
.getFeature().equals(wsFeature
)){
246 if(wsFeature
.isSupportsCategoricalData()){
247 newDesription
.addElement(CategoricalData
.NewInstance(wsFeature
));
249 else if(wsFeature
.isSupportsQuantitativeData()){
250 newDesription
.addElement(QuantitativeData
.NewInstance(wsFeature
));
254 return newDesription
;