Project

General

Profile

Download (15.5 KB) Statistics
| Branch: | Tag: | Revision:
1
// $Id$
2
/**
3
 * Copyright (C) 2007 EDIT
4
 * European Distributed Institute of Taxonomy
5
 * http://www.e-taxonomy.eu
6
 *
7
 * The contents of this file are subject to the Mozilla Public License Version 1.1
8
 * See LICENSE.TXT at the top of this package for the full license terms.
9
 */
10

    
11
package eu.etaxonomy.taxeditor.navigation.navigator;
12

    
13
import java.util.ArrayList;
14
import java.util.Arrays;
15
import java.util.Comparator;
16
import java.util.HashMap;
17
import java.util.HashSet;
18
import java.util.List;
19
import java.util.Map;
20
import java.util.Observable;
21
import java.util.Observer;
22
import java.util.Set;
23
import java.util.UUID;
24

    
25
import org.eclipse.core.runtime.IAdaptable;
26
import org.eclipse.core.runtime.IProgressMonitor;
27
import org.eclipse.jface.viewers.DoubleClickEvent;
28
import org.eclipse.jface.viewers.ISelection;
29
import org.eclipse.jface.viewers.IStructuredSelection;
30
import org.eclipse.jface.viewers.TreePath;
31
import org.eclipse.ui.IMemento;
32
import org.eclipse.ui.IViewSite;
33
import org.eclipse.ui.PartInitException;
34
import org.eclipse.ui.navigator.CommonNavigator;
35

    
36
import eu.etaxonomy.cdm.api.application.CdmApplicationState;
37
import eu.etaxonomy.cdm.api.application.CdmChangeEvent;
38
import eu.etaxonomy.cdm.api.application.CdmChangeEvent.Action;
39
import eu.etaxonomy.cdm.api.application.ICdmChangeListener;
40
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
41
import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
42
import eu.etaxonomy.cdm.api.service.IClassificationService;
43
import eu.etaxonomy.cdm.model.common.CdmBase;
44
import eu.etaxonomy.cdm.model.common.ICdmBase;
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.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
	/**
75
	 * Constant
76
	 * <code>ID="eu.etaxonomy.taxeditor.navigation.navig"{trunked}</code>
77
	 */
78
	public static final String ID = "eu.etaxonomy.taxeditor.navigation.navigator"; //$NON-NLS-1$
79

    
80
	private static final String TREE_PATH = "treepath";
81

    
82
	private static final String TREE_PATHS = "treepaths";
83

    
84
	private ConversationHolder conversation;
85

    
86
	private ICdmEntitySession cdmEntitySession;
87

    
88
	private String partNameCache;
89

    
90
	private IDataChangeBehavior dataChangeBehavior;
91

    
92
	private Root root;
93

    
94
	/*
95
	 * (non-Javadoc)
96
	 *
97
	 * @see org.eclipse.ui.navigator.CommonNavigator#getInitialInput()
98
	 */
99
	/** {@inheritDoc} */
100
	@Override
101
	protected IAdaptable getInitialInput() {
102
		Comparator<TaxonNode> comparator;
103
		if (PreferencesUtil.getSortNodesNaturally()){
104
			comparator = new TaxonNaturalComparator();
105
		} else if (PreferencesUtil.getSortNodesStrictlyAlphabetically()){
106
			comparator = new TaxonNodeByNameComparator();
107
		}else {
108
			comparator = new TaxonNodeByRankAndNameComparator();
109
		}
110
		TaxonNodeNavigatorComparator viewerComparator = new TaxonNodeNavigatorComparator(comparator);
111
		this.getCommonViewer().setComparator(viewerComparator);
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
			return root;
137
		}
138
		return new EmptyRoot();
139
	}
140

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

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

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

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

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

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

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

    
218
		IMemento treePathsMemento = memento.getChild(TREE_PATHS);
219

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

    
230
		subProgressMonitor.beginTask("Restoring Taxon Navigator",
231
				1 + mementoWork + 5);
232
		subProgressMonitor.subTask("Restoring Taxon Navigator");
233
		subProgressMonitor.worked(1);
234

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

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

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

    
268
		List<CdmBase> pathList = new ArrayList<CdmBase>();
269

    
270
		if (string.length() == 0) {
271
            return null;
272
        }
273

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

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

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

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

    
316
		super.saveState(memento);
317

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

    
321
		monitor.beginTask("Saving Taxon Navigator State", treePaths.length);
322

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

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

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

    
375
		DataChangeBridge.handleDataChange(changeEvents, dataChangeBehavior);
376
	}
377

    
378
	/** {@inheritDoc} */
379
	@Override
380
	public String getFrameToolTipText(Object element) {
381
		if (element instanceof Root) {
382
			return "Taxonomic Tree";
383
		}
384
		return super.getFrameToolTipText(element);
385
	}
386

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

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

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

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

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

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

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

    
506

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

    
516
	}
517

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

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

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

    
559
    }
560

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