Project

General

Profile

Download (19.6 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.swt.SWT;
40
import org.eclipse.swt.custom.SashForm;
41
import org.eclipse.swt.dnd.Transfer;
42
import org.eclipse.swt.events.ModifyEvent;
43
import org.eclipse.swt.events.ModifyListener;
44
import org.eclipse.swt.events.SelectionAdapter;
45
import org.eclipse.swt.events.SelectionEvent;
46
import org.eclipse.swt.layout.GridData;
47
import org.eclipse.swt.layout.GridLayout;
48
import org.eclipse.swt.widgets.Button;
49
import org.eclipse.swt.widgets.Composite;
50
import org.eclipse.swt.widgets.Display;
51
import org.eclipse.swt.widgets.Label;
52
import org.eclipse.swt.widgets.Text;
53
import org.eclipse.ui.forms.widgets.FormToolkit;
54

    
55
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
56
import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
57
import eu.etaxonomy.cdm.api.service.IFeatureNodeService;
58
import eu.etaxonomy.cdm.api.service.IFeatureTreeService;
59
import eu.etaxonomy.cdm.api.service.ITermService;
60
import eu.etaxonomy.cdm.api.service.IVocabularyService;
61
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
62
import eu.etaxonomy.cdm.model.term.Representation;
63
import eu.etaxonomy.cdm.model.term.TermType;
64
import eu.etaxonomy.cdm.model.term.TermVocabulary;
65
import eu.etaxonomy.cdm.model.term.VocabularyEnum;
66
import eu.etaxonomy.cdm.model.description.Character;
67
import eu.etaxonomy.cdm.model.description.FeatureNode;
68
import eu.etaxonomy.cdm.model.description.FeatureTree;
69
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
70
import eu.etaxonomy.taxeditor.editor.AppModelId;
71
import eu.etaxonomy.taxeditor.editor.l10n.Messages;
72
import eu.etaxonomy.taxeditor.featuretree.CharacterTransfer;
73
import eu.etaxonomy.taxeditor.featuretree.FeatureNodeTransfer;
74
import eu.etaxonomy.taxeditor.featuretree.e4.FeatureNodeDragListener;
75
import eu.etaxonomy.taxeditor.featuretree.e4.FeatureTreeDropAdapter;
76
import eu.etaxonomy.taxeditor.featuretree.e4.FeatureTreeEditorComposite;
77
import eu.etaxonomy.taxeditor.featuretree.e4.IFeatureTreeEditor;
78
import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
79
import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
80
import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
81
import eu.etaxonomy.taxeditor.model.ImageResources;
82
import eu.etaxonomy.taxeditor.model.MessagingUtils;
83
import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
84
import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
85
import eu.etaxonomy.taxeditor.store.CdmStore;
86
import eu.etaxonomy.taxeditor.ui.dialog.selection.FeatureTreeSelectionDialog;
87
import eu.etaxonomy.taxeditor.ui.dialog.selection.TermVocabularySelectionDialog;
88
import eu.etaxonomy.taxeditor.workbench.part.IE4ViewerPart;
89

    
90
/**
91
 * Editor for combining structure and property terms to characters.
92
 * @author pplitzner
93
 * @date 24.05.2017
94
 *
95
 */
96
public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled, ISelectionChangedListener,
97
        ModifyListener, IE4ViewerPart, IPartContentHasDetails, IPartContentHasSupplementalData, IDirtyMarkable {
98

    
99
    private FeatureTreeEditorComposite<Character> characterTreeEditorComposite;
100
    private FeatureTreeEditorComposite<DefinedTermBase> propertiesTreeEditorComposite;
101
    private FeatureTreeEditorComposite<DefinedTermBase> structuresTreeEditorComposite;
102
    private final FormToolkit formToolkit = new FormToolkit(Display.getDefault());
103

    
104
    @Inject
105
    private ESelectionService selService;
106

    
107
    @Inject
108
    private UISynchronize sync;
109

    
110
    @Inject
111
    private MDirtyable dirty;
112

    
113
    private ConversationHolder conversation;
114

    
115
    private ICdmEntitySession cdmEntitySession;
116
    private Composite composite;
117

    
118
    private TermVocabulary vocabulary;
119

    
120
    public CharacterEditor() {
121
    }
122

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

    
141
        Composite vocChooserComposite = new Composite(parent, SWT.NONE);
142
        vocChooserComposite.setLayout(new GridLayout(3, false));
143
        vocChooserComposite.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, false, false, 2, 1));
144
        Label lblVocImport = new Label(vocChooserComposite, SWT.NONE);
145
        lblVocImport.setText("Character vocabulary");
