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