Project

General

Profile

Download (15 KB) Statistics
| Branch: | Tag: | Revision:
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.services.EMenuService;
34
import org.eclipse.e4.ui.services.IServiceConstants;
35
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
36
import org.eclipse.jface.util.LocalSelectionTransfer;
37
import org.eclipse.jface.viewers.IStructuredSelection;
38
import org.eclipse.jface.viewers.StructuredSelection;
39
import org.eclipse.jface.viewers.Viewer;
40
import org.eclipse.jface.window.Window;
41
import org.eclipse.swt.SWT;
42
import org.eclipse.swt.dnd.DND;
43
import org.eclipse.swt.dnd.Transfer;
44
import org.eclipse.swt.events.FocusAdapter;
45
import org.eclipse.swt.events.FocusEvent;
46
import org.eclipse.swt.events.KeyAdapter;
47
import org.eclipse.swt.events.KeyEvent;
48
import org.eclipse.swt.events.ModifyEvent;
49
import org.eclipse.swt.events.ModifyListener;
50
import org.eclipse.swt.events.SelectionAdapter;
51
import org.eclipse.swt.widgets.Composite;
52
import org.eclipse.swt.widgets.Display;
53
import org.eclipse.swt.widgets.Shell;
54

    
55
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
56
import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
57
import eu.etaxonomy.cdm.api.service.IDescriptiveDataSetService;
58
import eu.etaxonomy.cdm.api.service.ITaxonNodeService;
59
import eu.etaxonomy.cdm.api.service.ITermService;
60
import eu.etaxonomy.cdm.model.description.Character;
61
import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
62
import eu.etaxonomy.cdm.model.location.NamedArea;
63
import eu.etaxonomy.cdm.model.name.Rank;
64
import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
65
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
66
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
67
import eu.etaxonomy.cdm.model.term.FeatureTree;
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.l10n.Messages;
73
import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
74
import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
75
import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
76
import eu.etaxonomy.taxeditor.model.MessagingUtils;
77
import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
78
import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
79
import eu.etaxonomy.taxeditor.store.CdmStore;
80
import eu.etaxonomy.taxeditor.ui.element.CdmFormFactory;
81
import eu.etaxonomy.taxeditor.workbench.part.IE4SavablePart;
82

    
83
/**
84
 * Editor for configuring DescriptiveDataSets
85
 * @author pplitzner
86
 * @since Nov 21, 2017
87
 *
88
 */
89
public class DescriptiveDataSetEditor implements IE4SavablePart, IConversationEnabled, ICdmEntitySessionEnabled,
90
IPartContentHasDetails, IPartContentHasSupplementalData, IDirtyMarkable {
91

    
92
    private DescriptiveDataSetComposite composite;
93

    
94
    private ConversationHolder conversation;
95

    
96
    private ICdmEntitySession cdmEntitySession;
97

    
98
    private DescriptiveDataSet descriptiveDataSet;
99

    
100
    private final int dndOperations = DND.DROP_MOVE;
101

    
102
    @Inject
103
    private MDirtyable dirty;
104

    
105
    @Inject
106
    private ESelectionService selectionService;
107

    
108
    private ModifyListener labelModifyListener;
109

    
110
    @PostConstruct
111
    public void create(Composite parent, IEclipseContext context, @Named(IServiceConstants.ACTIVE_SHELL)Shell shell,
112
            EMenuService menuService){
113
        if (CdmStore.isActive()){
114
            if(conversation == null){
115
                conversation = CdmStore.createConversation();
116
            }
117
            if(cdmEntitySession == null){
118
                cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
119
            }
120
        }
121
        else{
122
            return;
123
        }
124
        CdmFormFactory cdmFormFactory = new CdmFormFactory(Display.getCurrent());
125
        ContextInjectionFactory.inject(cdmFormFactory, context);
126

    
127
        composite = new DescriptiveDataSetComposite(parent, SWT.NONE);
128

    
129
        labelModifyListener = new ModifyListener() {
130
            @Override
131
            public void modifyText(ModifyEvent e) {
132
                descriptiveDataSet.setLabel(composite.getTxt_label().getText());
133
                dirty.setDirty(true);
134
            }
135
        };
136
        composite.getRankMin().addSelectionChangedListener(event->dirty.setDirty(true));
137
        composite.getRankMin().setText("Select min rank...");
138
        composite.getRankMax().addSelectionChangedListener(event->dirty.setDirty(true));
139
        composite.getRankMax().setText("Select max rank...");
140
        composite.getBtnRemoveRankMin().addSelectionListener(new SelectionAdapter() {
141
            @Override
142
            public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
143
             composite.getRankMin().setElement(null);
144
             dirty.setDirty(true);
145
            }
146
        });
147
        composite.getBtnRemoveRankMax().addSelectionListener(new SelectionAdapter() {
148
            @Override
149
            public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
150
                composite.getRankMax().setElement(null);
151
                dirty.setDirty(true);
152
            }
153
        });
