Project

General

Profile

Download (16.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

    
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.services.EMenuService;
37
import org.eclipse.e4.ui.workbench.modeling.EModelService;
38
import org.eclipse.e4.ui.workbench.modeling.EPartService;
39
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
40
import org.eclipse.jface.util.LocalSelectionTransfer;
41
import org.eclipse.jface.viewers.ISelection;
42
import org.eclipse.jface.viewers.ISelectionChangedListener;
43
import org.eclipse.jface.viewers.IStructuredSelection;
44
import org.eclipse.jface.viewers.StructuredSelection;
45
import org.eclipse.jface.viewers.TreePath;
46
import org.eclipse.jface.viewers.TreeViewer;
47
import org.eclipse.swt.SWT;
48
import org.eclipse.swt.dnd.DND;
49
import org.eclipse.swt.dnd.Transfer;
50
import org.eclipse.swt.layout.FillLayout;
51
import org.eclipse.swt.widgets.Composite;
52
import org.eclipse.swt.widgets.Tree;
53
import org.eclipse.ui.IMemento;
54

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

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

    
101
    private static final String RESTORING_TAXON_NAVIGATOR = Messages.TaxonNavigator_RESTORE;
102

    
103
	private static final String TREE_PATH = "treepath"; //$NON-NLS-1$
104

    
105
	private static final String TREE_PATHS = "treepaths"; //$NON-NLS-1$
106

    
107
	private final int dndOperations = DND.DROP_MOVE;
108

    
109
	private ConversationHolder conversation;
110

    
111
	private ICdmEntitySession cdmEntitySession;
112

    
113
	private IDataChangeBehavior dataChangeBehavior;
114

    
115
	private Root root;
116

    
117
	private TreeViewer viewer;
118

    
119
    @Inject
120
    private ESelectionService selService;
121

    
122
    @Inject
123
    private UISynchronize sync;
124

    
125
    private ISelectionChangedListener selectionChangedListener;
126

    
127
    private UndoContext undoContext;
128

    
129
    @Inject
130
    private MApplication application;
131

    
132
    @Inject
133
    private EModelService modelService;
134

    
135
    @Inject
136
    private EPartService partService;
137

    
138
    private boolean linkWithTaxon = false;
139

    
140
    @Inject
141
    public TaxonNavigatorE4() {
142
	    undoContext = new UndoContext();
143
	    CdmStore.getContextManager().addContextListener(this);
144
    }
145

    
146
	@PostConstruct
147
	private void create(Composite parent, EMenuService menuService){
148
	    FillLayout layout = new FillLayout();
149
	    layout.marginHeight = 0;
150
	    layout.marginWidth = 0;
151
	    layout.type = SWT.VERTICAL;
152

    
153
	    parent.setLayout(layout);
154
	    viewer = new TreeViewer(new Tree(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION));
155
	    viewer.getControl().setLayoutData(LayoutConstants.FILL());
156

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

    
169
        //propagate selection
170
        selectionChangedListener = (event -> selService.setSelection(event.getSelection()));
171
        viewer.addSelectionChangedListener(selectionChangedListener);
172

    
173
        //create context menu
174
        menuService.registerContextMenu(viewer.getControl(), "eu.etaxonomy.taxeditor.navigator.popupmenu.taxonnavigator");
175

    
176
        //add drag'n'drop support
177
        Transfer[] transfers = new Transfer[] {LocalSelectionTransfer.getTransfer()};
178
        viewer.addDragSupport(dndOperations, transfers, new TreeNodeDragListenerE4(viewer));
179
        viewer.addDropSupport(dndOperations, transfers, new TreeNodeDropAdapterE4(this));
180

    
181
        //add toolbar
182
//        MToolBar toolBar = MMenuFactory.INSTANCE.createToolBar();
183
//        MHandledToolItem linkWithEditor = MMenuFactory.INSTANCE.createHandledToolItem();
184
//        linkWithEditor.setIconURI("platform:/plugin/eu.etaxonomy.taxeditor.store/icons/synced.gif");
185
//        Command command = commandService.getCommand("eu.etaxonomy.taxeditor.navigation.command.linkWithTaxon");
186
//        MCommand mCommand = MCommandsFactory.INSTANCE.createCommand();
187
//        mCommand.setElementId(command.getId());
188
//        try {
189
//            mCommand.setCommandName(command.getName());
190
//        } catch (NotDefinedException e) {
191
//            e.printStackTrace();
192
//        }
193
//        linkWithEditor.setCommand(mCommand);
194
//        linkWithEditor.setType(ItemType.CHECK);
195
//        toolBar.getChildren().add(linkWithEditor);
196
//        thisPart.setToolbar(toolBar);
197

    
198
	    init();
199
	}
200

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

    
214
		if (CdmStore.isActive()) {
215

    
216
			// TODO when closing and reopening the taxon navigator
217
			// we do not preserve state. Closing the view, in contrary to
218
			// closing the whole application
219
			// should be handled by the state manager too
220
		    root = new Root(conversation);
221

    
222
			return root;
223
		}
224
		return new EmptyRoot();
225
	}