146
        Text txtVocabulary = new Text(vocChooserComposite, SWT.NONE);
147
        txtVocabulary.setEditable(false);
148
        Button btnChooseVoc = new Button(vocChooserComposite, SWT.PUSH);
149
        btnChooseVoc.setImage(ImageResources.getImage(ImageResources.BROWSE_ICON));
150
        btnChooseVoc.addSelectionListener(new SelectionAdapter() {
151

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

    
168
        SashForm sashForm = new SashForm(parent, SWT.NONE);
169
        sashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
170
        formToolkit.adapt(sashForm);
171
        formToolkit.paintBordersFor(sashForm);
172

    
173
        composite = new Composite(sashForm, SWT.NONE);
174
        formToolkit.adapt(composite);
175
        formToolkit.paintBordersFor(composite);
176
        GridLayout gl_composite = new GridLayout(1, false);
177
        gl_composite.marginWidth = 0;
178
        composite.setLayout(gl_composite);
179

    
180
        structuresTreeEditorComposite = addFeatureTreeEditor(composite);
181

    
182
        initFeatureTreeComposite(TermType.Structure, structuresTreeEditorComposite,
183
                new FeatureNodeDragListener(structuresTreeEditorComposite.getViewer()), null, null, null, null);
184

    
185
        structuresTreeEditorComposite.getLabel_title().setText(Messages.CharacterEditor_STRUCTURES);
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
        propertiesTreeEditorComposite = addFeatureTreeEditor(composite_1);
195
        initFeatureTreeComposite(TermType.Property, propertiesTreeEditorComposite,
196

    
197
                new CharacterDragListener(structuresTreeEditorComposite.getViewer(), propertiesTreeEditorComposite.getViewer()),
198
                null,
199
                new Transfer[] {CharacterTransfer.getInstance()},
200
                null,
201
                null
202

    
203
        );
204
        propertiesTreeEditorComposite.getLabel_title().setText(Messages.CharacterEditor_PROPERTIES);
205

    
206
        Composite composite_3 = new Composite(sashForm, SWT.NONE);
207
        formToolkit.adapt(composite_3);
208
        formToolkit.paintBordersFor(composite_3);
209
        GridLayout gl_composite_3 = new GridLayout(2, false);
210
        gl_composite_3.marginWidth = 0;
211
        composite_3.setLayout(gl_composite_3);
212

    
213
        Button btnAddCharacter = new Button(composite_3, SWT.NONE);
214
        btnAddCharacter.setText(">>"); //$NON-NLS-1$
215
        formToolkit.adapt(btnAddCharacter, true, true);
216
        btnAddCharacter.addSelectionListener(new SelectionAdapter() {
217
            @Override
218
            public void widgetSelected(SelectionEvent e) {
219
                if(!isVocabularySet()){
220
                    return;
221
                }
222
                ISelection structureTreeSelection = structuresTreeEditorComposite.getViewer().getSelection();
223
                ISelection propertyTreeSelection = propertiesTreeEditorComposite.getViewer().getSelection();
224
                if(structureTreeSelection==null || propertyTreeSelection==null || characterTreeEditorComposite.getFeatureTree()==null){
225
                    MessagingUtils.warningDialog(Messages.CharacterEditor_CANNOT_PERFORM_TITLE, CharacterEditor.this,
226
                            Messages.CharacterEditor_CANNOT_PERFORM_MESSAGE);
227
                    return;
228
                }
229
                Collection<Character> characters = createCharacters((TreeSelection)structureTreeSelection, (TreeSelection)propertyTreeSelection);
230
                for (Character character : characters) {
231
                    //add new Character to feature tree
232
                    FeatureNode<Character> parent = ((FeatureTree<Character>) characterTreeEditorComposite.getViewer().getInput()).getRoot();
233
                    vocabulary.addTerm(character);
234
                    CdmStore.getService(IFeatureNodeService.class).createChildFeatureNode(parent, character);
235
                }
236
                characterTreeEditorComposite.getViewer().refresh();
237
            }
238
        });
239

    
240
        characterTreeEditorComposite = addFeatureTreeEditor(composite_3);
241
        initFeatureTreeComposite(TermType.Character, characterTreeEditorComposite, new FeatureNodeDragListener(characterTreeEditorComposite.getViewer()),
242
                new CharacterDropAdapter(this, characterTreeEditorComposite.getViewer(), sync),
243

    
244
                new Transfer[] {FeatureNodeTransfer.getInstance(), CharacterTransfer.getInstance()},
245
                this,
246
                this);
247

    
248
        characterTreeEditorComposite.getLabel_title().setText(Messages.CharacterEditor_CHARACTERS);
249

    
250
        //add context menu to character viewer
251
        menuService.registerContextMenu(characterTreeEditorComposite.getViewer().getControl(),
252
                AppModelId.POPUPMENU_EU_ETAXONOMY_TAXEDITOR_EDITOR_POPUPMENU_CHARACTEREDITOR);
253

    
254
    }
255

    
256
    private <T extends DefinedTermBase> FeatureTreeEditorComposite<T> addFeatureTreeEditor(Composite composite_3) {
257
        FeatureTreeEditorComposite<T> featureTreeEditorComposite = new FeatureTreeEditorComposite<>(composite_3, SWT.NONE);
258
        featureTreeEditorComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
259
        return featureTreeEditorComposite;
260
    }
261

    
262
    private void initFeatureTreeComposite(
263
            TermType termType,
264
            FeatureTreeEditorComposite featureTreeEditorComposite,
265
            FeatureNodeDragListener featureNodeDragListener,
266
            FeatureTreeDropAdapter featureNodeDropAdapter,
267
            Transfer[] transfers,
268
            ISelectionChangedListener viewerSelectionChangedListener,
269
            ModifyListener modifyListener) {
270

    
271
        featureTreeEditorComposite.init(
272
                featureNodeDragListener,
273
                featureNodeDropAdapter,
274
                transfers,
275
                viewerSelectionChangedListener,
276
                new FeatureTreeChooserListener(featureTreeEditorComposite, termType),
277
                modifyListener);
278
    }
279

    
280
    @Focus
281
    public void focus(){
282
        if(characterTreeEditorComposite!=null){
283
            characterTreeEditorComposite.getViewer().getControl().setFocus();
284
        }
285
        if(conversation!=null && !conversation.isBound()){
286
            conversation.bind();
287
        }
288
        if(cdmEntitySession != null) {
289
            cdmEntitySession.bind();
290
        }
291
    }
292

    
293
    public static Collection<Character> createCharacters(TreeSelection structureTreeSelection, TreeSelection propertyTreeSelection){
294
        Set<Character> characters = new HashSet<>();
295
        //get selected structures and properties
296
        Iterator<FeatureNode<DefinedTermBase>> structureIterator = structureTreeSelection.iterator();
297

    
298
        //create all combinations of structures and properties
299
        while(structureIterator.hasNext()){
300
            FeatureNode<DefinedTermBase> structureNode = structureIterator.next();
301
            Iterator<FeatureNode<DefinedTermBase>> propertiesIterator = propertyTreeSelection.iterator();
302
            while(propertiesIterator.hasNext()){
303
                FeatureNode<DefinedTermBase> propertyNode = propertiesIterator.next();
304
                Representation structureRepresentation = structureNode.getTerm().getRepresentation(PreferencesUtil.getGlobalLanguage());
305
                Representation propertyRepresentation = propertyNode.getTerm().getRepresentation(PreferencesUtil.getGlobalLanguage());
306
                String label = null;
307
                String abbrevLabel = null;
308
                if(structureRepresentation.getLabel()!=null && propertyRepresentation.getLabel()!=null){
309
                    label = structureRepresentation.getLabel()+" "+propertyRepresentation.getLabel();
310
                }
311
                if(structureRepresentation.getAbbreviatedLabel()!=null && propertyRepresentation.getAbbreviatedLabel()!=null){
312
                    abbrevLabel = structureRepresentation.getAbbreviatedLabel()+" "+propertyRepresentation.getAbbreviatedLabel();
313
                }
314
                //create new Character
315
                Character character = Character.NewInstance(structureNode, propertyNode, null, label, abbrevLabel);
316
                characters.add(character);
317
            }
318
        }
319
        return characters;
320
    }
321

    
322
    @Override
323
    @Persist
324
    public void save(IProgressMonitor monitor){
325
        if (!conversation.isBound()) {
326
            conversation.bind();
327
        }
328

    
329
        // commit the conversation and start a new transaction immediately
330
        conversation.commit(true);
331

    
332
        FeatureTree<Character> featureTree = characterTreeEditorComposite.getFeatureTree();
333
        if(featureTree!=null){
334
            //save characters because they can be modified in this editor
335
            featureTree.getDistinctFeatures().forEach(character->CdmStore.getService(ITermService.class).merge(character,true));
336
        }
337
        CdmStore.getService(IFeatureTreeService.class).saveOrUpdate(featureTree);
338

    
339

    
340
        dirty.setDirty(false);
341
    }
342

    
343
    @Override
344
    public boolean isDirty() {
345
        return dirty.isDirty();
346
    }
347

    
348
    @PreDestroy
349
    public void dispose(){
350
        if(conversation!=null){
351
            conversation.close();
352
            conversation = null;
353
        }
354
        if(cdmEntitySession != null) {
355
            cdmEntitySession.dispose();
356
            cdmEntitySession = null;
357
        }
358
        dirty.setDirty(false);
359
    }
360

    
361
    public boolean isVocabularySet() {
362
        if(vocabulary==null){
363
            MessagingUtils.warningDialog("Character creation not possible", this.getClass(), "Please select a vocabulary for the characters.");
364
        }
365
        return vocabulary!=null;
366
    }
367

    
368
    public TermVocabulary getVocabulary() {
369
        return vocabulary;
370
    }
371

    
372
    @Override
373
    public Map<Object, List<String>> getPropertyPathsMap() {
374
        List<String> propertyPaths = Arrays.asList(new String[] {
375
                "children", //$NON-NLS-1$
376
                "feature", //$NON-NLS-1$
377
                "featureTree", //$NON-NLS-1$
378
        });
379
        Map<Object, List<String>> propertyPathMap =
380
                new HashMap<Object, List<String>>();
381
        propertyPathMap.put(FeatureNode.class,propertyPaths);
382
        return propertyPathMap;
383
    }
384

    
385
    @Override
386
    public List<FeatureTree<Character>> getRootEntities() {
387
        List<FeatureTree<Character>> root = new ArrayList<>();
388
        root.add(characterTreeEditorComposite.getFeatureTree());
389
        return root;
390
    }
391

    
392
    @Override
393
    public ICdmEntitySession getCdmEntitySession() {
394
        return cdmEntitySession;
395
    }
396

    
397
    @Focus
398
    public void setFocus() {
399
        if(conversation!=null && !conversation.isBound()){
400
            conversation.bind();
401
        }
402
    }
403

    
404
    @Override
405
    public void selectionChanged(SelectionChangedEvent event) {
406
        //propagate selection
407
        selService.setSelection(event.getSelection());
408
    }
409

    
410

    
411
    @Override
412
    public void modifyText(ModifyEvent e) {
413
        characterTreeEditorComposite.getFeatureTree().setTitleCache(((Text) e.widget).getText(), true);
414
        setDirty();
415
    }
416

    
417

    
418
    private void setDirty() {
419
        dirty.setDirty(true);
420
    }
421

    
422
    @Override
423
    public IStructuredSelection getSelection() {
424
        return (IStructuredSelection) characterTreeEditorComposite.getViewer().getSelection();
425
    }
426

    
427
    public FeatureTree<Character> getCharacterTree(){
428
        return characterTreeEditorComposite.getFeatureTree();
429
    }
430

    
431
    @Override
432
    public void refresh(){
433
        structuresTreeEditorComposite.getViewer().refresh();
434
        propertiesTreeEditorComposite.getViewer().refresh();
435
        characterTreeEditorComposite.getViewer().refresh();
436
    }
437

    
438
    private class FeatureTreeChooserListener extends SelectionAdapter{
439
        private FeatureTreeEditorComposite<?> featureTreeEditorComposite;
440
        private TermType termType;
441

    
442
        public FeatureTreeChooserListener(FeatureTreeEditorComposite<?> featureTreeEditorComposite, TermType termType) {
443
            super();
444
            this.featureTreeEditorComposite = featureTreeEditorComposite;
445
            this.termType = termType;
446
        }
447

    
448
        @Override
449
        public void widgetSelected(SelectionEvent e) {
450
            FeatureTree tree = FeatureTreeSelectionDialog.select(featureTreeEditorComposite.getDisplay().getActiveShell(), null, termType);
451
            if(tree!=null){
452
                featureTreeEditorComposite.setSelectedTree(tree);
453
            }
454
        }
455
    }
456

    
457
    @Override
458
    public void update(CdmDataChangeMap arg0) {
459
    }
460

    
461
    @Override
462
    public ConversationHolder getConversationHolder() {
463
        return conversation;
464
    }
465

    
466
    @Override
467
    public void changed(Object element) {
468
        setDirty();
469
    }
470

    
471
    @Override
472
    public void forceDirty() {
473
        setDirty();
474
    }
475

    
476
    @Override
477
    public boolean postOperation(Object objectAffectedByOperation) {
478
        characterTreeEditorComposite.getViewer().refresh();
479
        if(objectAffectedByOperation instanceof FeatureNode){
480
            StructuredSelection selection = new StructuredSelection(objectAffectedByOperation);
481
            characterTreeEditorComposite.getViewer().setSelection(selection);
482
        }
483
        return true;
484
    }
485

    
486
    @Override
487
    public boolean onComplete() {
488
        return false;
489
    }
490

    
491
}
(3-3/3)