2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.taxeditor
.navigation
.navigator
.e4
;
12 import java
.util
.ArrayList
;
13 import java
.util
.Arrays
;
14 import java
.util
.Comparator
;
15 import java
.util
.HashMap
;
16 import java
.util
.HashSet
;
17 import java
.util
.List
;
19 import java
.util
.Observable
;
20 import java
.util
.Observer
;
22 import java
.util
.UUID
;
24 import javax
.annotation
.PostConstruct
;
25 import javax
.annotation
.PreDestroy
;
26 import javax
.inject
.Inject
;
28 import org
.eclipse
.core
.commands
.operations
.UndoContext
;
29 import org
.eclipse
.core
.runtime
.IAdaptable
;
30 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
31 import org
.eclipse
.e4
.core
.di
.annotations
.Optional
;
32 import org
.eclipse
.e4
.ui
.di
.Focus
;
33 import org
.eclipse
.e4
.ui
.di
.UIEventTopic
;
34 import org
.eclipse
.e4
.ui
.di
.UISynchronize
;
35 import org
.eclipse
.e4
.ui
.model
.application
.MApplication
;
36 import org
.eclipse
.e4
.ui
.services
.EMenuService
;
37 import org
.eclipse
.e4
.ui
.workbench
.modeling
.EModelService
;
38 import org
.eclipse
.e4
.ui
.workbench
.modeling
.EPartService
;
39 import org
.eclipse
.e4
.ui
.workbench
.modeling
.ESelectionService
;
40 import org
.eclipse
.jface
.util
.LocalSelectionTransfer
;
41 import org
.eclipse
.jface
.viewers
.ISelection
;
42 import org
.eclipse
.jface
.viewers
.ISelectionChangedListener
;
43 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
44 import org
.eclipse
.jface
.viewers
.StructuredSelection
;
45 import org
.eclipse
.jface
.viewers
.TreePath
;
46 import org
.eclipse
.jface
.viewers
.TreeViewer
;
47 import org
.eclipse
.swt
.SWT
;
48 import org
.eclipse
.swt
.dnd
.DND
;
49 import org
.eclipse
.swt
.dnd
.Transfer
;
50 import org
.eclipse
.swt
.layout
.FillLayout
;
51 import org
.eclipse
.swt
.widgets
.Composite
;
52 import org
.eclipse
.swt
.widgets
.Tree
;
53 import org
.eclipse
.ui
.IMemento
;
55 import eu
.etaxonomy
.cdm
.api
.application
.CdmApplicationState
;
56 import eu
.etaxonomy
.cdm
.api
.application
.CdmChangeEvent
;
57 import eu
.etaxonomy
.cdm
.api
.application
.ICdmChangeListener
;
58 import eu
.etaxonomy
.cdm
.api
.conversation
.ConversationHolder
;
59 import eu
.etaxonomy
.cdm
.api
.conversation
.IConversationEnabled
;
60 import eu
.etaxonomy
.cdm
.api
.service
.IClassificationService
;
61 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
62 import eu
.etaxonomy
.cdm
.model
.common
.ICdmBase
;
63 import eu
.etaxonomy
.cdm
.model
.common
.ITreeNode
;
64 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
65 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNaturalComparator
;
66 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
67 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNodeByNameComparator
;
68 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNodeByRankAndNameComparator
;
69 import eu
.etaxonomy
.cdm
.persistence
.hibernate
.CdmDataChangeMap
;
70 import eu
.etaxonomy
.taxeditor
.editor
.ITaxonEditor
;
71 import eu
.etaxonomy
.taxeditor
.event
.WorkbenchEventConstants
;
72 import eu
.etaxonomy
.taxeditor
.model
.AbstractUtility
;
73 import eu
.etaxonomy
.taxeditor
.model
.DataChangeBridge
;
74 import eu
.etaxonomy
.taxeditor
.model
.IContextListener
;
75 import eu
.etaxonomy
.taxeditor
.model
.IDataChangeBehavior
;
76 import eu
.etaxonomy
.taxeditor
.navigation
.NavigationUtil
;
77 import eu
.etaxonomy
.taxeditor
.navigation
.l10n
.Messages
;
78 import eu
.etaxonomy
.taxeditor
.navigation
.navigator
.EmptyRoot
;
79 import eu
.etaxonomy
.taxeditor
.navigation
.navigator
.Root
;
80 import eu
.etaxonomy
.taxeditor
.navigation
.navigator
.TaxonNodeNavigatorComparator
;
81 import eu
.etaxonomy
.taxeditor
.operation
.IPostOperationEnabled
;
82 import eu
.etaxonomy
.taxeditor
.preference
.PreferencesUtil
;
83 import eu
.etaxonomy
.taxeditor
.session
.ICdmEntitySession
;
84 import eu
.etaxonomy
.taxeditor
.session
.ICdmEntitySessionEnabled
;
85 import eu
.etaxonomy
.taxeditor
.store
.CdmStore
;
86 import eu
.etaxonomy
.taxeditor
.store
.LoginManager
;
87 import eu
.etaxonomy
.taxeditor
.ui
.element
.LayoutConstants
;
88 import eu
.etaxonomy
.taxeditor
.workbench
.part
.ICollapsableExpandable
;
96 public class TaxonNavigatorE4
implements
97 IPostOperationEnabled
, IConversationEnabled
, Observer
,
98 ICdmEntitySessionEnabled
, ICdmChangeListener
, IContextListener
,
99 ICollapsableExpandable
{
101 private static final String RESTORING_TAXON_NAVIGATOR
= Messages
.TaxonNavigator_RESTORE
;
103 private static final String TREE_PATH
= "treepath"; //$NON-NLS-1$
105 private static final String TREE_PATHS
= "treepaths"; //$NON-NLS-1$
107 private final int dndOperations
= DND
.DROP_MOVE
;
109 private ConversationHolder conversation
;
111 private ICdmEntitySession cdmEntitySession
;
113 private IDataChangeBehavior dataChangeBehavior
;
117 private TreeViewer viewer
;
120 private ESelectionService selService
;
123 private UISynchronize sync
;
125 private ISelectionChangedListener selectionChangedListener
;
127 private UndoContext undoContext
;
130 private MApplication application
;
133 private EModelService modelService
;
136 private EPartService partService
;
138 private boolean linkWithTaxon
= false;
141 public TaxonNavigatorE4() {
142 undoContext
= new UndoContext();
143 CdmStore
.getContextManager().addContextListener(this);
147 private void create(Composite parent
, EMenuService menuService
){
148 FillLayout layout
= new FillLayout();
149 layout
.marginHeight
= 0;
150 layout
.marginWidth
= 0;
151 layout
.type
= SWT
.VERTICAL
;
153 parent
.setLayout(layout
);
154 viewer
= new TreeViewer(new Tree(parent
, SWT
.H_SCROLL
| SWT
.V_SCROLL
| SWT
.FULL_SELECTION
));
155 viewer
.getControl().setLayoutData(LayoutConstants
.FILL());
157 viewer
.setContentProvider(new TaxonNavigatorContentProviderE4());
158 viewer
.setLabelProvider(new TaxonNavigatorLabelProviderE4());
159 viewer
.addDoubleClickListener(event
->{
160 ISelection selection
= event
.getSelection();
161 if(selection
instanceof IStructuredSelection
){
162 Object firstElement
= ((IStructuredSelection
) selection
).getFirstElement();
163 if(firstElement
instanceof ICdmBase
){
164 NavigationUtil
.openEditor((ICdmBase
) firstElement
, viewer
.getControl().getShell(), modelService
, partService
, application
);
169 //propagate selection
170 selectionChangedListener
= (event
-> selService
.setSelection(event
.getSelection()));
171 viewer
.addSelectionChangedListener(selectionChangedListener
);
173 //create context menu
174 menuService
.registerContextMenu(viewer
.getControl(), "eu.etaxonomy.taxeditor.navigator.popupmenu.taxonnavigator");
176 //add drag'n'drop support
177 Transfer
[] transfers
= new Transfer
[] {LocalSelectionTransfer
.getTransfer()};
178 viewer
.addDragSupport(dndOperations
, transfers
, new TreeNodeDragListenerE4(viewer
));
179 viewer
.addDropSupport(dndOperations
, transfers
, new TreeNodeDropAdapterE4(this));
182 // MToolBar toolBar = MMenuFactory.INSTANCE.createToolBar();
183 // MHandledToolItem linkWithEditor = MMenuFactory.INSTANCE.createHandledToolItem();
184 // linkWithEditor.setIconURI("platform:/plugin/eu.etaxonomy.taxeditor.store/icons/synced.gif");
185 // Command command = commandService.getCommand("eu.etaxonomy.taxeditor.navigation.command.linkWithTaxon");
186 // MCommand mCommand = MCommandsFactory.INSTANCE.createCommand();
187 // mCommand.setElementId(command.getId());
189 // mCommand.setCommandName(command.getName());
190 // } catch (NotDefinedException e) {
191 // e.printStackTrace();
193 // linkWithEditor.setCommand(mCommand);
194 // linkWithEditor.setType(ItemType.CHECK);
195 // toolBar.getChildren().add(linkWithEditor);
196 // thisPart.setToolbar(toolBar);
202 protected IAdaptable
getInitialInput() {
203 Comparator
<TaxonNode
> comparator
;
204 if (PreferencesUtil
.getSortNodesNaturally()){
205 comparator
= new TaxonNaturalComparator();
206 } else if (PreferencesUtil
.getSortNodesStrictlyAlphabetically()){
207 comparator
= new TaxonNodeByNameComparator();
209 comparator
= new TaxonNodeByRankAndNameComparator();
211 TaxonNodeNavigatorComparator viewerComparator
= new TaxonNodeNavigatorComparator(comparator
);
212 viewer
.setComparator(viewerComparator
);
214 if (CdmStore
.isActive()) {
216 // TODO when closing and reopening the taxon navigator
217 // we do not preserve state. Closing the view, in contrary to
218 // closing the whole application
219 // should be handled by the state manager too
220 root
= new Root(conversation
);
224 return new EmptyRoot();
228 if (CdmStore
.isActive() && conversation
== null) {
229 conversation
= CdmStore
.createConversation();
230 conversation
.registerForDataStoreChanges(TaxonNavigatorE4
.this);
232 if (CdmStore
.isActive()) {
233 cdmEntitySession
= CdmStore
.getCurrentSessionManager().newSession(this, true);
234 CdmApplicationState
.getCurrentDataChangeService().register(this);
236 CdmStore
.getLoginManager().addObserver(this);
237 viewer
.setInput(getInitialInput());
240 //Link with taxon selection
243 public void updateCurrentTaxon(@UIEventTopic(WorkbenchEventConstants
.CURRENT_ACTIVE_EDITOR
)ITaxonEditor editor
){
244 if(linkWithTaxon
&& editor
!=null){
246 TaxonNode taxonNode
= null;
247 if(editor
.getTaxon()!=null && editor
.getTaxon().getTaxonNodes()!=null){
248 taxonNode
= editor
.getTaxon().getTaxonNodes().iterator().next();
249 viewer
.reveal(taxonNode
);
250 viewer
.setSelection(new StructuredSelection(taxonNode
));
255 public void setLinkWithTaxon(boolean linkWithTaxon
) {
256 this.linkWithTaxon
= linkWithTaxon
;
259 public boolean isLinkWithTaxon() {
260 return linkWithTaxon
;
264 * Refresh this navigators viewer
266 public void refresh() {
267 if(getConversationHolder() != null){
268 getConversationHolder().bind();
269 //FIXME : Need to make sure this is a stable fix (ticket 3822)
270 if(!getConversationHolder().isCompleted()){
271 getConversationHolder().commit();
274 if(!viewer
.getTree().isDisposed()){
280 * Refresh this navigators viewer
282 public void refresh(Set
<?
> objects
) {
283 for(Object obj
: objects
) {
289 * Removes all content
291 public void clear() {
292 viewer
.setInput(new EmptyRoot());
295 private void restore(IMemento memento
, IProgressMonitor monitor
) {
296 root
= new Root(conversation
);
297 if (memento
== null) {
298 viewer
.setInput(root
);
302 Set
<TreePath
> treePaths
= new HashSet
<TreePath
>();
303 IMemento
[] treePathMementos
= null;
305 IMemento treePathsMemento
= memento
.getChild(TREE_PATHS
);
307 if (treePathsMemento
!= null) {
308 treePathMementos
= treePathsMemento
.getChildren(TREE_PATH
);
309 mementoWork
= treePathMementos
.length
;
311 // begin the monitor with steps for all tree paths and steps for
313 // conversation s.o., refreshing the tree and setting the paths
314 IProgressMonitor subProgressMonitor
= AbstractUtility
315 .getSubProgressMonitor(monitor
, 1);
317 subProgressMonitor
.beginTask(RESTORING_TAXON_NAVIGATOR
,
318 1 + mementoWork
+ 5);
319 subProgressMonitor
.subTask(RESTORING_TAXON_NAVIGATOR
);
320 subProgressMonitor
.worked(1);
322 conversation
= CdmStore
.createConversation();
323 subProgressMonitor
.worked(1);
324 conversation
.registerForDataStoreChanges(TaxonNavigatorE4
.this);
325 subProgressMonitor
.worked(1);
326 viewer
.setInput(root
);
327 subProgressMonitor
.worked(1);
329 subProgressMonitor
.worked(1);
331 if (treePathMementos
!= null && treePathMementos
.length
> 0) {
332 for (IMemento treePathMemento
: treePathMementos
) {
333 TreePath treePath
= createTreePathFromString(treePathMemento
335 if (!subProgressMonitor
.isCanceled() && treePath
!= null) {
336 treePaths
.add(treePath
);
337 subProgressMonitor
.worked(1);
341 if (treePaths
.size() > 0) {
342 TaxonNavigatorE4
.this.viewer
.setExpandedTreePaths(
343 treePaths
.toArray(new TreePath
[0]));
344 subProgressMonitor
.worked(1);
346 subProgressMonitor
.done();
349 private TreePath
createTreePathFromString(String string
) {
351 List
<CdmBase
> pathList
= new ArrayList
<CdmBase
>();
353 if (string
.length() == 0) {
357 for (String uuid
: string
.split(" ")) { //$NON-NLS-1$
358 CdmBase cdmBaseObject
= CdmStore
.getService(
359 IClassificationService
.class).getTaxonNodeByUuid(
360 UUID
.fromString(uuid
));
361 if (cdmBaseObject
== null) {
362 // is this a tree uuid?
363 cdmBaseObject
= CdmStore
.getService(
364 IClassificationService
.class).load(
365 UUID
.fromString(uuid
));
367 if (cdmBaseObject
== null) {
371 pathList
.add(cdmBaseObject
);
373 return new TreePath(pathList
.toArray());
380 public void collapse() {
381 viewer
.collapseAll();
388 public void expand() {
393 public ConversationHolder
getConversationHolder() {
399 public void dispose() {
400 dataChangeBehavior
= null;
401 if (conversation
!= null) {
402 conversation
.unregisterForDataStoreChanges(this);
405 if(cdmEntitySession
!= null) {
406 cdmEntitySession
.dispose();
407 cdmEntitySession
= null;
409 if(CdmApplicationState
.getCurrentDataChangeService() != null) {
410 CdmApplicationState
.getCurrentDataChangeService().unregister(this);
416 public void setFocus() {
417 if (getConversationHolder() != null) {
418 getConversationHolder().bind();
420 if(cdmEntitySession
!= null) {
421 cdmEntitySession
.bind();
425 public UISynchronize
getSync() {
429 public TreeViewer
getViewer() {
433 public UndoContext
getUndoContext() {
439 public boolean postOperation(CdmBase objectAffectedByOperation
) {
445 public boolean onComplete() {
450 public void update(Observable o
, Object arg
) {
451 if(o
instanceof LoginManager
){
457 public void update(CdmDataChangeMap changeEvents
) {
458 if (dataChangeBehavior
== null) {
459 dataChangeBehavior
= new TaxonNavigatorDataChangeBehaviorE4(this);
462 DataChangeBridge
.handleDataChange(changeEvents
, dataChangeBehavior
);
466 public ICdmEntitySession
getCdmEntitySession() {
467 return cdmEntitySession
;
471 public List
<ITreeNode
> getRootEntities() {
473 return root
.getParentBeans();
479 public void onChange(CdmChangeEvent event
) {
481 for(CdmBase cb
: event
.getChangedObjects()) {
482 if(cb
instanceof TaxonNode
) {
483 TaxonNode tn
= (TaxonNode
)cb
;
484 if(tn
.getTaxon() == null) {
485 viewer
.refresh(tn
.getClassification());
489 } else if (cb
instanceof Classification
) {
496 public Map
<Object
, List
<String
>> getPropertyPathsMap() {
497 Map
<Object
, List
<String
>> propertyPathsMap
= new HashMap
<Object
, List
<String
>>();
498 List
<String
> taxonNodePropertyPaths
= Arrays
.asList(new String
[] {
499 "taxon.name" //$NON-NLS-1$
501 propertyPathsMap
.put("childNodes", taxonNodePropertyPaths
); //$NON-NLS-1$
502 return propertyPathsMap
;
509 public void contextAboutToStop(IMemento memento
, IProgressMonitor monitor
) {
510 // TODO Auto-generated method stub
518 public void contextStop(IMemento memento
, IProgressMonitor monitor
) {
525 public void contextStart(IMemento memento
, IProgressMonitor monitor
) {
526 if(viewer
!=null && viewer
.getControl()!=null && !viewer
.getControl().isDisposed()){
535 public void contextRefresh(IProgressMonitor monitor
) {
542 public void workbenchShutdown(IMemento memento
, IProgressMonitor monitor
) {