Project

General

Profile

Download (16.7 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.Arrays;
13
import java.util.Collection;
14
import java.util.Collections;
15
import java.util.HashSet;
16
import java.util.Iterator;
17
import java.util.List;
18
import java.util.Map;
19
import java.util.Set;
20
import java.util.UUID;
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.dialogs.Dialog;
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.StyledString.Styler;
41
import org.eclipse.jface.viewers.Viewer;
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.graphics.TextStyle;
53
import org.eclipse.swt.widgets.Composite;
54
import org.eclipse.swt.widgets.Control;
55
import org.eclipse.swt.widgets.Display;
56
import org.eclipse.swt.widgets.Shell;
57

    
58
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
59
import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
60
import eu.etaxonomy.cdm.api.service.IDescriptiveDataSetService;
61
import eu.etaxonomy.cdm.api.service.ITaxonNodeService;
62
import eu.etaxonomy.cdm.api.service.ITermService;
63
import eu.etaxonomy.cdm.api.service.IVocabularyService;
64
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
65
import eu.etaxonomy.cdm.model.common.TermType;
66
import eu.etaxonomy.cdm.model.common.TermVocabulary;
67
import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
68
import eu.etaxonomy.cdm.model.description.FeatureTree;
69
import eu.etaxonomy.cdm.model.location.NamedArea;
70
import eu.etaxonomy.cdm.model.name.Rank;
71
import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
72
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
73
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
74
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
75
import eu.etaxonomy.taxeditor.editor.l10n.Messages;
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.preference.wizard.AreaLabelProvider;
81
import eu.etaxonomy.taxeditor.preference.wizard.CheckBoxTreeComposite;
82
import eu.etaxonomy.taxeditor.preference.wizard.DistributionContentProvider;
83
import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
84
import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
85
import eu.etaxonomy.taxeditor.store.CdmStore;
86
import eu.etaxonomy.taxeditor.ui.element.CdmFormFactory;
87
import eu.etaxonomy.taxeditor.workbench.part.IE4SavablePart;
88

    
89
/**
90
 * Editor for configuring DescriptiveDataSets
91
 * @author pplitzner
92
 * @since Nov 21, 2017
93
 *
94
 */
95
public class DescriptiveDataSetEditor implements IE4SavablePart, IConversationEnabled, ICdmEntitySessionEnabled,
96
IPartContentHasDetails, IPartContentHasSupplementalData, IDirtyMarkable {
97

    
98
    private DescriptiveDataSetComposite composite;
99

    
100
    private ConversationHolder conversation;
101

    
102
    private ICdmEntitySession cdmEntitySession;
103

    
104
    private DescriptiveDataSet descriptiveDataSet;
105

    
106
    private final int dndOperations = DND.DROP_MOVE;
107

    
108
    @Inject
109
    private MDirtyable dirty;
110

    
111
    @Inject
112
    private ESelectionService selectionService;
113

    
114
    private ModifyListener labelModifyListener;
115

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

    
133
        composite = new DescriptiveDataSetComposite(parent, SWT.NONE);
134

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

    
161
        composite.getBtnChooseArea().addSelectionListener(new SelectionAdapter() {
162

    
163
            @Override
164
            public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
165
                AreasSelectionDialog areasSelectionDialog = new AreasSelectionDialog(composite.getShell(), composite.getAreas());
166
                areasSelectionDialog.open();
167
                Set<NamedArea> selectedAreas = areasSelectionDialog.getSelectedAreas();
168
                if(selectedAreas!=null){
169
                    composite.setAreas(selectedAreas);
170
                    dirty.setDirty(true);
171
                }
172
            }
173
        });
174
        composite.getBtnRemoveArea().addSelectionListener(new SelectionAdapter() {
175

    
176
            @Override
177
            public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
178
                composite.removeArea();
179
                dirty.setDirty(true);
180
            }
181
        });
182

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

    
185
        //add drag'n'drop support
186
        Transfer[] transfers = new Transfer[] {LocalSelectionTransfer.getTransfer()};
187
        composite.getTaxonNodeTree().addDropSupport(dndOperations, transfers, new TaxonNodeDropAdapter(this));
188

    
189
        composite.getTaxonNodeTree().getTree().addKeyListener(new KeyAdapter() {
190
            @Override
191
            public void keyPressed(KeyEvent e) {
192
                if(e.character==SWT.DEL){
193
                    removeSelectedTaxonNodes();
194
                }
195
            }
196
        });
197

    
198

    
199
        //create context menu
200
        menuService.registerContextMenu(composite.getTaxonNodeTree().getControl(), "eu.etaxonomy.taxeditor.editor.descriptiveDataSet.DescriptiveDataSetEditor.popupmenu.specimeneditor");
201

    
202
    }
