adapt comparators to new model.compare structure (cont.)
[taxeditor.git] / eu.etaxonomy.taxeditor.editor / src / main / java / eu / etaxonomy / taxeditor / editor / descriptiveDataSet / DescriptiveDataSetEditor.java
1 /**
2 * Copyright (C) 2017 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;
10
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.HashSet;
15 import java.util.Iterator;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Set;
19 import java.util.UUID;
20 import java.util.stream.Collectors;
21
22 import javax.annotation.PostConstruct;
23 import javax.annotation.PreDestroy;
24 import javax.inject.Inject;
25 import javax.inject.Named;
26
27 import org.eclipse.core.runtime.IProgressMonitor;
28 import org.eclipse.e4.core.contexts.ContextInjectionFactory;
29 import org.eclipse.e4.core.contexts.IEclipseContext;
30 import org.eclipse.e4.ui.di.Focus;
31 import org.eclipse.e4.ui.di.Persist;
32 import org.eclipse.e4.ui.model.application.ui.MDirtyable;
33 import org.eclipse.e4.ui.model.application.ui.basic.MPart;
34 import org.eclipse.e4.ui.services.EMenuService;
35 import org.eclipse.e4.ui.services.IServiceConstants;
36 import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
37 import org.eclipse.jface.util.LocalSelectionTransfer;
38 import org.eclipse.jface.viewers.IStructuredSelection;
39 import org.eclipse.jface.viewers.StructuredSelection;
40 import org.eclipse.jface.viewers.Viewer;
41 import org.eclipse.jface.window.Window;
42 import org.eclipse.swt.SWT;
43 import org.eclipse.swt.dnd.DND;
44 import org.eclipse.swt.dnd.Transfer;
45 import org.eclipse.swt.events.FocusAdapter;
46 import org.eclipse.swt.events.FocusEvent;
47 import org.eclipse.swt.events.KeyAdapter;
48 import org.eclipse.swt.events.KeyEvent;
49 import org.eclipse.swt.events.ModifyEvent;
50 import org.eclipse.swt.events.ModifyListener;
51 import org.eclipse.swt.events.SelectionAdapter;
52 import org.eclipse.swt.widgets.Composite;
53 import org.eclipse.swt.widgets.Display;
54 import org.eclipse.swt.widgets.Shell;
55
56 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
57 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
58 import eu.etaxonomy.cdm.api.service.IDescriptiveDataSetService;
59 import eu.etaxonomy.cdm.api.service.ITaxonNodeService;
60 import eu.etaxonomy.cdm.api.service.ITermService;
61 import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
62 import eu.etaxonomy.cdm.model.description.Feature;
63 import eu.etaxonomy.cdm.model.location.NamedArea;
64 import eu.etaxonomy.cdm.model.name.Rank;
65 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
66 import eu.etaxonomy.cdm.model.term.DefinedTermBase;
67 import eu.etaxonomy.cdm.model.term.TermTree;
68 import eu.etaxonomy.cdm.model.term.TermType;
69 import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
70 import eu.etaxonomy.cdm.persistence.dto.TermDto;
71 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
72 import eu.etaxonomy.taxeditor.editor.IDescriptiveDataSetEditor;
73 import eu.etaxonomy.taxeditor.editor.l10n.Messages;
74 import eu.etaxonomy.taxeditor.event.EventUtility;
75 import eu.etaxonomy.taxeditor.event.WorkbenchEventConstants;
76 import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
77 import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
78 import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
79 import eu.etaxonomy.taxeditor.model.MessagingUtils;
80 import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
81 import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
82 import eu.etaxonomy.taxeditor.store.CdmStore;
83 import eu.etaxonomy.taxeditor.ui.element.CdmFormFactory;
84 import eu.etaxonomy.taxeditor.workbench.part.IE4SavablePart;
85
86 /**
87 * Editor for configuring DescriptiveDataSets
88 * @author pplitzner
89 * @since Nov 21, 2017
90 *
91 */
92 public class DescriptiveDataSetEditor implements IE4SavablePart, IConversationEnabled,
93 ICdmEntitySessionEnabled<DescriptiveDataSet>, IPartContentHasDetails,
94 IPartContentHasSupplementalData, IDirtyMarkable, IDescriptiveDataSetEditor {
95
96 private DescriptiveDataSetComposite composite;
97
98 private ConversationHolder conversation;
99
100 private ICdmEntitySession cdmEntitySession;
101
102 private DescriptiveDataSet descriptiveDataSet;
103
104 private final int dndOperations = DND.DROP_MOVE;
105
106 @Inject
107 private MDirtyable dirty;
108
109 @Inject
110 private MPart thisPart;
111
112 @Inject
113 private ESelectionService selectionService;
114
115 private ModifyListener labelModifyListener;
116
117 @PostConstruct
118 public void create(Composite parent, IEclipseContext context, @Named(IServiceConstants.ACTIVE_SHELL)Shell shell,
119 EMenuService menuService){
120 if (CdmStore.isActive()){
121 if(conversation == null){
122 conversation = CdmStore.createConversation();
123 }
124 if(cdmEntitySession == null){
125 cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
126 }
127 }
128 else{
129 return;
130 }
131 CdmFormFactory cdmFormFactory = new CdmFormFactory(Display.getCurrent());
132 ContextInjectionFactory.inject(cdmFormFactory, context);
133
134 composite = new DescriptiveDataSetComposite(parent, SWT.NONE);
135
136 labelModifyListener = new ModifyListener() {
137 @Override
138 public void modifyText(ModifyEvent e) {
139 descriptiveDataSet.setLabel(composite.getTxt_label().getText());
140 EventUtility.postSyncEvent(WorkbenchEventConstants.REFRESH_DATASET_NAVIGATOR, descriptiveDataSet);
141 dirty.setDirty(true);
142 }
143 };
144 composite.getRankMin().addSelectionChangedListener(event->dirty.setDirty(true));
145 composite.getRankMin().setText("Select min rank...");
146 composite.getRankMax().addSelectionChangedListener(event->dirty.setDirty(true));
147 composite.getRankMax().setText("Select max rank...");
148 composite.getBtnRemoveRankMin().addSelectionListener(new SelectionAdapter() {
149 @Override
150 public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
151 composite.getRankMin().setElement(null);
152 dirty.setDirty(true);
153 }
154 });
155 composite.getBtnRemoveRankMax().addSelectionListener(new SelectionAdapter() {
156 @Override
157 public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
158 composite.getRankMax().setElement(null);
159 dirty.setDirty(true);
160 }
161 });
162
163 composite.getBtnChooseArea().addSelectionListener(new SelectionAdapter() {
164
165 @Override
166 public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
167 AreasSelectionDialog areasSelectionDialog = new AreasSelectionDialog(composite.getShell(), composite.getAreas());
168 if(areasSelectionDialog.open()==Window.OK){
169 List<TermDto> selectedAreas = areasSelectionDialog.getSelectedAreas();
170 if(selectedAreas!=null){
171 composite.setAreas(selectedAreas);
172 dirty.setDirty(true);
173 }
174 }
175 }
176 });
177
178 composite.getTermTreeEditorComposite().init("Character Tree",
179 TermType.Character,
180 null,
181 null,
182 e->selectionService.setSelection(e.getSelection()),
183 this,
184 null);
185
186 //add drag'n'drop support
187 Transfer[] transfers = new Transfer[] {LocalSelectionTransfer.getTransfer()};
188 composite.getTaxonNodeTree().addDropSupport(dndOperations, transfers, new TaxonNodeDropAdapter(this));
189
190 composite.getTaxonNodeTree().getTree().addKeyListener(new KeyAdapter() {
191 @Override
192 public void keyPressed(KeyEvent e) {
193 if(e.character==SWT.DEL){
194 removeSelectedTaxonNodes();
195 }
196 }
197 });
198
199
200 //create context menu
201 menuService.registerContextMenu(composite.getTaxonNodeTree().getControl(), "eu.etaxonomy.taxeditor.editor.descriptiveDataSet.DescriptiveDataSetEditor.popupmenu.specimeneditor");
202
203 }
204
205 public void init(UUID descriptiveDataSetUuid) {
206 this.descriptiveDataSet = cdmEntitySession.remoteLoad(CdmStore.getService(IDescriptiveDataSetService.class), descriptiveDataSetUuid);
207 if(descriptiveDataSet.getLabel()!=null){
208 composite.getTxt_label().setText(descriptiveDataSet.getLabel());
209 }
210 if(descriptiveDataSet.getDescriptiveSystem()!=null){
211 composite.setCharacters(descriptiveDataSet.getDescriptiveSystem());
212 }
213 Rank maxRank = descriptiveDataSet.getMaxRank();
214 if(maxRank!=null){
215 composite.setRankMax(maxRank);
216 }
217 Rank minRank = descriptiveDataSet.getMinRank();
218 if(minRank!=null){
219 composite.setRankMin(minRank);
220 }
221 Set<NamedArea> geoFilter = descriptiveDataSet.getGeoFilter();
222 if(geoFilter!=null && !geoFilter.isEmpty()){
223 Set<TermDto> terms = geoFilter.stream().map(filter->TermDto.fromTerm(filter, true)).collect(Collectors.toSet());
224 composite.setAreas(new ArrayList<>(terms));
225 }
226 Set<TaxonNode> taxonSubtreeFilter = descriptiveDataSet.getTaxonSubtreeFilter();
227 if(taxonSubtreeFilter!=null){
228 Set<TaxonNodeDto> dtoSet = new HashSet<>();
229 for (TaxonNode node: taxonSubtreeFilter){
230 dtoSet.add(new TaxonNodeDto(node));
231 }
232 composite.getTaxonNodeTree().setInput(dtoSet);
233 }
234 composite.getTxt_label().addModifyListener(labelModifyListener);
235 composite.getTxt_label().addFocusListener(new FocusAdapter() {
236 @Override
237 public void focusGained(FocusEvent e) {
238 super.focusGained(e);
239 selectionService.setSelection(new StructuredSelection(descriptiveDataSet));
240 }
241 });
242 selectionService.setSelection(new StructuredSelection(descriptiveDataSet));
243 thisPart.setLabel(descriptiveDataSet.getLabel());
244 }
245
246 public void addTaxonNode(TaxonNodeDto taxonNodeDto){
247 // TaxonNode taxonNode = cdmEntitySession.remoteLoad(CdmStore.getService(ITaxonNodeService.class), taxonNodeDto.getUuid());
248 //check if node belongs to same classification
249 Set<TaxonNode> taxonSubtreeFilter = descriptiveDataSet.getTaxonSubtreeFilter();
250 if(taxonSubtreeFilter!=null && !taxonSubtreeFilter.isEmpty()){
251 if(!taxonSubtreeFilter.iterator().next().getClassification().getUuid().equals(taxonNodeDto.getClassificationUUID())){
252 MessagingUtils.warningDialog(Messages.TaxonNodeDropAdapter_CLASSIFICATIONS_NO_MATCH, this.getClass(),
253 Messages.TaxonNodeDropAdapter_CLASSIFICATIONS_NO_MATCH_MESSAGE);
254 return;
255 }
256 }
257 Viewer taxonTreeViewer = getTaxonTreeViewer();
258 Object input = taxonTreeViewer.getInput();
259 Collection<TaxonNodeDto> treeNodes;
260 if(input==null){
261 treeNodes = new ArrayList<>();
262 }
263 else{
264 treeNodes = (Collection<TaxonNodeDto>) input;
265 }
266 treeNodes.add(taxonNodeDto);
267 taxonTreeViewer.setInput(treeNodes);
268 dirty.setDirty(true);
269 }
270
271 public void removeSelectedTaxonNodes(){
272 IStructuredSelection selection = (IStructuredSelection) composite.getTaxonNodeTree().getSelection();
273 if(selection.toList().stream().anyMatch(object->!(object instanceof TaxonNodeDto))){
274 MessagingUtils.warningDialog(Messages.DescriptiveDataSetEditor_DELETE_FAIL_TITLE, this.getClass(), Messages.DescriptiveDataSetEditor_DELETE_FAIL_MESSAGE);
275 return;
276 }
277 Iterator<Object> iterator = selection.iterator();
278 Viewer taxonTreeViewer = getTaxonTreeViewer();
279 Collection<TaxonNodeDto> input = (Collection<TaxonNodeDto>) taxonTreeViewer.getInput();
280 while(iterator.hasNext()){
281 Object next = iterator.next();
282 TaxonNodeDto taxonNode = (TaxonNodeDto) next;
283 input.remove(taxonNode);
284 TaxonNode node = CdmStore.getService(ITaxonNodeService.class).load(taxonNode.getUuid());
285 descriptiveDataSet.removeTaxonSubtree(node);
286 }
287 taxonTreeViewer.setInput(input);
288 dirty.setDirty(true);
289 }
290
291 @Persist
292 @Override
293 public void save(IProgressMonitor monitor) {
294
295 if (!conversation.isBound()) {
296 conversation.bind();
297
298 }
299 conversation.commit(true);
300 Collection<TermDto> areas = composite.getAreas();
301 Object input = composite.getTaxonNodeTree().getInput();
302 if(input!=null){
303 descriptiveDataSet.setTaxonSubtreeFilter(new HashSet<>());//clear existing filter
304 Collection<TaxonNodeDto> taxonNodes = (Collection<TaxonNodeDto>) input;
305 for (TaxonNodeDto taxonTreeNode : taxonNodes) {
306 TaxonNode taxonNode = CdmStore.getService(ITaxonNodeService.class).load(taxonTreeNode.getUuid());
307 descriptiveDataSet.addTaxonSubtree(taxonNode);
308 }
309 }
310 TermTree<Feature> characters = composite.getCharacters();
311 if(characters!=null){
312 //save characters because they can be modified in this editor
313 characters.getDistinctTerms().forEach(character->CdmStore.getService(ITermService.class).merge(character,true));
314 }
315
316
317 DefinedTermBase rankMaxSelection = composite.getRankMax().getSelection();
318 Rank rankMax = null;
319 if(rankMaxSelection instanceof Rank){
320 rankMax = (Rank) rankMaxSelection;
321 }
322 DefinedTermBase rankMinSelection = composite.getRankMin().getSelection();
323 Rank rankMin = null;
324 if(rankMinSelection instanceof Rank){
325 rankMin = (Rank) rankMinSelection;
326 }
327
328 descriptiveDataSet.setMaxRank(rankMax);
329 descriptiveDataSet.setMinRank(rankMin);
330 descriptiveDataSet.setDescriptiveSystem(characters);
331 List<DefinedTermBase> terms = CdmStore.getService(ITermService.class)
332 .load(areas.stream().map(area -> area.getUuid()).collect(Collectors.toList()), null);
333 Set<NamedArea> areaTerms = new HashSet<>();
334 terms.forEach(term->areaTerms.add((NamedArea) term));
335 descriptiveDataSet.setGeoFilter(areaTerms);
336
337 // conversation.commit();
338 CdmStore.getService(IDescriptiveDataSetService.class).merge(descriptiveDataSet, true);
339 //event for updating matrix
340 EventUtility.postEvent(WorkbenchEventConstants.REFRESH_DESCRIPTIVE_DATASET, descriptiveDataSet.getUuid());
341 dirty.setDirty(false);
342 }
343
344 @Override
345 public boolean isDirty() {
346 return dirty.isDirty();
347 }
348
349 @PreDestroy
350 public void dispose() {
351 if (conversation != null) {
352 conversation.close();
353 conversation = null;
354 }
355 if(cdmEntitySession != null) {
356 cdmEntitySession.dispose();
357 cdmEntitySession = null;
358 }
359 dirty.setDirty(false);
360 selectionService.setSelection(null);
361 }
362
363 @Focus
364 public void setFocus() {
365 if(composite!=null){
366 composite.setFocus();
367 }
368 if (getConversationHolder() != null) {
369 getConversationHolder().bind();
370 }
371 if(cdmEntitySession != null) {
372 cdmEntitySession.bind();
373 }
374 }
375
376 public Viewer getTaxonTreeViewer() {
377 return composite.getTaxonNodeTree();
378 }
379
380 public DescriptiveDataSet getDescriptiveDataSet() {
381 return descriptiveDataSet;
382 }
383
384 @Override
385 public void update(CdmDataChangeMap arg0) {
386 }
387
388 @Override
389 public ICdmEntitySession getCdmEntitySession() {
390 return cdmEntitySession;
391 }
392
393 @Override
394 public Collection<DescriptiveDataSet> getRootEntities() {
395 return Collections.singleton(descriptiveDataSet);
396 }
397
398 @Override
399 public Map<Object, List<String>> getPropertyPathsMap() {
400 return null;
401 }
402
403 @Override
404 public ConversationHolder getConversationHolder() {
405 return conversation;
406 }
407
408 @Override
409 public void changed(Object element) {
410 dirty.setDirty(true);
411 }
412
413 @Override
414 public void forceDirty() {
415 dirty.setDirty(true);
416 }
417
418 }