154

    
155
        composite.getBtnChooseArea().addSelectionListener(new SelectionAdapter() {
156

    
157
            @Override
158
            public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
159
                AreasSelectionDialog areasSelectionDialog = new AreasSelectionDialog(composite.getShell(), composite.getAreas());
160
                if(areasSelectionDialog.open()==Window.OK){
161
                    List<TermDto> selectedAreas = areasSelectionDialog.getSelectedAreas();
162
                    if(selectedAreas!=null){
163
                        composite.setAreas(selectedAreas);
164
                        dirty.setDirty(true);
165
                    }
166
                }
167
            }
168
        });
169

    
170
        composite.getFeatureTreeEditorComposite().init("Character Tree",
171
                TermType.Character,
172
                null,
173
                null,
174
                e->selectionService.setSelection(e.getSelection()),
175
                this,
176
                null);
177

    
178
        //add drag'n'drop support
179
        Transfer[] transfers = new Transfer[] {LocalSelectionTransfer.getTransfer()};
180
        composite.getTaxonNodeTree().addDropSupport(dndOperations, transfers, new TaxonNodeDropAdapter(this));
181

    
182
        composite.getTaxonNodeTree().getTree().addKeyListener(new KeyAdapter() {
183
            @Override
184
            public void keyPressed(KeyEvent e) {
185
                if(e.character==SWT.DEL){
186
                    removeSelectedTaxonNodes();
187
                }
188
            }
189
        });
190

    
191

    
192
        //create context menu
193
        menuService.registerContextMenu(composite.getTaxonNodeTree().getControl(), "eu.etaxonomy.taxeditor.editor.descriptiveDataSet.DescriptiveDataSetEditor.popupmenu.specimeneditor");
194

    
195
    }
196

    
197
    public void init(UUID descriptiveDataSetUuid) {
198
        this.descriptiveDataSet = cdmEntitySession.remoteLoad(CdmStore.getService(IDescriptiveDataSetService.class), descriptiveDataSetUuid);
199
        if(descriptiveDataSet.getLabel()!=null){
200
            composite.getTxt_label().setText(descriptiveDataSet.getLabel());
201
        }
202
        if(descriptiveDataSet.getDescriptiveSystem()!=null){
203
            composite.setCharacters(descriptiveDataSet.getDescriptiveSystem());
204
        }
205
        Rank maxRank = descriptiveDataSet.getMaxRank();
206
        if(maxRank!=null){
207
            composite.setRankMax(maxRank);
208
        }
209
        Rank minRank = descriptiveDataSet.getMinRank();
210
        if(minRank!=null){
211
            composite.setRankMin(minRank);
212
        }
213
        Set<NamedArea> geoFilter = descriptiveDataSet.getGeoFilter();
214
        if(geoFilter!=null && !geoFilter.isEmpty()){
215
            Set<TermDto> terms = geoFilter.stream().map(filter->TermDto.fromTerm(filter, true)).collect(Collectors.toSet());
216
            composite.setAreas(new ArrayList<>(terms));
217
        }
218
        Set<TaxonNode> taxonSubtreeFilter = descriptiveDataSet.getTaxonSubtreeFilter();
219
        if(taxonSubtreeFilter!=null){
220
            composite.getTaxonNodeTree().setInput(taxonSubtreeFilter);
221
        }
222
        composite.getTxt_label().addModifyListener(labelModifyListener);
223
        composite.getTxt_label().addFocusListener(new FocusAdapter() {
224
            @Override
225
            public void focusGained(FocusEvent e) {
226
                super.focusGained(e);
227
                selectionService.setSelection(new StructuredSelection(descriptiveDataSet));
228
            }
229
        });
230
        selectionService.setSelection(new StructuredSelection(descriptiveDataSet));
231
    }
