Project

General

Profile

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

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

    
85
/**
86
 *
87
 * @author pplitzner
88
 * @since Sep 7, 2017
89
 *
90
 */
91
public class TaxonNavigatorE4 implements
92
		IPostOperationEnabled, IConversationEnabled, Observer,
93
		ICdmEntitySessionEnabled, ICdmChangeListener, IContextListener {
94

    
95
    private static final String RESTORING_TAXON_NAVIGATOR = Messages.TaxonNavigator_RESTORE;
96

    
97
	private static final String TREE_PATH = "treepath"; //$NON-NLS-1$
98

    
99
	private static final String TREE_PATHS = "treepaths"; //$NON-NLS-1$
100

    
101
	private final int dndOperations = DND.DROP_MOVE;
102

    
103
	private ConversationHolder conversation;
104

    
105
	private ICdmEntitySession cdmEntitySession;
106

    
107
	private IDataChangeBehavior dataChangeBehavior;
108

    
109
	private Root root;
110

    
111
	private TreeViewer viewer;
112

    
113
    @Inject
114
    private ESelectionService selService;
115

    
116
    @Inject
117
    private UISynchronize sync;
118

    
119
    private ISelectionChangedListener selectionChangedListener;
120

    
121
    private UndoContext undoContext;
122

    
123
    @Inject
124
    public TaxonNavigatorE4() {
125
	    undoContext = new UndoContext();
126
	    CdmStore.getContextManager().addContextListener(this);
127
    }
128

    
129
	@PostConstruct
130
	private void create(Composite parent, EMenuService menuService){
131
	    FillLayout layout = new FillLayout();
132
	    layout.marginHeight = 0;
133
	    layout.marginWidth = 0;
134
	    layout.type = SWT.VERTICAL;
135

    
136
	    parent.setLayout(layout);
137
	    viewer = new TreeViewer(parent);
138
	    viewer.getControl().setLayoutData(LayoutConstants.FILL());
139

    
140
	    viewer.setContentProvider(new TaxonNavigatorContentProviderE4());
141
        viewer.setLabelProvider(new TaxonNavigatorLabelProviderE4());
142
        viewer.addDoubleClickListener(event->{
143
            ISelection selection = event.getSelection();
144
            if(selection instanceof IStructuredSelection){
145
                Object firstElement = ((IStructuredSelection) selection).getFirstElement();
146
                if(firstElement instanceof ICdmBase){
147
                    NavigationUtil.openEditor((ICdmBase) firstElement, viewer.getControl().getShell());
148
                }
149
            }
150
        });
151

    
152
        //propagate selection
153
        selectionChangedListener = (event -> selService.setSelection(event.getSelection()));
154
        viewer.addSelectionChangedListener(selectionChangedListener);
155

    
156
        //create context menu
157
        menuService.registerContextMenu(viewer.getControl(), "eu.etaxonomy.taxeditor.navigator.popupmenu.taxonnavigator");
158

    
159
        //add drag'n'drop support
160
        Transfer[] transfers = new Transfer[] {LocalSelectionTransfer.getTransfer()};
161
        viewer.addDragSupport(dndOperations, transfers, new TreeNodeDragListenerE4(viewer));
162
        viewer.addDropSupport(dndOperations, transfers, new TreeNodeDropAdapterE4(this));
163

    
164
	    init();
165
	}
166

    
167
	/** {@inheritDoc} */
168
	protected IAdaptable getInitialInput() {
169
		Comparator<TaxonNode> comparator;
170
		if (PreferencesUtil.getSortNodesNaturally()){
171
			comparator = new TaxonNaturalComparator();
172
		} else if (PreferencesUtil.getSortNodesStrictlyAlphabetically()){
173
			comparator = new TaxonNodeByNameComparator();
174
		}else {
175
			comparator = new TaxonNodeByRankAndNameComparator();
176
		}
177
		TaxonNodeNavigatorComparator viewerComparator = new TaxonNodeNavigatorComparator(comparator);
178
		viewer.setComparator(viewerComparator);
179

    
180
		if (CdmStore.isActive()) {
181

    
182
			// TODO when closing and reopening the taxon navigator
183
			// we do not preserve state. Closing the view, in contrary to
184
			// closing the whole application
185
			// should be handled by the state manager too
186
		    root = new Root(conversation);
187

    
188
			return root;
189
		}
190
		return new EmptyRoot();
191
	}
192

    
193
	public void init() {
194
		if (CdmStore.isActive() && conversation == null) {
195
			conversation = CdmStore.createConversation();
196
			conversation.registerForDataStoreChanges(TaxonNavigatorE4.this);
197
		}
198
		if (CdmStore.isActive()) {
199
		    cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
200
		    CdmApplicationState.getCurrentDataChangeService().register(this);
201
		}
202
		CdmStore.getLoginManager().addObserver(this);
203
        viewer.setInput(getInitialInput());
204
	}
205

    
206
	//Link with taxon selection
207
	@Inject
208
	@Optional
209
	private void updateCurrentTaxon(@UIEventTopic(WorkbenchEventConstants.CURRENT_ACTIVE_EDITOR)ITaxonEditor editor){
210
	    viewer.refresh();
211
	    TaxonNode taxonNode = null;
212
	    if(editor.getTaxon()!=null && editor.getTaxon().getTaxonNodes()!=null){
213
	        taxonNode = editor.getTaxon().getTaxonNodes().iterator().next();
214
	        viewer.reveal(taxonNode);
215
	        viewer.setSelection(null);
216
	        Widget testFindItem = viewer.testFindItem(taxonNode);
217
	        if(testFindItem instanceof TreeItem){
218
	            viewer.getTree().select((TreeItem) testFindItem);
219
	        }
220
	    }
221
	}
222

    
223
	/**
224
	 * Refresh this navigators viewer
225
	 */
226
	public void refresh() {
227
		if(getConversationHolder() != null){
228
			getConversationHolder().bind();
229
			//FIXME : Need to make sure this is a stable fix (ticket 3822)
230
			if(!getConversationHolder().isCompleted()){
231
			    getConversationHolder().commit();
232
			}
233
		}
234
		if(!viewer.getTree().isDisposed()){
235
		    viewer.refresh();
236
		}
237
	}
238

    
239
	/**
240
     * Refresh this navigators viewer
241
     */
242
    public void refresh(Set<?> objects) {
243
        for(Object obj : objects) {
244
            viewer.refresh(obj);
245
        }
246
    }
247

    
248
	/**
249
	 * Removes all content
250
	 */
251
	public void clear() {
252
	    viewer.setInput(new EmptyRoot());
253
	}
254

    
255
	public void restore(IMemento memento, IProgressMonitor monitor) {
256
	    root = new Root(conversation);
257
		if (memento == null) {
258
		    viewer.setInput(root);
259
			return;
260
		}
261
		int mementoWork = 0;
262
		Set<TreePath> treePaths = new HashSet<TreePath>();
263
		IMemento[] treePathMementos = null;
264

    
265
		IMemento treePathsMemento = memento.getChild(TREE_PATHS);
266

    
267
		if (treePathsMemento != null) {
268
			treePathMementos = treePathsMemento.getChildren(TREE_PATH);
269
			mementoWork = treePathMementos.length;
270
		}
271
		// begin the monitor with steps for all tree paths and steps for
272
		// creating
273
		// conversation s.o., refreshing the tree and setting the paths
274
		IProgressMonitor subProgressMonitor = NavigationUtil
275
				.getSubProgressMonitor(monitor, 1);
276

    
277
		subProgressMonitor.beginTask(RESTORING_TAXON_NAVIGATOR,
278
				1 + mementoWork + 5);
279
		subProgressMonitor.subTask(RESTORING_TAXON_NAVIGATOR);
280
		subProgressMonitor.worked(1);
281

    
282
		conversation = CdmStore.createConversation();
283
		subProgressMonitor.worked(1);
284
		conversation.registerForDataStoreChanges(TaxonNavigatorE4.this);
285
		subProgressMonitor.worked(1);
286
		viewer.setInput(root);
287
		subProgressMonitor.worked(1);
288
		viewer.refresh();
289
		subProgressMonitor.worked(1);
290

    
291
		if (treePathMementos != null && treePathMementos.length > 0) {
292
			for (IMemento treePathMemento : treePathMementos) {
293
				TreePath treePath = createTreePathFromString(treePathMemento
294
						.getID());
295
				if (!subProgressMonitor.isCanceled() && treePath != null) {
296
					treePaths.add(treePath);
297
					subProgressMonitor.worked(1);
298
				}
299
			}
300
		}
301
		if (treePaths.size() > 0) {
302
			TaxonNavigatorE4.this.viewer.setExpandedTreePaths(
303
					treePaths.toArray(new TreePath[0]));
304
			subProgressMonitor.worked(1);
305
		}
306
		subProgressMonitor.done();
307
	}
308

    
309
	private TreePath createTreePathFromString(String string) {
310

    
311
		List<CdmBase> pathList = new ArrayList<CdmBase>();
312

    
313
		if (string.length() == 0) {
314
            return null;
315
        }
316

    
317
		for (String uuid : string.split(" ")) { //$NON-NLS-1$
318
			CdmBase cdmBaseObject = CdmStore.getService(
319
					IClassificationService.class).getTaxonNodeByUuid(
320
					UUID.fromString(uuid));
321
			if (cdmBaseObject == null) {
322
				// is this a tree uuid?
323
				cdmBaseObject = CdmStore.getService(
324
						IClassificationService.class).load(
325
						UUID.fromString(uuid));
326

    
327
				if (cdmBaseObject == null) {
328
                    return null;
329
                }
330
			}
331
			pathList.add(cdmBaseObject);
332
		}
333
		return new TreePath(pathList.toArray());
334
	}
335

    
336
	@Override
337
	public ConversationHolder getConversationHolder() {
338
		return conversation;
339
	}
340

    
341
	/** {@inheritDoc} */
342
	@PreDestroy
343
	public void dispose() {
344
		dataChangeBehavior = null;
345
		if (conversation != null) {
346
			conversation.unregisterForDataStoreChanges(this);
347
		}
348
		if(cdmEntitySession != null) {
349
		    cdmEntitySession.dispose();
350
		}
351
		if(CdmApplicationState.getCurrentDataChangeService() != null) {
352
		    CdmApplicationState.getCurrentDataChangeService().unregister(this);
353
		}
354
	}
355

    
356
	/** {@inheritDoc} */
357
	@Focus
358
	public void setFocus() {
359
		if (getConversationHolder() != null) {
360
			getConversationHolder().bind();
361
		}
362
		if(cdmEntitySession != null) {
363
		    cdmEntitySession.bind();
364
		}
365
	}
366

    
367
    public UISynchronize getSync() {
368
        return sync;
369
    }
370

    
371
    public TreeViewer getViewer() {
372
        return viewer;
373
    }
374

    
375
    public UndoContext getUndoContext() {
376
        return undoContext;
377
    }
378

    
379
	/** {@inheritDoc} */
380
	@Override
381
	public boolean postOperation(CdmBase objectAffectedByOperation) {
382
	    viewer.refresh();
383
		return true;
384
	}
385

    
386
	@Override
387
	public boolean onComplete() {
388
		return true;
389
	}
390

    
391
	@Override
392
	public void update(Observable o, Object arg) {
393
		if(o instanceof LoginManager){
394
			refresh();
395
		}
396
	}
397
	   /** {@inheritDoc} */
398
    @Override
399
    public void update(CdmDataChangeMap changeEvents) {
400
        if (dataChangeBehavior == null) {
401
            dataChangeBehavior = new TaxonNavigatorDataChangeBehaviorE4(this);
402
        }
403

    
404
        DataChangeBridge.handleDataChange(changeEvents, dataChangeBehavior);
405
    }
406

    
407
    @Override
408
    public ICdmEntitySession getCdmEntitySession() {
409
       return cdmEntitySession;
410
    }
411

    
412
    @Override
413
    public List<ITreeNode> getRootEntities() {
414
        if(root != null) {
415
            return root.getParentBeans();
416
        }
417
        return null;
418
    }
419

    
420
    @Override
421
    public void onChange(CdmChangeEvent event) {
422
        refresh();
423
        for(CdmBase cb : event.getChangedObjects()) {
424
        	if(cb instanceof TaxonNode) {
425
                TaxonNode tn = (TaxonNode)cb;
426
                if(tn.getTaxon() == null) {
427
                    viewer.refresh(tn.getClassification());
428
                } else {
429
                    viewer.refresh(cb);
430
                }
431
            } else if (cb instanceof Classification) {
432
                viewer.refresh();
433
            }
434
        }
435
    }
436

    
437
    @Override
438
    public Map<Object, List<String>> getPropertyPathsMap() {
439
        Map<Object, List<String>> propertyPathsMap = new HashMap<Object, List<String>>();
440
        List<String> taxonNodePropertyPaths = Arrays.asList(new String[] {
441
                "taxon.name" //$NON-NLS-1$
442
        });
443
         propertyPathsMap.put("childNodes", taxonNodePropertyPaths); //$NON-NLS-1$
444
        return propertyPathsMap;
445
    }
446

    
447
    /**
448
     * {@inheritDoc}
449
     */
450
    @Override
451
    public void contextAboutToStop(IMemento memento, IProgressMonitor monitor) {
452
        // TODO Auto-generated method stub
453

    
454
    }
455

    
456
    /**
457
     * {@inheritDoc}
458
     */
459
    @Override
460
    public void contextStop(IMemento memento, IProgressMonitor monitor) {
461
    }
462

    
463
    /**
464
     * {@inheritDoc}
465
     */
466
    @Override
467
    public void contextStart(IMemento memento, IProgressMonitor monitor) {
468
        if(viewer!=null){
469
            init();
470
        }
471
    }
472

    
473
    /**
474
     * {@inheritDoc}
475
     */
476
    @Override
477
    public void contextRefresh(IProgressMonitor monitor) {
478
    }
479

    
480
    /**
481
     * {@inheritDoc}
482
     */
483
    @Override
484
    public void workbenchShutdown(IMemento memento, IProgressMonitor monitor) {
485
    }
486
}
(3-3/6)