Project

General

Profile

Download (16 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.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
}
(3-3/5)