232

    
233
    public void addTaxonNode(TaxonNodeDto taxonNodeDto){
234
        TaxonNode taxonNode = cdmEntitySession.remoteLoad(CdmStore.getService(ITaxonNodeService.class), taxonNodeDto.getUuid());
235
        //check if node belongs to same classification
236
        Set<TaxonNode> taxonSubtreeFilter = descriptiveDataSet.getTaxonSubtreeFilter();
237
        if(taxonSubtreeFilter!=null && !taxonSubtreeFilter.isEmpty()){
238
            if(!taxonSubtreeFilter.iterator().next().getClassification().equals(taxonNode.getClassification())){
239
                MessagingUtils.warningDialog(Messages.TaxonNodeDropAdapter_CLASSIFICATIONS_NO_MATCH, this.getClass(),
240
                        Messages.TaxonNodeDropAdapter_CLASSIFICATIONS_NO_MATCH_MESSAGE);
241
                return;
242
            }
243
        }
244
        Viewer taxonTreeViewer = getTaxonTreeViewer();
245
        Object input = taxonTreeViewer.getInput();
246
        Collection<TaxonNode> treeNodes;
247
        if(input==null){
248
            treeNodes = new ArrayList<>();
249
        }
250
        else{
251
            treeNodes = (Collection<TaxonNode>) input;
252
        }
253
        treeNodes.add(taxonNode);
254
        taxonTreeViewer.setInput(treeNodes);
255
        dirty.setDirty(true);
256
    }
257

    
258
    public void removeSelectedTaxonNodes(){
259
        IStructuredSelection selection = (IStructuredSelection) composite.getTaxonNodeTree().getSelection();
260
        if(selection.toList().stream().anyMatch(object->!(object instanceof TaxonNode))){
261
            MessagingUtils.warningDialog(Messages.DescriptiveDataSetEditor_DELETE_FAIL_TITLE, this.getClass(), Messages.DescriptiveDataSetEditor_DELETE_FAIL_MESSAGE);
262
            return;
263
        }
264
        Iterator<Object> iterator = selection.iterator();
265
        Viewer taxonTreeViewer = getTaxonTreeViewer();
266
        Collection<TaxonNode> input = (Collection<TaxonNode>) taxonTreeViewer.getInput();
267
        while(iterator.hasNext()){
268
            Object next = iterator.next();
269
            TaxonNode taxonNode = (TaxonNode) next;
270
            input.remove(taxonNode);
271
            descriptiveDataSet.removeTaxonSubtree(taxonNode);
272
        }
273
        taxonTreeViewer.setInput(input);
274
        dirty.setDirty(true);
275
    }
276

    
277
    @Persist
278
    @Override
