Project

General

Profile

Download (14.2 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.AbstractTreeViewer;
39
import org.eclipse.jface.viewers.ISelection;
40
import org.eclipse.jface.viewers.ISelectionChangedListener;
41
import org.eclipse.jface.viewers.IStructuredSelection;
42
import org.eclipse.jface.viewers.TreePath;
43
import org.eclipse.jface.viewers.TreeViewer;
44
import org.eclipse.swt.SWT;
45
import org.eclipse.swt.dnd.DND;
46
import org.eclipse.swt.dnd.Transfer;
47
import org.eclipse.swt.layout.FillLayout;
48
import org.eclipse.swt.widgets.Composite;
49
import org.eclipse.ui.IMemento;
50

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

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

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

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

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

    
100
	private final int dndOperations = DND.DROP_MOVE;
101

    
102
	private ConversationHolder conversation;
103

    
104
	private ICdmEntitySession cdmEntitySession;
105

    
106
	private IDataChangeBehavior dataChangeBehavior;
107

    
108
	private Root root;
109

    
110
	private TreeViewer viewer;
111

    
112
    @Inject
113
    private ESelectionService selService;
114

    
115
    @Inject
116
    private UISynchronize sync;
117

    
118
    private ISelectionChangedListener selectionChangedListener;
119

    
120
    private UndoContext undoContext;
121

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

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

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

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

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

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

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

    
163
	    init();
164
	}
