Project

General

Profile

Download (20.4 KB) Statistics
| Branch: | Tag: | Revision:
1
// $Id$
2
/**
3
* Copyright (C) 2017 EDIT
4
* European Distributed Institute of Taxonomy
5
* http://www.e-taxonomy.eu
6
*
7
* The contents of this file are subject to the Mozilla Public License Version 1.1
8
* See LICENSE.TXT at the top of this package for the full license terms.
9
*/
10
package eu.etaxonomy.taxeditor.editor.descriptiveDataSet.character;
11

    
12
import java.util.ArrayList;
13
import java.util.Arrays;
14
import java.util.Collection;
15
import java.util.HashMap;
16
import java.util.HashSet;
17
import java.util.Iterator;
18
import java.util.List;
19
import java.util.Map;
20
import java.util.Set;
21

    
22
import javax.annotation.PostConstruct;
23
import javax.annotation.PreDestroy;
24
import javax.inject.Inject;
25

    
26
import org.eclipse.core.runtime.IProgressMonitor;
27
import org.eclipse.e4.ui.di.Focus;
28
import org.eclipse.e4.ui.di.Persist;
29
import org.eclipse.e4.ui.di.UISynchronize;
30
import org.eclipse.e4.ui.model.application.ui.MDirtyable;
31
import org.eclipse.e4.ui.services.EMenuService;
32
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
33
import org.eclipse.jface.viewers.ISelection;
34
import org.eclipse.jface.viewers.ISelectionChangedListener;
35
import org.eclipse.jface.viewers.IStructuredSelection;
36
import org.eclipse.jface.viewers.SelectionChangedEvent;
37
import org.eclipse.jface.viewers.StructuredSelection;
38
import org.eclipse.jface.viewers.TreeSelection;
39
import org.eclipse.jface.viewers.TreeViewer;
40
import org.eclipse.swt.SWT;
41
import org.eclipse.swt.custom.SashForm;
42
import org.eclipse.swt.dnd.DND;
43
import org.eclipse.swt.dnd.Transfer;
44
import org.eclipse.swt.events.ModifyEvent;
45
import org.eclipse.swt.events.ModifyListener;
46
import org.eclipse.swt.events.SelectionAdapter;
47
import org.eclipse.swt.events.SelectionEvent;
48
import org.eclipse.swt.layout.GridData;
49
import org.eclipse.swt.layout.GridLayout;
50
import org.eclipse.swt.widgets.Button;
51
import org.eclipse.swt.widgets.Composite;
52
import org.eclipse.swt.widgets.Display;
53
import org.eclipse.swt.widgets.Label;
54
import org.eclipse.swt.widgets.Text;
55
import org.eclipse.ui.forms.widgets.FormToolkit;
56

    
57
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
58
import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
59
import eu.etaxonomy.cdm.api.service.IFeatureNodeService;
60
import eu.etaxonomy.cdm.api.service.ITermTreeService;
61
import eu.etaxonomy.cdm.api.service.IVocabularyService;
62
import eu.etaxonomy.cdm.api.service.UpdateResult;
63
import eu.etaxonomy.cdm.model.description.Character;
64
import eu.etaxonomy.cdm.model.description.Feature;
65
import eu.etaxonomy.cdm.model.term.DefinedTerm;
66
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
67
import eu.etaxonomy.cdm.model.term.TermNode;
68
import eu.etaxonomy.cdm.model.term.TermTree;
69
import eu.etaxonomy.cdm.model.term.TermType;
70
import eu.etaxonomy.cdm.model.term.TermVocabulary;
71
import eu.etaxonomy.cdm.model.term.VocabularyEnum;
72
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
73
import eu.etaxonomy.taxeditor.editor.AppModelId;
74
import eu.etaxonomy.taxeditor.editor.definedterm.FeatureTreeViewerComparator;
75
import eu.etaxonomy.taxeditor.editor.l10n.Messages;
76
import eu.etaxonomy.taxeditor.featuretree.CharacterTransfer;
77
import eu.etaxonomy.taxeditor.featuretree.FeatureNodeTransfer;
78
import eu.etaxonomy.taxeditor.featuretree.FeatureTreeContentProvider;
79
import eu.etaxonomy.taxeditor.featuretree.FeatureTreeLabelProvider;
80
import eu.etaxonomy.taxeditor.featuretree.e4.AbstractTermTreeEditor;
81
import eu.etaxonomy.taxeditor.featuretree.e4.FeatureNodeDragListener;
82
import eu.etaxonomy.taxeditor.featuretree.e4.FeatureTreeDropAdapter;
83
import eu.etaxonomy.taxeditor.featuretree.e4.FeatureTreeEditorComposite;
84
import eu.etaxonomy.taxeditor.featuretree.e4.IFeatureTreeEditor;
85
import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
86
import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
87
import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
88
import eu.etaxonomy.taxeditor.model.ImageResources;
89
import eu.etaxonomy.taxeditor.model.MessagingUtils;
90
import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
91
import eu.etaxonomy.taxeditor.store.CdmStore;
92
import eu.etaxonomy.taxeditor.ui.dialog.selection.FeatureTreeSelectionDialog;
93
import eu.etaxonomy.taxeditor.ui.dialog.selection.TermVocabularySelectionDialog;
94
import eu.etaxonomy.taxeditor.workbench.part.IE4ViewerPart;
95

    
96
/**
97
 * Editor for combining structure and property terms to characters.
98
 * @author pplitzner
99
 * @date 24.05.2017
100
 *
101
 */
