Project

General

Profile

Download (16.1 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.Command;
29
import org.eclipse.core.commands.common.NotDefinedException;
30
import org.eclipse.core.commands.operations.UndoContext;
31
import org.eclipse.core.runtime.IAdaptable;
32
import org.eclipse.core.runtime.IProgressMonitor;
33
import org.eclipse.e4.core.commands.ECommandService;
34
import org.eclipse.e4.core.di.annotations.Optional;
35
import org.eclipse.e4.ui.di.Focus;
36
import org.eclipse.e4.ui.di.UIEventTopic;
37
import org.eclipse.e4.ui.di.UISynchronize;
38
import org.eclipse.e4.ui.model.application.commands.MCommand;
39
import org.eclipse.e4.ui.model.application.commands.MCommandsFactory;
40
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
41
import org.eclipse.e4.ui.model.application.ui.menu.ItemType;
42
import org.eclipse.e4.ui.model.application.ui.menu.MHandledToolItem;
43
import org.eclipse.e4.ui.model.application.ui.menu.MMenuFactory;
44
import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
45
import org.eclipse.e4.ui.services.EMenuService;
46
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
47
import org.eclipse.jface.util.LocalSelectionTransfer;
48
import org.eclipse.jface.viewers.ISelection;
49
import org.eclipse.jface.viewers.ISelectionChangedListener;
50
import org.eclipse.jface.viewers.IStructuredSelection;
51
import org.eclipse.jface.viewers.StructuredSelection;
52
import org.eclipse.jface.viewers.TreePath;
53
import org.eclipse.jface.viewers.TreeViewer;
54
import org.eclipse.swt.SWT;
55
import org.eclipse.swt.dnd.DND;
56
import org.eclipse.swt.dnd.Transfer;
57
import org.eclipse.swt.layout.FillLayout;
58
import org.eclipse.swt.widgets.Composite;
59
import org.eclipse.ui.IMemento;
60

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

    
94
/**
95
 *
96
 * @author pplitzner
97
 * @since Sep 7, 2017
98
 *
99
 */
100
public class TaxonNavigatorE4 implements
101
		IPostOperationEnabled, IConversationEnabled, Observer,
102
		ICdmEntitySessionEnabled, ICdmChangeListener, IContextListener {
103

    
104
    private static final String RESTORING_TAXON_NAVIGATOR = Messages.TaxonNavigator_RESTORE;
105

    
106
	private static final String TREE_PATH = "treepath"; //$NON-NLS-1$
107

    
108
	private static final String TREE_PATHS = "treepaths"; //$NON-NLS-1$
109

    
110
	private final int dndOperations = DND.DROP_MOVE;
111

    
112
	private ConversationHolder conversation;
113

    
114
	private ICdmEntitySession cdmEntitySession;
115

    
116
	private IDataChangeBehavior dataChangeBehavior;
117

    
118
	private Root root;
119

    
120
	private TreeViewer viewer;
121

    
122
    @Inject
123
    private ESelectionService selService;
124

    
125
    @Inject
126
    private UISynchronize sync;
127

    
128
    private ISelectionChangedListener selectionChangedListener;
129

    
130
    private UndoContext undoContext;
131

    
132
    @Inject
133
    private MPart thisPart;
134

    
135
    private boolean linkWithTaxon = false;
136

    
137
    @Inject
138
    public TaxonNavigatorE4() {
139
	    undoContext = new UndoContext();
140
	    CdmStore.getContextManager().addContextListener(this);
141
    }
142

    
143
	@PostConstruct
144
	private void create(Composite parent, EMenuService menuService, ECommandService commandService){
145
	    FillLayout layout = new FillLayout();
146
	    layout.marginHeight = 0;
147
	    layout.marginWidth = 0;
148
	    layout.type = SWT.VERTICAL;
149

    
150
	    parent.setLayout(layout);
151
	    viewer = new TreeViewer(parent);
152
	    viewer.getControl().setLayoutData(LayoutConstants.FILL());
153

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

    
166
        //propagate selection
167
        selectionChangedListener = (event -> selService.setSelection(event.getSelection()));
168
        viewer.addSelectionChangedListener(selectionChangedListener);
169

    
170
        //create context menu
171
        menuService.registerContextMenu(viewer.getControl(), "eu.etaxonomy.taxeditor.navigator.popupmenu.taxonnavigator");
172

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

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

    
195
	    init();
196
	}
197

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

    
211
		if (CdmStore.isActive()) {
212

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

    
219
			return root;
220
		}
221
		return new EmptyRoot();
222
	}
223

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

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

    
252
    public void setLinkWithTaxon(boolean linkWithTaxon) {
253
        this.linkWithTaxon = linkWithTaxon;
254
    }
255

    
256
    public boolean isLinkWithTaxon() {
257
        return linkWithTaxon;
258
    }
259

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

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

    
285
	/**
286
	 * Removes all content
287
	 */
288
	public void clear() {
289
	    viewer.setInput(new EmptyRoot());
290
	}
291

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

    
302
		IMemento treePathsMemento = memento.getChild(TREE_PATHS);
303

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

    
314
		subProgressMonitor.beginTask(RESTORING_TAXON_NAVIGATOR,
315
				1 + mementoWork + 5);
316
		subProgressMonitor.subTask(RESTORING_TAXON_NAVIGATOR);
317
		subProgressMonitor.worked(1);
318

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

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

    
346
	private TreePath createTreePathFromString(String string) {
347

    
348
		List<CdmBase> pathList = new ArrayList<CdmBase>();
349

    
350
		if (string.length() == 0) {
351
            return null;
352
        }
353

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

    
364
				if (cdmBaseObject == null) {
365
                    return null;
366
                }
367
			}
368
			pathList.add(cdmBaseObject);
369
		}