165

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

    
179
		if (CdmStore.isActive()) {
180

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

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

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

    
205
	//Link with taxon selection
206
	@Inject
207
	@Optional
208
	private void updateCurrentTaxon(@UIEventTopic(WorkbenchEventConstants.CURRENT_ACTIVE_EDITOR)ITaxonEditor editor){
209
	    TaxonNode taxonNode = editor.getTaxon().getTaxonNodes().iterator().next();
210
	    viewer.refresh();
211
	    viewer.expandToLevel(taxonNode, AbstractTreeViewer.ALL_LEVELS);
212
	}
213

    
214
	/**
215
	 * Refresh this navigators viewer
216
	 */
217
	public void refresh() {
218
		if(getConversationHolder() != null){
219
			getConversationHolder().bind();
220
			//FIXME : Need to make sure this is a stable fix (ticket 3822)
221
			if(!getConversationHolder().isCompleted()){
222
			    getConversationHolder().commit();
223
			}
224
		}
225
		if(!viewer.getTree().isDisposed()){
226
		    viewer.refresh();
227
		}
228
	}
229

    
230
	/**
231
     * Refresh this navigators viewer
232
     */
233
    public void refresh(Set<?> objects) {
234
        for(Object obj : objects) {
235
            viewer.refresh(obj);
236
        }
237
    }
238

    
239
	/**
240
	 * Removes all content
241
	 */
242
	public void clear() {
243
	    viewer.setInput(new EmptyRoot());
244
	}
245

    
246
	public void restore(IMemento memento, IProgressMonitor monitor) {
247
	    root = new Root(conversation);
248
		if (memento == null) {
249
		    viewer.setInput(root);
250
			return;
251
		}
252
		int mementoWork = 0;
253
		Set<TreePath> treePaths = new HashSet<TreePath>();
254
		IMemento[] treePathMementos = null;
255

    
256
		IMemento treePathsMemento = memento.getChild(TREE_PATHS);
257

    
258
		if (treePathsMemento != null) {
259
			treePathMementos = treePathsMemento.getChildren(TREE_PATH);
260
			mementoWork = treePathMementos.length;
261
		}
262
		// begin the monitor with steps for all tree paths and steps for
263
		// creating
264
		// conversation s.o., refreshing the tree and setting the paths
265
		IProgressMonitor subProgressMonitor = NavigationUtil
266
				.getSubProgressMonitor(monitor, 1);
267

    
268
		subProgressMonitor.beginTask(RESTORING_TAXON_NAVIGATOR,
269
				1 + mementoWork + 5);
270
		subProgressMonitor.subTask(RESTORING_TAXON_NAVIGATOR);
271
		subProgressMonitor.worked(1);
272

    
273
		conversation = CdmStore.createConversation();
274
		subProgressMonitor.worked(1);
275
		conversation.registerForDataStoreChanges(TaxonNavigatorE4.this);
276
		subProgressMonitor.worked(1);
277
		viewer.setInput(root);
278
		subProgressMonitor.worked(1);
279
		viewer.refresh();
280
		subProgressMonitor.worked(1);
281

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

    
300
	private TreePath createTreePathFromString(String string) {
301

    
302
		List<CdmBase> pathList = new ArrayList<CdmBase>();
303

    
304
		if (string.length() == 0) {
305
            return null;
306
        }
307

    
308
		for (String uuid : string.split(" ")) { //$NON-NLS-1$
309
			CdmBase cdmBaseObject = CdmStore.getService(
310
					IClassificationService.class).getTaxonNodeByUuid(
311
					UUID.fromString(uuid));
312
			if (cdmBaseObject == null) {
313
				// is this a tree uuid?
314
				cdmBaseObject = CdmStore.getService(
315
						IClassificationService.class).load(
316
						UUID.fromString(uuid));
317

    
318
				if (cdmBaseObject == null) {
319
                    return null;
320
                }
321
			}
322
			pathList.add(cdmBaseObject);
323
		}
324
		return new TreePath(pathList.toArray());
325
	}
326

    
327
	@Override
328
	public ConversationHolder getConversationHolder() {
329
		return conversation;
330
	}
331

    
332
	/** {@inheritDoc} */
333
	@PreDestroy
334
	public void dispose() {
335
		dataChangeBehavior = null;
336
		if (conversation != null) {
337
			conversation.unregisterForDataStoreChanges(this);
338
		}
339
		if(cdmEntitySession != null) {
340
		    cdmEntitySession.dispose();
341
		}
342
		if(CdmApplicationState.getCurrentDataChangeService() != null) {
343
		    CdmApplicationState.getCurrentDataChangeService().unregister(this);
344
		}
345
	}
346

    
347
	/** {@inheritDoc} */
348
	@Focus
349
	public void setFocus() {
350
		if (getConversationHolder() != null) {
351
			getConversationHolder().bind();
352
		}
353
		if(cdmEntitySession != null) {
354
		    cdmEntitySession.bind();
355
		}
356
	}
357

    
358
    public UISynchronize getSync() {
359
        return sync;
360
    }
361

    
362
    public TreeViewer getViewer() {
363
        return viewer;
364
    }
365

    
366
    public UndoContext getUndoContext() {
367
        return undoContext;
368
    }
369

    
370
	/** {@inheritDoc} */
371
	@Override
372
	public boolean postOperation(CdmBase objectAffectedByOperation) {
373
	    viewer.refresh();
374
		return true;
375
	}
376

    
377
	@Override
378
	public boolean onComplete() {
379
		return true;
380
	}
381

    
382
	@Override
383
	public void update(Observable o, Object arg) {
384
		if(o instanceof LoginManager){
385
			refresh();
386
		}
387
	}
388
	   /** {@inheritDoc} */
389
    @Override
390
    public void update(CdmDataChangeMap changeEvents) {
391
        if (dataChangeBehavior == null) {
392
            dataChangeBehavior = new TaxonNavigatorDataChangeBehaviorE4(this);
393
        }
394

    
395
        DataChangeBridge.handleDataChange(changeEvents, dataChangeBehavior);
396
    }
397

    
398
    @Override
399
    public ICdmEntitySession getCdmEntitySession() {
400
       return cdmEntitySession;
401
    }
402

    
403
    @Override
404
    public List<ITreeNode> getRootEntities() {
405
        if(root != null) {
406
            return root.getParentBeans();
407
        }
408
        return null;
409
    }
410

    
411
    @Override
412
    public void onChange(CdmChangeEvent event) {
413
        refresh();
414
        for(CdmBase cb : event.getChangedObjects()) {
415
        	if(cb instanceof TaxonNode) {
416
                TaxonNode tn = (TaxonNode)cb;
417
                if(tn.getTaxon() == null) {
418
                    viewer.refresh(tn.getClassification());
419
                } else {
420
                    viewer.refresh(cb);
421
                }
422
            } else if (cb instanceof Classification) {
423
                viewer.refresh();
424
            }
425
        }
426
    }
427

    
428
    @Override
429
    public Map<Object, List<String>> getPropertyPathsMap() {
430
        Map<Object, List<String>> propertyPathsMap = new HashMap<Object, List<String>>();
431
        List<String> taxonNodePropertyPaths = Arrays.asList(new String[] {
432
                "taxon.name" //$NON-NLS-1$
433
        });
434
         propertyPathsMap.put("childNodes", taxonNodePropertyPaths); //$NON-NLS-1$
435
        return propertyPathsMap;
436
    }
437

    
438
    /**
439
     * {@inheritDoc}
440
     */
441
    @Override
442
    public void contextAboutToStop(IMemento memento, IProgressMonitor monitor) {
443
        // TODO Auto-generated method stub
444

    
445
    }
446

    
447
    /**
448
     * {@inheritDoc}
449
     */
450
    @Override
451
    public void contextStop(IMemento memento, IProgressMonitor monitor) {
452
    }
453

    
454
    /**
455
     * {@inheritDoc}
456
     */
457
    @Override
458
    public void contextStart(IMemento memento, IProgressMonitor monitor) {
459
        if(viewer!=null){
460
            init();
461
        }
462
    }
463

    
464
    /**
465
     * {@inheritDoc}
466
     */
467
    @Override
468
    public void contextRefresh(IProgressMonitor monitor) {
469
    }
470

    
471
    /**
472
     * {@inheritDoc}
473
     */
474
    @Override
475
    public void workbenchShutdown(IMemento memento, IProgressMonitor monitor) {
476
    }
477
}
(3-3/6)