226

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

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

    
255
    public void setLinkWithTaxon(boolean linkWithTaxon) {
256
        this.linkWithTaxon = linkWithTaxon;
257
    }
258

    
259
    public boolean isLinkWithTaxon() {
260
        return linkWithTaxon;
261
    }
262

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

    
279
	/**
280
     * Refresh this navigators viewer
281
     */
282
    public void refresh(Set<?> objects) {
283
        for(Object obj : objects) {
284
            viewer.refresh(obj);
285
        }
286
    }
287

    
288
	/**
289
	 * Removes all content
290
	 */
291
	public void clear() {
292
	    viewer.setInput(new EmptyRoot());
293
	}
294

    
295
	public void restore(IMemento memento, IProgressMonitor monitor) {
296
	    root = new Root(conversation);
297
		if (memento == null) {
298
		    viewer.setInput(root);
299
			return;
300
		}
301
		int mementoWork = 0;
302
		Set<TreePath> treePaths = new HashSet<TreePath>();
303
		IMemento[] treePathMementos = null;
304

    
305
		IMemento treePathsMemento = memento.getChild(TREE_PATHS);
306

    
307
		if (treePathsMemento != null) {
308
			treePathMementos = treePathsMemento.getChildren(TREE_PATH);
309
			mementoWork = treePathMementos.length;
310
		}
311
		// begin the monitor with steps for all tree paths and steps for
312
		// creating
313
		// conversation s.o., refreshing the tree and setting the paths
314
		IProgressMonitor subProgressMonitor = AbstractUtility
315
				.getSubProgressMonitor(monitor, 1);
316

    
317
		subProgressMonitor.beginTask(RESTORING_TAXON_NAVIGATOR,
318
				1 + mementoWork + 5);
319
		subProgressMonitor.subTask(RESTORING_TAXON_NAVIGATOR);
320
		subProgressMonitor.worked(1);
321

    
322
		conversation = CdmStore.createConversation();
323
		subProgressMonitor.worked(1);
324
		conversation.registerForDataStoreChanges(TaxonNavigatorE4.this);
325
		subProgressMonitor.worked(1);
326
		viewer.setInput(root);
327
		subProgressMonitor.worked(1);
328
		viewer.refresh();
329
		subProgressMonitor.worked(1);
330

    
331
		if (treePathMementos != null && treePathMementos.length > 0) {
332
			for (IMemento treePathMemento : treePathMementos) {
333
				TreePath treePath = createTreePathFromString(treePathMemento
334
						.getID());
335
				if (!subProgressMonitor.isCanceled() && treePath != null) {
336
					treePaths.add(treePath);
337
					subProgressMonitor.worked(1);
338
				}
339
			}
340
		}
341
		if (treePaths.size() > 0) {
342
			TaxonNavigatorE4.this.viewer.setExpandedTreePaths(
343
					treePaths.toArray(new TreePath[0]));
344
			subProgressMonitor.worked(1);
345
		}
346
		subProgressMonitor.done();
347
	}
348

    
349
	private TreePath createTreePathFromString(String string) {
350

    
351
		List<CdmBase> pathList = new ArrayList<CdmBase>();
352

    
353
		if (string.length() == 0) {
354
            return null;
355
        }
356

    
357
		for (String uuid : string.split(" ")) { //$NON-NLS-1$
358
			CdmBase cdmBaseObject = CdmStore.getService(
359
					IClassificationService.class).getTaxonNodeByUuid(
360
					UUID.fromString(uuid));
361
			if (cdmBaseObject == null) {
362
				// is this a tree uuid?
363
				cdmBaseObject = CdmStore.getService(
364
						IClassificationService.class).load(
365
						UUID.fromString(uuid));
366

    
367
				if (cdmBaseObject == null) {
368
                    return null;
369
                }
370
			}
371
			pathList.add(cdmBaseObject);
372
		}
373
		return new TreePath(pathList.toArray());
374
	}
375

    
376
	/**
377
	 * {@inheritDoc}
378
	 */
379
	@Override
380
	public void collapse() {
381
	    viewer.collapseAll();
382
	}
