TaxonNavigator : added refresh of navigator on data change
[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.TaxonComparatorSearch;
39 import eu.etaxonomy.cdm.model.taxon.TaxonNaturalComparator;
40 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
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 TaxonComparatorSearch();
97 }
98 TaxonNodeComparator viewerComparator = new TaxonNodeComparator(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 if (cdmEntitySession != null) {
166 cdmEntitySession.fireNotifications();
167 }
168 getCommonViewer().refresh();
169 }
170
171 /**
172 * Refresh this navigators viewer
173 */
174 public void refresh(Set objects) {
175 for(Object obj : objects) {
176 getCommonViewer().refresh(obj);
177 }
178 }
179
180 /**
181 * Removes all content
182 */
183 public void clear() {
184 getCommonViewer().setInput(new EmptyRoot());
185 }
186
187 /**
188 * <p>
189 * restore
190 * </p>
191 *
192 * @param memento
193 * a {@link org.eclipse.ui.IMemento} object.
194 * @param monitor
195 * a {@link org.eclipse.core.runtime.IProgressMonitor} object.
196 */
197 public void restore(IMemento memento, IProgressMonitor monitor) {
198 root = new Root(conversation);
199 if (memento == null) {
200 getCommonViewer().setInput(root);
201 return;
202 }
203 int mementoWork = 0;
204 Set<TreePath> treePaths = new HashSet<TreePath>();
205 IMemento[] treePathMementos = null;
206
207 IMemento treePathsMemento = memento.getChild(TREE_PATHS);
208
209 if (treePathsMemento != null) {
210 treePathMementos = treePathsMemento.getChildren(TREE_PATH);
211 mementoWork = treePathMementos.length;
212 }
213 // begin the monitor with steps for all tree paths and steps for
214 // creating
215 // conversation s.o., refreshing the tree and setting the paths
216 IProgressMonitor subProgressMonitor = NavigationUtil
217 .getSubProgressMonitor(monitor, 1);
218
219 subProgressMonitor.beginTask("Restoring Taxon Navigator",
220 1 + mementoWork + 5);
221 subProgressMonitor.subTask("Restoring Taxon Navigator");
222 subProgressMonitor.worked(1);
223
224 conversation = CdmStore.createConversation();
225 subProgressMonitor.worked(1);
226 conversation.registerForDataStoreChanges(TaxonNavigator.this);
227 subProgressMonitor.worked(1);
228 getCommonViewer().setInput(root);
229 subProgressMonitor.worked(1);
230 getCommonViewer().refresh();
231 subProgressMonitor.worked(1);
232
233 if (treePathMementos != null && treePathMementos.length > 0) {
234 for (IMemento treePathMemento : treePathMementos) {
235 TreePath treePath = createTreePathFromString(treePathMemento
236 .getID());
237 if (!subProgressMonitor.isCanceled() && treePath != null) {
238 treePaths.add(treePath);
239 subProgressMonitor.worked(1);
240 }
241 }
242 }
243 if (treePaths.size() > 0) {
244 TaxonNavigator.this.getCommonViewer().setExpandedTreePaths(
245 treePaths.toArray(new TreePath[0]));
246 subProgressMonitor.worked(1);
247 }
248 subProgressMonitor.done();
249 }
250
251 /**
252 * @param string
253 * @return
254 */
255 private TreePath createTreePathFromString(String string) {
256
257 List<CdmBase> pathList = new ArrayList<CdmBase>();
258
259 if (string.length() == 0) {
260 return null;
261 }
262
263 for (String uuid : string.split(" ")) {
264 CdmBase cdmBaseObject = CdmStore.getService(
265 IClassificationService.class).getTaxonNodeByUuid(
266 UUID.fromString(uuid));
267 if (cdmBaseObject == null) {
268 // is this a tree uuid?
269 cdmBaseObject = CdmStore.getService(
270 IClassificationService.class).load(
271 UUID.fromString(uuid));
272
273 if (cdmBaseObject == null) {
274 return null;
275 }
276 }
277 pathList.add(cdmBaseObject);
278 }
279 return new TreePath(pathList.toArray());
280 }
281
282 /** {@inheritDoc} */
283 @Override
284 public void saveState(IMemento aMemento) {
285 //
286 }
287
288 /**
289 * <p>
290 * saveTreeState
291 * </p>
292 *
293 * @param memento
294 * a {@link org.eclipse.ui.IMemento} object.
295 * @param progressMonitor
296 * a {@link org.eclipse.core.runtime.IProgressMonitor} object.
297 */
298 public void saveTreeState(IMemento memento, IProgressMonitor progressMonitor) {
299 if (memento == null) {
300 return;
301 }
302 IProgressMonitor monitor = NavigationUtil.getSubProgressMonitor(
303 progressMonitor, 1);
304
305 super.saveState(memento);
306
307 memento = memento.createChild(TREE_PATHS);
308 TreePath[] treePaths = this.getCommonViewer().getExpandedTreePaths();
309
310 monitor.beginTask("Saving Taxon Navigator State", treePaths.length);
311
312 for (TreePath treePath : treePaths) {
313 int pathLength = treePath.getSegmentCount();
314 String path = "";
315 for (int i = 0; i < pathLength; i++) {
316 Object segment = treePath.getSegment(i);
317 if (segment instanceof CdmBase) {
318 path += ((CdmBase) segment).getUuid().toString() + " ";
319 monitor.worked(1);
320 } else {
321 MessagingUtils.warn(getClass(),
322 "Non-taxon tree path segment " + segment);
323 }
324 }
325 memento.createChild(TREE_PATH, path.trim());
326 }
327 monitor.done();
328 }
329
330 /*
331 * (non-Javadoc)
332 *
333 * @see
334 * eu.etaxonomy.cdm.api.conversation.IConversationEnabled#getConversationHolder
335 * ()
336 */
337 /**
338 * <p>
339 * getConversationHolder
340 * </p>
341 *
342 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
343 * object.
344 */
345 @Override
346 public ConversationHolder getConversationHolder() {
347 return conversation;
348 }
349
350 /*
351 * (non-Javadoc)
352 *
353 * @see
354 * eu.etaxonomy.cdm.persistence.hibernate.ICdmPostDataChangeObserver#update
355 * (eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap)
356 */
357 /** {@inheritDoc} */
358 @Override
359 public void update(CdmDataChangeMap changeEvents) {
360 if (dataChangeBehavior == null) {
361 dataChangeBehavior = new TaxonNavigatorDataChangeBehavior(this);
362 }
363
364 DataChangeBridge.handleDataChange(changeEvents, dataChangeBehavior);
365 }
366
367 /** {@inheritDoc} */
368 @Override
369 public String getFrameToolTipText(Object element) {
370 if (element instanceof Root) {
371 return "Taxonomic Tree";
372 }
373 return super.getFrameToolTipText(element);
374 }
375
376 /*
377 * (non-Javadoc)
378 *
379 * @see org.eclipse.ui.part.WorkbenchPart#dispose()
380 */
381 /** {@inheritDoc} */
382 @Override
383 public void dispose() {
384 super.dispose();
385 dataChangeBehavior = null;
386 if (conversation != null) {
387 conversation.unregisterForDataStoreChanges(this);
388 }
389 if(cdmEntitySession != null) {
390 cdmEntitySession.dispose();
391 }
392 }
393
394 /*
395 * (non-Javadoc)
396 *
397 * @see org.eclipse.ui.navigator.CommonNavigator#setFocus()
398 */
399 /** {@inheritDoc} */
400 @Override
401 public void setFocus() {
402 // logger.warn("Setting focus to navigator");
403 super.setFocus();
404 if (getConversationHolder() != null) {
405 getConversationHolder().bind();
406 }
407 if(cdmEntitySession != null) {
408 cdmEntitySession.bind();
409 }
410 }
411
412 /*
413 * (non-Javadoc)
414 *
415 * @see
416 * eu.etaxonomy.taxeditor.operations.IPostOperationEnabled#postOperation
417 * (eu.etaxonomy.cdm.model.common.CdmBase)
418 */
419 /** {@inheritDoc} */
420 @Override
421 public boolean postOperation(CdmBase objectAffectedByOperation) {
422 // nothing to do here
423 return true;
424 }
425
426 /**
427 * <p>
428 * save
429 * </p>
430 *
431 * @param memento
432 * a {@link org.eclipse.ui.IMemento} object.
433 * @param monitor
434 * a {@link org.eclipse.core.runtime.IProgressMonitor} object.
435 */
436 public void save(IMemento memento, IProgressMonitor monitor) {
437 saveTreeState(memento, monitor);
438 if (conversation != null) {
439 conversation.unregisterForDataStoreChanges(this);
440 conversation = null;
441 }
442 }
443
444 /** {@inheritDoc} */
445 @Override
446 protected void handleDoubleClick(DoubleClickEvent anEvent) {
447 NavigationUtil.executeEditHandler();
448 // If the double click is passed up to the super-class it will
449 // expand/collapse trees.
450 // We do not want that
451 // super.handleDoubleClick(anEvent);
452 }
453
454 /**
455 * <p>
456 * onComplete
457 * </p>
458 *
459 * @return a boolean.
460 */
461 @Override
462 public boolean onComplete() {
463 return true;
464 }
465
466 /*
467 * (non-Javadoc)
468 *
469 * @see org.eclipse.ui.part.WorkbenchPart#showBusy(boolean)
470 */
471 /** {@inheritDoc} */
472 @Override
473 public void showBusy(boolean busy) {
474 super.showBusy(busy);
475 getCommonViewer().getControl().setEnabled(!busy);
476 if (busy) {
477 partNameCache = getPartName();
478 setPartName("Loading datasources");
479 } else {
480 if (partNameCache != null) {
481 setPartName(partNameCache);
482 }
483 }
484 }
485
486
487 /* (non-Javadoc)
488 * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
489 */
490 @Override
491 public void update(Observable o, Object arg) {
492 if(o instanceof LoginManager){
493 refresh();
494 }
495
496 }
497
498 /* (non-Javadoc)
499 * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled#getCdmEntitySession()
500 */
501 @Override
502 public ICdmEntitySession getCdmEntitySession() {
503 return cdmEntitySession;
504 }
505
506 /* (non-Javadoc)
507 * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled#getRootEntities()
508 */
509 @Override
510 public List<Classification> getRootEntities() {
511 if(root != null) {
512 return root.getParentBeans();
513 }
514 return null;
515 }
516
517 /* (non-Javadoc)
518 * @see eu.etaxonomy.cdm.api.application.ICdmChangeListener#onChange(eu.etaxonomy.cdm.api.application.CdmChangeEvent)
519 */
520 @Override
521 public void onChange(CdmChangeEvent event) {
522 for(CdmBase cb : event.getChangedObjects()) {
523 if(cb instanceof TaxonNode) {
524 getCommonViewer().refresh(cb);
525 }
526 }
527
528 }
529 }