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.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.taxon.Classification;
45
import eu.etaxonomy.cdm.model.taxon.TaxonNaturalComparator;
46
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
47
import eu.etaxonomy.cdm.model.taxon.TaxonNodeByNameComparator;
48
import eu.etaxonomy.cdm.model.taxon.TaxonNodeByRankAndNameComparator;
49
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
50
import eu.etaxonomy.taxeditor.model.DataChangeBridge;
51
import eu.etaxonomy.taxeditor.model.IDataChangeBehavior;
52
import eu.etaxonomy.taxeditor.model.MessagingUtils;
53
import eu.etaxonomy.taxeditor.navigation.NavigationUtil;
54
import eu.etaxonomy.taxeditor.navigation.l10n.Messages;
55
import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
56
import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
57
import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
58
import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
59
import eu.etaxonomy.taxeditor.store.CdmStore;
60
import eu.etaxonomy.taxeditor.store.LoginManager;
61

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

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

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

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

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

    
86
	private ConversationHolder conversation;
87

    
88
	private ICdmEntitySession cdmEntitySession;
89

    
90
	private String partNameCache;
91

    
92
	private IDataChangeBehavior dataChangeBehavior;
93

    
94
	private Root root;
95

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

    
131
		if (CdmStore.isActive()) {
132

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
318
		super.saveState(memento);
319

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
508

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

    
518
	}
519

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

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

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

    
561
    }
562

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