Project

General

Profile

Download (16.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.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.AppModelId;
81
import eu.etaxonomy.taxeditor.navigation.NavigationUtil;
82
import eu.etaxonomy.taxeditor.navigation.l10n.Messages;
83
import eu.etaxonomy.taxeditor.navigation.navigator.EmptyRoot;
84
import eu.etaxonomy.taxeditor.navigation.navigator.Root;
85
import eu.etaxonomy.taxeditor.navigation.navigator.TaxonNodeNavigatorComparator;
86
import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
87
import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
88
import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
89
import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
90
import eu.etaxonomy.taxeditor.store.CdmStore;
91
import eu.etaxonomy.taxeditor.store.LoginManager;
92
import eu.etaxonomy.taxeditor.ui.element.LayoutConstants;
93
import eu.etaxonomy.taxeditor.workbench.part.ICollapsableExpandable;
94

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

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

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

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

    
112
	private final int dndOperations = DND.DROP_MOVE;
113

    
114
	private ConversationHolder conversation;
115

    
116
	private ICdmEntitySession cdmEntitySession;
117

    
118
	private IDataChangeBehavior dataChangeBehavior;
119

    
120
	private Root root;
121

    
122
	private TreeViewer viewer;
123

    
124
    @Inject
125
    private ESelectionService selService;
126

    
127
    @Inject
128
    private UISynchronize sync;
129

    
130
    private ISelectionChangedListener selectionChangedListener;
131

    
132
    private UndoContext undoContext;
133

    
134
    @Inject
135
    private MApplication application;
136

    
137
    @Inject
138
    private EModelService modelService;
139

    
140
    @Inject
141
    private EPartService partService;
142

    
143
    private boolean linkWithTaxon = false;
144

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

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

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

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

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

    
178
        //create context menu
179
        menuService.registerContextMenu(viewer.getControl(), AppModelId.POPUPMENU_EU_ETAXONOMY_TAXEDITOR_NAVIGATOR_POPUPMENU_TAXONNAVIGATOR );
180

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

    
186
        updateSyncButton();
187

    
188

    
189

    
190
	    init();
191
	}
192

    
193
    protected void updateSyncButton() {
194
        MPart viewPart = partService.findPart(AppModelId.PARTDESCRIPTOR_EU_ETAXONOMY_TAXEDITOR_NAVIGATION_NAVIGATOR);
195

    
196
        MToolBar toolBar = viewPart.getToolbar();
197

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

    
200

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

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

    
220
		if (CdmStore.isActive()) {
221

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
357
	private TreePath createTreePathFromString(String string) {
358

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
475
    }
476

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

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

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

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

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

    
525
    }
526

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

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

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

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

    
558
    @Inject
559
    @Optional
560
    private void updateView(@UIEventTopic(WorkbenchEventConstants.REFRESH_NAVIGATOR)boolean refresh){
561
        if(refresh){
562
            refresh();
563
        }
564
    }
565
}
(3-3/6)