Project

General

Profile

Download (16.4 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.navigation.navigator.e4;
11

    
12
import java.util.ArrayList;
13
import java.util.Arrays;
14
import java.util.Comparator;
15
import java.util.HashMap;
16
import java.util.HashSet;
17
import java.util.List;
18
import java.util.Map;
19
import java.util.Observable;
20
import java.util.Observer;
21
import java.util.Set;
22
import java.util.UUID;
23

    
24
import javax.annotation.PostConstruct;
25
import javax.annotation.PreDestroy;
26
import javax.inject.Inject;
27

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

    
59
import eu.etaxonomy.cdm.api.application.CdmApplicationState;
60
import eu.etaxonomy.cdm.api.application.CdmChangeEvent;
61
import eu.etaxonomy.cdm.api.application.ICdmChangeListener;
62
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
63
import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
64
import eu.etaxonomy.cdm.api.service.IClassificationService;
65
import eu.etaxonomy.cdm.model.common.CdmBase;
66
import eu.etaxonomy.cdm.model.common.ICdmBase;
67
import eu.etaxonomy.cdm.model.common.ITreeNode;
68
import eu.etaxonomy.cdm.model.taxon.Classification;
69
import eu.etaxonomy.cdm.model.taxon.TaxonNaturalComparator;
70
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
71
import eu.etaxonomy.cdm.model.taxon.TaxonNodeByNameComparator;
72
import eu.etaxonomy.cdm.model.taxon.TaxonNodeByRankAndNameComparator;
73
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
74
import eu.etaxonomy.taxeditor.editor.ITaxonEditor;
75
import eu.etaxonomy.taxeditor.event.WorkbenchEventConstants;
76
import eu.etaxonomy.taxeditor.model.AbstractUtility;
77
import eu.etaxonomy.taxeditor.model.DataChangeBridge;
78
import eu.etaxonomy.taxeditor.model.IContextListener;
79
import eu.etaxonomy.taxeditor.model.IDataChangeBehavior;
80
import eu.etaxonomy.taxeditor.navigation.NavigationUtil;
81
import eu.etaxonomy.taxeditor.navigation.l10n.Messages;
82
import eu.etaxonomy.taxeditor.navigation.navigator.EmptyRoot;
83
import eu.etaxonomy.taxeditor.navigation.navigator.Root;
84
import eu.etaxonomy.taxeditor.navigation.navigator.TaxonNodeNavigatorComparator;
85
import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
86
import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
87
import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
88
import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
89
import eu.etaxonomy.taxeditor.store.CdmStore;
90
import eu.etaxonomy.taxeditor.store.LoginManager;
91
import eu.etaxonomy.taxeditor.ui.element.LayoutConstants;
92
import eu.etaxonomy.taxeditor.workbench.part.ICollapsableExpandable;
93

    
94
/**
95
 *
96
 * @author pplitzner
97
 * @since Sep 7, 2017
98
 *
99
 */
100
public class TaxonNavigatorE4 implements
101
		IPostOperationEnabled, IConversationEnabled, Observer,
102
		ICdmEntitySessionEnabled, ICdmChangeListener, IContextListener,
103
		ICollapsableExpandable {
104

    
105
    private static final String RESTORING_TAXON_NAVIGATOR = Messages.TaxonNavigator_RESTORE;
106

    
107
	private static final String TREE_PATH = "treepath"; //$NON-NLS-1$
108

    
109
	private static final String TREE_PATHS = "treepaths"; //$NON-NLS-1$
110

    
111
	private final int dndOperations = DND.DROP_MOVE;
112

    
113
	private ConversationHolder conversation;
114

    
115
	private ICdmEntitySession cdmEntitySession;
116

    
117
	private IDataChangeBehavior dataChangeBehavior;
118

    
119
	private Root root;
120

    
121
	private TreeViewer viewer;
122

    
123
    @Inject
124
    private ESelectionService selService;
125

    
126
    @Inject
127
    private UISynchronize sync;
128

    
129
    private ISelectionChangedListener selectionChangedListener;
130

    
131
    private UndoContext undoContext;
132

    
133
    @Inject
134
    private MApplication application;
135

    
136
    @Inject
137
    private EModelService modelService;
138

    
139
    @Inject
140
    private EPartService partService;
141

    
142
    private boolean linkWithTaxon = false;
143

    
144
    @Inject
145
    public TaxonNavigatorE4() {
146
	    undoContext = new UndoContext();
147
	    CdmStore.getContextManager().addContextListener(this);
148
    }
149

    
150
	@PostConstruct
151
	private void create(Composite parent, EMenuService menuService){
152
	    FillLayout layout = new FillLayout();
153
	    layout.marginHeight = 0;
154
	    layout.marginWidth = 0;
155
	    layout.type = SWT.VERTICAL;
156

    
157
	    parent.setLayout(layout);
158
	    viewer = new TreeViewer(new Tree(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.MULTI));
159
	    viewer.getControl().setLayoutData(LayoutConstants.FILL());
160

    
161
	    viewer.setContentProvider(new TaxonNavigatorContentProviderE4());
162
        viewer.setLabelProvider(new TaxonNavigatorLabelProviderE4());
163
        viewer.addDoubleClickListener(event->{
164
            ISelection selection = event.getSelection();
165
            if(selection instanceof IStructuredSelection){
166
                Object firstElement = ((IStructuredSelection) selection).getFirstElement();
167
                if(firstElement instanceof ICdmBase){
168
                    NavigationUtil.openEditor((ICdmBase) firstElement, viewer.getControl().getShell(), modelService, partService, application);
169
                }
170
            }
171
        });
172

    
173
        //propagate selection
174
        selectionChangedListener = (event -> selService.setSelection(event.getSelection()));
175
        viewer.addSelectionChangedListener(selectionChangedListener);
176

    
177
        //create context menu
178
        menuService.registerContextMenu(viewer.getControl(), "eu.etaxonomy.taxeditor.navigator.popupmenu.taxonnavigator");
179

    
180
        //add drag'n'drop support
181
        Transfer[] transfers = new Transfer[] {LocalSelectionTransfer.getTransfer()};
182
        viewer.addDragSupport(dndOperations, transfers, new TreeNodeDragListenerE4(viewer));
183
        viewer.addDropSupport(dndOperations, transfers, new TreeNodeDropAdapterE4(this));
184

    
185
        updateSyncButton();
186

    
187

    
188

    
189
	    init();
190
	}
191

    
192
    protected void updateSyncButton() {
193
        MPart viewPart = partService.findPart("eu.etaxonomy.taxeditor.navigation.navigator");
194

    
195
        MToolBar toolBar = viewPart.getToolbar();
196

    
197
        List<MToolBarElement> toolBarElements = toolBar.getChildren();
198

    
199

    
200
        MToolBarElement upperHandledMenuItem = toolBarElements.get(1);
201
        if (upperHandledMenuItem instanceof HandledToolItemImpl){
202
            ((HandledToolItemImpl)upperHandledMenuItem).setSelected(linkWithTaxon);
203
        }
204
    }
205

    
206
	/** {@inheritDoc} */
207
	protected IAdaptable getInitialInput() {
208
		Comparator<TaxonNode> comparator;
209
		if (PreferencesUtil.getSortNodesNaturally()){
210
			comparator = new TaxonNaturalComparator();
211
		} else if (PreferencesUtil.getSortNodesStrictlyAlphabetically()){
212
			comparator = new TaxonNodeByNameComparator();
213
		}else {
214
			comparator = new TaxonNodeByRankAndNameComparator();
215
		}
216
		TaxonNodeNavigatorComparator viewerComparator = new TaxonNodeNavigatorComparator(comparator);
217
		viewer.setComparator(viewerComparator);
218

    
219
		if (CdmStore.isActive()) {
220

    
221
			// TODO when closing and reopening the taxon navigator
222
			// we do not preserve state. Closing the view, in contrary to
223
			// closing the whole application
224
			// should be handled by the state manager too
225
		    root = new Root(conversation);
226

    
227
			return root;
228
		}
229
		return new EmptyRoot();
230
	}
231

    
232
	public void init() {
233
		if (CdmStore.isActive() && conversation == null) {
234
			conversation = CdmStore.createConversation();
235
			conversation.registerForDataStoreChanges(TaxonNavigatorE4.this);
236
		}
237
		if (CdmStore.isActive()) {
238
		    cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
239
		    CdmApplicationState.getCurrentDataChangeService().register(this);
240
		}
241
		CdmStore.getLoginManager().addObserver(this);
242
        viewer.setInput(getInitialInput());
243
	}
244

    
245
	//Link with taxon selection
246
	@Inject
247
	@Optional
248
	public void updateCurrentTaxon(@UIEventTopic(WorkbenchEventConstants.CURRENT_ACTIVE_EDITOR)ITaxonEditor editor){
249
	    if(linkWithTaxon && editor!=null){
250
	        viewer.refresh();
251
	        TaxonNode taxonNode = null;
252
	        if(editor.getTaxon()!=null && editor.getTaxon().getTaxonNodes()!=null){
253
	            taxonNode = editor.getTaxon().getTaxonNodes().iterator().next();
254
	            viewer.reveal(taxonNode);
255
	            viewer.setSelection(new StructuredSelection(taxonNode));
256
	        }
257
	    }
258
	}
259

    
260
    public void setLinkWithTaxon(boolean linkWithTaxon) {
261
        this.linkWithTaxon = linkWithTaxon;
262
    }
263

    
264
    public boolean isLinkWithTaxon() {
265
        return linkWithTaxon;
266
    }
267

    
268
	/**
269
	 * Refresh this navigators viewer
270
	 */
271
	public void refresh() {
272
		if(getConversationHolder() != null){
273
			getConversationHolder().bind();
274
			//FIXME : Need to make sure this is a stable fix (ticket 3822)
275
			if(!getConversationHolder().isCompleted()){
276
			    getConversationHolder().commit();
277
			}
278
		}
279
		if(!viewer.getTree().isDisposed()){
280
		    viewer.refresh();
281
		}
282
		updateSyncButton();
283
	}
284

    
285
	/**
286
     * Refresh this navigators viewer
287
     */
288
    public void refresh(Set<?> objects) {
289
        for(Object obj : objects) {
290
            viewer.refresh(obj);
291
        }
292
        updateSyncButton();
293
    }
294

    
295
	/**
296
	 * Removes all content
297
	 */
298
	public void clear() {
299
	    viewer.setInput(new EmptyRoot());
300
	}
301

    
302
	private void restore(IMemento memento, IProgressMonitor monitor) {
303
	    root = new Root(conversation);
304
		if (memento == null) {
305
		    viewer.setInput(root);
306
			return;
307
		}
308
		int mementoWork = 0;
309
		Set<TreePath> treePaths = new HashSet<TreePath>();
310
		IMemento[] treePathMementos = null;
311

    
312
		IMemento treePathsMemento = memento.getChild(TREE_PATHS);
313

    
314
		if (treePathsMemento != null) {
315
			treePathMementos = treePathsMemento.getChildren(TREE_PATH);
316
			mementoWork = treePathMementos.length;
317
		}
318
		// begin the monitor with steps for all tree paths and steps for
319
		// creating
320
		// conversation s.o., refreshing the tree and setting the paths
321
		IProgressMonitor subProgressMonitor = AbstractUtility
322
				.getSubProgressMonitor(monitor, 1);
323

    
324
		subProgressMonitor.beginTask(RESTORING_TAXON_NAVIGATOR,
325
				1 + mementoWork + 5);
326
		subProgressMonitor.subTask(RESTORING_TAXON_NAVIGATOR);
327
		subProgressMonitor.worked(1);
328

    
329
		conversation = CdmStore.createConversation();
330
		subProgressMonitor.worked(1);
331
		conversation.registerForDataStoreChanges(TaxonNavigatorE4.this);
332
		subProgressMonitor.worked(1);
333
		viewer.setInput(root);
334
		subProgressMonitor.worked(1);
335
		viewer.refresh();
336
		subProgressMonitor.worked(1);
337

    
338
		if (treePathMementos != null && treePathMementos.length > 0) {
339
			for (IMemento treePathMemento : treePathMementos) {
340
				TreePath treePath = createTreePathFromString(treePathMemento
341
						.getID());
342
				if (!subProgressMonitor.isCanceled() && treePath != null) {
343
					treePaths.add(treePath);
344
					subProgressMonitor.worked(1);
345
				}
346
			}
347
		}
348
		if (treePaths.size() > 0) {
349
			TaxonNavigatorE4.this.viewer.setExpandedTreePaths(
350
					treePaths.toArray(new TreePath[0]));
351
			subProgressMonitor.worked(1);
352
		}
353
		subProgressMonitor.done();
354
	}
355

    
356
	private TreePath createTreePathFromString(String string) {
357

    
358
		List<CdmBase> pathList = new ArrayList<CdmBase>();
359

    
360
		if (string.length() == 0) {
361
            return null;
362
        }
363

    
364
		for (String uuid : string.split(" ")) { //$NON-NLS-1$
365
			CdmBase cdmBaseObject = CdmStore.getService(
366
					IClassificationService.class).getTaxonNodeByUuid(
367
					UUID.fromString(uuid));
368
			if (cdmBaseObject == null) {
369
				// is this a tree uuid?
370
				cdmBaseObject = CdmStore.getService(
371
						IClassificationService.class).load(
372
						UUID.fromString(uuid));
373

    
374
				if (cdmBaseObject == null) {
375
                    return null;
376
                }
377
			}
378
			pathList.add(cdmBaseObject);
379
		}
380
		return new TreePath(pathList.toArray());
381
	}
382

    
383
	/**
384
	 * {@inheritDoc}
385
	 */
386
	@Override
387
	public void collapse() {
388
	    viewer.collapseAll();
389
	}
390

    
391
	/**
392
	 * {@inheritDoc}
393
	 */
394
	@Override
395
	public void expand() {
396
	    viewer.expandAll();
397
	}
398

    
399
	@Override
400
	public ConversationHolder getConversationHolder() {
401
		return conversation;
402
	}
403

    
404
	/** {@inheritDoc} */
405
	@PreDestroy
406
	public void dispose() {
407
		dataChangeBehavior = null;
408
		if (conversation != null) {
409
			conversation.unregisterForDataStoreChanges(this);
410
			conversation.close();
411
		}
412
		if(cdmEntitySession != null) {
413
		    cdmEntitySession.dispose();
414
		    cdmEntitySession = null;
415
		}
416
		if(CdmApplicationState.getCurrentDataChangeService() != null) {
417
		    CdmApplicationState.getCurrentDataChangeService().unregister(this);
418
		}
419
	}
420

    
421
	/** {@inheritDoc} */
422
	@Focus
423
	public void setFocus() {
424
		if (getConversationHolder() != null) {
425
			getConversationHolder().bind();
426
		}
427
		if(cdmEntitySession != null) {
428
		    cdmEntitySession.bind();
429
		}
430
	}
431

    
432
    public UISynchronize getSync() {
433
        return sync;
434
    }
435

    
436
    public TreeViewer getViewer() {
437
        return viewer;
438
    }
439

    
440
    public UndoContext getUndoContext() {
441
        return undoContext;
442
    }
443

    
444
	/** {@inheritDoc} */
445
	@Override
446
	public boolean postOperation(CdmBase objectAffectedByOperation) {
447
	    viewer.refresh();
448
		return true;
449
	}
450

    
451
	@Override
452
	public boolean onComplete() {
453
		return true;
454
	}
455

    
456
	@Override
457
	public void update(Observable o, Object arg) {
458
		if(o instanceof LoginManager){
459
			refresh();
460
			updateSyncButton();
461
		}
462

    
463
	}
464
	   /** {@inheritDoc} */
465
    @Override
466
    public void update(CdmDataChangeMap changeEvents) {
467
        if (dataChangeBehavior == null) {
468
            dataChangeBehavior = new TaxonNavigatorDataChangeBehaviorE4(this);
469
        }
470

    
471
        DataChangeBridge.handleDataChange(changeEvents, dataChangeBehavior);
472
        updateSyncButton();
473

    
474
    }
475

    
476
    @Override
477
    public ICdmEntitySession getCdmEntitySession() {
478
       return cdmEntitySession;
479
    }
480

    
481
    @Override
482
    public List<ITreeNode> getRootEntities() {
483
        if(root != null) {
484
            return root.getParentBeans();
485
        }
486
        return null;
487
    }
488

    
489
    @Override
490
    public void onChange(CdmChangeEvent event) {
491
        refresh();
492
        for(CdmBase cb : event.getChangedObjects()) {
493
        	if(cb instanceof TaxonNode) {
494
                TaxonNode tn = (TaxonNode)cb;
495
                if(tn.getTaxon() == null) {
496
                    viewer.refresh(tn.getClassification());
497
                } else {
498
                    viewer.refresh(cb);
499
                }
500
            } else if (cb instanceof Classification) {
501
                viewer.refresh();
502
            }
503
        }
504
        updateSyncButton();
505
    }
506

    
507
    @Override
508
    public Map<Object, List<String>> getPropertyPathsMap() {
509
        Map<Object, List<String>> propertyPathsMap = new HashMap<Object, List<String>>();
510
        List<String> taxonNodePropertyPaths = Arrays.asList(new String[] {
511
                "taxon.name" //$NON-NLS-1$
512
        });
513
         propertyPathsMap.put("childNodes", taxonNodePropertyPaths); //$NON-NLS-1$
514
        return propertyPathsMap;
515
    }
516

    
517
    /**
518
     * {@inheritDoc}
519
     */
520
    @Override
521
    public void contextAboutToStop(IMemento memento, IProgressMonitor monitor) {
522
        // TODO Auto-generated method stub
523

    
524
    }
525

    
526
    /**
527
     * {@inheritDoc}
528
     */
529
    @Override
530
    public void contextStop(IMemento memento, IProgressMonitor monitor) {
531
    }
532

    
533
    /**
534
     * {@inheritDoc}
535
     */
536
    @Override
537
    public void contextStart(IMemento memento, IProgressMonitor monitor) {
538
        if(viewer!=null && viewer.getControl()!=null && !viewer.getControl().isDisposed()){
539
            init();
540
        }
541
    }
542

    
543
    /**
544
     * {@inheritDoc}
545
     */
546
    @Override
547
    public void contextRefresh(IProgressMonitor monitor) {
548
    }
549

    
550
    /**
551
     * {@inheritDoc}
552
     */
553
    @Override
554
    public void workbenchShutdown(IMemento memento, IProgressMonitor monitor) {
555
    }
556
}
(3-3/6)