Project

General

Profile

Download (17.7 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 * Copyright (C) 2007 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

    
10
package eu.etaxonomy.taxeditor.featuretree.e4;
11

    
12
import java.util.ArrayList;
13
import java.util.Arrays;
14
import java.util.HashMap;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.UUID;
18

    
19
import javax.annotation.PostConstruct;
20
import javax.annotation.PreDestroy;
21
import javax.inject.Inject;
22

    
23
import org.eclipse.core.runtime.IProgressMonitor;
24
import org.eclipse.e4.core.di.annotations.Optional;
25
import org.eclipse.e4.ui.di.Focus;
26
import org.eclipse.e4.ui.di.Persist;
27
import org.eclipse.e4.ui.di.UIEventTopic;
28
import org.eclipse.e4.ui.di.UISynchronize;
29
import org.eclipse.e4.ui.model.application.ui.MDirtyable;
30
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
31
import org.eclipse.e4.ui.services.EMenuService;
32
import org.eclipse.e4.ui.workbench.modeling.EPartService;
33
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
34
import org.eclipse.jface.util.LocalSelectionTransfer;
35
import org.eclipse.jface.viewers.ISelection;
36
import org.eclipse.jface.viewers.ISelectionChangedListener;
37
import org.eclipse.jface.viewers.IStructuredSelection;
38
import org.eclipse.jface.viewers.SelectionChangedEvent;
39
import org.eclipse.jface.viewers.StructuredSelection;
40
import org.eclipse.jface.viewers.TreeViewer;
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.KeyAdapter;
45
import org.eclipse.swt.events.KeyEvent;
46
import org.eclipse.swt.layout.FillLayout;
47
import org.eclipse.swt.widgets.Composite;
48
import org.eclipse.ui.IMemento;
49

    
50
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
51
import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
52
import eu.etaxonomy.cdm.api.service.ITermNodeService;
53
import eu.etaxonomy.cdm.api.service.ITermTreeService;
54
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
55
import eu.etaxonomy.cdm.model.term.TermNode;
56
import eu.etaxonomy.cdm.model.term.TermType;
57
import eu.etaxonomy.cdm.persistence.dto.TermDto;
58
import eu.etaxonomy.cdm.persistence.dto.TermNodeDto;
59
import eu.etaxonomy.cdm.persistence.dto.TermTreeDto;
60
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
61
import eu.etaxonomy.taxeditor.editor.definedterm.TermTreeViewerComparator;
62
import eu.etaxonomy.taxeditor.editor.definedterm.TermTransfer;
63
import eu.etaxonomy.taxeditor.event.WorkbenchEventConstants;
64
import eu.etaxonomy.taxeditor.featuretree.TermNodeDtoTransfer;
65
import eu.etaxonomy.taxeditor.featuretree.TermTreeContentProvider;
66
import eu.etaxonomy.taxeditor.featuretree.TermTreeLabelProvider;
67
import eu.etaxonomy.taxeditor.featuretree.e4.operation.AddFeatureOperation;
68
import eu.etaxonomy.taxeditor.featuretree.e4.operation.CreateFeatureTreeOperation;
69
import eu.etaxonomy.taxeditor.l10n.Messages;
70
import eu.etaxonomy.taxeditor.model.AbstractUtility;
71
import eu.etaxonomy.taxeditor.model.IContextListener;
72
import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
73
import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
74
import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
75
import eu.etaxonomy.taxeditor.model.MessagingUtils;
76
import eu.etaxonomy.taxeditor.operation.AbstractPostOperation;
77
import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
78
import eu.etaxonomy.taxeditor.store.AppModelId;
79
import eu.etaxonomy.taxeditor.store.CdmStore;
80
import eu.etaxonomy.taxeditor.store.StoreUtil;
81
import eu.etaxonomy.taxeditor.workbench.part.IE4ViewerPart;
82

    
83
/**
84
 *
85
 * @author pplitzner
86
 * @date 06.06.2017
87
 *
88
 */
89
public class TermTreeEditor<T extends DefinedTermBase>
90
		implements ITermTreeEditor, ISelectionChangedListener,
91
        	IE4ViewerPart, IPartContentHasDetails, IPartContentHasSupplementalData,
92
        	IContextListener, IConversationEnabled, IDirtyMarkable {
93

    
94
    public static final List<String> TREE_PROPERTY_PATH = Arrays.asList(new String[] {
95
            "root", //$NON-NLS-1$
96
            "root.children", //$NON-NLS-1$
97
            "root.children.inapplicableIf", //$NON-NLS-1$
98
            "root.children.inapplicableIf.feature", //$NON-NLS-1$
99
            "root.children.inapplicableIf.state", //$NON-NLS-1$
100
            "root.children.onlyApplicableIf", //$NON-NLS-1$
101
            "root.children.onlyApplicableIf.feature", //$NON-NLS-1$
102
            "root.children.onlyApplicableIf.state", //$NON-NLS-1$
103
    });
104

    
105
    private ConversationHolder conversation;
106

    
107
    private ICdmEntitySession cdmEntitySession;
108

    
109
    @Inject
110
    private ESelectionService selService;
111

    
112
    @Inject
113
    private MDirtyable dirty;
114

    
115
    @Inject
116
    private UISynchronize sync;
117

    
118
    @Inject
119
    private MPart thisPart;
120

    
121
    private TreeViewer viewer;
122

    
123
    Map<UUID,TermTreeDto> trees;
124

    
125
    Map<UUID, TermNodeDto> uuidTermMap = new HashMap<>();
126
    List<AbstractPostOperation<TermNode>> createOperationList = new ArrayList<>();
127
    List<AbstractPostOperation<TermNode>> operationList = new ArrayList<>();
128
    List<TermNodeDto> listToUpdate = new ArrayList<>();
129

    
130
    TermType termType;
131

    
132
    @Inject
133
    public TermTreeEditor() {
134
        CdmStore.getContextManager().addContextListener(this);
135
    }
136

    
137
    @PostConstruct
138
    public void createControl(Composite parent, EMenuService menuService){
139
        if (CdmStore.isActive()){
140
            initSession();
141
        }
142
        else{
143
            return;
144
        }
145
        parent.setLayout(new FillLayout());
146
        viewer = new TreeViewer(parent);
147
        TermTreeContentProvider contentProvider = new TermTreeContentProvider();
148

    
149
        viewer.setContentProvider(contentProvider);
150
        viewer.setLabelProvider(new TermTreeLabelProvider());
151

    
152
        int ops = DND.DROP_COPY | DND.DROP_MOVE;
153
        Transfer[] transfers = new Transfer[] {
154
                TermNodeDtoTransfer.getInstance(),
155
                TermTransfer.getInstance(),
156
                LocalSelectionTransfer.getTransfer()};
157
        viewer.addDragSupport(ops, transfers, new TermNodeDtoDragListener(viewer));
158
        viewer.addDropSupport(ops, transfers, new TermTreeDtoDropAdapter(this, viewer, sync));
159
        viewer.addSelectionChangedListener(this);
160
        viewer.getTree().addKeyListener(new KeyAdapter() {
161
            @Override
162
            public void keyPressed(KeyEvent e) {
163
                if(e.stateMask == SWT.MOD1 && e.keyCode == 'c'){
164
                    copy(viewer.getStructuredSelection());
165
                }
166
                else if(e.stateMask == SWT.MOD1 && e.keyCode == 'v'){
167
                    paste(viewer.getStructuredSelection());
168
                }
169
            }
170
        });
171

    
172
        updateTrees();
173
        viewer.setComparator(new TermTreeViewerComparator());
174
        viewer.setInput(getTrees());
175
        contentProvider.setUuidTermMap(uuidTermMap);
176
        //create context menu
177
        menuService.registerContextMenu(viewer.getControl(), AppModelId.POPUPMENU_EU_ETAXONOMY_TAXEDITOR_STORE_POPUPMENU_FEATURETREEEDITOR);
178
    }
179

    
180
    public void init(TermType type, String label){
181
        this.termType = type;
182
        updateTrees();
183
        viewer.setComparator(new TermTreeViewerComparator());
184
        viewer.setInput(getTrees());
185
        ((TermTreeContentProvider)viewer.getContentProvider()).setUuidTermMap(uuidTermMap);
186
        thisPart.setLabel(label);
187
    }
188

    
189
//    protected abstract List<TermTreeDto> getTrees();
190

    
191
    public void paste(IStructuredSelection selection) {
192
        if (StoreUtil.promptCheckIsDirty(this)) {
193
            return;
194
        }
195

    
196
        ISelection clipBoardSelection = LocalSelectionTransfer.getTransfer().getSelection();
197
        Object firstElement = selection.getFirstElement();
198
        TermNodeDto parentNode = null;
199
        if(firstElement instanceof TermNodeDto){
200
            parentNode = (TermNodeDto) firstElement;
201
        }
202
        else if(firstElement instanceof TermTreeDto){
203
            parentNode = ((TermTreeDto)firstElement).getRoot();
204
        }
205
        if(parentNode!=null){
206

    
207
        	TermNodeDto copiedNode = (TermNodeDto) ((IStructuredSelection)clipBoardSelection).getFirstElement();
208
        	boolean isDuplicate = this.checkDuplicates(copiedNode.getTerm().getUuid(), parentNode.getTree().getUuid());
209
            if (isDuplicate && !parentNode.getTree().isAllowDuplicate()){
210
                MessagingUtils.informationDialog(Messages.AddFeatureHandler_Duplicates_not_allowed, Messages.AddFeatureHandler_Duplicates_not_allowed_message +  "\n"+copiedNode.getTerm().getTitleCache());
211
                return;
212
            }
213
        	TermNodeDto newDto = new TermNodeDto(copiedNode.getTerm(), parentNode, 0, parentNode.getTree(), null, null, null);
214
        	this.refresh();
215
        	this.setDirty();
216
            AddFeatureOperation operation = new AddFeatureOperation(copiedNode.getTerm().getUuid(), parentNode, this, this);
217
//            AbstractUtility.executeOperation(operation, sync);
218
            this.addOperation(operation);
219
        }
220

    
221
    }
222

    
223
    public void copy(IStructuredSelection selection) {
224
        LocalSelectionTransfer.getTransfer().setSelection(selection);
225
    }
226

    
227
    private void initSession(){
228
        if(conversation == null){
229
            conversation = CdmStore.createConversation();
230
        }
231
        if(cdmEntitySession==null){
232
            cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
233
        }
234
    }
235

    
236
    private void clearSession() {
237
        if(conversation!=null){
238
            conversation.close();
239
            conversation = null;
240
        }
241
        if(cdmEntitySession != null) {
242
            cdmEntitySession.dispose();
243
            cdmEntitySession = null;
244
        }
245
        dirty.setDirty(false);
246
    }
247

    
248
	public void setDirty(boolean isDirty){
249
	    this.dirty.setDirty(isDirty);
250
	}
251
	@Override
252
    public void setDirty(){
253
        this.dirty.setDirty(true);
254
    }
255

    
256
	@Override
257
    public boolean isDirty(){
258
	    return dirty.isDirty();
259
	}
260

    
261
	@Override
262
	public void selectionChanged(SelectionChangedEvent event) {
263
		//propagate selection
264
		selService.setSelection(event.getSelection());
265
	}
266

    
267
	@Focus
268
	public void focus(){
269
	    if(viewer!=null){
270
	        viewer.getControl().setFocus();
271
	    }
272
        if(conversation!=null && !conversation.isBound()){
273
            conversation.bind();
274
        }
275
        if(cdmEntitySession != null) {
276
            cdmEntitySession.bind();
277
        }
278
	}
279

    
280
	@Override
281
    public void refresh(){
282
	    viewer.refresh();
283
	}
284

    
285
	@Override
286
    public TreeViewer getViewer(){
287
	    return viewer;
288
	}
289

    
290
	@Override
291
	public IStructuredSelection getSelection() {
292
	    return (IStructuredSelection) viewer.getSelection();
293
	}
294

    
295
	@Override
296
	public ConversationHolder getConversationHolder() {
297
	    return conversation;
298
	}
299

    
300
	@Override
301
    @Persist
302
	public void save(IProgressMonitor monitor){
303
        if (!conversation.isBound()) {
304
            conversation.bind();
305
        }
306

    
307
        // commit the conversation and start a new transaction immediately
308
        Object[] expandedElements = this.viewer.getExpandedElements();
309
        conversation.commit(true);
310
        if (createOperationList != null && !createOperationList.isEmpty()){
311
            for (AbstractPostOperation<TermNode> operation: createOperationList){
312
                AbstractUtility.executeOperation(operation, sync);
313
            }
314
            createOperationList.clear();
315
        }
316

    
317
        if (operationList != null && !operationList.isEmpty()){
318
            for (AbstractPostOperation<TermNode> operation: operationList){
319
                AbstractUtility.executeOperation(operation, sync);
320
            }
321
            operationList.clear();
322
        }
323

    
324
        CdmStore.getService(ITermNodeService.class).saveTermNodeDtoList(listToUpdate);
325
        listToUpdate.clear();
326
        List<TermTreeDto> rootEntities = getRootEntities();
327
        CdmStore.getService(ITermTreeService.class).saveOrUpdateTermTreeDtoList(rootEntities);
328
        initializeTrees();
329
        conversation.commit(true);
330

    
331
        this.setDirty(false);
332
//        this.viewer.setExpandedElements(expandedElements);
333
	}
334

    
335
    private void initializeTrees() {
336
        Object[] expandedElements = viewer.getExpandedElements();
337
        viewer.getTree().removeAll();
338
        updateTrees();
339
        viewer.setInput(getTrees());
340
        viewer.setExpandedElements(expandedElements);
341

    
342
    }
343

    
344
	@PreDestroy
345
	public void dispose(){
346
	    selService.setSelection(null);
347
	    clearSession();
348
	}
349

    
350
    @Override
351
    public ICdmEntitySession getCdmEntitySession() {
352
        return cdmEntitySession;
353
    }
354

    
355
    @Override
356
    public Map<Object, List<String>> getPropertyPathsMap() {
357
        List<String> propertyPaths = Arrays.asList(new String[] {
358
                "children", //$NON-NLS-1$
359
                "feature", //$NON-NLS-1$
360
                "featureTree", //$NON-NLS-1$
361
        });
362
        Map<Object, List<String>> propertyPathMap =
363
                new HashMap<Object, List<String>>();
364
        propertyPathMap.put(TermNode.class,propertyPaths);
365
        return propertyPathMap;
366
    }
367

    
368
    @Override
369
    public List<TermTreeDto> getRootEntities() {
370
        return (List<TermTreeDto>) viewer.getInput();
371
    }
372

    
373
    @Override
374
    public void contextAboutToStop(IMemento memento, IProgressMonitor monitor) {
375
    }
376

    
377
    @Override
378
    public void contextStop(IMemento memento, IProgressMonitor monitor) {
379
        //close view when workbench closes
380
        try{
381
            thisPart.getContext().get(EPartService.class).hidePart(thisPart);
382
        }
383
        catch(Exception e){
384
            //nothing
385
        }
386
    }
387

    
388
    @Override
389
    public void contextStart(IMemento memento, IProgressMonitor monitor) {
390
    }
391

    
392
    @Override
393
    public void contextRefresh(IProgressMonitor monitor) {
394
    }
395

    
396
    @Override
397
    public void workbenchShutdown(IMemento memento, IProgressMonitor monitor) {
398
    }
399

    
400
    @Override
401
    public void update(CdmDataChangeMap arg0) {
402
    }
403

    
404
    @Override
405
    public void changed(Object element) {
406
        dirty.setDirty(true);
407
        viewer.refresh();
408
    }
409

    
410
    @Override
411
    public void forceDirty() {
412
        dirty.setDirty(true);
413
    }
414

    
415
    @Override
416
    public boolean postOperation(Object objectAffectedByOperation) {
417
        initializeTrees();
418
        viewer.refresh();
419
        if(objectAffectedByOperation instanceof TermNodeDto){
420
        	TermNodeDto node = (TermNodeDto)objectAffectedByOperation;
421
//            viewer.expandToLevel(((TermRelationBase) node).getGraph(), 1); find a solution for dto editor
422
        }
423
        if(objectAffectedByOperation!=null){
424
            StructuredSelection selection = new StructuredSelection(objectAffectedByOperation);
425
            viewer.setSelection(selection);
426
        }
427
        return true;
428
    }
429

    
430
    @Override
431
    public boolean onComplete() {
432
        return false;
433
    }
434

    
435
    @Override
436
    public TermNodeDto getNodeDtoForUuid(UUID nodeUuid){
437
        return uuidTermMap.get(nodeUuid);
438
    }
439

    
440
    protected void addAllNodesToMap(TermNodeDto root){
441
        if (!uuidTermMap.containsKey(root.getUuid())){
442
            uuidTermMap.put(root.getUuid(), root);
443
            if (root.getTerm() != null){
444
                getTreeDtoForUuid(root.getTree().getUuid()).addTerm(root.getTerm());
445
            }
446
        }
447
        for (TermNodeDto child: root.getChildren()){
448
            uuidTermMap.put(child.getUuid(), child);
449
            if (child.getTerm() != null){
450
                getTreeDtoForUuid(child.getTree().getUuid()).addTerm(child.getTerm());
451
            }
452
            if (child.getChildren() != null && !child.getChildren().isEmpty()){
453
                addAllNodesToMap(child);
454
            }
455
        }
456
    }
457

    
458
    /**
459
     * @param term
460
     * @param treeUuid
461
     */
462
    @Override
463
    public boolean checkDuplicates(UUID termUuid, UUID treeUuid) {
464
        TermTreeDto tree = this.getTreeDtoForUuid(treeUuid);
465
        for (TermDto dto: tree.getTerms()){
466
            if (dto.getUuid().equals(termUuid)) {
467
                return true;
468
            }
469
        }
470
        return false;
471
    }
472

    
473
    protected void updateTrees(){
474
        uuidTermMap.clear();
475
        if (trees != null && !trees.isEmpty()){
476
            trees.clear();
477
        }
478
        if (trees == null){
479
            trees = new HashMap<>();
480
        }
481
        List<TermTreeDto> treeList = CdmStore.getService(ITermTreeService.class).listTermTreeDtosByTermType(getTermType());
482
        treeList.stream().forEach(tree -> trees.put(tree.getUuid(), tree));
483
//        trees.addAll(CdmStore.getService(ITermTreeService.class).listTermTreeDtosByTermType(getTermType()));
484
        for (TermTreeDto tree: trees.values()){
485
            addAllNodesToMap(tree.getRoot());
486
        }
487
        ((TermTreeContentProvider<T>)viewer.getContentProvider()).setUuidTermMap(uuidTermMap);
488
//        viewer.refresh();
489

    
490
    }
491

    
492
    public List<TermTreeDto> getTrees(){
493
        List<TermTreeDto> treeList = new ArrayList<>(trees.values());
494
        return treeList;
495
    }
496

    
497
    public void putTree(TermTreeDto tree){
498
       trees.put(tree.getUuid(), tree);
499

    
500
    }
501

    
502
    public void removeTree(TermTreeDto tree){
503
        trees.remove(tree.getUuid());
504

    
505
     }
506

    
507
    @Override
508
    public TermTreeDto getTreeDtoForUuid(UUID treeUuid){
509
        return trees.get(treeUuid);
510
    }
511

    
512
    @Override
513
    public void setTreeDtoForUuid(TermTreeDto tree){
514
        trees.put(tree.getUuid(), tree);
515
    }
516

    
517
    @Override
518
    public void setNodeDtoForUuid(TermNodeDto node){
519
        this.uuidTermMap.put(node.getUuid(), node);
520
    }
521

    
522
    @Override
523
    public void addOperation(AbstractPostOperation operation) {
524
        if (operation instanceof CreateFeatureTreeOperation){
525
            createOperationList.add(operation);
526
        }else{
527
            operationList.add(operation);
528
        }
529
    }
530

    
531
    @Inject
532
    @Optional
533
    private void addSaveCandidate(@UIEventTopic(WorkbenchEventConstants.ADD_SAVE_CANDIDATE) UUID cdmbaseUuid) {
534
        for (UUID uuid: uuidTermMap.keySet()) {
535
            if (uuid.equals(cdmbaseUuid)){
536
                listToUpdate.add(uuidTermMap.get(uuid));
537
            }
538

    
539
        }
540
    }
541

    
542
    @Override
543
    public TermType getTermType() {
544
        return termType;
545
    }
546

    
547

    
548
}
(8-8/9)