Merge branch 'develop' of wp5.e-taxonomy.eu:/var/git/taxeditor into remoting-4.0
[taxeditor.git] / eu.etaxonomy.taxeditor.navigation / src / main / java / eu / etaxonomy / taxeditor / navigation / navigator / TaxonNavigator.java
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.Comparator;
15 import java.util.HashSet;
16 import java.util.List;
17 import java.util.Observable;
18 import java.util.Observer;
19 import java.util.Set;
20 import java.util.UUID;
21
22 import org.eclipse.core.runtime.IAdaptable;
23 import org.eclipse.core.runtime.IProgressMonitor;
24 import org.eclipse.jface.viewers.DoubleClickEvent;
25 import org.eclipse.jface.viewers.TreePath;
26 import org.eclipse.ui.IMemento;
27 import org.eclipse.ui.IViewSite;
28 import org.eclipse.ui.PartInitException;
29 import org.eclipse.ui.navigator.CommonNavigator;
30
31 import eu.etaxonomy.cdm.api.application.CdmApplicationState;
32 import eu.etaxonomy.cdm.api.application.CdmChangeEvent;
33 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
34 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
35 import eu.etaxonomy.cdm.api.service.IClassificationService;
36 import eu.etaxonomy.cdm.model.common.CdmBase;
37 import eu.etaxonomy.cdm.model.taxon.Classification;
38 import eu.etaxonomy.cdm.model.taxon.TaxonNaturalComparator;
39 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
40 import eu.etaxonomy.cdm.model.taxon.TaxonNodeComparator;
41 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
42 import eu.etaxonomy.taxeditor.model.DataChangeBridge;
43 import eu.etaxonomy.taxeditor.model.IDataChangeBehavior;
44 import eu.etaxonomy.taxeditor.model.MessagingUtils;
45 import eu.etaxonomy.taxeditor.navigation.NavigationUtil;
46 import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
47 import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
48 import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
49 import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
50 import eu.etaxonomy.taxeditor.store.CdmStore;
51 import eu.etaxonomy.taxeditor.store.LoginManager;
52
53 /**
54 * Taxonomic tree implementation using Common Navigator Framework.
55 *
56 * @author p.ciardelli
57 * @author n.hoffmann
58 * @created 02.06.2009
59 * @version 1.0
60 */
61 public class TaxonNavigator extends CommonNavigator implements
62 IPostOperationEnabled, IConversationEnabled, Observer, ICdmEntitySessionEnabled {
63
64 /**
65 * Constant
66 * <code>ID="eu.etaxonomy.taxeditor.navigation.navig"{trunked}</code>
67 */
68 public static final String ID = "eu.etaxonomy.taxeditor.navigation.navigator"; //$NON-NLS-1$
69
70 private static final String TREE_PATH = "treepath";
71
72 private static final String TREE_PATHS = "treepaths";
73
74 private ConversationHolder conversation;
75
76 private ICdmEntitySession cdmEntitySession;
77
78 private String partNameCache;
79
80 private IDataChangeBehavior dataChangeBehavior;
81
82 private Root root;
83
84 /*
85 * (non-Javadoc)
86 *
87 * @see org.eclipse.ui.navigator.CommonNavigator#getInitialInput()
88 */
89 /** {@inheritDoc} */
90 @Override
91 protected IAdaptable getInitialInput() {
92 Comparator comparator;
93 if (PreferencesUtil.getSortNodesNaturally()){
94 comparator = new TaxonNaturalComparator();
95 } else{
96 comparator = new TaxonNodeComparator();
97 }
98 TaxonNodeNavigatorComparator viewerComparator = new TaxonNodeNavigatorComparator(comparator);
99 this.getCommonViewer().setComparator(viewerComparator);
100 setLinkingEnabled(true);
101 // this.getCommonViewer().addSelectionChangedListener(new ISelectionChangedListener() {
102 //
103 // @Override
104 // public void selectionChanged(SelectionChangedEvent arg0) {
105 // IStructuredSelection selection = (IStructuredSelection) getCommonViewer().getSelection();
106 //
107 // Object firstElement = selection.getFirstElement();
108 // //
109 // if (!(firstElement instanceof Classification)){
110 // //NavigationUtil.selectInNavigator(firstElement, null);
111 // NavigationUtil.openEditor(firstElement);
112 // }
113 //
114 // }
115 // } );
116
117 if (CdmStore.isActive()) {
118
119 // TODO when closing and reopening the taxon navigator
120 // we do not preserve state. Closing the view, in contrary to
121 // closing the whole application
122 // should be handled by the state manager too
123 root = new Root(conversation);
124 return root;
125 }
126 return new EmptyRoot();
127 }
128
129 /** {@inheritDoc} */
130 @Override
131 public void init(IViewSite site) throws PartInitException {
132 super.init(site);
133 init();
134 }
135
136 /**
137 * <p>
138 * init
139 * </p>
140 */
141 public void init() {
142
143 if (CdmStore.isActive() && conversation == null) {
144 conversation = CdmStore.createConversation();
145 conversation.registerForDataStoreChanges(TaxonNavigator.this);
146 }
147 if (CdmStore.isActive() && cdmEntitySession == null) {
148 cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
149 CdmApplicationState.getCurrentDataChangeService().register(this);
150 }
151 CdmStore.getLoginManager().addObserver(this);
152 }
153
154 /**
155 * Refresh this navigators viewer
156 */
157 public void refresh() {
158 if(getConversationHolder() != null){
159 getConversationHolder().bind();
160 //FIXME : Need to make sure this is a stable fix (ticket 3822)
161 if(!getConversationHolder().isCompleted()){
162 getConversationHolder().commit();
163 }
164 }
165 getCommonViewer().refresh();
166 }
167
168 /**
169 * Refresh this navigators viewer
170 */
171 public void refresh(Set objects) {
172 for(Object obj : objects) {
173 getCommonViewer().refresh(obj);
174 }
175 }
176
177 /**
178 * Removes all content
179 */
180 public void clear() {
181 getCommonViewer().setInput(new EmptyRoot());
182 }
183
184 /**
185 * <p>
186 * restore
187 * </p>
188 *
189 * @param memento
190 * a {@link org.eclipse.ui.IMemento} object.
191 * @param monitor
192 * a {@link org.eclipse.core.runtime.IProgressMonitor} object.
193 */
194 public void restore(IMemento memento, IProgressMonitor monitor) {
195 root = new Root(conversation);
196 if (memento == null) {
197 getCommonViewer().setInput(root);
198 return;
199 }
200 int mementoWork = 0;
201 Set<TreePath> treePaths = new HashSet<TreePath>();
202 IMemento[] treePathMementos = null;
203
204 IMemento treePathsMemento = memento.getChild(TREE_PATHS);
205
206 if (treePathsMemento != null) {
207 treePathMementos = treePathsMemento.getChildren(TREE_PATH);
208 mementoWork = treePathMementos.length;
209 }
210 // begin the monitor with steps for all tree paths and steps for
211 // creating
212 // conversation s.o., refreshing the tree and setting the paths
213 IProgressMonitor subProgressMonitor = NavigationUtil
214 .getSubProgressMonitor(monitor, 1);
215
216 subProgressMonitor.beginTask("Restoring Taxon Navigator",
217 1 + mementoWork + 5);
218 subProgressMonitor.subTask("Restoring Taxon Navigator");
219 subProgressMonitor.worked(1);
220
221 conversation = CdmStore.createConversation();
222 subProgressMonitor.worked(1);
223 conversation.registerForDataStoreChanges(TaxonNavigator.this);
224 subProgressMonitor.worked(1);
225 getCommonViewer().setInput(root);
226 subProgressMonitor.worked(1);
227 getCommonViewer().refresh();
228 subProgressMonitor.worked(1);
229
230 if (treePathMementos != null && treePathMementos.length > 0) {
231 for (IMemento treePathMemento : treePathMementos) {
232 TreePath treePath = createTreePathFromString(treePathMemento
233 .getID());
234 if (!subProgressMonitor.isCanceled() && treePath != null) {
235 treePaths.add(treePath);
236 subProgressMonitor.worked(1);
237 }
238 }
239 }
240 if (treePaths.size() > 0) {
241 TaxonNavigator.this.getCommonViewer().setExpandedTreePaths(
242 treePaths.toArray(new TreePath[0]));
243 subProgressMonitor.worked(1);
244 }
245 subProgressMonitor.done();
246 }
247
248 /**
249 * @param string
250 * @return
251 */
252 private TreePath createTreePathFromString(String string) {
253
254 List<CdmBase> pathList = new ArrayList<CdmBase>();
255
256 if (string.length() == 0) {
257 return null;
258 }
259
260 for (String uuid : string.split(" ")) {
261 CdmBase cdmBaseObject = CdmStore.getService(
262 IClassificationService.class).getTaxonNodeByUuid(
263 UUID.fromString(uuid));
264 if (cdmBaseObject == null) {
265 // is this a tree uuid?
266 cdmBaseObject = CdmStore.getService(
267 IClassificationService.class).load(
268 UUID.fromString(uuid));
269
270 if (cdmBaseObject == null) {
271 return null;
272 }
273 }
274 pathList.add(cdmBaseObject);
275 }
276 return new TreePath(pathList.toArray());
277 }
278
279 /** {@inheritDoc} */
280 @Override
281 public void saveState(IMemento aMemento) {
282 //
283 }
284
285 /**
286 * <p>
287 * saveTreeState
288 * </p>
289 *
290 * @param memento
291 * a {@link org.eclipse.ui.IMemento} object.
292 * @param progressMonitor
293 * a {@link org.eclipse.core.runtime.IProgressMonitor} object.
294 */
295 public void saveTreeState(IMemento memento, IProgressMonitor progressMonitor) {
296 if (memento == null) {
297 return;
298 }
299 IProgressMonitor monitor = NavigationUtil.getSubProgressMonitor(
300 progressMonitor, 1);
301
302 super.saveState(memento);
303
304 memento = memento.createChild(TREE_PATHS);
305 TreePath[] treePaths = this.getCommonViewer().getExpandedTreePaths();
306
307 monitor.beginTask("Saving Taxon Navigator State", treePaths.length);
308
309 for (TreePath treePath : treePaths) {
310 int pathLength = treePath.getSegmentCount();
311 String path = "";
312 for (int i = 0; i < pathLength; i++) {
313 Object segment = treePath.getSegment(i);
314 if (segment instanceof CdmBase) {
315 path += ((CdmBase) segment).getUuid().toString() + " ";
316 monitor.worked(1);
317 } else {
318 MessagingUtils.warn(getClass(),
319 "Non-taxon tree path segment " + segment);
320 }
321 }
322 memento.createChild(TREE_PATH, path.trim());
323 }
324 monitor.done();
325 }
326
327 /*
328 * (non-Javadoc)
329 *
330 * @see
331 * eu.etaxonomy.cdm.api.conversation.IConversationEnabled#getConversationHolder
332 * ()
333 */
334 /**
335 * <p>
336 * getConversationHolder
337 * </p>
338 *
339 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
340 * object.
341 */
342 @Override
343 public ConversationHolder getConversationHolder() {
344 return conversation;
345 }
346
347 /*
348 * (non-Javadoc)
349 *
350 * @see
351 * eu.etaxonomy.cdm.persistence.hibernate.ICdmPostDataChangeObserver#update
352 * (eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap)
353 */
354 /** {@inheritDoc} */
355 @Override
356 public void update(CdmDataChangeMap changeEvents) {
357 if (dataChangeBehavior == null) {
358 dataChangeBehavior = new TaxonNavigatorDataChangeBehavior(this);
359 }
360
361 DataChangeBridge.handleDataChange(changeEvents, dataChangeBehavior);
362 }
363
364 /** {@inheritDoc} */
365 @Override
366 public String getFrameToolTipText(Object element) {
367 if (element instanceof Root) {
368 return "Taxonomic Tree";
369 }
370 return super.getFrameToolTipText(element);
371 }
372
373 /*
374 * (non-Javadoc)
375 *
376 * @see org.eclipse.ui.part.WorkbenchPart#dispose()
377 */
378 /** {@inheritDoc} */
379 @Override
380 public void dispose() {
381 super.dispose();
382 dataChangeBehavior = null;
383 if (conversation != null) {
384 conversation.unregisterForDataStoreChanges(this);
385 }
386 if(cdmEntitySession != null) {
387 cdmEntitySession.dispose();
388 }
389 }
390
391 /*
392 * (non-Javadoc)
393 *
394 * @see org.eclipse.ui.navigator.CommonNavigator#setFocus()
395 */
396 /** {@inheritDoc} */
397 @Override
398 public void setFocus() {
399 // logger.warn("Setting focus to navigator");
400 super.setFocus();
401 if (getConversationHolder() != null) {
402 getConversationHolder().bind();
403 }
404 if(cdmEntitySession != null) {
405 cdmEntitySession.bind();
406 }
407 }
408
409 /*
410 * (non-Javadoc)
411 *
412 * @see
413 * eu.etaxonomy.taxeditor.operations.IPostOperationEnabled#postOperation
414 * (eu.etaxonomy.cdm.model.common.CdmBase)
415 */
416 /** {@inheritDoc} */
417 @Override
418 public boolean postOperation(CdmBase objectAffectedByOperation) {
419 // nothing to do here
420 return true;
421 }
422
423 /**
424 * <p>
425 * save
426 * </p>
427 *
428 * @param memento
429 * a {@link org.eclipse.ui.IMemento} object.
430 * @param monitor
431 * a {@link org.eclipse.core.runtime.IProgressMonitor} object.
432 */
433 public void save(IMemento memento, IProgressMonitor monitor) {
434 saveTreeState(memento, monitor);
435 if (conversation != null) {
436 conversation.unregisterForDataStoreChanges(this);
437 conversation = null;
438 }
439 }
440
441 /** {@inheritDoc} */
442 @Override
443 protected void handleDoubleClick(DoubleClickEvent anEvent) {
444 NavigationUtil.executeEditHandler();
445 // If the double click is passed up to the super-class it will
446 // expand/collapse trees.
447 // We do not want that
448 // super.handleDoubleClick(anEvent);
449 }
450
451 /**
452 * <p>
453 * onComplete
454 * </p>
455 *
456 * @return a boolean.
457 */
458 @Override
459 public boolean onComplete() {
460 return true;
461 }
462
463 /*
464 * (non-Javadoc)
465 *
466 * @see org.eclipse.ui.part.WorkbenchPart#showBusy(boolean)
467 */
468 /** {@inheritDoc} */
469 @Override
470 public void showBusy(boolean busy) {
471 super.showBusy(busy);
472 getCommonViewer().getControl().setEnabled(!busy);
473 if (busy) {
474 partNameCache = getPartName();
475 setPartName("Loading datasources");
476 } else {
477 if (partNameCache != null) {
478 setPartName(partNameCache);
479 }
480 }
481 }
482
483
484 /* (non-Javadoc)
485 * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
486 */
487 @Override
488 public void update(Observable o, Object arg) {
489 if(o instanceof LoginManager){
490 refresh();
491 }
492
493 }
494
495 /* (non-Javadoc)
496 * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled#getCdmEntitySession()
497 */
498 @Override
499 public ICdmEntitySession getCdmEntitySession() {
500 return cdmEntitySession;
501 }
502
503 /* (non-Javadoc)
504 * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled#getRootEntities()
505 */
506 @Override
507 public List<Classification> getRootEntities() {
508 if(root != null) {
509 return root.getParentBeans();
510 }
511 return null;
512 }
513
514 /* (non-Javadoc)
515 * @see eu.etaxonomy.cdm.api.application.ICdmChangeListener#onChange(eu.etaxonomy.cdm.api.application.CdmChangeEvent)
516 */
517 @Override
518 public void onChange(CdmChangeEvent event) {
519 for(CdmBase cb : event.getChangedObjects()) {
520 if(cb instanceof TaxonNode) {
521 getCommonViewer().refresh(cb);
522 } else if (cb instanceof Classification) {
523 getCommonViewer().refresh();
524 }
525 }
526
527 }
528 }