279
    public void save(IProgressMonitor monitor) {
280
        Collection<TermDto> areas = composite.getAreas();
281
        Object input = composite.getTaxonNodeTree().getInput();
282
        if(input!=null){
283
            descriptiveDataSet.setTaxonSubtreeFilter(new HashSet<>());//clear existing filter
284
            Collection<ITaxonTreeNode> taxonNodes = (Collection<ITaxonTreeNode>) input;
285
            for (ITaxonTreeNode taxonTreeNode : taxonNodes) {
286
                if(taxonTreeNode instanceof TaxonNode){
287
                    TaxonNode taxonNode = (TaxonNode)taxonTreeNode;
288
                    descriptiveDataSet.addTaxonSubtree(taxonNode);
289
                }
290
            }
291
        }
292
        FeatureTree<Character> characters = composite.getCharacters();
293
        if(characters!=null){
294
            //save characters because they can be modified in this editor
295
            characters.getDistinctFeatures().forEach(character->CdmStore.getService(ITermService.class).merge(character,true));
296
        }
297

    
298

    
299
        DefinedTermBase rankMaxSelection = composite.getRankMax().getSelection();
300
        Rank rankMax = null;
301
        if(rankMaxSelection instanceof Rank){
302
            rankMax = (Rank) rankMaxSelection;
303
        }
304
        DefinedTermBase rankMinSelection = composite.getRankMin().getSelection();
305
        Rank rankMin = null;
306
        if(rankMinSelection instanceof Rank){
307
            rankMin = (Rank) rankMinSelection;
308
        }
309

    
310
        descriptiveDataSet.setMaxRank(rankMax);
311
        descriptiveDataSet.setMinRank(rankMin);
312
        descriptiveDataSet.setDescriptiveSystem(characters);
313
        List<DefinedTermBase> terms = CdmStore.getService(ITermService.class)
314
                .load(areas.stream().map(area -> area.getUuid()).collect(Collectors.toList()), null);
315
        Set<NamedArea> areaTerms = new HashSet<>();
316
        terms.forEach(term->areaTerms.add((NamedArea) term));
317
        descriptiveDataSet.setGeoFilter(areaTerms);
318

    
319
        conversation.commit();
320
        CdmStore.getService(IDescriptiveDataSetService.class).merge(descriptiveDataSet, true);
321

    
322
        dirty.setDirty(false);
323
    }
324

    
325
    @Override
326
    public boolean isDirty() {
327
        return dirty.isDirty();
328
    }
329

    
330
    @PreDestroy
331
    public void dispose() {
332
        if (conversation != null) {
333
            conversation.close();
334
            conversation = null;
335
        }
336
        if(cdmEntitySession != null) {
337
            cdmEntitySession.dispose();
338
            cdmEntitySession = null;
339
        }
340
        dirty.setDirty(false);
341
    }
342

    
343
    @Focus
344
    public void setFocus() {
345
        if(composite!=null){
346
            composite.setFocus();
347
        }
348
        if (getConversationHolder() != null) {
349
            getConversationHolder().bind();
350
        }
351
        if(cdmEntitySession != null) {
352
            cdmEntitySession.bind();
353
        }
354
    }
355

    
356
    public Viewer getTaxonTreeViewer() {
357
        return composite.getTaxonNodeTree();
358
    }
359

    
360
    public DescriptiveDataSet getDescriptiveDataSet() {
361
        return descriptiveDataSet;
362
    }
363

    
364
    @Override
365
    public void update(CdmDataChangeMap arg0) {
366
    }
367

    
368
    @Override
369
    public ICdmEntitySession getCdmEntitySession() {
370
        return cdmEntitySession;
371
    }
372

    
373
    @Override
374
    public Collection<DescriptiveDataSet> getRootEntities() {
375
        return Collections.singleton(descriptiveDataSet);
376
    }
377

    
378
    @Override
379
    public Map<Object, List<String>> getPropertyPathsMap() {
380
        return null;
381
    }
382

    
383
    @Override
384
    public ConversationHolder getConversationHolder() {
385
        return conversation;
386
    }
387

    
388
    @Override
389
    public void changed(Object element) {
390
        dirty.setDirty(true);
391
    }
392

    
393
    @Override
394
    public void forceDirty() {
395
        dirty.setDirty(true);
396
    }
397

    
398
}
(3-3/5)