102
public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled, ISelectionChangedListener,
103
        ModifyListener, IE4ViewerPart, IPartContentHasDetails, IPartContentHasSupplementalData, IDirtyMarkable {
104

    
105
    private FeatureTreeEditorComposite<Character> characterTreeEditorComposite;
106
    private final FormToolkit formToolkit = new FormToolkit(Display.getDefault());
107

    
108
    @Inject
109
    private ESelectionService selService;
110

    
111
    @Inject
112
    private UISynchronize sync;
113

    
114
    @Inject
115
    private MDirtyable dirty;
116

    
117
    private ConversationHolder conversation;
118

    
119
    private ICdmEntitySession cdmEntitySession;
120

    
121
    private TermVocabulary vocabulary;
122
    private TreeViewer structureViewer;
123
    private TreeViewer propertyViewer;
124

    
125
    public CharacterEditor() {
126
    }
127

    
128
    /**
129
     * Create contents of the view part.
130
     */
131
    @PostConstruct
132
    public void createControls(Composite parent, EMenuService menuService ) {
133
        if (CdmStore.isActive()){
134
            if(conversation == null){
135
                conversation = CdmStore.createConversation();
136
            }
137
            if(cdmEntitySession==null){
138
                cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
139
            }
140
        }
141
        else{
142
            return;
143
        }
144
        parent.setLayout(new GridLayout(1, false));
145

    
146
        Composite vocChooserComposite = new Composite(parent, SWT.NONE);
147
        vocChooserComposite.setLayout(new GridLayout(4, false));
148
        vocChooserComposite.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, false, false, 2, 1));
149
        Label lblVocImport = new Label(vocChooserComposite, SWT.NONE);
150
        lblVocImport.setText("Character vocabulary");
151
        Text txtVocabulary = new Text(vocChooserComposite, SWT.NONE);
152
        txtVocabulary.setEditable(false);
153
        Button btnChooseVoc = new Button(vocChooserComposite, SWT.PUSH);
154
        btnChooseVoc.setImage(ImageResources.getImage(ImageResources.BROWSE_ICON));
