Project

General

Profile

Download (14.8 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.common.DefinedTermBase;
61
import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
62
import eu.etaxonomy.cdm.model.description.FeatureTree;
63
import eu.etaxonomy.cdm.model.location.NamedArea;
64
import eu.etaxonomy.cdm.model.name.Rank;
65
import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
66
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
67
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
68
import eu.etaxonomy.cdm.persistence.dto.TermDto;
69
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
70
import eu.etaxonomy.taxeditor.editor.l10n.Messages;
71
import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
72
import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
73
import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
74
import eu.etaxonomy.taxeditor.model.MessagingUtils;
75
import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
76
import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
77
import eu.etaxonomy.taxeditor.store.CdmStore;
78
import eu.etaxonomy.taxeditor.ui.element.CdmFormFactory;
79
import eu.etaxonomy.taxeditor.workbench.part.IE4SavablePart;
80

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

    
90
    private DescriptiveDataSetComposite composite;
91

    
92
    private ConversationHolder conversation;
93

    
94
    private ICdmEntitySession cdmEntitySession;
95

    
96
    private DescriptiveDataSet descriptiveDataSet;
97

    
98
    private final int dndOperations = DND.DROP_MOVE;
99

    
100
    @Inject
101
    private MDirtyable dirty;
102

    
103
    @Inject
104
    private ESelectionService selectionService;
105

    
106
    private ModifyListener labelModifyListener;
107

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

    
125
        composite = new DescriptiveDataSetComposite(parent, SWT.NONE);
126

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

    
153
        composite.getBtnChooseArea().addSelectionListener(new SelectionAdapter() {
154

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

    
168
        composite.getFeatureTreeEditorComposite().init("Character Tree", null, null, e->selectionService.setSelection(e.getSelection()), this, null);
169

    
170
        //add drag'n'drop support
171
        Transfer[] transfers = new Transfer[] {LocalSelectionTransfer.getTransfer()};
172
        composite.getTaxonNodeTree().addDropSupport(dndOperations, transfers, new TaxonNodeDropAdapter(this));
173

    
174
        composite.getTaxonNodeTree().getTree().addKeyListener(new KeyAdapter() {
175
            @Override
176
            public void keyPressed(KeyEvent e) {
177
                if(e.character==SWT.DEL){
178
                    removeSelectedTaxonNodes();
179
                }
180
            }
181
        });
182

    
183

    
184
        //create context menu
185
        menuService.registerContextMenu(composite.getTaxonNodeTree().getControl(), "eu.etaxonomy.taxeditor.editor.descriptiveDataSet.DescriptiveDataSetEditor.popupmenu.specimeneditor");
186

    
187
    }
188

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

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

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

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

    
290

    
291
        DefinedTermBase rankMaxSelection = composite.getRankMax().getSelection();
292
        Rank rankMax = null;
293
        if(rankMaxSelection instanceof Rank){
294
            rankMax = (Rank) rankMaxSelection;
295
        }
296
        DefinedTermBase rankMinSelection = composite.getRankMin().getSelection();
297
        Rank rankMin = null;
298
        if(rankMinSelection instanceof Rank){
299
            rankMin = (Rank) rankMinSelection;
300
        }
301

    
302
        descriptiveDataSet.setMaxRank(rankMax);
303
        descriptiveDataSet.setMinRank(rankMin);
304
        descriptiveDataSet.setDescriptiveSystem(characters);
305
        List<DefinedTermBase> terms = CdmStore.getService(ITermService.class)
306
                .load(areas.stream().map(area -> area.getUuid()).collect(Collectors.toList()), null);
307
        Set<NamedArea> areaTerms = new HashSet<>();
308
        terms.forEach(term->areaTerms.add((NamedArea) term));
309
        descriptiveDataSet.setGeoFilter(areaTerms);
310

    
311
        conversation.commit();
312
        CdmStore.getService(IDescriptiveDataSetService.class).merge(descriptiveDataSet, true);
313

    
314
        dirty.setDirty(false);
315
    }
316

    
317
    @Override
318
    public boolean isDirty() {
319
        return dirty.isDirty();
320
    }
321

    
322
    @PreDestroy
323
    public void dispose() {
324
        if (conversation != null) {
325
            conversation.close();
326
            conversation = null;
327
        }
328
        if(cdmEntitySession != null) {
329
            cdmEntitySession.dispose();
330
            cdmEntitySession = null;
331
        }
332
        dirty.setDirty(false);
333
    }
334

    
335
    @Focus
336
    public void setFocus() {
337
        if(composite!=null){
338
            composite.setFocus();
339
        }
340
        if (getConversationHolder() != null) {
341
            getConversationHolder().bind();
342
        }
343
        if(cdmEntitySession != null) {
344
            cdmEntitySession.bind();
345
        }
346
    }
347

    
348
    public Viewer getTaxonTreeViewer() {
349
        return composite.getTaxonNodeTree();
350
    }
351

    
352
    public DescriptiveDataSet getDescriptiveDataSet() {
353
        return descriptiveDataSet;
354
    }
355

    
356
    @Override
357
    public void update(CdmDataChangeMap arg0) {
358
    }
359

    
360
    @Override
361
    public ICdmEntitySession getCdmEntitySession() {
362
        return cdmEntitySession;
363
    }
364

    
365
    @Override
366
    public Collection<DescriptiveDataSet> getRootEntities() {
367
        return Collections.singleton(descriptiveDataSet);
368
    }
369

    
370
    @Override
371
    public Map<Object, List<String>> getPropertyPathsMap() {
372
        return null;
373
    }
374

    
375
    @Override
376
    public ConversationHolder getConversationHolder() {
377
        return conversation;
378
    }
379

    
380
    @Override
381
    public void changed(Object element) {
382
        dirty.setDirty(true);
383
    }
384

    
385
    @Override
386
    public void forceDirty() {
387
        dirty.setDirty(true);
388
    }
389

    
390
}
(3-3/5)