383

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

    
392
	@Override
393
	public ConversationHolder getConversationHolder() {
394
		return conversation;
395
	}
396

    
397
	/** {@inheritDoc} */
398
	@PreDestroy
399
	public void dispose() {
400
		dataChangeBehavior = null;
401
		if (conversation != null) {
402
			conversation.unregisterForDataStoreChanges(this);
403
		}
404
		if(cdmEntitySession != null) {
405
		    cdmEntitySession.dispose();
406
		}
407
		if(CdmApplicationState.getCurrentDataChangeService() != null) {
408
		    CdmApplicationState.getCurrentDataChangeService().unregister(this);
409
		}
410
	}
411

    
412
	/** {@inheritDoc} */
413
	@Focus
414
	public void setFocus() {
415
		if (getConversationHolder() != null) {
416
			getConversationHolder().bind();
417
		}
418
		if(cdmEntitySession != null) {
419
		    cdmEntitySession.bind();
420
		}
421
	}
422

    
423
    public UISynchronize getSync() {
424
        return sync;
425
    }
426

    
427
    public TreeViewer getViewer() {
428
        return viewer;
429
    }
430

    
431
    public UndoContext getUndoContext() {
432
        return undoContext;
433
    }
434

    
435
	/** {@inheritDoc} */
436
	@Override
437
	public boolean postOperation(CdmBase objectAffectedByOperation) {
438
	    viewer.refresh();
439
		return true;
440
	}
441

    
442
	@Override
443
	public boolean onComplete() {
444
		return true;
445
	}
446

    
447
	@Override
448
	public void update(Observable o, Object arg) {
449
		if(o instanceof LoginManager){
450
			refresh();
451
		}
452
	}
453
	   /** {@inheritDoc} */
454
    @Override
455
    public void update(CdmDataChangeMap changeEvents) {
456
        if (dataChangeBehavior == null) {
457
            dataChangeBehavior = new TaxonNavigatorDataChangeBehaviorE4(this);
458
        }
459

    
460
        DataChangeBridge.handleDataChange(changeEvents, dataChangeBehavior);
461
    }
462

    
463
    @Override
464
    public ICdmEntitySession getCdmEntitySession() {
465
       return cdmEntitySession;
466
    }
467

    
468
    @Override
469
    public List<ITreeNode> getRootEntities() {
470
        if(root != null) {
471
            return root.getParentBeans();
472
        }
473
        return null;
474
    }
475

    
476
    @Override
477
    public void onChange(CdmChangeEvent event) {
478
        refresh();
479
        for(CdmBase cb : event.getChangedObjects()) {
480
        	if(cb instanceof TaxonNode) {
481
                TaxonNode tn = (TaxonNode)cb;
482
                if(tn.getTaxon() == null) {
483
                    viewer.refresh(tn.getClassification());
484
                } else {
485
                    viewer.refresh(cb);
486
                }
487
            } else if (cb instanceof Classification) {
488
                viewer.refresh();
489
            }
490
        }
491
    }
492

    
493
    @Override
494
    public Map<Object, List<String>> getPropertyPathsMap() {
495
        Map<Object, List<String>> propertyPathsMap = new HashMap<Object, List<String>>();
496
        List<String> taxonNodePropertyPaths = Arrays.asList(new String[] {
497
                "taxon.name" //$NON-NLS-1$
498
        });
499
         propertyPathsMap.put("childNodes", taxonNodePropertyPaths); //$NON-NLS-1$
500
        return propertyPathsMap;
501
    }
502

    
503
    /**
504
     * {@inheritDoc}
505
     */
506
    @Override
507
    public void contextAboutToStop(IMemento memento, IProgressMonitor monitor) {
508
        // TODO Auto-generated method stub
509

    
510
    }
511

    
512
    /**
513
     * {@inheritDoc}
514
     */
515
    @Override
516
    public void contextStop(IMemento memento, IProgressMonitor monitor) {
517
    }
518

    
519
    /**
520
     * {@inheritDoc}
521
     */
522
    @Override
523
    public void contextStart(IMemento memento, IProgressMonitor monitor) {
524
        if(viewer!=null && viewer.getControl()!=null && !viewer.getControl().isDisposed()){
525
            init();
526
        }
527
    }
528

    
529
    /**
530
     * {@inheritDoc}
531
     */
532
    @Override
533
    public void contextRefresh(IProgressMonitor monitor) {
534
    }
535

    
536
    /**
537
     * {@inheritDoc}
538
     */
539
    @Override
540
    public void workbenchShutdown(IMemento memento, IProgressMonitor monitor) {
541
    }
542
}
(3-3/6)