155
        btnChooseVoc.addSelectionListener(new SelectionAdapter() {
156

    
157
            @Override
158
            public void widgetSelected(SelectionEvent e) {
159
                // hard-coded filter for "built-in" vocabularies Feature and Name Feature
160
                Set<TermVocabulary> vocabulariesToBeFiltered = new HashSet<>();
161
                vocabulariesToBeFiltered.add(CdmStore.getService(IVocabularyService.class).load(VocabularyEnum.Feature.getUuid()));
162
                vocabulariesToBeFiltered.add(CdmStore.getService(IVocabularyService.class).load(VocabularyEnum.NameFeature.getUuid()));
163
                if(vocabulary!=null){
164
                    vocabulariesToBeFiltered.add(vocabulary);
165
                }
166
                vocabulary = TermVocabularySelectionDialog.select("Select vocabulary for characters", btnChooseVoc.getShell(), vocabulariesToBeFiltered, TermType.Character);
167
                if(vocabulary!=null){
168
                    txtVocabulary.setText(vocabulary.getLabel());
169
                }
170
            }
171
        });
172

    
173
        SashForm sashForm = new SashForm(parent, SWT.NONE);
174
        sashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
175
        formToolkit.adapt(sashForm);
176
        formToolkit.paintBordersFor(sashForm);
177

    
178
        Composite composite = new Composite(sashForm, SWT.NONE);
179
        formToolkit.adapt(composite);
180
        formToolkit.paintBordersFor(composite);
181
        GridLayout gl_composite = new GridLayout(1, false);
182
        gl_composite.marginWidth = 0;
183
        composite.setLayout(gl_composite);
184

    
185
        structureViewer = createTreeViewer(composite, TermType.Structure);
186

    
187
        Composite composite_1 = new Composite(sashForm, SWT.NONE);
188
        formToolkit.adapt(composite_1);
189
        formToolkit.paintBordersFor(composite_1);
190
        GridLayout gl_composite_1 = new GridLayout(1, false);
191
        gl_composite_1.marginWidth = 0;
192
        composite_1.setLayout(gl_composite_1);
193

    
194
        propertyViewer = createTreeViewer(composite_1, TermType.Property);
195

    
196
        int ops = DND.DROP_COPY | DND.DROP_MOVE;
197
        Transfer[] transfers = new Transfer[] {CharacterTransfer.getInstance()};
198
        propertyViewer.addDragSupport(ops, transfers, new CharacterDragListener(structureViewer, propertyViewer));
199

    
200
        Composite composite_3 = new Composite(sashForm, SWT.NONE);
201
        formToolkit.adapt(composite_3);
202
        formToolkit.paintBordersFor(composite_3);
203
        GridLayout gl_composite_3 = new GridLayout(2, false);
204
        gl_composite_3.marginWidth = 0;
205
        composite_3.setLayout(gl_composite_3);
206

    
207
        Button btnAddCharacter = new Button(composite_3, SWT.NONE);
208
        btnAddCharacter.setText(">>"); //$NON-NLS-1$
209
        formToolkit.adapt(btnAddCharacter, true, true);
210
        btnAddCharacter.addSelectionListener(new SelectionAdapter() {
211
            @Override
212
            public void widgetSelected(SelectionEvent e) {
213
                if(!isVocabularySet()){
214
                    return;
215
                }
216
                ISelection structureTreeSelection = structureViewer.getSelection();
217
                ISelection propertyTreeSelection = propertyViewer.getSelection();
218
                if(structureTreeSelection==null || propertyTreeSelection==null || characterTreeEditorComposite.getFeatureTree()==null){
219
                    MessagingUtils.warningDialog(Messages.CharacterEditor_CANNOT_PERFORM_TITLE, CharacterEditor.this,
220
                            Messages.CharacterEditor_CANNOT_PERFORM_MESSAGE);
221
                    return;
222
                }
223
                Collection<Character> characters = createCharacters((TreeSelection)structureTreeSelection, (TreeSelection)propertyTreeSelection);
224
                TermNode<Character> parent = ((TermTree<Character>) characterTreeEditorComposite.getViewer().getInput()).getRoot();
225
                for (Character character : characters) {
226
                    //add new Character to feature tree
227
                    UpdateResult result = CdmStore.getService(IFeatureNodeService.class).createChildFeatureNode(parent.getUuid(), character, vocabulary.getUuid());
228
                    cdmEntitySession.load(result, true);
229
                }
230
                refresh();
231
            }
232
        });
