Project

General

Profile

Download (18.1 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.navigation.navigator.e4;
10

    
11
import java.util.ArrayList;
12
import java.util.Comparator;
13
import java.util.HashSet;
14
import java.util.List;
15
import java.util.Observable;
16
import java.util.Observer;
17
import java.util.Set;
18
import java.util.UUID;
19

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

    
24
import org.eclipse.core.commands.operations.UndoContext;
25
import org.eclipse.core.runtime.IAdaptable;
26
import org.eclipse.core.runtime.IProgressMonitor;
27
import org.eclipse.e4.core.contexts.ContextInjectionFactory;
28
import org.eclipse.e4.core.contexts.IEclipseContext;
29
import org.eclipse.e4.core.di.annotations.Optional;
30
import org.eclipse.e4.ui.di.Focus;
31
import org.eclipse.e4.ui.di.UIEventTopic;
32
import org.eclipse.e4.ui.di.UISynchronize;
33
import org.eclipse.e4.ui.model.application.MApplication;
34
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
35
import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
36
import org.eclipse.e4.ui.model.application.ui.menu.MToolBarElement;
37
import org.eclipse.e4.ui.model.application.ui.menu.impl.HandledToolItemImpl;
38
import org.eclipse.e4.ui.services.EMenuService;
39
import org.eclipse.e4.ui.workbench.modeling.EModelService;
40
import org.eclipse.e4.ui.workbench.modeling.EPartService;
41
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
42
import org.eclipse.jface.util.LocalSelectionTransfer;
43
import org.eclipse.jface.viewers.IElementComparer;
44
import org.eclipse.jface.viewers.ISelection;
45
import org.eclipse.jface.viewers.ISelectionChangedListener;
46
import org.eclipse.jface.viewers.IStructuredSelection;
47
import org.eclipse.jface.viewers.StructuredSelection;
48
import org.eclipse.jface.viewers.TreePath;
49
import org.eclipse.jface.viewers.TreeViewer;
50
import org.eclipse.swt.SWT;
51
import org.eclipse.swt.dnd.DND;
52
import org.eclipse.swt.dnd.Transfer;
53
import org.eclipse.swt.layout.FillLayout;
54
import org.eclipse.swt.widgets.Composite;
55
import org.eclipse.swt.widgets.Tree;
56
import org.eclipse.ui.IMemento;
57

    
58
import eu.etaxonomy.cdm.api.application.CdmApplicationState;
59
import eu.etaxonomy.cdm.api.application.CdmChangeEvent;
60
import eu.etaxonomy.cdm.api.application.CdmChangeEvent.Action;
61
import eu.etaxonomy.cdm.api.application.ICdmChangeListener;
62
import eu.etaxonomy.cdm.api.service.IClassificationService;
63
import eu.etaxonomy.cdm.api.service.ITaxonNodeService;
64
import eu.etaxonomy.cdm.model.common.CdmBase;
65
import eu.etaxonomy.cdm.model.common.ICdmBase;
66
import eu.etaxonomy.cdm.model.taxon.Classification;
67
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
68
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
69
import eu.etaxonomy.taxeditor.editor.ITaxonEditor;
70
import eu.etaxonomy.taxeditor.editor.name.e4.TaxonEditor;
71
import eu.etaxonomy.taxeditor.event.EventUtility;
72
import eu.etaxonomy.taxeditor.event.WorkbenchEventConstants;
73
import eu.etaxonomy.taxeditor.model.AbstractUtility;
74
import eu.etaxonomy.taxeditor.model.IContextListener;
75
import eu.etaxonomy.taxeditor.model.IDataChangeBehavior;
76
import eu.etaxonomy.taxeditor.navigation.AppModelId;
77
import eu.etaxonomy.taxeditor.navigation.NavigationUtil;
78
import eu.etaxonomy.taxeditor.navigation.l10n.Messages;
79
import eu.etaxonomy.taxeditor.navigation.navigator.EmptyRoot;
80
import eu.etaxonomy.taxeditor.navigation.navigator.Root;
81
import eu.etaxonomy.taxeditor.navigation.navigator.TaxonNodeNavigatorComparator;
82
import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
83
import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
84
import eu.etaxonomy.taxeditor.store.CdmStore;
85
import eu.etaxonomy.taxeditor.store.LoginManager;
86
import eu.etaxonomy.taxeditor.ui.element.LayoutConstants;
87
import eu.etaxonomy.taxeditor.workbench.part.ICollapsableExpandable;
88

    
89
/**
90
 * @author pplitzner
91
 * @since Sep 7, 2017
92
 */
93
public class TaxonNavigatorE4 implements
94
		IPostOperationEnabled, Observer,
95
		ICdmChangeListener, IContextListener,
96
		ICollapsableExpandable {
97

    
98
    private static final String RESTORING_TAXON_NAVIGATOR = Messages.TaxonNavigator_RESTORE;
99

    
100
	private static final String TREE_PATH = "treepath"; //$NON-NLS-1$
101

    
102
	private static final String TREE_PATHS = "treepaths"; //$NON-NLS-1$
103

    
104
	private final int dndOperations = DND.DROP_MOVE;
105

    
106
	private IDataChangeBehavior dataChangeBehavior;
107

    
108
	private Root root;
109

    
110
	private TreeViewer viewer;
111

    
112
    @Inject
113
    private ESelectionService selService;
114

    
115
    @Inject
116
    private UISynchronize sync;
117

    
118
    private ISelectionChangedListener selectionChangedListener;
119

    
120
    private UndoContext undoContext;
121

    
122
    @Inject
123
    private MApplication application;
124

    
125
    @Inject
126
    private EModelService modelService;
127

    
128
    @Inject
129
    private EPartService partService;
130

    
131
    private boolean linkWithTaxon = false;
132

    
133
    @Inject
134
    public TaxonNavigatorE4() {
135
	    undoContext = new UndoContext();
136
	    CdmStore.getContextManager().addContextListener(this);
137
    }
138

    
139
	@PostConstruct
140
	private void create(Composite parent, EMenuService menuService, IEclipseContext context){
141
	    FillLayout layout = new FillLayout();
142
	    layout.marginHeight = 0;
143
	    layout.marginWidth = 0;
144
	    layout.type = SWT.VERTICAL;
145

    
146
	    parent.setLayout(layout);
147
	    viewer = new TreeViewer(new Tree(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.MULTI));
148
	    viewer.getControl().setLayoutData(LayoutConstants.FILL());
149

    
150
	    viewer.setContentProvider(new TaxonNavigatorContentProviderE4());
151
        viewer.setLabelProvider(new TaxonNavigatorLabelProviderE4());
152
        viewer.addDoubleClickListener(event->{
153
            ISelection selection = event.getSelection();
154
            if(selection instanceof IStructuredSelection){
155
                Object firstElement = ((IStructuredSelection) selection).getFirstElement();
156
                if(firstElement instanceof ICdmBase){
157
                    NavigationUtil.openEditor((ICdmBase) firstElement, viewer.getControl().getShell(), modelService, partService, application);
158
                }
159
                if(firstElement instanceof TaxonNodeDto){
160
                    NavigationUtil.openEditor((TaxonNodeDto) firstElement, viewer.getControl().getShell(), modelService, partService, application);
161
                }
162
            }
163
        });
164

    
165
        //propagate selection
166
        selectionChangedListener = (event -> selService.setSelection(event.getSelection()));
167
        viewer.addSelectionChangedListener(selectionChangedListener);
168

    
169
        //create context menu
170
        menuService.registerContextMenu(viewer.getControl(), AppModelId.POPUPMENU_EU_ETAXONOMY_TAXEDITOR_NAVIGATOR_POPUPMENU_TAXONNAVIGATOR );
171

    
172
        //add drag'n'drop support
173
        Transfer[] transfers = new Transfer[] {LocalSelectionTransfer.getTransfer()};
174
        viewer.addDragSupport(dndOperations, transfers, new TreeNodeDragListenerE4(viewer));
175
        TreeNodeDropAdapterE4 dropAdapter = new TreeNodeDropAdapterE4(this);
176
        ContextInjectionFactory.inject(dropAdapter, context);
177
        viewer.addDropSupport(dndOperations, transfers, dropAdapter);
178

    
179
        updateSyncButton();
180

    
181
	    init();
182
	}
183

    
184
    protected void updateSyncButton() {
185
        MPart viewPart = partService.findPart(AppModelId.PARTDESCRIPTOR_EU_ETAXONOMY_TAXEDITOR_NAVIGATION_NAVIGATOR);
186
        if(viewPart!=null){
187
            MToolBar toolBar = viewPart.getToolbar();
188

    
189
            List<MToolBarElement> toolBarElements = toolBar.getChildren();
190

    
191
            MToolBarElement upperHandledMenuItem = toolBarElements.get(1);
192
            if (upperHandledMenuItem instanceof HandledToolItemImpl){
193
                ((HandledToolItemImpl)upperHandledMenuItem).setSelected(linkWithTaxon);
194
            }
195
        }
196
    }
197

    
198
	protected IAdaptable getInitialInput() {
199
		Comparator<TaxonNodeDto> comparator = PreferencesUtil.getNodeComparator();
200

    
201
		TaxonNodeNavigatorComparator viewerComparator = new TaxonNodeNavigatorComparator(comparator);
202
		viewer.setComparator(viewerComparator);
203
		viewer.setComparer(new IElementComparer() {
204

    
205
    	        @Override
206
                public int hashCode(Object element) {
207
    	            if (element instanceof TaxonNodeDto){
208
        	            TaxonNodeDto nodeDto = (TaxonNodeDto)element;
209

    
210
        	            String s = nodeDto.getUuid().toString();
211
        	            if (s != null) {
212
        	                return s.hashCode();
213
        	            }
214
        	            return element.hashCode();
215
    	            }else{
216
    	                return element.toString().hashCode();
217
    	            }
218
    	        }
219

    
220
                @Override
221
                public boolean equals(Object element1, Object element2) {
222
                    if (element1 instanceof TaxonNodeDto && element2 instanceof TaxonNodeDto){
223
                        TaxonNodeDto node1 = (TaxonNodeDto)element1;
224
                        TaxonNodeDto node2 = (TaxonNodeDto)element2;
225
                        return (node1.getUuid().equals(node2.getUuid()));
226
                    }else {
227
                        return element1.equals(element2);
228
                    }
229
                }
230
    		}
231
		);
232

    
233
		if (CdmStore.isActive()) {
234

    
235
			// TODO when closing and reopening the taxon navigator
236
			// we do not preserve state. Closing the view, in contrary to
237
			// closing the whole application
238
			// should be handled by the state manager too
239
		    root = new Root();
240

    
241
			return root;
242
		}
243
		return new EmptyRoot();
244
	}
245

    
246
	public void init() {
247
//		if (CdmStore.isActive() && conversation == null) {
248
//			conversation = CdmStore.createConversation();
249
//			conversation.registerForDataStoreChanges(TaxonNavigatorE4.this);
250
//		}
251
		if (CdmStore.isActive()) {
252
//		    cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
253
		    CdmApplicationState.getCurrentDataChangeService().register(this);
254
		    viewer.setInput(getInitialInput());
255
		}
256
		CdmStore.getLoginManager().addObserver(this);
257

    
258
	}
259

    
260
	//Link with taxon selection
261
	@Inject
262
	@Optional
263
	public void updateCurrentTaxon(@UIEventTopic(WorkbenchEventConstants.CURRENT_ACTIVE_EDITOR)ITaxonEditor editor){
264
	    if(linkWithTaxon && editor!=null){
265
	        viewer.refresh();
266
	        TaxonNodeDto taxonNode = null;
267
	        if(editor.getTaxon()!=null && editor.getTaxon().getTaxonNodes()!=null){
268
	            if (editor instanceof TaxonEditor){
269
	                taxonNode = new TaxonNodeDto( ((TaxonEditor)editor).getEditorInput().getTaxonNode());
270
	            }else{
271
	                if (editor.getTaxon().getTaxonNodes() != null && !editor.getTaxon().getTaxonNodes().isEmpty()){
272
	                    taxonNode = new TaxonNodeDto(editor.getTaxon().getTaxonNodes().iterator().next());
273
	                }
274
	            }
275
                if (taxonNode != null){
276
                    viewer.reveal(taxonNode);
277
                    viewer.setSelection(new StructuredSelection(taxonNode));
278
                }else{
279
                    //TODO: show message in status bar
280
                }
281
	        }
282
	    }
283
	}
284

    
285
	@Inject
286
    @Optional
287
    public void updateLinkWithTaxon(@UIEventTopic(WorkbenchEventConstants.UPDATE_LINK_WITH_TAXON) boolean isDummy){
288
	    this.linkWithTaxon = !linkWithTaxon;
289

    
290
        if(this.isLinkWithTaxon()){
291
            this.updateCurrentTaxon(EventUtility.getTaxonEditor());
292
        }
293
	}
294

    
295
    public void setLinkWithTaxon(boolean linkWithTaxon) {
296
        this.linkWithTaxon = linkWithTaxon;
297
    }
298

    
299
    public boolean isLinkWithTaxon() {
300
        return linkWithTaxon;
301
    }
302

    
303
	/**
304
	 * Refresh this navigators viewer
305
	 */
306
	public void refresh() {
307

    
308
		if(!viewer.getTree().isDisposed()){
309
		    if (CdmStore.isActive()){
310

    
311
		        viewer.setInput(getInitialInput());
312
		    }
313
		    viewer.refresh();
314
		}
315

    
316
		updateSyncButton();
317
	}
318

    
319
	/**
320
     * Refresh this navigators viewer
321
     */
322
    public void refresh(Set<?> objects) {
323
        for(Object obj : objects) {
324
            viewer.refresh(obj);
325
        }
326
        updateSyncButton();
327
    }
328

    
329
    /**
330
     * Refresh this navigators viewer
331
     */
332
    public void refresh(Object object) {
333
        viewer.refresh(object);
334
        updateSyncButton();
335
    }
336

    
337
	/**
338
	 * Removes all content
339
	 */
340
	public void clear() {
341
	    viewer.setInput(new EmptyRoot());
342
	}
343

    
344
	private void restore(IMemento memento, IProgressMonitor monitor) {
345
	    root = new Root();//conversation);
346
		if (memento == null) {
347
		    viewer.setInput(root);
348
			return;
349
		}
350
		int mementoWork = 0;
351
		Set<TreePath> treePaths = new HashSet<>();
352
		IMemento[] treePathMementos = null;
353

    
354
		IMemento treePathsMemento = memento.getChild(TREE_PATHS);
355

    
356
		if (treePathsMemento != null) {
357
			treePathMementos = treePathsMemento.getChildren(TREE_PATH);
358
			mementoWork = treePathMementos.length;
359
		}
360
		// begin the monitor with steps for all tree paths and steps for
361
		// creating
362
		// conversation s.o., refreshing the tree and setting the paths
363
		IProgressMonitor subProgressMonitor = AbstractUtility
364
				.getSubProgressMonitor(monitor, 1);
365

    
366
		subProgressMonitor.beginTask(RESTORING_TAXON_NAVIGATOR,
367
				1 + mementoWork + 5);
368
		subProgressMonitor.subTask(RESTORING_TAXON_NAVIGATOR);
369
		subProgressMonitor.worked(1);
370

    
371
		//conversation = CdmStore.createConversation();
372
		subProgressMonitor.worked(1);
373
		//conversation.registerForDataStoreChanges(TaxonNavigatorE4.this);
374
		subProgressMonitor.worked(1);
375
		viewer.setInput(root);
376
		subProgressMonitor.worked(1);
377
		viewer.refresh();
378
		subProgressMonitor.worked(1);
379

    
380
		if (treePathMementos != null && treePathMementos.length > 0) {
381
			for (IMemento treePathMemento : treePathMementos) {
382
				TreePath treePath = createTreePathFromString(treePathMemento
383
						.getID());
384
				if (!subProgressMonitor.isCanceled() && treePath != null) {
385
					treePaths.add(treePath);
386
					subProgressMonitor.worked(1);
387
				}
388
			}
389
		}
390
		if (treePaths.size() > 0) {
391
			TaxonNavigatorE4.this.viewer.setExpandedTreePaths(
392
					treePaths.toArray(new TreePath[0]));
393
			subProgressMonitor.worked(1);
394
		}
395
		subProgressMonitor.done();
396
	}
397

    
398
	private TreePath createTreePathFromString(String string) {
399

    
400
		List<CdmBase> pathList = new ArrayList<>();
401

    
402
		if (string.length() == 0) {
403
            return null;
404
        }
405

    
406
		for (String uuid : string.split(" ")) { //$NON-NLS-1$
407
			CdmBase cdmBaseObject = CdmStore.getService(
408
					ITaxonNodeService.class).find(
409
					UUID.fromString(uuid));
410
			if (cdmBaseObject == null) {
411
				// is this a tree uuid?
412
				cdmBaseObject = CdmStore.getService(
413
						IClassificationService.class).load(
414
						UUID.fromString(uuid));
415

    
416
				if (cdmBaseObject == null) {
417
                    return null;
418
                }
419
			}
420
			pathList.add(cdmBaseObject);
421
		}
422
		return new TreePath(pathList.toArray());
423
	}
424

    
425
	@Override
426
	public void collapse() {
427
	    viewer.collapseAll();
428
	}
429

    
430
	@Override
431
	public void expand() {
432
	    viewer.expandAll();
433
	}
434

    
435

    
436

    
437
	@PreDestroy
438
	public void dispose() {
439
		if(CdmApplicationState.getCurrentDataChangeService() != null) {
440
		    CdmApplicationState.getCurrentDataChangeService().unregister(this);
441
		}
442
	}
443

    
444
	@Focus
445
	public void setFocus() {
446

    
447
	}
448

    
449
    public UISynchronize getSync() {
450
        return sync;
451
    }
452

    
453
    public TreeViewer getViewer() {
454
        return viewer;
455
    }
456

    
457
    public UndoContext getUndoContext() {
458
        return undoContext;
459
    }
460

    
461
	@Override
462
	public boolean postOperation(Object objectAffectedByOperation) {
463
	    viewer.refresh();
464
		return true;
465
	}
466

    
467
	@Override
468
	public boolean onComplete() {
469
		return true;
470
	}
471

    
472
	@Override
473
	public void update(Observable o, Object arg) {
474
		if(o instanceof LoginManager){
475
			refresh();
476
		}
477
	}
478

    
479
//    @Override
480
//    public void update(CdmDataChangeMap changeEvents) {
481
//        if (dataChangeBehavior == null) {
482
//            dataChangeBehavior = new TaxonNavigatorDataChangeBehaviorE4(this);
483
//        }
484
//
485
//        DataChangeBridge.handleDataChange(changeEvents, dataChangeBehavior);
486
//        updateSyncButton();
487
//
488
//    }
489

    
490
    public List<TaxonNodeDto> getRootEntities() {
491
        if(root != null) {
492
            return root.getParentBeans();
493
        }
494
        return null;
495
    }
496

    
497
    @Override
498
    public void onChange(CdmChangeEvent event) {
499
        Object[] expandedElements = viewer.getExpandedElements();
500
        refresh();
501
        for(CdmBase cb : event.getChangedObjects()) {
502
        	if(cb instanceof TaxonNode) {
503
                TaxonNode tn = (TaxonNode)cb;
504
                if(tn.getTaxon() == null) {
505
                    viewer.refresh(tn.getClassification());
506
                } else {
507
                    viewer.refresh(cb);
508
                }
509
            } else if (cb instanceof Classification) {
510
                if ( event.getAction().equals(Action.Create)){
511
                    root.addRootNode((Classification)cb);
512
                } else if ( event.getAction().equals(Action.Delete)){
513
                    root.removeRootNode((Classification)cb);
514
                }
515
                viewer.refresh();
516
            }
517
        }
518
        viewer.setExpandedElements(expandedElements);
519
    }
520

    
521
    @Override
522
    public void contextAboutToStop(IMemento memento, IProgressMonitor monitor) {
523
        // TODO Auto-generated method stub
524
    }
525

    
526
    @Override
527
    public void contextStop(IMemento memento, IProgressMonitor monitor) {
528
    }
529

    
530
    @Override
531
    public void contextStart(IMemento memento, IProgressMonitor monitor) {
532
        if(viewer!=null && viewer.getControl()!=null && !viewer.getControl().isDisposed()){
533
            init();
534
        }
535
    }
536

    
537
    @Override
538
    public void contextRefresh(IProgressMonitor monitor) {
539
//        viewer.refresh();
540
    }
541

    
542
    @Override
543
    public void workbenchShutdown(IMemento memento, IProgressMonitor monitor) {
544
    }
545

    
546
    @Inject
547
    @Optional
548
    private void updateView(@UIEventTopic(WorkbenchEventConstants.REFRESH_NAVIGATOR)TaxonNodeDto dto){
549
        if(dto!= null){
550
            Object[] expandedElements = viewer.getExpandedElements();
551
            ISelection sel = viewer.getSelection();
552
            refresh(dto);
553
            viewer.setExpandedElements(expandedElements);
554
            if (sel != null && !sel.isEmpty()){
555
                viewer.reveal(dto);
556
                viewer.setSelection(sel);
557
            }
558
        }
559
    }
560

    
561
    @Inject
562
    @Optional
563
    private void updateView(@UIEventTopic(WorkbenchEventConstants.REFRESH_NAVIGATOR)boolean refresh){
564
        if(refresh){
565
            Object[] expandedElements = viewer.getExpandedElements();
566
            refresh();
567
            viewer.setExpandedElements(expandedElements);
568
        }
569
    }
570
}
(2-2/5)