Project

General

Profile

Download (15.8 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.TreePath;
28
import org.eclipse.ui.IMemento;
29
import org.eclipse.ui.IViewSite;
30
import org.eclipse.ui.PartInitException;
31
import org.eclipse.ui.navigator.CommonNavigator;
32

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

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

    
71
    private static final String RESTORING_TAXON_NAVIGATOR = Messages.TaxonNavigator_RESTORE;
72

    
73
    /**
74
	 * Constant
75
	 * <code>ID="eu.etaxonomy.taxeditor.navigation.navig"{trunked}</code>
76
	 */
77
	public static final String ID = "eu.etaxonomy.taxeditor.navigation.navigator"; //$NON-NLS-1$
78

    
79
	private static final String TREE_PATH = "treepath"; //$NON-NLS-1$
80

    
81
	private static final String TREE_PATHS = "treepaths"; //$NON-NLS-1$
82

    
83
	private ConversationHolder conversation;
84

    
85
	private ICdmEntitySession cdmEntitySession;
86

    
87
	private String partNameCache;
88

    
89
	private IDataChangeBehavior dataChangeBehavior;
90

    
91
	private Root root;
92

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

    
129
		if (CdmStore.isActive()) {
130

    
131
			// TODO when closing and reopening the taxon navigator
132
			// we do not preserve state. Closing the view, in contrary to
133
			// closing the whole application
134
			// should be handled by the state manager too
135
		    root = new Root(conversation);
136

    
137
			return root;
138
		}
139
		return new EmptyRoot();
140
	}
141

    
142
	/** {@inheritDoc} */
143
	@Override
144
	public void init(IViewSite site) throws PartInitException {
145
		super.init(site);
146
		init();
147
	}
148

    
149
	/**
150
	 * <p>
151
	 * init
152
	 * </p>
153
	 */
154
	public void init() {
155

    
156
		if (CdmStore.isActive() && conversation == null) {
157
			conversation = CdmStore.createConversation();
158
			conversation.registerForDataStoreChanges(TaxonNavigator.this);
159
		}
160
		if (CdmStore.isActive()) {
161
		    cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
162
		    CdmApplicationState.getCurrentDataChangeService().register(this);
163
		}
164
		CdmStore.getLoginManager().addObserver(this);
165

    
166

    
167
	}
168

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

    
185
	   /**
186
     * Refresh this navigators viewer
187
     */
188
    public void refresh(Set<?> objects) {
189
        for(Object obj : objects) {
190
            getCommonViewer().refresh(obj);
191
        }
192
    }
193

    
194
	/**
195
	 * Removes all content
196
	 */
197
	public void clear() {
198
		getCommonViewer().setInput(new EmptyRoot());
199
	}
200

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

    
221
		IMemento treePathsMemento = memento.getChild(TREE_PATHS);
222

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

    
233
		subProgressMonitor.beginTask(RESTORING_TAXON_NAVIGATOR,
234
				1 + mementoWork + 5);
235
		subProgressMonitor.subTask(RESTORING_TAXON_NAVIGATOR);
236
		subProgressMonitor.worked(1);
237

    
238
		conversation = CdmStore.createConversation();
239
		subProgressMonitor.worked(1);
240
		conversation.registerForDataStoreChanges(TaxonNavigator.this);
241
		subProgressMonitor.worked(1);
242
		getCommonViewer().setInput(root);
243
		subProgressMonitor.worked(1);
244
		getCommonViewer().refresh();
245
		subProgressMonitor.worked(1);
246

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

    
265
	/**
266
	 * @param string
267
	 * @return
268
	 */
269
	private TreePath createTreePathFromString(String string) {
270

    
271
		List<CdmBase> pathList = new ArrayList<CdmBase>();
272

    
273
		if (string.length() == 0) {
274
            return null;
275
        }
276

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

    
287
				if (cdmBaseObject == null) {
288
                    return null;
289
                }
290
			}
291
			pathList.add(cdmBaseObject);
292
		}
293
		return new TreePath(pathList.toArray());
294
	}
295

    
296
	/** {@inheritDoc} */
297
	@Override
298
	public void saveState(IMemento aMemento) {
299
		//
300
	}
301

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

    
319
		super.saveState(memento);
320

    
321
		memento = memento.createChild(TREE_PATHS);
322
		TreePath[] treePaths = this.getCommonViewer().getExpandedTreePaths();
323

    
324
		monitor.beginTask(Messages.TaxonNavigator_SAVE_TASK, treePaths.length);
325

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

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

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

    
378
		DataChangeBridge.handleDataChange(changeEvents, dataChangeBehavior);
379
	}
380

    
381
	/** {@inheritDoc} */
382
	@Override
383
	public String getFrameToolTipText(Object element) {
384
		if (element instanceof Root) {
385
			return Messages.TaxonNavigator_TAXON_TREE;
386
		}
387
		return super.getFrameToolTipText(element);
388
	}
389

    
390
	/*
391
	 * (non-Javadoc)
392
	 *
393
	 * @see org.eclipse.ui.part.WorkbenchPart#dispose()
394
	 */
395
	/** {@inheritDoc} */
396
	@Override
397
	public void dispose() {
398
		super.dispose();
399
		dataChangeBehavior = null;
400
		if (conversation != null) {
401
			conversation.unregisterForDataStoreChanges(this);
402
		}
403
		if(cdmEntitySession != null) {
404
		    cdmEntitySession.dispose();
405
		}
406
		if(CdmApplicationState.getCurrentDataChangeService() != null) {
407
		    CdmApplicationState.getCurrentDataChangeService().unregister(this);
408
		}
409
	}
410

    
411
	/*
412
	 * (non-Javadoc)
413
	 *
414
	 * @see org.eclipse.ui.navigator.CommonNavigator#setFocus()
415
	 */
416
	/** {@inheritDoc} */
417
	@Override
418
	public void setFocus() {
419
		// logger.warn("Setting focus to navigator");
420
		super.setFocus();
421
		if (getConversationHolder() != null) {
422
			getConversationHolder().bind();
423
		}
424
		if(cdmEntitySession != null) {
425
		    cdmEntitySession.bind();
426
		}
427
	}
428

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

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

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

    
477
	/**
478
	 * <p>
479
	 * onComplete
480
	 * </p>
481
	 *
482
	 * @return a boolean.
483
	 */
484
	@Override
485
	public boolean onComplete() {
486
		return true;
487
	}
488

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

    
509

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

    
519
	}
520

    
521
    /* (non-Javadoc)
522
     * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled#getCdmEntitySession()
523
     */
524
    @Override
525
    public ICdmEntitySession getCdmEntitySession() {
526
       return cdmEntitySession;
527
    }
528

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

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

    
563
    }
564

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