Project

General

Profile

Download (14.9 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.TreePath;
29
import org.eclipse.ui.IMemento;
30
import org.eclipse.ui.IViewSite;
31
import org.eclipse.ui.PartInitException;
32
import org.eclipse.ui.navigator.CommonNavigator;
33

    
34
import eu.etaxonomy.cdm.api.application.CdmApplicationState;
35
import eu.etaxonomy.cdm.api.application.CdmChangeEvent;
36
import eu.etaxonomy.cdm.api.application.CdmChangeEvent.Action;
37
import eu.etaxonomy.cdm.api.application.ICdmChangeListener;
38
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
39
import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
40
import eu.etaxonomy.cdm.api.service.IClassificationService;
41
import eu.etaxonomy.cdm.model.common.CdmBase;
42
import eu.etaxonomy.cdm.model.taxon.Classification;
43
import eu.etaxonomy.cdm.model.taxon.TaxonNaturalComparator;
44
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
45
import eu.etaxonomy.cdm.model.taxon.TaxonNodeByRankAndNameComparator;
46
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
47
import eu.etaxonomy.taxeditor.model.DataChangeBridge;
48
import eu.etaxonomy.taxeditor.model.IDataChangeBehavior;
49
import eu.etaxonomy.taxeditor.model.MessagingUtils;
50
import eu.etaxonomy.taxeditor.navigation.NavigationUtil;
51
import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
52
import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
53
import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
54
import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
55
import eu.etaxonomy.taxeditor.store.CdmStore;
56
import eu.etaxonomy.taxeditor.store.LoginManager;
57

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

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

    
76
	private static final String TREE_PATH = "treepath";
77

    
78
	private static final String TREE_PATHS = "treepaths";
79

    
80
	private ConversationHolder conversation;
81

    
82
	private ICdmEntitySession cdmEntitySession;
83

    
84
	private String partNameCache;
85

    
86
	private IDataChangeBehavior dataChangeBehavior;
87

    
88
	private Root root;
89

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

    
123
		if (CdmStore.isActive()) {
124

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

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

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

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

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

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

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

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

    
210
		IMemento treePathsMemento = memento.getChild(TREE_PATHS);
211

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

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

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

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

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

    
260
		List<CdmBase> pathList = new ArrayList<CdmBase>();
261

    
262
		if (string.length() == 0) {
263
            return null;
264
        }
265

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

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

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

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

    
308
		super.saveState(memento);
309

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

    
313
		monitor.beginTask("Saving Taxon Navigator State", treePaths.length);
314

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

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

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

    
367
		DataChangeBridge.handleDataChange(changeEvents, dataChangeBehavior);
368
	}
369

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

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

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

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

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

    
450
	/** {@inheritDoc} */
451
	@Override
452
	protected void handleDoubleClick(DoubleClickEvent anEvent) {
453
		NavigationUtil.executeEditHandler();
454
		// If the double click is passed up to the super-class it will
455
		// expand/collapse trees.
456
		// We do not want that
457
		// super.handleDoubleClick(anEvent);
458
	}
459

    
460
	/**
461
	 * <p>
462
	 * onComplete
463
	 * </p>
464
	 *
465
	 * @return a boolean.
466
	 */
467
	@Override
468
	public boolean onComplete() {
469
		return true;
470
	}
471

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

    
492

    
493
	/* (non-Javadoc)
494
	 * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
495
	 */
496
	@Override
497
	public void update(Observable o, Object arg) {
498
		if(o instanceof LoginManager){
499
			refresh();
500
		}
501

    
502
	}
503

    
504
    /* (non-Javadoc)
505
     * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled#getCdmEntitySession()
506
     */
507
    @Override
508
    public ICdmEntitySession getCdmEntitySession() {
509
       return cdmEntitySession;
510
    }
511

    
512
    /* (non-Javadoc)
513
     * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled#getRootEntities()
514
     */
515
    @Override
516
    public List<Classification> getRootEntities() {
517
        if(root != null) {
518
            return root.getParentBeans();
519
        }
520
        return null;
521
    }
522

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

    
545
    }
546

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