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