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
		getCommonViewer().refresh();
178
	}
179

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
314
		super.saveState(memento);
315

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
504

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

    
514
	}
515

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

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

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

    
557
    }
558

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