233

    
234
        characterTreeEditorComposite = addFeatureTreeEditor(composite_3);
235
        initFeatureTreeComposite(TermType.Character, characterTreeEditorComposite, new FeatureNodeDragListener(characterTreeEditorComposite.getViewer()),
236
                new CharacterDropAdapter(this, characterTreeEditorComposite.getViewer(), sync),
237

    
238
                new Transfer[] {FeatureNodeTransfer.getInstance(), CharacterTransfer.getInstance()},
239
                this,
240
                this);
241

    
242
        characterTreeEditorComposite.getLabel_title().setText(Messages.CharacterEditor_CHARACTERS);
243

    
244
        //add context menu to character viewer
245
        menuService.registerContextMenu(characterTreeEditorComposite.getViewer().getControl(),
246
                AppModelId.POPUPMENU_EU_ETAXONOMY_TAXEDITOR_EDITOR_POPUPMENU_CHARACTEREDITOR);
247

    
248
    }
249

    
250
    private TreeViewer createTreeViewer(Composite parent, TermType termType) {
251
        Composite composite = new Composite(parent, SWT.NONE);
252
        composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
253
        composite.setLayout(new GridLayout(2, false));
254
        Label label = new Label(composite, SWT.NONE);
255
        label.setText(termType.getMessage());
256
        Button btnRefresh = new Button(composite, SWT.PUSH);
257
        btnRefresh.setImage(ImageResources.getImage(ImageResources.REFRESH));
258
        btnRefresh.setToolTipText("Refresh");
259

    
260

    
261
        TreeViewer viewer = new TreeViewer(composite);
262
        viewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
263
        viewer.setContentProvider(new FeatureTreeContentProvider());
264
        viewer.setLabelProvider(new FeatureTreeLabelProvider());
265
        viewer.setComparator(new FeatureTreeViewerComparator());
266
        viewer.addSelectionChangedListener(this);
267
        viewer.setInput(CdmStore.getService(ITermTreeService.class).list(termType, null, null, null, AbstractTermTreeEditor.TREE_PROPERTY_PATH));
268
        btnRefresh.addSelectionListener(new SelectionAdapter() {
269

    
270
            @Override
271
            public void widgetSelected(SelectionEvent e) {
272
                refresh(viewer);
273
            }
274
        });
275
        return viewer;
276
    }
277

    
278
    private <T extends DefinedTermBase> FeatureTreeEditorComposite<T> addFeatureTreeEditor(Composite composite_3) {
279
        FeatureTreeEditorComposite<T> featureTreeEditorComposite = new FeatureTreeEditorComposite<>(composite_3, SWT.NONE);
280
        featureTreeEditorComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
281
        return featureTreeEditorComposite;
282
    }
283

    
284
    private void initFeatureTreeComposite(
285
            TermType termType,
286
            FeatureTreeEditorComposite featureTreeEditorComposite,
287
            FeatureNodeDragListener featureNodeDragListener,
288
            FeatureTreeDropAdapter featureNodeDropAdapter,
289
            Transfer[] transfers,
290
            ISelectionChangedListener viewerSelectionChangedListener,
291
            ModifyListener modifyListener) {
292

    
293
        featureTreeEditorComposite.init(
294
                featureNodeDragListener,
295
                featureNodeDropAdapter,
296
                transfers,
297
                viewerSelectionChangedListener,
298
                new FeatureTreeChooserListener(featureTreeEditorComposite, termType),
299
                modifyListener);
300
    }
301

    
302
    @Focus