370
		return new TreePath(pathList.toArray());
371
	}
372

    
373
	@Override
374
	public ConversationHolder getConversationHolder() {
375
		return conversation;
376
	}
377

    
378
	/** {@inheritDoc} */
379
	@PreDestroy
380
	public void dispose() {
381
		dataChangeBehavior = null;
382
		if (conversation != null) {
383
			conversation.unregisterForDataStoreChanges(this);
384
		}
385
		if(cdmEntitySession != null) {
386
		    cdmEntitySession.dispose();
387
		}
388
		if(CdmApplicationState.getCurrentDataChangeService() != null) {
389
		    CdmApplicationState.getCurrentDataChangeService().unregister(this);
390
		}
391
	}
392

    
393
	/** {@inheritDoc} */
394
	@Focus
395
	public void setFocus() {
396
		if (getConversationHolder() != null) {
397
			getConversationHolder().bind();
398
		}
399
		if(cdmEntitySession != null) {
400
		    cdmEntitySession.bind();
401
		}
402
	}
403

    
404
    public UISynchronize getSync() {
405
        return sync;
406
    }
407

    
408
    public TreeViewer getViewer() {
409
        return viewer;
410
    }
411

    
412
    public UndoContext getUndoContext() {
413
        return undoContext;
414
    }
415

    
416
	/** {@inheritDoc} */
417
	@Override
418
	public boolean postOperation(CdmBase objectAffectedByOperation) {
419
	    viewer.refresh();
420
		return true;
421
	}
422

    
423
	@Override
424
	public boolean onComplete() {
425
		return true;
426
	}
427

    
428
	@Override
429
	public void update(Observable o, Object arg) {
430
		if(o instanceof LoginManager){
431
			refresh();
432
		}
433
	}
434
	   /** {@inheritDoc} */
435
    @Override
436
    public void update(CdmDataChangeMap changeEvents) {
437
        if (dataChangeBehavior == null) {
438
            dataChangeBehavior = new TaxonNavigatorDataChangeBehaviorE4(this);
439
        }
440

    
441
        DataChangeBridge.handleDataChange(changeEvents, dataChangeBehavior);
442
    }
443

    
444
    @Override
445
    public ICdmEntitySession getCdmEntitySession() {
446
       return cdmEntitySession;
447
    }
448

    
449
    @Override
450
    public List<ITreeNode> getRootEntities() {
451
        if(root != null) {
452
            return root.getParentBeans();
453
        }
454
        return null;
455
    }
456

    
457
    @Override
458
    public void onChange(CdmChangeEvent event) {
459
        refresh();
460
        for(CdmBase cb : event.getChangedObjects()) {
461
        	if(cb instanceof TaxonNode) {
462
                TaxonNode tn = (TaxonNode)cb;
463
                if(tn.getTaxon() == null) {
464
                    viewer.refresh(tn.getClassification());
465
                } else {
466
                    viewer.refresh(cb);
467
                }
468
            } else if (cb instanceof Classification) {
469
                viewer.refresh();
470
            }
471
        }
472
    }
473

    
474
    @Override
475
    public Map<Object, List<String>> getPropertyPathsMap() {
476
        Map<Object, List<String>> propertyPathsMap = new HashMap<Object, List<String>>();
477
        List<String> taxonNodePropertyPaths = Arrays.asList(new String[] {
478
                "taxon.name" //$NON-NLS-1$
479
        });
480
         propertyPathsMap.put("childNodes", taxonNodePropertyPaths); //$NON-NLS-1$
481
        return propertyPathsMap;
482
    }
483

    
484
    /**
485
     * {@inheritDoc}
486
     */
487
    @Override
488
    public void contextAboutToStop(IMemento memento, IProgressMonitor monitor) {
489
        // TODO Auto-generated method stub
490

    
491
    }
492

    
493
    /**
494
     * {@inheritDoc}
495
     */
496
    @Override
497
    public void contextStop(IMemento memento, IProgressMonitor monitor) {
498
    }
499

    
500
    /**
501
     * {@inheritDoc}
502
     */
503
    @Override
504
    public void contextStart(IMemento memento, IProgressMonitor monitor) {
505
        if(viewer!=null){
506
            init();
507
        }
508
    }
509

    
510
    /**
511
     * {@inheritDoc}
512
     */
513
    @Override
514
    public void contextRefresh(IProgressMonitor monitor) {
515
    }
516

    
517
    /**
518
     * {@inheritDoc}
519
     */
520
    @Override
521
    public void workbenchShutdown(IMemento memento, IProgressMonitor monitor) {
522
    }
523
}
(3-3/6)