Project

General

Profile

Download (15.9 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;
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 org.eclipse.core.runtime.IAdaptable;
25
import org.eclipse.core.runtime.IProgressMonitor;
26
import org.eclipse.jface.viewers.DoubleClickEvent;
27
import org.eclipse.jface.viewers.ISelection;
28
import org.eclipse.jface.viewers.IStructuredSelection;
29
import org.eclipse.jface.viewers.TreePath;
30
import org.eclipse.ui.IMemento;
31
import org.eclipse.ui.IViewSite;
32
import org.eclipse.ui.PartInitException;
33
import org.eclipse.ui.navigator.CommonNavigator;
34

    
35
import eu.etaxonomy.cdm.api.application.CdmApplicationState;
36
import eu.etaxonomy.cdm.api.application.CdmChangeEvent;
37
import eu.etaxonomy.cdm.api.application.CdmChangeEvent.Action;
38
import eu.etaxonomy.cdm.api.application.ICdmChangeListener;
39
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
40
import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
41
import eu.etaxonomy.cdm.api.service.IClassificationService;
42
import eu.etaxonomy.cdm.model.common.CdmBase;
43
import eu.etaxonomy.cdm.model.common.ICdmBase;
44
import eu.etaxonomy.cdm.model.common.ITreeNode;
45
import eu.etaxonomy.cdm.model.taxon.Classification;
46
import eu.etaxonomy.cdm.model.taxon.TaxonNaturalComparator;
47
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
48
import eu.etaxonomy.cdm.model.taxon.TaxonNodeByNameComparator;
49
import eu.etaxonomy.cdm.model.taxon.TaxonNodeByRankAndNameComparator;
50
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
51
import eu.etaxonomy.taxeditor.model.DataChangeBridge;
52
import eu.etaxonomy.taxeditor.model.IDataChangeBehavior;
53
import eu.etaxonomy.taxeditor.model.MessagingUtils;
54
import eu.etaxonomy.taxeditor.navigation.NavigationUtil;
55
import eu.etaxonomy.taxeditor.navigation.l10n.Messages;
56
import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
57
import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
58
import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
59
import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
60
import eu.etaxonomy.taxeditor.store.CdmStore;
61
import eu.etaxonomy.taxeditor.store.LoginManager;
62

    
63
/**
64
 * Taxonomic tree implementation using Common Navigator Framework.
65
 *
66
 * @author p.ciardelli
67
 * @author n.hoffmann
68
 * @created 02.06.2009
69
 * @version 1.0+-
70
 */
71
public class TaxonNavigator extends CommonNavigator implements
72
		IPostOperationEnabled, IConversationEnabled, Observer,
73
		ICdmEntitySessionEnabled, ICdmChangeListener {
74

    
75
    private static final String RESTORING_TAXON_NAVIGATOR = Messages.TaxonNavigator_RESTORE;
76

    
77
    /**
78
	 * Constant
79
	 * <code>ID="eu.etaxonomy.taxeditor.navigation.navig"{trunked}</code>
80
	 */
81
	public static final String ID = "eu.etaxonomy.taxeditor.navigation.navigator"; //$NON-NLS-1$
82

    
83
	private static final String TREE_PATH = "treepath"; //$NON-NLS-1$
84

    
85
	private static final String TREE_PATHS = "treepaths"; //$NON-NLS-1$
86

    
87
	private ConversationHolder conversation;
88

    
89
	private ICdmEntitySession cdmEntitySession;
90

    
91
	private String partNameCache;
92

    
93
	private IDataChangeBehavior dataChangeBehavior;
94

    
95
	private Root root;
96

    
97
	/*
98
	 * (non-Javadoc)
99
	 *
100
	 * @see org.eclipse.ui.navigator.CommonNavigator#getInitialInput()
101
	 */
102
	/** {@inheritDoc} */
103
	@Override
104
	protected IAdaptable getInitialInput() {
105
		Comparator<TaxonNode> comparator;
106
		if (PreferencesUtil.getSortNodesNaturally()){
107
			comparator = new TaxonNaturalComparator();
108
		} else if (PreferencesUtil.getSortNodesStrictlyAlphabetically()){
109
			comparator = new TaxonNodeByNameComparator();
110
		}else {
111
			comparator = new TaxonNodeByRankAndNameComparator();
112
		}
113
		TaxonNodeNavigatorComparator viewerComparator = new TaxonNodeNavigatorComparator(comparator);
114
		this.getCommonViewer().setComparator(viewerComparator);
115
		//this.getCommonViewer().setAutoExpandLevel(2);
116
        setLinkingEnabled(true);
117
//		this.getCommonViewer().addSelectionChangedListener(new ISelectionChangedListener() {
118
//
119
//			@Override
120
//			public void selectionChanged(SelectionChangedEvent arg0) {
121
//				IStructuredSelection selection = (IStructuredSelection) getCommonViewer().getSelection();
122
//
123
//				Object firstElement =  selection.getFirstElement();
124
//				//
125
//				if (!(firstElement instanceof Classification)){
126
//					//NavigationUtil.selectInNavigator(firstElement, null);
127
//					NavigationUtil.openEditor(firstElement);
128
//				}
129
//
130
//			}
131
//		} );
132

    
133
		if (CdmStore.isActive()) {
134

    
135
			// TODO when closing and reopening the taxon navigator
136
			// we do not preserve state. Closing the view, in contrary to
137
			// closing the whole application
138
			// should be handled by the state manager too
139
		    root = new Root(conversation);
140
		    
141
			return root;
142
		}
143
		return new EmptyRoot();
144
	}
145

    
146
	/** {@inheritDoc} */
147
	@Override
148
	public void init(IViewSite site) throws PartInitException {
149
		super.init(site);
150
		init();
151
	}
152

    
153
	/**
154
	 * <p>
155
	 * init
156
	 * </p>
157
	 */
158
	public void init() {
159

    
160
		if (CdmStore.isActive() && conversation == null) {
161
			conversation = CdmStore.createConversation();
162
			conversation.registerForDataStoreChanges(TaxonNavigator.this);
163
		}
164
		if (CdmStore.isActive()) {
165
		    cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
166
		    CdmApplicationState.getCurrentDataChangeService().register(this);
167
		}
168
		CdmStore.getLoginManager().addObserver(this);
169
		
170
		
171
	}
172

    
173
	/**
174
	 * Refresh this navigators viewer
175
	 */
176
	public void refresh() {
177
		if(getConversationHolder() != null){
178
			getConversationHolder().bind();
179
			//FIXME : Need to make sure this is a stable fix (ticket 3822)
180
			if(!getConversationHolder().isCompleted()){
181
			    getConversationHolder().commit();
182
			}
183
		}
184
		if(!getCommonViewer().getTree().isDisposed()){
185
		    getCommonViewer().refresh();
186
		}
187
	}
188

    
189
	   /**
190
     * Refresh this navigators viewer
191
     */
192
    public void refresh(Set<?> objects) {
193
        for(Object obj : objects) {
194
            getCommonViewer().refresh(obj);
195
        }
196
    }
197

    
198
	/**
199
	 * Removes all content
200
	 */
201
	public void clear() {
202
		getCommonViewer().setInput(new EmptyRoot());
203
	}
204

    
205
	/**
206
	 * <p>
207
	 * restore
208
	 * </p>
209
	 *
210
	 * @param memento
211
	 *            a {@link org.eclipse.ui.IMemento} object.
212
	 * @param monitor
213
	 *            a {@link org.eclipse.core.runtime.IProgressMonitor} object.
214
	 */
215
	public void restore(IMemento memento, IProgressMonitor monitor) {
216
	    root = new Root(conversation);
217
		if (memento == null) {
218
			getCommonViewer().setInput(root);
219
			return;
220
		}
221
		int mementoWork = 0;
222
		Set<TreePath> treePaths = new HashSet<TreePath>();
223
		IMemento[] treePathMementos = null;
224

    
225
		IMemento treePathsMemento = memento.getChild(TREE_PATHS);
226

    
227
		if (treePathsMemento != null) {
228
			treePathMementos = treePathsMemento.getChildren(TREE_PATH);
229
			mementoWork = treePathMementos.length;
230
		}
231
		// begin the monitor with steps for all tree paths and steps for
232
		// creating
233
		// conversation s.o., refreshing the tree and setting the paths
234
		IProgressMonitor subProgressMonitor = NavigationUtil
235
				.getSubProgressMonitor(monitor, 1);
236

    
237
		subProgressMonitor.beginTask(RESTORING_TAXON_NAVIGATOR,
238
				1 + mementoWork + 5);
239
		subProgressMonitor.subTask(RESTORING_TAXON_NAVIGATOR);
240
		subProgressMonitor.worked(1);
241

    
242
		conversation = CdmStore.createConversation();
243
		subProgressMonitor.worked(1);
244
		conversation.registerForDataStoreChanges(TaxonNavigator.this);
245
		subProgressMonitor.worked(1);
246
		getCommonViewer().setInput(root);
247
		subProgressMonitor.worked(1);
248
		getCommonViewer().refresh();
249
		subProgressMonitor.worked(1);
250

    
251
		if (treePathMementos != null && treePathMementos.length > 0) {
252
			for (IMemento treePathMemento : treePathMementos) {
253
				TreePath treePath = createTreePathFromString(treePathMemento
254
						.getID());
255
				if (!subProgressMonitor.isCanceled() && treePath != null) {
256
					treePaths.add(treePath);
257
					subProgressMonitor.worked(1);
258
				}
259
			}
260
		}
261
		if (treePaths.size() > 0) {
262
			TaxonNavigator.this.getCommonViewer().setExpandedTreePaths(
263
					treePaths.toArray(new TreePath[0]));
264
			subProgressMonitor.worked(1);
265
		}
266
		subProgressMonitor.done();
267
	}
268

    
269
	/**
270
	 * @param string
271
	 * @return
272
	 */
273
	private TreePath createTreePathFromString(String string) {
274

    
275
		List<CdmBase> pathList = new ArrayList<CdmBase>();
276

    
277
		if (string.length() == 0) {
278
            return null;
279
        }
280

    
281
		for (String uuid : string.split(" ")) { //$NON-NLS-1$
282
			CdmBase cdmBaseObject = CdmStore.getService(
283
					IClassificationService.class).getTaxonNodeByUuid(
284
					UUID.fromString(uuid));
285
			if (cdmBaseObject == null) {
286
				// is this a tree uuid?
287
				cdmBaseObject = CdmStore.getService(
288
						IClassificationService.class).load(
289
						UUID.fromString(uuid));
290

    
291
				if (cdmBaseObject == null) {
292
                    return null;
293
                }
294
			}
295
			pathList.add(cdmBaseObject);
296
		}
297
		return new TreePath(pathList.toArray());
298
	}
299

    
300
	/** {@inheritDoc} */
301
	@Override
302
	public void saveState(IMemento aMemento) {
303
		//
304
	}
305

    
306
	/**
307
	 * <p>
308
	 * saveTreeState
309
	 * </p>
310
	 *
311
	 * @param memento
312
	 *            a {@link org.eclipse.ui.IMemento} object.
313
	 * @param progressMonitor
314
	 *            a {@link org.eclipse.core.runtime.IProgressMonitor} object.
315
	 */
316
	public void saveTreeState(IMemento memento, IProgressMonitor progressMonitor) {
317
		if (memento == null) {
318
			return;
319
		}
320
		IProgressMonitor monitor = NavigationUtil.getSubProgressMonitor(
321
				progressMonitor, 1);
322

    
323
		super.saveState(memento);
324

    
325
		memento = memento.createChild(TREE_PATHS);
326
		TreePath[] treePaths = this.getCommonViewer().getExpandedTreePaths();
327

    
328
		monitor.beginTask(Messages.TaxonNavigator_SAVE_TASK, treePaths.length);
329

    
330
		for (TreePath treePath : treePaths) {
331
			int pathLength = treePath.getSegmentCount();
332
			String path = ""; //$NON-NLS-1$
333
			for (int i = 0; i < pathLength; i++) {
334
				Object segment = treePath.getSegment(i);
335
				if (segment instanceof CdmBase) {
336
					path += ((CdmBase) segment).getUuid().toString() + " "; //$NON-NLS-1$
337
					monitor.worked(1);
338
				} else {
339
					MessagingUtils.warn(getClass(),
340
							"Non-taxon tree path segment " + segment); //$NON-NLS-1$
341
				}
342
			}
343
			memento.createChild(TREE_PATH, path.trim());
344
		}
345
		monitor.done();
346
	}
347

    
348
	/*
349
	 * (non-Javadoc)
350
	 *
351
	 * @see
352
	 * eu.etaxonomy.cdm.api.conversation.IConversationEnabled#getConversationHolder
353
	 * ()
354
	 */
355
	/**
356
	 * <p>
357
	 * getConversationHolder
358
	 * </p>
359
	 *
360
	 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
361
	 *         object.
362
	 */
363
	@Override
364
	public ConversationHolder getConversationHolder() {
365
		return conversation;
366
	}
367

    
368
	/*
369
	 * (non-Javadoc)
370
	 *
371
	 * @see
372
	 * eu.etaxonomy.cdm.persistence.hibernate.ICdmPostDataChangeObserver#update
373
	 * (eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap)
374
	 */
375
	/** {@inheritDoc} */
376
	@Override
377
	public void update(CdmDataChangeMap changeEvents) {
378
		if (dataChangeBehavior == null) {
379
			dataChangeBehavior = new TaxonNavigatorDataChangeBehavior(this);
380
		}
381

    
382
		DataChangeBridge.handleDataChange(changeEvents, dataChangeBehavior);
383
	}
384

    
385
	/** {@inheritDoc} */
386
	@Override
387
	public String getFrameToolTipText(Object element) {
388
		if (element instanceof Root) {
389
			return Messages.TaxonNavigator_TAXON_TREE;
390
		}
391
		return super.getFrameToolTipText(element);
392
	}
393

    
394
	/*
395
	 * (non-Javadoc)
396
	 *
397
	 * @see org.eclipse.ui.part.WorkbenchPart#dispose()
398
	 */
399
	/** {@inheritDoc} */
400
	@Override
401
	public void dispose() {
402
		super.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
	/*
416
	 * (non-Javadoc)
417
	 *
418
	 * @see org.eclipse.ui.navigator.CommonNavigator#setFocus()
419
	 */
420
	/** {@inheritDoc} */
421
	@Override
422
	public void setFocus() {
423
		// logger.warn("Setting focus to navigator");
424
		super.setFocus();
425
		if (getConversationHolder() != null) {
426
			getConversationHolder().bind();
427
		}
428
		if(cdmEntitySession != null) {
429
		    cdmEntitySession.bind();
430
		}
431
	}
432

    
433
	/*
434
	 * (non-Javadoc)
435
	 *
436
	 * @see
437
	 * eu.etaxonomy.taxeditor.operations.IPostOperationEnabled#postOperation
438
	 * (eu.etaxonomy.cdm.model.common.CdmBase)
439
	 */
440
	/** {@inheritDoc} */
441
	@Override
442
	public boolean postOperation(CdmBase objectAffectedByOperation) {
443
		// nothing to do here
444
		return true;
445
	}
446

    
447
	/**
448
	 * <p>
449
	 * save
450
	 * </p>
451
	 *
452
	 * @param memento
453
	 *            a {@link org.eclipse.ui.IMemento} object.
454
	 * @param monitor
455
	 *            a {@link org.eclipse.core.runtime.IProgressMonitor} object.
456
	 */
457
	public void save(IMemento memento, IProgressMonitor monitor) {
458
		saveTreeState(memento, monitor);
459
		if (conversation != null) {
460
			conversation.unregisterForDataStoreChanges(this);
461
			conversation = null;
462
		}
463
	}
464

    
465
	/** {@inheritDoc} */
466
	@Override
467
	protected void handleDoubleClick(DoubleClickEvent event) {
468
		ISelection selection = event.getSelection();
469
		if(selection instanceof IStructuredSelection){
470
			Object firstElement = ((IStructuredSelection) selection).getFirstElement();
471
			if(firstElement instanceof ICdmBase){
472
				NavigationUtil.openEditor((ICdmBase) firstElement);
473
			}
474
		}
475
		// If the double click is passed up to the super-class it will
476
		// expand/collapse trees.
477
		// We do not want that
478
		// super.handleDoubleClick(anEvent);
479
	}
480

    
481
	/**
482
	 * <p>
483
	 * onComplete
484
	 * </p>
485
	 *
486
	 * @return a boolean.
487
	 */
488
	@Override
489
	public boolean onComplete() {
490
		return true;
491
	}
492

    
493
	/*
494
	 * (non-Javadoc)
495
	 *
496
	 * @see org.eclipse.ui.part.WorkbenchPart#showBusy(boolean)
497
	 */
498
	/** {@inheritDoc} */
499
	@Override
500
	public void showBusy(boolean busy) {
501
		super.showBusy(busy);
502
		getCommonViewer().getControl().setEnabled(!busy);
503
		if (busy) {
504
			partNameCache = getPartName();
505
			setPartName(Messages.TaxonNavigator_LOAD_DATASOURCE);
506
		} else {
507
			if (partNameCache != null) {
508
				setPartName(partNameCache);
509
			}
510
		}
511
	}
512

    
513

    
514
	/* (non-Javadoc)
515
	 * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
516
	 */
517
	@Override
518
	public void update(Observable o, Object arg) {
519
		if(o instanceof LoginManager){
520
			refresh();
521
		}
522

    
523
	}
524

    
525
    /* (non-Javadoc)
526
     * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled#getCdmEntitySession()
527
     */
528
    @Override
529
    public ICdmEntitySession getCdmEntitySession() {
530
       return cdmEntitySession;
531
    }
532

    
533
    /* (non-Javadoc)
534
     * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled#getRootEntities()
535
     */
536
    @Override
537
    public List<ITreeNode> getRootEntities() {
538
        if(root != null) {
539
            return root.getParentBeans();
540
        }
541
        return null;
542
    }
543

    
544
    /* (non-Javadoc)
545
     * @see eu.etaxonomy.cdm.api.application.ICdmChangeListener#onChange(eu.etaxonomy.cdm.api.application.CdmChangeEvent)
546
     */
547
    @Override
548
    public void onChange(CdmChangeEvent event) {
549
        if(event.getAction() == Action.Delete && Classification.class.equals(event.getEntityType())) {
550
            refresh();
551
            return;
552
        }
553
        for(CdmBase cb : event.getChangedObjects()) {
554
            if(cb instanceof TaxonNode) {
555
                TaxonNode tn = (TaxonNode)cb;
556
                if(tn.getTaxon() == null) {
557
                    getCommonViewer().refresh(tn.getClassification());
558
                } else {
559
                    getCommonViewer().refresh(cb);
560
                }
561
            } else if (cb instanceof Classification) {
562
                getCommonViewer().refresh();
563
            }
564
        }
565

    
566
    }
567

    
568
    /* (non-Javadoc)
569
     * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled#getPropertyPathsMap()
570
     */
571
    @Override
572
    public Map<Object, List<String>> getPropertyPathsMap() {
573
        Map<Object, List<String>> propertyPathsMap = new HashMap<Object, List<String>>();
574
        List<String> taxonNodePropertyPaths = Arrays.asList(new String[] {
575
                "taxon.name" //$NON-NLS-1$
576
        });
577
         propertyPathsMap.put("childNodes", taxonNodePropertyPaths); //$NON-NLS-1$
578
        return propertyPathsMap;
579
    }
580
}
(9-9/21)