added a readme file
[taxeditor.git] / 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.Set;
17 import java.util.UUID;
18
19 import org.apache.log4j.Logger;
20 import org.eclipse.core.commands.Command;
21 import org.eclipse.core.commands.common.NotDefinedException;
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.swt.widgets.Composite;
27 import org.eclipse.ui.IMemento;
28 import org.eclipse.ui.IViewSite;
29 import org.eclipse.ui.PartInitException;
30 import org.eclipse.ui.commands.ICommandService;
31 import org.eclipse.ui.handlers.IHandlerService;
32 import org.eclipse.ui.navigator.CommonNavigator;
33 import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
34
35 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
36 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
37 import eu.etaxonomy.cdm.model.common.CdmBase;
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.navigation.NavigationUtil;
42 import eu.etaxonomy.taxeditor.operations.IPostOperationEnabled;
43 import eu.etaxonomy.taxeditor.store.CdmStore;
44
45 /**
46 * Taxonomic tree implementation using Common Navigator Framework.
47 *
48 * @author p.ciardelli
49 * @created 02.06.2009
50 * @version 1.0
51 */
52 public class TaxonNavigator extends CommonNavigator implements IPostOperationEnabled, IConversationEnabled{
53 private static final Logger logger = Logger
54 .getLogger(TaxonNavigator.class);
55
56 /** Constant <code>ID="eu.etaxonomy.taxeditor.navigation.navig"{trunked}</code> */
57 public static final String ID = "eu.etaxonomy.taxeditor.navigation.navigator"; //$NON-NLS-1$
58
59 /** Constant <code>OPEN_COMMAND_ID="eu.etaxonomy.taxeditor.navigation.comma"{trunked}</code> */
60 public static final String OPEN_COMMAND_ID = "eu.etaxonomy.taxeditor.navigation.command.editSelection";
61
62 private static final String TREE_PATH = "treepath";
63
64 private static final String TREE_PATHS = "treepaths";
65
66 private ConversationHolder conversation;
67
68 private String partNameCache;
69
70 private IWorkbenchSiteProgressService service;
71
72 private IDataChangeBehavior dataChangeBehavior;
73
74 /* (non-Javadoc)
75 * @see org.eclipse.ui.navigator.CommonNavigator#getInitialInput()
76 */
77 /** {@inheritDoc} */
78 @Override
79 protected IAdaptable getInitialInput() {
80 if(CdmStore.isActive()){
81 // TODO when closing and reopening the taxon navigator
82 // we do not preserve state. Closing the view, in contrary to closing the whole application
83 // should be handled by the state manager too
84
85 return new Root(conversation);
86 }
87 return new EmptyRoot();
88 }
89
90 /** {@inheritDoc} */
91 public void init(IViewSite site)
92 throws PartInitException {
93 super.init(site);
94 service = (IWorkbenchSiteProgressService) getSite().getAdapter(IWorkbenchSiteProgressService.class);
95 init();
96 }
97
98 /**
99 * <p>init</p>
100 */
101 public void init(){
102 if(CdmStore.isActive() && conversation == null){
103 conversation = CdmStore.createConversation();
104 conversation.registerForDataStoreChanges(TaxonNavigator.this);
105 }
106 }
107
108 /**
109 * Refresh this navigators viewer
110 */
111 public void refresh(){
112 logger.warn("Refreshing navigator");
113 getConversationHolder().bind();
114 this.getCommonViewer().refresh();
115 }
116
117 /**
118 * Removes all content
119 */
120 public void clear(){
121 getCommonViewer().setInput(new EmptyRoot());
122 }
123
124 /**
125 * <p>restore</p>
126 *
127 * @param memento a {@link org.eclipse.ui.IMemento} object.
128 * @param monitor a {@link org.eclipse.core.runtime.IProgressMonitor} object.
129 */
130 public void restore(IMemento memento, IProgressMonitor monitor) {
131 if (memento == null) {
132 getCommonViewer().setInput(new Root(conversation));
133 return;
134 }
135 int mementoWork = 0;
136 Set<TreePath> treePaths = new HashSet<TreePath>();
137 IMemento[] treePathMementos = null;
138
139 IMemento treePathsMemento = memento.getChild(TREE_PATHS);
140
141 if (treePathsMemento != null) {
142 treePathMementos = treePathsMemento.getChildren(TREE_PATH);
143 mementoWork = treePathMementos.length;
144 }
145 // begin the monitor with steps for all tree paths and steps for creating
146 // conversation s.o., refreshing the tree and setting the paths
147 IProgressMonitor subProgressMonitor = NavigationUtil.getSubProgressMonitor(monitor, 1);
148
149 subProgressMonitor.beginTask("Restoring Taxon Navigator", 1 + mementoWork + 5);
150 subProgressMonitor.subTask("");
151 subProgressMonitor.worked(1);
152
153 conversation = CdmStore.createConversation();
154 subProgressMonitor.worked(1);
155 conversation.registerForDataStoreChanges(TaxonNavigator.this);
156 subProgressMonitor.worked(1);
157 getCommonViewer().setInput(new Root(conversation));
158 subProgressMonitor.worked(1);
159 getCommonViewer().refresh();
160 subProgressMonitor.worked(1);
161
162
163
164 if (treePathMementos != null && treePathMementos.length > 0) {
165 for (IMemento treePathMemento : treePathMementos) {
166 TreePath treePath = createTreePathFromString(treePathMemento.getID());
167 if (!subProgressMonitor.isCanceled() && treePath != null) {
168 treePaths.add(treePath);
169 subProgressMonitor.worked(1);
170 }
171 }
172 }
173 if (treePaths.size() > 0) {
174 TaxonNavigator.this.getCommonViewer().setExpandedTreePaths(treePaths.toArray(new TreePath[0]));
175 subProgressMonitor.worked(1);
176 }
177 subProgressMonitor.done();
178 }
179
180 /**
181 * @param string
182 * @return
183 */
184 private TreePath createTreePathFromString(String string) {
185
186 List<CdmBase> pathList = new ArrayList<CdmBase>();
187
188 if(string.length() == 0) return null;
189
190 for (String uuid : string.split(" ")) {
191 CdmBase cdmBaseObject = CdmStore.getClassificationService().getTaxonNodeByUuid(UUID.fromString(uuid));
192 if (cdmBaseObject == null) {
193 // is this a tree uuid?
194 cdmBaseObject = CdmStore.getClassificationService().getClassificationByUuid(UUID.fromString(uuid));
195
196 if(cdmBaseObject == null) return null;
197 }
198 pathList.add(cdmBaseObject);
199 }
200 return new TreePath(pathList.toArray());
201 }
202
203
204 /** {@inheritDoc} */
205 @Override
206 public void saveState(IMemento aMemento) {
207 //
208 }
209
210 /**
211 * <p>saveTreeState</p>
212 *
213 * @param memento a {@link org.eclipse.ui.IMemento} object.
214 * @param progressMonitor a {@link org.eclipse.core.runtime.IProgressMonitor} object.
215 */
216 public void saveTreeState(IMemento memento, IProgressMonitor progressMonitor) {
217 if (memento == null) {
218 return;
219 }
220 IProgressMonitor monitor = NavigationUtil.getSubProgressMonitor(progressMonitor, 1);
221
222 super.saveState(memento);
223
224 memento = memento.createChild(TREE_PATHS);
225 TreePath[] treePaths = this.getCommonViewer().getExpandedTreePaths();
226
227 monitor.beginTask("Saving Taxon Navigator State", treePaths.length);
228
229 for (TreePath treePath : treePaths) {
230 int pathLength = treePath.getSegmentCount();
231 String path = "";
232 for (int i = 0; i < pathLength; i++) {
233 Object segment = treePath.getSegment(i);
234 if (segment instanceof CdmBase) {
235 path += ((CdmBase) segment).getUuid().toString() + " ";
236 monitor.worked(1);
237 } else {
238 logger.warn("Non-taxon tree path segment " + segment);
239 }
240 }
241 logger.info("Creating memento child for path " + path.trim());
242 memento.createChild(TREE_PATH, path.trim());
243 }
244 monitor.done();
245 }
246
247 /**
248 * Activates the current view.
249 */
250 private void activateView() {
251 getSite().getPage().activate(this);
252 }
253
254 /* (non-Javadoc)
255 * @see org.eclipse.ui.navigator.CommonNavigator#createPartControl(org.eclipse.swt.widgets.Composite)
256 */
257 /** {@inheritDoc} */
258 public void createPartControl(Composite aParent) {
259 super.createPartControl(aParent);
260
261 // It seems the workbench does not set the focus at the right time. This should fix this.
262 // getCommonViewer().addSelectionChangedListener(new ISelectionChangedListener() {
263 // public void selectionChanged(SelectionChangedEvent event) {
264 // activateView();
265 // }
266 // });
267 }
268
269
270 /* (non-Javadoc)
271 * @see eu.etaxonomy.cdm.api.conversation.IConversationEnabled#getConversationHolder()
272 */
273 /**
274 * <p>getConversationHolder</p>
275 *
276 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder} object.
277 */
278 public ConversationHolder getConversationHolder() {
279 return conversation;
280 }
281
282 /* (non-Javadoc)
283 * @see eu.etaxonomy.cdm.persistence.hibernate.ICdmPostDataChangeObserver#update(eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap)
284 */
285 /** {@inheritDoc} */
286 public void update(CdmDataChangeMap changeEvents) {
287 if(dataChangeBehavior == null){
288 dataChangeBehavior = new TaxonNavigatorDataChangeBehavior(this);
289 }
290
291 DataChangeBridge.handleDataChange(changeEvents, dataChangeBehavior);
292 }
293
294 /** {@inheritDoc} */
295 public String getFrameToolTipText(Object element) {
296 if (element instanceof Root) {
297 return "Taxonomic Tree";
298 }
299 return super.getFrameToolTipText(element);
300 }
301
302 /* (non-Javadoc)
303 * @see org.eclipse.ui.part.WorkbenchPart#dispose()
304 */
305 /** {@inheritDoc} */
306 @Override
307 public void dispose() {
308 super.dispose();
309 dataChangeBehavior = null;
310 if(conversation != null){
311 conversation.unregisterForDataStoreChanges(this);
312 }
313 }
314
315 /* (non-Javadoc)
316 * @see org.eclipse.ui.navigator.CommonNavigator#setFocus()
317 */
318 /** {@inheritDoc} */
319 @Override
320 public void setFocus() {
321 //logger.warn("Setting focus to navigator");
322 super.setFocus();
323 if(getConversationHolder() != null){
324 getConversationHolder().bind();
325 }
326 }
327
328 /* (non-Javadoc)
329 * @see eu.etaxonomy.taxeditor.operations.IPostOperationEnabled#postOperation(eu.etaxonomy.cdm.model.common.CdmBase)
330 */
331 /** {@inheritDoc} */
332 public boolean postOperation(CdmBase objectAffectedByOperation) {
333 // nothing to do here
334 return true;
335 }
336
337 /**
338 * <p>save</p>
339 *
340 * @param memento a {@link org.eclipse.ui.IMemento} object.
341 * @param monitor a {@link org.eclipse.core.runtime.IProgressMonitor} object.
342 */
343 public void save(IMemento memento, IProgressMonitor monitor) {
344 saveTreeState(memento, monitor);
345 if(conversation != null){
346 conversation.unregisterForDataStoreChanges(this);
347 conversation = null;
348 }
349 }
350
351 /** {@inheritDoc} */
352 @Override
353 protected void handleDoubleClick(DoubleClickEvent anEvent) {
354
355 ICommandService commandService = (ICommandService)getSite().getService(ICommandService.class);
356
357 Command command = commandService.getCommand(OPEN_COMMAND_ID);
358 if(command.isEnabled()) {
359 IHandlerService handlerService = (IHandlerService)getSite().getService(IHandlerService.class);
360 try {
361 handlerService.executeCommand(OPEN_COMMAND_ID, null);
362 } catch (NotDefinedException e) {
363 throw new RuntimeException("Could not find open command: " + OPEN_COMMAND_ID);
364 } catch (Exception e) {
365 logger.error("An exception occured while trying to open a selection", e);
366 }
367 }
368 // If the double click is passed up to the super-class it will expand/collapse trees.
369 // We do not want that
370 //super.handleDoubleClick(anEvent);
371 }
372
373 /**
374 * <p>onComplete</p>
375 *
376 * @return a boolean.
377 */
378 public boolean onComplete() {
379 // TODO Auto-generated method stub
380 return false;
381 }
382
383 /* (non-Javadoc)
384 * @see org.eclipse.ui.part.WorkbenchPart#showBusy(boolean)
385 */
386 /** {@inheritDoc} */
387 @Override
388 public void showBusy(boolean busy) {
389 super.showBusy(busy);
390 getCommonViewer().getControl().setEnabled(!busy);
391 if(busy){
392 partNameCache = getPartName();
393 setPartName("Loading datasources");
394 }else{
395 if(partNameCache != null){
396 setPartName(partNameCache);
397 }
398 }
399 }
400 }