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