Project

General

Profile

Download (18.3 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
package eu.etaxonomy.taxeditor.termtree.e4;
10

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

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

    
22
import org.eclipse.core.runtime.IProgressMonitor;
23
import org.eclipse.e4.core.di.annotations.Optional;
24
import org.eclipse.e4.ui.di.Focus;
25
import org.eclipse.e4.ui.di.Persist;
26
import org.eclipse.e4.ui.di.UIEventTopic;
27
import org.eclipse.e4.ui.di.UISynchronize;
28
import org.eclipse.e4.ui.model.application.ui.MDirtyable;
29
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
30
import org.eclipse.e4.ui.services.EMenuService;
31
import org.eclipse.e4.ui.workbench.modeling.EPartService;
32
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
33
import org.eclipse.jface.util.LocalSelectionTransfer;
34
import org.eclipse.jface.viewers.ISelection;
35
import org.eclipse.jface.viewers.ISelectionChangedListener;
36
import org.eclipse.jface.viewers.IStructuredSelection;
37
import org.eclipse.jface.viewers.SelectionChangedEvent;
38
import org.eclipse.jface.viewers.StructuredSelection;
39
import org.eclipse.jface.viewers.TreeViewer;
40
import org.eclipse.swt.SWT;
41
import org.eclipse.swt.dnd.DND;
42
import org.eclipse.swt.dnd.Transfer;
43
import org.eclipse.swt.events.KeyAdapter;
44
import org.eclipse.swt.events.KeyEvent;
45
import org.eclipse.swt.layout.FillLayout;
46
import org.eclipse.swt.widgets.Composite;
47
import org.eclipse.ui.IMemento;
48

    
49
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
50
import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
51
import eu.etaxonomy.cdm.api.service.ITermNodeService;
52
import eu.etaxonomy.cdm.api.service.ITermTreeService;
53
import eu.etaxonomy.cdm.api.service.UpdateResult;
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.TermTransfer;
62
import eu.etaxonomy.taxeditor.editor.definedterm.TermTreeViewerComparator;
63
import eu.etaxonomy.taxeditor.event.WorkbenchEventConstants;
64
import eu.etaxonomy.taxeditor.l10n.Messages;
65
import eu.etaxonomy.taxeditor.model.AbstractUtility;
66
import eu.etaxonomy.taxeditor.model.IContextListener;
67
import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
68
import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
69
import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
70
import eu.etaxonomy.taxeditor.model.MessagingUtils;
71
import eu.etaxonomy.taxeditor.operation.AbstractPostOperation;
72
import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
73
import eu.etaxonomy.taxeditor.store.AppModelId;
74
import eu.etaxonomy.taxeditor.store.CdmStore;
75
import eu.etaxonomy.taxeditor.store.StoreUtil;
76
import eu.etaxonomy.taxeditor.termtree.TermNodeDtoTransfer;
77
import eu.etaxonomy.taxeditor.termtree.TermTreeContentProvider;
78
import eu.etaxonomy.taxeditor.termtree.TermTreeLabelProvider;
79
import eu.etaxonomy.taxeditor.termtree.e4.operation.AddFeatureOperation;
80
import eu.etaxonomy.taxeditor.termtree.e4.operation.CreateFeatureTreeOperation;
81
import eu.etaxonomy.taxeditor.workbench.part.IE4ViewerPart;
82

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

    
92
    public static final String OPEN_COMMAND_ID = "eu.etaxonomy.taxeditor.store.openTermTreeEditor";
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.term", //$NON-NLS-1$
99
            "root.children.inapplicableIf.state", //$NON-NLS-1$
100
            "root.children.onlyApplicableIf", //$NON-NLS-1$
101
            "root.children.onlyApplicableIf.term", //$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
    Map<UUID, CreateFeatureTreeOperation> createOperationList = new HashMap<>();
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
    public void copy(IStructuredSelection selection) {
223
        LocalSelectionTransfer.getTransfer().setSelection(selection);
224
    }
225

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

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

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

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

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

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

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

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

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

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

    
308
        // commit the conversation and start a new transaction immediately
309
        ISelection sel = this.viewer.getSelection();
310
        conversation.commit(true);
311
        if (createOperationList != null && !createOperationList.isEmpty()){
312
            for (CreateFeatureTreeOperation operation: createOperationList.values()){
313
                TermTreeDto termDto = getTreeDtoForUuid(operation.getElementUuid());
314
                operation.getElement().setTitleCache(termDto.getTitleCache(), true);
315
                operation.getElement().setAllowDuplicates(termDto.isAllowDuplicate());
316
                operation.getElement().setFlat(termDto.isFlat());
317
                operation.getElement().setOrderRelevant(termDto.isOrderRelevant());
318
                AbstractUtility.executeOperation(operation, sync);
319
            }
320
            createOperationList.clear();
321
        }
322

    
323
        if (operationList != null && !operationList.isEmpty()){
324
            for (AbstractPostOperation<TermNode> operation: operationList){
325
                AbstractUtility.executeOperation(operation, sync);
326
            }
327
            operationList.clear();
328
        }
329

    
330
        CdmStore.getService(ITermNodeService.class).saveTermNodeDtoList(listToUpdate);
331
        listToUpdate.clear();
332
        List<TermTreeDto> rootEntities = getRootEntities();
333
        UpdateResult result = CdmStore.getService(ITermTreeService.class).saveOrUpdateTermTreeDtoList(rootEntities);
334
        conversation.commit(true);
335
        this.setDirty(false);
336
        initializeTrees();
337
        this.viewer.setSelection(sel);
338
//        this.viewer.setExpandedElements(expandedElements);
339
	}
