Project

General

Profile

Download (14.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.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
	    TaxonNode taxonNode = editor.getTaxon().getTaxonNodes().iterator().next();
211
	    viewer.refresh();
212
	    viewer.reveal(taxonNode);
213
	    viewer.setSelection(null);
214
	    Widget testFindItem = viewer.testFindItem(taxonNode);
215
	    if(testFindItem instanceof TreeItem){
216
	        viewer.getTree().select((TreeItem) testFindItem);
217
	    }
218
	}
219

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

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

    
245
	/**
246
	 * Removes all content
247
	 */
248
	public void clear() {
249
	    viewer.setInput(new EmptyRoot());
250
	}
251

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

    
262
		IMemento treePathsMemento = memento.getChild(TREE_PATHS);
263

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

    
274
		subProgressMonitor.beginTask(RESTORING_TAXON_NAVIGATOR,
275
				1 + mementoWork + 5);
276
		subProgressMonitor.subTask(RESTORING_TAXON_NAVIGATOR);
277
		subProgressMonitor.worked(1);
278

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

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

    
306
	private TreePath createTreePathFromString(String string) {
307

    
308
		List<CdmBase> pathList = new ArrayList<CdmBase>();
309

    
310
		if (string.length() == 0) {
311
            return null;
312
        }
313

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

    
324
				if (cdmBaseObject == null) {
325
                    return null;
326
                }
327
			}
328
			pathList.add(cdmBaseObject);
329
		}
330
		return new TreePath(pathList.toArray());
331
	}
332

    
333
	@Override
334
	public ConversationHolder getConversationHolder() {
335
		return conversation;
336
	}
337

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

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

    
364
    public UISynchronize getSync() {
365
        return sync;
366
    }
367

    
368
    public TreeViewer getViewer() {
369
        return viewer;
370
    }
371

    
372
    public UndoContext getUndoContext() {
373
        return undoContext;
374
    }
375

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

    
383
	@Override
384
	public boolean onComplete() {
385
		return true;
386
	}
387

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

    
401
        DataChangeBridge.handleDataChange(changeEvents, dataChangeBehavior);
402
    }
403

    
404
    @Override
405
    public ICdmEntitySession getCdmEntitySession() {
406
       return cdmEntitySession;
407
    }
408

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

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

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

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

    
451
    }
452

    
453
    /**
454
     * {@inheritDoc}
455
     */
456
    @Override
457
    public void contextStop(IMemento memento, IProgressMonitor monitor) {
458
    }
459

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

    
470
    /**
471
     * {@inheritDoc}
472
     */
473
    @Override
474
    public void contextRefresh(IProgressMonitor monitor) {
475
    }
476

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