Project

General

Profile

Download (15.3 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.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.taxon.Classification;
44
import eu.etaxonomy.cdm.model.taxon.TaxonNaturalComparator;
45
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
46
import eu.etaxonomy.cdm.model.taxon.TaxonNodeByRankAndNameComparator;
47
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
48
import eu.etaxonomy.taxeditor.model.DataChangeBridge;
49
import eu.etaxonomy.taxeditor.model.IDataChangeBehavior;
50
import eu.etaxonomy.taxeditor.model.MessagingUtils;
51
import eu.etaxonomy.taxeditor.navigation.NavigationUtil;
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
import eu.etaxonomy.taxeditor.view.CdmViewerChooser;
59

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

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

    
78
	private static final String TREE_PATH = "treepath";
79

    
80
	private static final String TREE_PATHS = "treepaths";
81

    
82
	private ConversationHolder conversation;
83

    
84
	private ICdmEntitySession cdmEntitySession;
85

    
86
	private String partNameCache;
87

    
88
	private IDataChangeBehavior dataChangeBehavior;
89

    
90
	private Root root;
91

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

    
125
		if (CdmStore.isActive()) {
126

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

    
137
	/** {@inheritDoc} */
138
	@Override
139
	public void init(IViewSite site) throws PartInitException {
140
		super.init(site);
141
		init();
142
	}
143

    
144
	/**
145
	 * <p>
146
	 * init
147
	 * </p>
148
	 */
149
	public void init() {
150

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

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

    
176
	   /**
177
     * Refresh this navigators viewer
178
     */
179
    public void refresh(Set objects) {
180
        for(Object obj : objects) {
181
            getCommonViewer().refresh(obj);
182
        }
183
    }
184

    
185
	/**
186
	 * Removes all content
187
	 */
188
	public void clear() {
189
		getCommonViewer().setInput(new EmptyRoot());
190
	}
191

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

    
212
		IMemento treePathsMemento = memento.getChild(TREE_PATHS);
213

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

    
224
		subProgressMonitor.beginTask("Restoring Taxon Navigator",
225
				1 + mementoWork + 5);
226
		subProgressMonitor.subTask("Restoring Taxon Navigator");
227
		subProgressMonitor.worked(1);
228

    
229
		conversation = CdmStore.createConversation();
230
		subProgressMonitor.worked(1);
231
		conversation.registerForDataStoreChanges(TaxonNavigator.this);
232
		subProgressMonitor.worked(1);
233
		getCommonViewer().setInput(root);
234
		subProgressMonitor.worked(1);
235
		getCommonViewer().refresh();
236
		subProgressMonitor.worked(1);
237

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

    
256
	/**
257
	 * @param string
258
	 * @return
259
	 */
260
	private TreePath createTreePathFromString(String string) {
261

    
262
		List<CdmBase> pathList = new ArrayList<CdmBase>();
263

    
264
		if (string.length() == 0) {
265
            return null;
266
        }
267

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

    
278
				if (cdmBaseObject == null) {
279
                    return null;
280
                }
281
			}
282
			pathList.add(cdmBaseObject);
283
		}
284
		return new TreePath(pathList.toArray());
285
	}
286

    
287
	/** {@inheritDoc} */
288
	@Override
289
	public void saveState(IMemento aMemento) {
290
		//
291
	}
292

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

    
310
		super.saveState(memento);
311

    
312
		memento = memento.createChild(TREE_PATHS);
313
		TreePath[] treePaths = this.getCommonViewer().getExpandedTreePaths();
314

    
315
		monitor.beginTask("Saving Taxon Navigator State", treePaths.length);
316

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

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

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

    
369
		DataChangeBridge.handleDataChange(changeEvents, dataChangeBehavior);
370
	}
371

    
372
	/** {@inheritDoc} */
373
	@Override
374
	public String getFrameToolTipText(Object element) {
375
		if (element instanceof Root) {
376
			return "Taxonomic Tree";
377
		}
378
		return super.getFrameToolTipText(element);
379
	}
380

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

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

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

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

    
452
	/** {@inheritDoc} */
453
	@Override
454
	protected void handleDoubleClick(DoubleClickEvent event) {
455
        if(event.getSelection() instanceof IStructuredSelection){
456
            Object selectedObject = ((IStructuredSelection) event.getSelection()).getFirstElement();
457
            CdmViewerChooser chooser = new CdmViewerChooser(getSite().getShell());
458
            chooser.chooseViewer(selectedObject);
459
        }
460
		// If the double click is passed up to the super-class it will
461
		// expand/collapse trees.
462
		// We do not want that
463
		// super.handleDoubleClick(anEvent);
464
	}
465

    
466
	/**
467
	 * <p>
468
	 * onComplete
469
	 * </p>
470
	 *
471
	 * @return a boolean.
472
	 */
473
	@Override
474
	public boolean onComplete() {
475
		return true;
476
	}
477

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

    
498

    
499
	/* (non-Javadoc)
500
	 * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
501
	 */
502
	@Override
503
	public void update(Observable o, Object arg) {
504
		if(o instanceof LoginManager){
505
			refresh();
506
		}
507

    
508
	}
509

    
510
    /* (non-Javadoc)
511
     * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled#getCdmEntitySession()
512
     */
513
    @Override
514
    public ICdmEntitySession getCdmEntitySession() {
515
       return cdmEntitySession;
516
    }
517

    
518
    /* (non-Javadoc)
519
     * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled#getRootEntities()
520
     */
521
    @Override
522
    public List<Classification> getRootEntities() {
523
        if(root != null) {
524
            return root.getParentBeans();
525
        }
526
        return null;
527
    }
528

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

    
551
    }
552

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