Project

General

Profile

Download (15.5 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.operation.IPostOperationEnabled;
55
import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
56
import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
57
import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
58
import eu.etaxonomy.taxeditor.store.CdmStore;
59
import eu.etaxonomy.taxeditor.store.LoginManager;
60

    
61
/**
62
 * Taxonomic tree implementation using Common Navigator Framework.
63
 *
64
 * @author p.ciardelli
65
 * @author n.hoffmann
66
 * @created 02.06.2009
67
 * @version 1.0
68
 */
69
public class TaxonNavigator extends CommonNavigator implements
70
		IPostOperationEnabled, IConversationEnabled, Observer,
71
		ICdmEntitySessionEnabled, ICdmChangeListener {
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";
80

    
81
	private static final String TREE_PATHS = "treepaths";
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
        setLinkingEnabled(true);
112
//		this.getCommonViewer().addSelectionChangedListener(new ISelectionChangedListener() {
113
//
114
//			@Override
115
//			public void selectionChanged(SelectionChangedEvent arg0) {
116
//				IStructuredSelection selection = (IStructuredSelection) getCommonViewer().getSelection();
117
//
118
//				Object firstElement =  selection.getFirstElement();
119
//				//
120
//				if (!(firstElement instanceof Classification)){
121
//					//NavigationUtil.selectInNavigator(firstElement, null);
122
//					NavigationUtil.openEditor(firstElement);
123
//				}
124
//
125
//			}
126
//		} );
127

    
128
		if (CdmStore.isActive()) {
129

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
315
		super.saveState(memento);
316

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
505

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

    
515
	}
516

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

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

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

    
558
    }
559

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