Remove "experimental" status from
[taxeditor.git] / eu.etaxonomy.taxeditor.editor / src / main / java / eu / etaxonomy / taxeditor / editor / descriptiveDataSet / matrix / CharacterMatrixBottomToolbar.java
1 /**
2 * Copyright (C) 2018 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
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.
8 */
9 package eu.etaxonomy.taxeditor.editor.descriptiveDataSet.matrix;
10
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.List;
14 import java.util.Set;
15 import java.util.UUID;
16 import java.util.stream.Collectors;
17
18 import org.eclipse.core.runtime.ICoreRunnable;
19 import org.eclipse.core.runtime.IProgressMonitor;
20 import org.eclipse.core.runtime.SubMonitor;
21 import org.eclipse.core.runtime.jobs.IJobChangeEvent;
22 import org.eclipse.core.runtime.jobs.Job;
23 import org.eclipse.core.runtime.jobs.JobChangeAdapter;
24 import org.eclipse.jface.layout.GridDataFactory;
25 import org.eclipse.jface.window.Window;
26 import org.eclipse.swt.SWT;
27 import org.eclipse.swt.events.SelectionAdapter;
28 import org.eclipse.swt.events.SelectionEvent;
29 import org.eclipse.swt.layout.RowLayout;
30 import org.eclipse.swt.widgets.Button;
31 import org.eclipse.swt.widgets.Composite;
32
33 import eu.etaxonomy.cdm.api.application.CdmApplicationState;
34 import eu.etaxonomy.cdm.api.service.IDescriptiveDataSetService;
35 import eu.etaxonomy.cdm.api.service.ITaxonNodeService;
36 import eu.etaxonomy.cdm.api.service.UpdateResult;
37 import eu.etaxonomy.cdm.api.service.description.AggregationMode;
38 import eu.etaxonomy.cdm.api.service.description.StructuredDescriptionAggregationConfiguration;
39 import eu.etaxonomy.cdm.api.service.dto.RowWrapperDTO;
40 import eu.etaxonomy.cdm.common.monitor.IRemotingProgressMonitor;
41 import eu.etaxonomy.cdm.filter.TaxonNodeFilter;
42 import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
43 import eu.etaxonomy.cdm.model.location.NamedArea;
44 import eu.etaxonomy.cdm.model.taxon.Taxon;
45 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
46 import eu.etaxonomy.cdm.persistence.dto.SpecimenNodeWrapper;
47 import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
48 import eu.etaxonomy.taxeditor.editor.internal.TaxeditorEditorPlugin;
49 import eu.etaxonomy.taxeditor.editor.l10n.Messages;
50 import eu.etaxonomy.taxeditor.model.ImageResources;
51 import eu.etaxonomy.taxeditor.model.MessagingUtils;
52 import eu.etaxonomy.taxeditor.store.CdmStore;
53 import eu.etaxonomy.taxeditor.store.StoreUtil;
54 import eu.etaxonomy.taxeditor.ui.dialog.selection.TaxonSelectionDialog;
55
56 /**
57 * @author pplitzner
58 * @since Jul 9, 2018
59 */
60 public class CharacterMatrixBottomToolbar extends Composite{
61
62 private CharacterMatrix matrix;
63
64 public CharacterMatrixBottomToolbar(CharacterMatrix matrix, int style) {
65 super(matrix, style);
66 this.matrix = matrix;
67
68 init();
69 }
70
71 private void init() {
72
73 setLayout(new RowLayout());
74 GridDataFactory.fillDefaults().grab(true, false).applyTo(this);
75
76 /**
77 * Add description button
78 */
79 Button btnAddDescription = new Button(this, SWT.PUSH);
80 btnAddDescription.setImage(ImageResources.getImage(ImageResources.ADD_ICON_GREEN));
81 btnAddDescription.addSelectionListener(new SelectionAdapter() {
82 @Override
83 public void widgetSelected(SelectionEvent e) {
84 if(StoreUtil.promptCheckIsDirty(matrix.getPart())){
85 return;
86 }
87 SpecimenSelectionDialog dialog = new SpecimenSelectionDialog(matrix.getShell(), matrix);
88 if(dialog.open()==Window.OK){
89 Collection<SpecimenNodeWrapper> wrappers = dialog.getSpecimen();
90 if(wrappers.stream().anyMatch(wrapper->wrapper.getTaxonDescriptionUuid()==null)
91 && !MessagingUtils.confirmDialog(
92 "Create Taxon Association",
93 "Some specimens are not linked with taxon via IndividualsAssociation yet.\n"
94 + "Do you want to create this association?")){
95 return;
96 }
97 addRowsToMatrix(wrappers, matrix.getDescriptiveDataSet().getUuid());
98 wrappers.forEach(wrapper->matrix.getSpecimenCache().remove(wrapper));
99 }
100 }
101 });
102 /**
103 * Remove description button
104 */
105 Button btnRemoveDescription = new Button(this, SWT.PUSH);
106 btnRemoveDescription.setImage(ImageResources.getImage(ImageResources.ACTIVE_DELETE_ICON));
107 btnRemoveDescription.addSelectionListener(new SelectionAdapter() {
108 @Override
109 public void widgetSelected(SelectionEvent e) {
110 if(StoreUtil.promptCheckIsDirty(matrix.getPart())){
111 return;
112 }
113 if(!MessagingUtils.confirmDialog(Messages.CharacterMatrixBottomToolbar_CONFIRM_DELETE_TITLE, Messages.CharacterMatrixBottomToolbar_CONFIRM_DELETE_MESSAGE)){
114 return;
115 }
116 int[] fullySelectedRowPositions = matrix.getBodyLayer().getSelectionLayer().getFullySelectedRowPositions();
117 List<RowWrapperDTO> toRemove = new ArrayList<>();
118 for (int i : fullySelectedRowPositions) {
119 Object rowObject = matrix.getBodyDataProvider().getRowObject(i);
120 if(rowObject instanceof RowWrapperDTO){
121 toRemove.add((RowWrapperDTO) rowObject);
122 }
123 }
124 toRemove.forEach(rowToRemove -> {
125 matrix.getDescriptions().remove(rowToRemove);
126 CdmStore.getService(IDescriptiveDataSetService.class).removeDescription(
127 rowToRemove.getDescription().getUuid(), matrix.getDescriptiveDataSet().getUuid());
128 });
129 }
130 });
131 /**
132 * Aggregate button
133 */
134 Button btnAggregate = new Button(this, SWT.PUSH);
135 btnAggregate.setText(Messages.CharacterMatrixBottomToolbar_AGGREGATE);
136 btnAggregate.addSelectionListener(new SelectionAdapter() {
137 @Override
138 public void widgetSelected(SelectionEvent e) {
139 if(StoreUtil.promptCheckIsDirty(matrix.getPart())){
140 return;
141 }
142 aggregatDescriptiveDataSet(matrix.getDescriptiveDataSet().getUuid());
143 }
144 });
145 /**
146 * Key generation button
147 */
148 Button btnGenerateKey = new Button(this, SWT.PUSH);
149 btnGenerateKey.setText("Generate Polytomous Key");
150 btnGenerateKey.addSelectionListener(new SelectionAdapter() {
151 @Override
152 public void widgetSelected(SelectionEvent e) {
153 if(StoreUtil.promptCheckIsDirty(matrix.getPart())){
154 return;
155 }
156 Set<TaxonNodeDto> nodeDtos = matrix.getDescriptiveDataSet().getTaxonSubtreeFilter().stream()
157 .map(node->new TaxonNodeDto(node))
158 .collect(Collectors.toSet());
159 TaxonNodeDto parentDto = CdmStore.getService(ITaxonNodeService.class).findCommonParentDto(nodeDtos);
160 UUID taxonUuid = parentDto.getTaxonUuid();
161 int response = MessagingUtils.confirmDialog(
162 "Choose taxonomic scope",
163 String.format("The common parent taxon of this data set is :\n%s\n\n"
164 + "Do you want to use this as the taxonomic scope for the polytomous key?"
165 , parentDto.getTaxonTitleCache()), "Yes", "Choose different taxon", "Cancel");
166 if(response==2){
167 return;
168 }
169 else if(response==1){
170 Taxon taxon = TaxonSelectionDialog.selectTaxon(getShell(), null);
171 if(taxon==null){
172 return;
173 }
174 taxonUuid = taxon.getUuid();
175 }
176 generateKey(matrix.getDescriptiveDataSet().getUuid(), taxonUuid);
177 }
178
179 });
180 }
181
182 private void aggregatDescriptiveDataSet(UUID descriptiveDataSetUuid){
183 // FIXME: set taxon node filter for config (this is still not used in the aggregation)
184 StructuredDescriptionAggregationConfiguration config = StructuredDescriptionAggregationConfiguration.NewInstance(
185 null, null);
186 config.setDatasetUuid(matrix.getDescriptiveDataSet().getUuid());
187 config.setAggregateToHigherRanks(true);
188 config.setAggregationMode(AggregationMode.byAreasAndRanks());
189 config.setAdaptBatchSize(false);
190
191 TaxonNodeFilter filter = TaxonNodeFilter.NewRankInstance(matrix.getDescriptiveDataSet().getMinRank(),
192 matrix.getDescriptiveDataSet().getMaxRank());
193 for (NamedArea namedArea : matrix.getDescriptiveDataSet().getGeoFilter()) {
194 filter = filter.orArea(namedArea.getUuid());
195 }
196 for (TaxonNode taxonNode : matrix.getDescriptiveDataSet().getTaxonSubtreeFilter()) {
197 filter = filter.orSubtree(taxonNode);
198 }
199 config.setTaxonNodeFilter(filter);
200
201 UUID monitorUuid = CdmApplicationState.getLongRunningTasksService().invoke(config);
202
203 String jobLabel = "Aggregate Descriptive Data Set";
204 Job job = Job.create(jobLabel, (ICoreRunnable) monitor -> {
205 SubMonitor subMonitor = SubMonitor.convert(monitor);
206 subMonitor.beginTask(jobLabel, IProgressMonitor.UNKNOWN);
207 IRemotingProgressMonitor remotingMonitor;
208 try {
209 remotingMonitor = CdmStore.getProgressMonitorClientManager()
210 .pollMonitor(jobLabel,
211 monitorUuid,
212 50,
213 null,
214 (List)null,
215 subMonitor);
216 Object resultObject = remotingMonitor.getResult();
217 if(resultObject instanceof Exception){
218 MessagingUtils.errorDialog("Aggregation failed", this, "Aggregation was not successfull", TaxeditorEditorPlugin.PLUGIN_ID, (Exception)resultObject, true, true);
219 }
220 else if(resultObject instanceof UpdateResult){
221 DescriptiveDataSet dataSet = (DescriptiveDataSet) ((UpdateResult) resultObject).getCdmEntity();
222 dataSet = matrix.getCdmEntitiySession().load(dataSet, true);
223 // update local dataset
224 matrix.setDescriptiveDataSet(dataSet);
225 matrix.loadDescriptions(descriptiveDataSetUuid, false);
226 }
227 } catch (InterruptedException e) {
228 return;
229 }
230 monitor.done();
231 });
232 job.addJobChangeListener(new JobChangeAdapter(){
233 @Override
234 public void done(IJobChangeEvent event) {
235 CharacterMatrixBottomToolbar.this.getDisplay().asyncExec(()->{
236 matrix.redraw();
237 });
238 }
239 });
240 job.schedule();
241 }
242
243 private void addRowsToMatrix(Collection<SpecimenNodeWrapper> wrappers, UUID descriptiveDataSetUuid){
244 UUID monitorUuid = CdmApplicationState.getLongRunningTasksService().addRowWrapperToDataset(wrappers, descriptiveDataSetUuid);
245
246 String jobLabel = "Add specimens to matrix";
247 Job job = Job.create(jobLabel, (ICoreRunnable) monitor -> {
248 SubMonitor subMonitor = SubMonitor.convert(monitor);
249 subMonitor.beginTask(jobLabel, IProgressMonitor.UNKNOWN);
250 IRemotingProgressMonitor remotingMonitor;
251 try {
252 remotingMonitor = CdmStore.getProgressMonitorClientManager()
253 .pollMonitor(jobLabel,
254 monitorUuid,
255 50,
256 null,
257 (List)null,
258 subMonitor);
259 Object resultObject = remotingMonitor.getResult();
260 if(resultObject instanceof Exception){
261 MessagingUtils.errorDialog("Adding specimens failed", this, "Adding specimens was not successfull", TaxeditorEditorPlugin.PLUGIN_ID, (Exception)resultObject, true, true);
262 }
263 else if(resultObject instanceof UpdateResult){
264 UpdateResult result = (UpdateResult)resultObject;
265 if(!result.getExceptions().isEmpty()){
266 MessagingUtils.warningDialog(Messages.CharacterMatrixBottomToolbar_ERROR_ROW_CREATION_TITLE, this,
267 String.format(Messages.CharacterMatrixBottomToolbar_ERROR_ROW_CREATION_MESSAGE, result.getExceptions()
268 .stream().map(ex->ex.toString())
269 .collect(Collectors.joining("\n"))));
270 }
271 DescriptiveDataSet dataSet = (DescriptiveDataSet) result.getCdmEntity();
272 dataSet = matrix.getCdmEntitiySession().load(dataSet, true);
273 // update local dataset
274 matrix.setDescriptiveDataSet(dataSet);
275 matrix.loadDescriptions(descriptiveDataSetUuid, false);
276 }
277 } catch (InterruptedException e) {
278 return;
279 }
280 monitor.done();
281 });
282 job.addJobChangeListener(new JobChangeAdapter(){
283 @Override
284 public void done(IJobChangeEvent event) {
285 CharacterMatrixBottomToolbar.this.getDisplay().asyncExec(()->{
286 matrix.redraw();
287 });
288 }
289 });
290 job.schedule();
291 }
292
293 private void generateKey(UUID datasetUuid, UUID taxonUuid) {
294
295 UUID monitorUuid = CdmApplicationState.getLongRunningTasksService().generatePolytomousKey(datasetUuid, taxonUuid);
296
297 String jobLabel = "Generate polytomous key";
298 Job job = Job.create(jobLabel, (ICoreRunnable) monitor -> {
299 SubMonitor subMonitor = SubMonitor.convert(monitor);
300 subMonitor.beginTask(jobLabel, IProgressMonitor.UNKNOWN);
301 IRemotingProgressMonitor remotingMonitor;
302 try {
303 remotingMonitor = CdmStore.getProgressMonitorClientManager()
304 .pollMonitor(jobLabel,
305 monitorUuid,
306 50,
307 null,
308 (List)null,
309 subMonitor);
310 Object resultObject = remotingMonitor.getResult();
311 if(resultObject instanceof Exception){
312 MessagingUtils.errorDialog("Key generation failed", this, "Generating the polytomous key was not successfull", TaxeditorEditorPlugin.PLUGIN_ID, (Exception)resultObject, true, true);
313 }
314 } catch (InterruptedException e) {
315 return;
316 }
317 monitor.done();
318 });
319 job.schedule();
320
321 }
322
323 }