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.commands.ECommandService;
32
import org.eclipse.e4.core.di.annotations.Optional;
33
import org.eclipse.e4.ui.di.Focus;
34
import org.eclipse.e4.ui.di.UIEventTopic;
35
import org.eclipse.e4.ui.di.UISynchronize;
36
import org.eclipse.e4.ui.model.application.MApplication;
37
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
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.ISelection;
44
import org.eclipse.jface.viewers.ISelectionChangedListener;
45
import org.eclipse.jface.viewers.IStructuredSelection;
46
import org.eclipse.jface.viewers.StructuredSelection;
47
import org.eclipse.jface.viewers.TreePath;
48
import org.eclipse.jface.viewers.TreeViewer;
49
import org.eclipse.swt.SWT;
50
import org.eclipse.swt.dnd.DND;
51
import org.eclipse.swt.dnd.Transfer;
52
import org.eclipse.swt.layout.FillLayout;
53
import org.eclipse.swt.widgets.Composite;
54
import org.eclipse.ui.IMemento;
55

    
56
import eu.etaxonomy.cdm.api.application.CdmApplicationState;
57
import eu.etaxonomy.cdm.api.application.CdmChangeEvent;
58
import eu.etaxonomy.cdm.api.application.ICdmChangeListener;
59
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
60
import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
61
import eu.etaxonomy.cdm.api.service.IClassificationService;
62
import eu.etaxonomy.cdm.model.common.CdmBase;
63
import eu.etaxonomy.cdm.model.common.ICdmBase;
64
import eu.etaxonomy.cdm.model.common.ITreeNode;
65
import eu.etaxonomy.cdm.model.taxon.Classification;
66
import eu.etaxonomy.cdm.model.taxon.TaxonNaturalComparator;
67
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
68
import eu.etaxonomy.cdm.model.taxon.TaxonNodeByNameComparator;
69
import eu.etaxonomy.cdm.model.taxon.TaxonNodeByRankAndNameComparator;
70
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
71
import eu.etaxonomy.taxeditor.editor.ITaxonEditor;
72
import eu.etaxonomy.taxeditor.event.WorkbenchEventConstants;
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 MPart thisPart;
131

    
132
    @Inject
133
    private MApplication application;
134

    
135
    @Inject
136
    private EModelService modelService;
137

    
138
    @Inject
139
    private EPartService partService;
140

    
141
    private boolean linkWithTaxon = false;
142

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

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

    
156
	    parent.setLayout(layout);
157
	    viewer = new TreeViewer(parent);
158
	    viewer.getControl().setLayoutData(LayoutConstants.FILL());
159

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

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

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

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

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

    
201
	    init();
202
	}
203

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

    
217
		if (CdmStore.isActive()) {
218

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

    
225
			return root;
226
		}
227
		return new EmptyRoot();
228
	}
229

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

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

    
258
    public void setLinkWithTaxon(boolean linkWithTaxon) {
259
        this.linkWithTaxon = linkWithTaxon;
260
    }
261

    
262
    public boolean isLinkWithTaxon() {
263
        return linkWithTaxon;
264
    }
265

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

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

    
291
	/**
292
	 * Removes all content
293
	 */
294
	public void clear() {
295
	    viewer.setInput(new EmptyRoot());
296
	}
297

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

    
308
		IMemento treePathsMemento = memento.getChild(TREE_PATHS);
309

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

    
320
		subProgressMonitor.beginTask(RESTORING_TAXON_NAVIGATOR,
321
				1 + mementoWork + 5);
322
		subProgressMonitor.subTask(RESTORING_TAXON_NAVIGATOR);
323
		subProgressMonitor.worked(1);
324

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

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

    
352
	private TreePath createTreePathFromString(String string) {
353

    
354
		List<CdmBase> pathList = new ArrayList<CdmBase>();
355

    
356
		if (string.length() == 0) {
357
            return null;
358
        }
359

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

    
370
				if (cdmBaseObject == null) {
371
                    return null;
372
                }
373
			}
374
			pathList.add(cdmBaseObject);
375
		}
376
		return new TreePath(pathList.toArray());
377
	}
378

    
379
	/**
380
	 * {@inheritDoc}
381
	 */
382
	@Override
383
	public void collapse() {
384
	    viewer.collapseAll();
385
	}
386

    
387
	/**
388
	 * {@inheritDoc}
389
	 */
390
	@Override
391
	public void expand() {
392
	    viewer.expandAll();
393
	}
394

    
395
	@Override
396
	public ConversationHolder getConversationHolder() {
397
		return conversation;
398
	}
399

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

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

    
426
    public UISynchronize getSync() {
427
        return sync;
428
    }
429

    
430
    public TreeViewer getViewer() {
431
        return viewer;
432
    }
433

    
434
    public UndoContext getUndoContext() {
435
        return undoContext;
436
    }
437

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

    
445
	@Override
446
	public boolean onComplete() {
447
		return true;
448
	}
449

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

    
463
        DataChangeBridge.handleDataChange(changeEvents, dataChangeBehavior);
464
    }
465

    
466
    @Override
467
    public ICdmEntitySession getCdmEntitySession() {
468
       return cdmEntitySession;
469
    }
470

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

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

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

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

    
513
    }
514

    
515
    /**
516
     * {@inheritDoc}
517
     */
518
    @Override
519
    public void contextStop(IMemento memento, IProgressMonitor monitor) {
520
    }
521

    
522
    /**
523
     * {@inheritDoc}
524
     */
525
    @Override
526
    public void contextStart(IMemento memento, IProgressMonitor monitor) {
527
        if(viewer!=null){
528
            init();
529
        }
530
    }
531

    
532
    /**
533
     * {@inheritDoc}
534
     */
535
    @Override
536
    public void contextRefresh(IProgressMonitor monitor) {
537
    }
538

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