303
    public void focus(){
304
        if(characterTreeEditorComposite!=null){
305
            characterTreeEditorComposite.getViewer().getControl().setFocus();
306
        }
307
        if(conversation!=null && !conversation.isBound()){
308
            conversation.bind();
309
        }
310
        if(cdmEntitySession != null) {
311
            cdmEntitySession.bind();
312
        }
313
    }
314

    
315
    public static Collection<Character> createCharacters(TreeSelection structureTreeSelection, TreeSelection propertyTreeSelection){
316
        Set<Character> characters = new HashSet<>();
317
        //get selected structures and properties
318
        Iterator<TermNode<DefinedTerm>> structureIterator = structureTreeSelection.iterator();
319

    
320
        //create all combinations of structures and properties
321
        while(structureIterator.hasNext()){
322
            TermNode<DefinedTerm> structureNode = structureIterator.next();
323
            Iterator<TermNode<DefinedTerm>> propertiesIterator = propertyTreeSelection.iterator();
324
            while(propertiesIterator.hasNext()){
325
                TermNode<DefinedTerm> propertyNode = propertiesIterator.next();
326
                Character character = CharacterTransfer.createCharacter(structureNode, propertyNode);
327
                characters.add(character);
328

    
329
            }
330
        }
331
        return characters;
332
    }
333

    
334
    @Override
335
    @Persist
336
    public void save(IProgressMonitor monitor){
337
        if (!conversation.isBound()) {
338
            conversation.bind();
339
        }
340

    
341
        TermTree<Character> featureTree = characterTreeEditorComposite.getFeatureTree();
342

    
343
        CdmStore.getService(ITermTreeService.class).merge(featureTree, true);
344

    
345
        // commit the conversation and start a new transaction immediately
346
        conversation.commit(true);
347

    
348
        initializeTrees();
349

    
350
        dirty.setDirty(false);
351
    }
352

    
353
    private void initializeTrees() {
354
        Object[] expandedElements = characterTreeEditorComposite.getViewer().getExpandedElements();
355
        characterTreeEditorComposite.getViewer().getTree().removeAll();
356
        TermTree tree = (TermTree) characterTreeEditorComposite.getViewer().getInput();
357
        cdmEntitySession.load(tree, true);
358
        characterTreeEditorComposite.getViewer().setInput(tree);
359
        characterTreeEditorComposite.getViewer().setExpandedElements(expandedElements);
360
    }
361

    
362
    @Override
363
    public boolean isDirty() {
364
        return dirty.isDirty();
365
    }
366

    
367
    @PreDestroy
368
    public void dispose(){
369
        if(conversation!=null){
370
            conversation.close();
371
            conversation = null;
372
        }
373
        if(cdmEntitySession != null) {
374
            cdmEntitySession.dispose();
375
            cdmEntitySession = null;
376
        }
377
        dirty.setDirty(false);
378
    }
379

    
380
    public boolean isVocabularySet() {
381
        if(vocabulary==null){
382
            MessagingUtils.warningDialog("Character creation not possible", this.getClass(), "Please select a vocabulary for the characters.");
383
        }
384
        return vocabulary!=null;
385
    }
386

    
387
    public TermVocabulary getVocabulary() {
388
        return vocabulary;
389
    }
390

    
391
    @Override
392
    public Map<Object, List<String>> getPropertyPathsMap() {
393
        List<String> propertyPaths = Arrays.asList(new String[] {
394
                "children", //$NON-NLS-1$
395
                "feature", //$NON-NLS-1$
396
                "featureTree", //$NON-NLS-1$
397
        });
398
        Map<Object, List<String>> propertyPathMap =
399
                new HashMap<Object, List<String>>();
400
        propertyPathMap.put(TermNode.class,propertyPaths);
401
        return propertyPathMap;
402
    }
403

    
404
    @Override