340

    
341
    private void initializeTrees() {
342
        Object[] expandedElements = viewer.getExpandedElements();
343
        viewer.getTree().removeAll();
344
        updateTrees();
345
        viewer.setInput(getTrees());
346
        viewer.setExpandedElements(expandedElements);
347
    }
348

    
349
	@PreDestroy
350
	public void dispose(){
351
	    selService.setSelection(null);
352
	    clearSession();
353
	}
354

    
355
    @Override
356
    public ICdmEntitySession getCdmEntitySession() {
357
        return cdmEntitySession;
358
    }
359

    
360
    @Override
361
    public Map<Object, List<String>> getPropertyPathsMap() {
362
        List<String> propertyPaths = Arrays.asList(new String[] {
363
                "children", //$NON-NLS-1$
364
                "term", //$NON-NLS-1$
365
                "termTree", //$NON-NLS-1$
366
        });
367
        Map<Object, List<String>> propertyPathMap = new HashMap<>();
368
        propertyPathMap.put(TermNode.class,propertyPaths);
369
        return propertyPathMap;
370
    }
371

    
372
    @Override
373
    public List<TermTreeDto> getRootEntities() {
374
        return (List<TermTreeDto>) viewer.getInput();
375
    }
376

    
377
    @Override
378
    public void contextAboutToStop(IMemento memento, IProgressMonitor monitor) {
379
    }
380

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

    
392
    @Override
393
    public void contextStart(IMemento memento, IProgressMonitor monitor) {
394
    }
395

    
396
    @Override
397
    public void contextRefresh(IProgressMonitor monitor) {
398
    }
399

    
400
    @Override
401
    public void workbenchShutdown(IMemento memento, IProgressMonitor monitor) {
402
    }
403

    
404
    @Override
405
    public void update(CdmDataChangeMap arg0) {
406
    }
407

    
408
    @Override
409
    public void changed(Object element) {
410
        dirty.setDirty(true);
411
        viewer.refresh();
412
    }
413

    
414
    @Override
415
    public void forceDirty() {
416
        dirty.setDirty(true);
417
    }
418

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

    
434
    @Override
435
    public boolean onComplete() {
436
        return false;
437
    }
438

    
439
    @Override
440
    public TermNodeDto getNodeDtoForUuid(UUID nodeUuid){
441
        return uuidTermMap.get(nodeUuid);
442
    }
443

    
444
    protected void addAllNodesToMap(TermNodeDto root){
445
        if (!uuidTermMap.containsKey(root.getUuid())){
446
            uuidTermMap.put(root.getUuid(), root);
447
            if (root.getTerm() != null){
448
                getTreeDtoForUuid(root.getTree().getUuid()).addTerm(root.getTerm());
449
            }
450
        }
451
        for (TermNodeDto child: root.getChildren()){
452
            uuidTermMap.put(child.getUuid(), child);
453
            if (child.getTerm() != null){
454
                getTreeDtoForUuid(child.getTree().getUuid()).addTerm(child.getTerm());
455
            }
456
            if (child.getChildren() != null && !child.getChildren().isEmpty()){
457
                addAllNodesToMap(child);
458
            }
459
        }
460
    }
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
    }
489

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

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

    
499
    public void removeTree(TermTreeDto tree){
500
        trees.remove(tree.getUuid());
501
     }
502

    
503
    @Override
504
    public TermTreeDto getTreeDtoForUuid(UUID treeUuid){
505
        return trees.get(treeUuid);
506
    }
507

    
508
    @Override
509
    public void setTreeDtoForUuid(TermTreeDto tree){
510
        trees.put(tree.getUuid(), tree);
511
    }
512

    
513
    @Override
514
    public void setNodeDtoForUuid(TermNodeDto node){
515
        this.uuidTermMap.put(node.getUuid(), node);
516
    }
517

    
518
    @Override
519
    public void addOperation(AbstractPostOperation operation) {
520
        if (operation instanceof CreateFeatureTreeOperation){
521
            createOperationList.put(((CreateFeatureTreeOperation)operation).getElementUuid(), (CreateFeatureTreeOperation)operation);
522
        }else{
523
            operationList.add(operation);
524
        }
525
    }
526

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

    
537
    @Override
538
    public TermType getTermType() {
539
        return termType;
540
    }
541
}
(8-8/10)