203

    
204
    public void init(UUID descriptiveDataSetUuid) {
205
        this.descriptiveDataSet = cdmEntitySession.remoteLoad(CdmStore.getService(IDescriptiveDataSetService.class), descriptiveDataSetUuid);
206
        if(descriptiveDataSet.getLabel()!=null){
207
            composite.getTxt_label().setText(descriptiveDataSet.getLabel());
208
        }
209
        if(descriptiveDataSet.getDescriptiveSystem()!=null){
210
            composite.setCharacters(descriptiveDataSet.getDescriptiveSystem());
211
        }
212
        Rank maxRank = descriptiveDataSet.getMaxRank();
213
        if(maxRank!=null){
214
            composite.setRankMax(maxRank);
215
        }
216
        Rank minRank = descriptiveDataSet.getMinRank();
217
        if(minRank!=null){
218
            composite.setRankMin(minRank);
219
        }
220
        Set<NamedArea> geoFilter = descriptiveDataSet.getGeoFilter();
221
        if(geoFilter!=null && !geoFilter.isEmpty()){
222
            composite.setAreas(geoFilter);
223
        }
224
        Set<TaxonNode> taxonSubtreeFilter = descriptiveDataSet.getTaxonSubtreeFilter();
225
        if(taxonSubtreeFilter!=null){
226
            composite.getTaxonNodeTree().setInput(taxonSubtreeFilter);
227
        }
228
        composite.getTxt_label().addModifyListener(labelModifyListener);
229
        composite.getTxt_label().addFocusListener(new FocusAdapter() {
230
            @Override
231
            public void focusGained(FocusEvent e) {
232
                super.focusGained(e);
233
                selectionService.setSelection(new StructuredSelection(descriptiveDataSet));
234
            }
235
        });
236
        selectionService.setSelection(new StructuredSelection(descriptiveDataSet));
237
    }
238

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

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

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

    
304

    
305
        DefinedTermBase rankMaxSelection = composite.getRankMax().getSelection();
306
        Rank rankMax = null;
307
        if(rankMaxSelection instanceof Rank){
308
            rankMax = (Rank) rankMaxSelection;
309
        }
310
        DefinedTermBase rankMinSelection = composite.getRankMin().getSelection();
311
        Rank rankMin = null;
312
        if(rankMinSelection instanceof Rank){
313
            rankMin = (Rank) rankMinSelection;
314
        }
315

    
316
        descriptiveDataSet.setMaxRank(rankMax);
317
        descriptiveDataSet.setMinRank(rankMin);
318
        descriptiveDataSet.setDescriptiveSystem(characters);
319
        descriptiveDataSet.setGeoFilter(areas);
320

    
321
        conversation.commit();
322
        CdmStore.getService(IDescriptiveDataSetService.class).merge(descriptiveDataSet, true);
323

    
324
        dirty.setDirty(false);
325
    }
326

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

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

    
353
    public Viewer getTaxonTreeViewer() {
354
        return composite.getTaxonNodeTree();
355
    }
356

    
357
    public DescriptiveDataSet getDescriptiveDataSet() {
358
        return descriptiveDataSet;
359
    }
360

    
361
    @Override
362
    public void update(CdmDataChangeMap arg0) {
363
    }
364

    
365
    @Override
366
    public ICdmEntitySession getCdmEntitySession() {
367
        return cdmEntitySession;
368
    }
369

    
370
    @Override
371
    public Collection<DescriptiveDataSet> getRootEntities() {
372
        return Collections.singleton(descriptiveDataSet);
373
    }
374

    
375
    @Override
376
    public Map<Object, List<String>> getPropertyPathsMap() {
377
        return null;
378
    }
379

    
380
    @Override
381
    public ConversationHolder getConversationHolder() {
382
        return conversation;
383
    }
384

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

    
390
    @Override
391
    public void forceDirty() {
392
        dirty.setDirty(true);
393
    }
394

    
395
    private class AreasSelectionDialog extends Dialog{
396

    
397
        private CheckBoxTreeComposite treeComposite;
398

    
399
        private Set<NamedArea> selectedAreas = new HashSet<>();
400

    
401
        private Collection<TermVocabulary<NamedArea>> namedAreas;
402

    
403

    
404
        protected AreasSelectionDialog(Shell parentShell, Set<NamedArea> selectedAreas) {
405
            super(parentShell);
406
            this.selectedAreas = selectedAreas;
407
            this.namedAreas = CdmStore.getService(IVocabularyService.class).findByTermType(TermType.NamedArea, null);
408
        }
409

    
410
        @Override
411
        protected Control createDialogArea(Composite parent) {
412
            Styler styler = new Styler() {
413
                @Override
414
                public void applyStyles(TextStyle textStyle) {
415
                    textStyle.foreground = Display.getCurrent().getSystemColor(SWT.COLOR_BLACK);
416
                }
417
            };
418
            treeComposite = new CheckBoxTreeComposite(parent, new DistributionContentProvider(), new AreaLabelProvider(styler), SWT.NONE);
419
            treeComposite.getViewer().setInput(namedAreas);
420
            treeComposite.getViewer().setCheckedElements(selectedAreas.toArray());
421
            return treeComposite;
422
        }
423

    
424
        @Override
425
        protected void configureShell(Shell newShell) {
426
            super.configureShell(newShell);
427
            newShell.setText("Choose areas");
428
        }
429

    
430
        @Override
431
        protected void okPressed() {
432
            selectedAreas.clear();
433
            selectedAreas = new HashSet(Arrays.asList(treeComposite.getViewer().getCheckedElements()));
434
            super.okPressed();
435
        }
436

    
437
        @Override
438
        protected boolean isResizable() {
439
            return true;
440
        }
441

    
442
        public Set<NamedArea> getSelectedAreas(){
443
            return selectedAreas;
444
        }
445
    }
446
}
(2-2/4)