405
    public List<TermTree<Character>> getRootEntities() {
406
        List<TermTree<Character>> root = new ArrayList<>();
407
        cdmEntitySession.load(characterTreeEditorComposite.getFeatureTree(), true);
408
        root.add(characterTreeEditorComposite.getFeatureTree());
409
        return root;
410
    }
411

    
412
    @Override
413
    public ICdmEntitySession getCdmEntitySession() {
414
        return cdmEntitySession;
415
    }
416

    
417
    @Focus
418
    public void setFocus() {
419
        if(conversation!=null && !conversation.isBound()){
420
            conversation.bind();
421
        }
422
    }
423

    
424
    @Override
425
    public void selectionChanged(SelectionChangedEvent event) {
426
        //propagate selection
427
        selService.setSelection(event.getSelection());
428
    }
429

    
430

    
431
    @Override
432
    public void modifyText(ModifyEvent e) {
433
        characterTreeEditorComposite.getFeatureTree().setTitleCache(((Text) e.widget).getText(), true);
434
        setDirty();
435
    }
436

    
437

    
438
    private void setDirty() {
439
        dirty.setDirty(true);
440
    }
441

    
442
    @Override
443
    public IStructuredSelection getSelection() {
444
        return (IStructuredSelection) characterTreeEditorComposite.getViewer().getSelection();
445
    }
446

    
447
    @Override
448
    public TermType getTermType() {
449
        return TermType.Character;
450
    }
451

    
452
    public TermTree<Character> getCharacterTree(){
453
        return characterTreeEditorComposite.getFeatureTree();
454
    }
455

    
456

    
457
    public void refresh(TreeViewer viewer){
458
        viewer.refresh();
459

    
460
        characterTreeEditorComposite.getViewer().setInput(characterTreeEditorComposite.getViewer().getInput());
461
    }
462

    
463
    private class FeatureTreeChooserListener extends SelectionAdapter{
464
        private FeatureTreeEditorComposite<Feature> featureTreeEditorComposite;
465
        private TermType termType;
466

    
467
        public FeatureTreeChooserListener(FeatureTreeEditorComposite<Feature> featureTreeEditorComposite, TermType termType) {
468
            super();
469
            this.featureTreeEditorComposite = featureTreeEditorComposite;
470
            this.termType = termType;
471
        }
472

    
473
        @Override
474
        public void widgetSelected(SelectionEvent e) {
475
            TermTree tree = FeatureTreeSelectionDialog.select(featureTreeEditorComposite.getDisplay().getActiveShell(), null, termType);
476
            if(tree!=null){
477
//                cdmEntitySession.load(tree, true);
478
                featureTreeEditorComposite.setSelectedTree(tree);
479
            }
480
        }
481
    }
482

    
483
    @Override
484
    public void update(CdmDataChangeMap arg0) {
485
    }
486

    
487
    @Override
488
    public ConversationHolder getConversationHolder() {
489
        return conversation;
490
    }
491

    
492
    @Override
493
    public void changed(Object element) {
494
        setDirty();
495
        characterTreeEditorComposite.getViewer().refresh();
496
    }
497

    
498
    @Override
499
    public void forceDirty() {
500
        setDirty();
501
    }
502

    
503
    @Override
504
    public boolean postOperation(Object objectAffectedByOperation) {
505
        characterTreeEditorComposite.getViewer().refresh();
506
        if(objectAffectedByOperation instanceof TermNode){
507
            StructuredSelection selection = new StructuredSelection(objectAffectedByOperation);
508
            characterTreeEditorComposite.getViewer().setSelection(selection);
509
        }
510
        return true;
511
    }
512

    
513
    @Override
514
    public boolean onComplete() {
515
        return false;
516
    }
517

    
518
    @Override
519
    public void refresh() {
520
        structureViewer.refresh();
521
        propertyViewer.refresh();
522
        characterTreeEditorComposite.getViewer().setInput(characterTreeEditorComposite.getViewer().getInput());
523

    
524
    }
525

    
526
}
(3-3/3)