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
.contexts
.ContextInjectionFactory
;
32 import org
.eclipse
.e4
.core
.contexts
.IEclipseContext
;
33 import org
.eclipse
.e4
.core
.di
.annotations
.Optional
;
34 import org
.eclipse
.e4
.ui
.di
.Focus
;
35 import org
.eclipse
.e4
.ui
.di
.UIEventTopic
;
36 import org
.eclipse
.e4
.ui
.di
.UISynchronize
;
37 import org
.eclipse
.e4
.ui
.model
.application
.MApplication
;
38 import org
.eclipse
.e4
.ui
.model
.application
.ui
.basic
.MPart
;
39 import org
.eclipse
.e4
.ui
.model
.application
.ui
.menu
.MToolBar
;
40 import org
.eclipse
.e4
.ui
.model
.application
.ui
.menu
.MToolBarElement
;
41 import org
.eclipse
.e4
.ui
.model
.application
.ui
.menu
.impl
.HandledToolItemImpl
;
42 import org
.eclipse
.e4
.ui
.services
.EMenuService
;
43 import org
.eclipse
.e4
.ui
.workbench
.modeling
.EModelService
;
44 import org
.eclipse
.e4
.ui
.workbench
.modeling
.EPartService
;
45 import org
.eclipse
.e4
.ui
.workbench
.modeling
.ESelectionService
;
46 import org
.eclipse
.jface
.util
.LocalSelectionTransfer
;
47 import org
.eclipse
.jface
.viewers
.IElementComparer
;
48 import org
.eclipse
.jface
.viewers
.ISelection
;
49 import org
.eclipse
.jface
.viewers
.ISelectionChangedListener
;
50 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
51 import org
.eclipse
.jface
.viewers
.StructuredSelection
;
52 import org
.eclipse
.jface
.viewers
.TreePath
;
53 import org
.eclipse
.jface
.viewers
.TreeViewer
;
54 import org
.eclipse
.swt
.SWT
;
55 import org
.eclipse
.swt
.dnd
.DND
;
56 import org
.eclipse
.swt
.dnd
.Transfer
;
57 import org
.eclipse
.swt
.layout
.FillLayout
;
58 import org
.eclipse
.swt
.widgets
.Composite
;
59 import org
.eclipse
.swt
.widgets
.Tree
;
60 import org
.eclipse
.ui
.IMemento
;
62 import eu
.etaxonomy
.cdm
.api
.application
.CdmApplicationState
;
63 import eu
.etaxonomy
.cdm
.api
.application
.CdmChangeEvent
;
64 import eu
.etaxonomy
.cdm
.api
.application
.CdmChangeEvent
.Action
;
65 import eu
.etaxonomy
.cdm
.api
.application
.ICdmChangeListener
;
66 import eu
.etaxonomy
.cdm
.api
.conversation
.ConversationHolder
;
67 import eu
.etaxonomy
.cdm
.api
.conversation
.IConversationEnabled
;
68 import eu
.etaxonomy
.cdm
.api
.service
.IClassificationService
;
69 import eu
.etaxonomy
.cdm
.api
.service
.ITaxonNodeService
;
70 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
71 import eu
.etaxonomy
.cdm
.model
.common
.ICdmBase
;
72 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
73 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
74 import eu
.etaxonomy
.cdm
.persistence
.dto
.TaxonNodeDto
;
75 import eu
.etaxonomy
.cdm
.persistence
.dto
.TaxonNodeDtoByNameComparator
;
76 import eu
.etaxonomy
.cdm
.persistence
.dto
.TaxonNodeDtoByRankAndNameComparator
;
77 import eu
.etaxonomy
.cdm
.persistence
.dto
.TaxonNodeDtoNaturalComparator
;
78 import eu
.etaxonomy
.cdm
.persistence
.hibernate
.CdmDataChangeMap
;
79 import eu
.etaxonomy
.taxeditor
.editor
.ITaxonEditor
;
80 import eu
.etaxonomy
.taxeditor
.editor
.name
.e4
.TaxonNameEditorE4
;
81 import eu
.etaxonomy
.taxeditor
.event
.WorkbenchEventConstants
;
82 import eu
.etaxonomy
.taxeditor
.model
.AbstractUtility
;
83 import eu
.etaxonomy
.taxeditor
.model
.DataChangeBridge
;
84 import eu
.etaxonomy
.taxeditor
.model
.IContextListener
;
85 import eu
.etaxonomy
.taxeditor
.model
.IDataChangeBehavior
;
86 import eu
.etaxonomy
.taxeditor
.navigation
.AppModelId
;
87 import eu
.etaxonomy
.taxeditor
.navigation
.NavigationUtil
;
88 import eu
.etaxonomy
.taxeditor
.navigation
.l10n
.Messages
;
89 import eu
.etaxonomy
.taxeditor
.navigation
.navigator
.EmptyRoot
;
90 import eu
.etaxonomy
.taxeditor
.navigation
.navigator
.Root
;
91 import eu
.etaxonomy
.taxeditor
.navigation
.navigator
.TaxonNodeNavigatorComparator
;
92 import eu
.etaxonomy
.taxeditor
.operation
.IPostOperationEnabled
;
93 import eu
.etaxonomy
.taxeditor
.preference
.NavigatorOrderEnum
;
94 import eu
.etaxonomy
.taxeditor
.preference
.PreferencesUtil
;
95 import eu
.etaxonomy
.taxeditor
.session
.ICdmEntitySession
;
96 import eu
.etaxonomy
.taxeditor
.session
.ICdmEntitySessionEnabled
;
97 import eu
.etaxonomy
.taxeditor
.store
.CdmStore
;
98 import eu
.etaxonomy
.taxeditor
.store
.LoginManager
;
99 import eu
.etaxonomy
.taxeditor
.ui
.element
.LayoutConstants
;
100 import eu
.etaxonomy
.taxeditor
.workbench
.part
.ICollapsableExpandable
;
108 public class TaxonNavigatorE4
implements
109 IPostOperationEnabled
, IConversationEnabled
, Observer
,
110 ICdmEntitySessionEnabled
, ICdmChangeListener
, IContextListener
,
111 ICollapsableExpandable
{
113 private static final String RESTORING_TAXON_NAVIGATOR
= Messages
.TaxonNavigator_RESTORE
;
115 private static final String TREE_PATH
= "treepath"; //$NON-NLS-1$
117 private static final String TREE_PATHS
= "treepaths"; //$NON-NLS-1$
119 private final int dndOperations
= DND
.DROP_MOVE
;
121 private ConversationHolder conversation
;
123 private ICdmEntitySession cdmEntitySession
;
125 private IDataChangeBehavior dataChangeBehavior
;
129 private TreeViewer viewer
;
132 private ESelectionService selService
;
135 private UISynchronize sync
;
137 private ISelectionChangedListener selectionChangedListener
;
139 private UndoContext undoContext
;
142 private MApplication application
;
145 private EModelService modelService
;
148 private EPartService partService
;
150 private boolean linkWithTaxon
= false;
153 public TaxonNavigatorE4() {
154 undoContext
= new UndoContext();
155 CdmStore
.getContextManager().addContextListener(this);
159 private void create(Composite parent
, EMenuService menuService
, IEclipseContext context
){
160 FillLayout layout
= new FillLayout();
161 layout
.marginHeight
= 0;
162 layout
.marginWidth
= 0;
163 layout
.type
= SWT
.VERTICAL
;
165 parent
.setLayout(layout
);
166 viewer
= new TreeViewer(new Tree(parent
, SWT
.H_SCROLL
| SWT
.V_SCROLL
| SWT
.FULL_SELECTION
| SWT
.MULTI
));
167 viewer
.getControl().setLayoutData(LayoutConstants
.FILL());
169 viewer
.setContentProvider(new TaxonNavigatorContentProviderE4());
170 viewer
.setLabelProvider(new TaxonNavigatorLabelProviderE4());
171 viewer
.addDoubleClickListener(event
->{
172 ISelection selection
= event
.getSelection();
173 if(selection
instanceof IStructuredSelection
){
174 Object firstElement
= ((IStructuredSelection
) selection
).getFirstElement();
175 if(firstElement
instanceof ICdmBase
){
176 NavigationUtil
.openEditor((ICdmBase
) firstElement
, viewer
.getControl().getShell(), modelService
, partService
, application
);
178 if(firstElement
instanceof TaxonNodeDto
){
179 NavigationUtil
.openEditor((TaxonNodeDto
) firstElement
, viewer
.getControl().getShell(), modelService
, partService
, application
);
184 //propagate selection
185 selectionChangedListener
= (event
-> selService
.setSelection(event
.getSelection()));
186 viewer
.addSelectionChangedListener(selectionChangedListener
);
188 //create context menu
189 menuService
.registerContextMenu(viewer
.getControl(), AppModelId
.POPUPMENU_EU_ETAXONOMY_TAXEDITOR_NAVIGATOR_POPUPMENU_TAXONNAVIGATOR
);
191 //add drag'n'drop support
192 Transfer
[] transfers
= new Transfer
[] {LocalSelectionTransfer
.getTransfer()};
193 viewer
.addDragSupport(dndOperations
, transfers
, new TreeNodeDragListenerE4(viewer
));
194 TreeNodeDropAdapterE4 dropAdapter
= new TreeNodeDropAdapterE4(this);
195 ContextInjectionFactory
.inject(dropAdapter
, context
);
196 viewer
.addDropSupport(dndOperations
, transfers
, dropAdapter
);
205 protected void updateSyncButton() {
206 MPart viewPart
= partService
.findPart(AppModelId
.PARTDESCRIPTOR_EU_ETAXONOMY_TAXEDITOR_NAVIGATION_NAVIGATOR
);
208 MToolBar toolBar
= viewPart
.getToolbar();
210 List
<MToolBarElement
> toolBarElements
= toolBar
.getChildren();
212 MToolBarElement upperHandledMenuItem
= toolBarElements
.get(1);
213 if (upperHandledMenuItem
instanceof HandledToolItemImpl
){
214 ((HandledToolItemImpl
)upperHandledMenuItem
).setSelected(linkWithTaxon
);
220 protected IAdaptable
getInitialInput() {
221 Comparator
<TaxonNodeDto
> comparator
;
222 NavigatorOrderEnum orderValue
= PreferencesUtil
.getSortNodes();
223 if (orderValue
.equals(NavigatorOrderEnum
.NaturalOrder
)){
224 comparator
= new TaxonNodeDtoNaturalComparator();
225 } else if (orderValue
.equals(NavigatorOrderEnum
.AlphabeticalOrder
)){
226 comparator
= new TaxonNodeDtoByNameComparator();
228 comparator
= new TaxonNodeDtoByRankAndNameComparator();
231 TaxonNodeNavigatorComparator viewerComparator
= new TaxonNodeNavigatorComparator(comparator
);
232 viewer
.setComparator(viewerComparator
);
233 viewer
.setComparer(new IElementComparer() {
236 public int hashCode(Object element
) {
237 if (element
instanceof TaxonNodeDto
){
238 TaxonNodeDto nodeDto
= (TaxonNodeDto
)element
;
240 String s
= nodeDto
.getUuid().toString();
244 return element
.hashCode();
246 return element
.toString().hashCode();
251 public boolean equals(Object element1
, Object element2
) {
252 if (element1
instanceof TaxonNodeDto
&& element2
instanceof TaxonNodeDto
){
253 TaxonNodeDto node1
= (TaxonNodeDto
)element1
;
254 TaxonNodeDto node2
= (TaxonNodeDto
)element2
;
255 return (node1
.getUuid().equals(node2
.getUuid()));
257 return element1
.equals(element2
);
263 if (CdmStore
.isActive()) {
265 // TODO when closing and reopening the taxon navigator
266 // we do not preserve state. Closing the view, in contrary to
267 // closing the whole application
268 // should be handled by the state manager too
269 root
= new Root(conversation
);
273 return new EmptyRoot();
277 if (CdmStore
.isActive() && conversation
== null) {
278 conversation
= CdmStore
.createConversation();
279 conversation
.registerForDataStoreChanges(TaxonNavigatorE4
.this);
281 if (CdmStore
.isActive()) {
282 cdmEntitySession
= CdmStore
.getCurrentSessionManager().newSession(this, true);
283 CdmApplicationState
.getCurrentDataChangeService().register(this);
284 viewer
.setInput(getInitialInput());
286 CdmStore
.getLoginManager().addObserver(this);
290 //Link with taxon selection
293 public void updateCurrentTaxon(@UIEventTopic(WorkbenchEventConstants
.CURRENT_ACTIVE_EDITOR
)ITaxonEditor editor
){
294 if(linkWithTaxon
&& editor
!=null){
296 TaxonNodeDto taxonNode
= null;
297 if(editor
.getTaxon()!=null && editor
.getTaxon().getTaxonNodes()!=null){
298 if (editor
instanceof TaxonNameEditorE4
){
299 taxonNode
= new TaxonNodeDto( ((TaxonNameEditorE4
)editor
).getEditorInput().getTaxonNode());
301 if (editor
.getTaxon().getTaxonNodes() != null && !editor
.getTaxon().getTaxonNodes().isEmpty()){
302 taxonNode
= new TaxonNodeDto(editor
.getTaxon().getTaxonNodes().iterator().next());
305 if (taxonNode
!= null){
306 viewer
.reveal(taxonNode
);
307 viewer
.setSelection(new StructuredSelection(taxonNode
));
309 //TODO: show message in status bar
316 public void setLinkWithTaxon(boolean linkWithTaxon
) {
317 this.linkWithTaxon
= linkWithTaxon
;
320 public boolean isLinkWithTaxon() {
321 return linkWithTaxon
;
325 * Refresh this navigators viewer
327 public void refresh() {
328 if(getConversationHolder() != null){
329 getConversationHolder().bind();
330 //FIXME : Need to make sure this is a stable fix (ticket 3822)
331 if(!getConversationHolder().isCompleted()){
332 getConversationHolder().commit();
335 if(!viewer
.getTree().isDisposed()){
336 viewer
.setInput(getInitialInput());
344 * Refresh this navigators viewer
346 public void refresh(Set
<?
> objects
) {
347 for(Object obj
: objects
) {
354 * Refresh this navigators viewer
356 public void refresh(Object object
) {
357 viewer
.refresh(object
);
362 * Removes all content
364 public void clear() {
365 viewer
.setInput(new EmptyRoot());
368 private void restore(IMemento memento
, IProgressMonitor monitor
) {
369 root
= new Root(conversation
);
370 if (memento
== null) {
371 viewer
.setInput(root
);
375 Set
<TreePath
> treePaths
= new HashSet
<TreePath
>();
376 IMemento
[] treePathMementos
= null;
378 IMemento treePathsMemento
= memento
.getChild(TREE_PATHS
);
380 if (treePathsMemento
!= null) {
381 treePathMementos
= treePathsMemento
.getChildren(TREE_PATH
);
382 mementoWork
= treePathMementos
.length
;
384 // begin the monitor with steps for all tree paths and steps for
386 // conversation s.o., refreshing the tree and setting the paths
387 IProgressMonitor subProgressMonitor
= AbstractUtility
388 .getSubProgressMonitor(monitor
, 1);
390 subProgressMonitor
.beginTask(RESTORING_TAXON_NAVIGATOR
,
391 1 + mementoWork
+ 5);
392 subProgressMonitor
.subTask(RESTORING_TAXON_NAVIGATOR
);
393 subProgressMonitor
.worked(1);
395 conversation
= CdmStore
.createConversation();
396 subProgressMonitor
.worked(1);
397 conversation
.registerForDataStoreChanges(TaxonNavigatorE4
.this);
398 subProgressMonitor
.worked(1);
399 viewer
.setInput(root
);
400 subProgressMonitor
.worked(1);
402 subProgressMonitor
.worked(1);
404 if (treePathMementos
!= null && treePathMementos
.length
> 0) {
405 for (IMemento treePathMemento
: treePathMementos
) {
406 TreePath treePath
= createTreePathFromString(treePathMemento
408 if (!subProgressMonitor
.isCanceled() && treePath
!= null) {
409 treePaths
.add(treePath
);
410 subProgressMonitor
.worked(1);
414 if (treePaths
.size() > 0) {
415 TaxonNavigatorE4
.this.viewer
.setExpandedTreePaths(
416 treePaths
.toArray(new TreePath
[0]));
417 subProgressMonitor
.worked(1);
419 subProgressMonitor
.done();
422 private TreePath
createTreePathFromString(String string
) {
424 List
<CdmBase
> pathList
= new ArrayList
<CdmBase
>();
426 if (string
.length() == 0) {
430 for (String uuid
: string
.split(" ")) { //$NON-NLS-1$
431 CdmBase cdmBaseObject
= CdmStore
.getService(
432 ITaxonNodeService
.class).find(
433 UUID
.fromString(uuid
));
434 if (cdmBaseObject
== null) {
435 // is this a tree uuid?
436 cdmBaseObject
= CdmStore
.getService(
437 IClassificationService
.class).load(
438 UUID
.fromString(uuid
));
440 if (cdmBaseObject
== null) {
444 pathList
.add(cdmBaseObject
);
446 return new TreePath(pathList
.toArray());
453 public void collapse() {
454 viewer
.collapseAll();
461 public void expand() {
466 public ConversationHolder
getConversationHolder() {
472 public void dispose() {
473 dataChangeBehavior
= null;
474 if (conversation
!= null) {
475 conversation
.unregisterForDataStoreChanges(this);
476 conversation
.close();
478 if(cdmEntitySession
!= null) {
479 cdmEntitySession
.dispose();
480 cdmEntitySession
= null;
482 if(CdmApplicationState
.getCurrentDataChangeService() != null) {
483 CdmApplicationState
.getCurrentDataChangeService().unregister(this);
489 public void setFocus() {
490 if (getConversationHolder() != null) {
491 getConversationHolder().bind();
493 if(cdmEntitySession
!= null) {
494 cdmEntitySession
.bind();
498 public UISynchronize
getSync() {
502 public TreeViewer
getViewer() {
506 public UndoContext
getUndoContext() {
512 public boolean postOperation(Object objectAffectedByOperation
) {
518 public boolean onComplete() {
523 public void update(Observable o
, Object arg
) {
524 if(o
instanceof LoginManager
){
531 public void update(CdmDataChangeMap changeEvents
) {
532 if (dataChangeBehavior
== null) {
533 dataChangeBehavior
= new TaxonNavigatorDataChangeBehaviorE4(this);
536 DataChangeBridge
.handleDataChange(changeEvents
, dataChangeBehavior
);
542 public ICdmEntitySession
getCdmEntitySession() {
543 return cdmEntitySession
;
547 public List
<TaxonNodeDto
> getRootEntities() {
549 return root
.getParentBeans();
555 public void onChange(CdmChangeEvent event
) {
557 for(CdmBase cb
: event
.getChangedObjects()) {
558 if(cb
instanceof TaxonNode
) {
559 TaxonNode tn
= (TaxonNode
)cb
;
560 if(tn
.getTaxon() == null) {
561 viewer
.refresh(tn
.getClassification());
565 } else if (cb
instanceof Classification
) {
566 if ( event
.getAction().equals(Action
.Create
)){
567 root
.addRootNode((Classification
)cb
);
568 } else if ( event
.getAction().equals(Action
.Delete
)){
569 root
.removeRootNode((Classification
)cb
);
577 public Map
<Object
, List
<String
>> getPropertyPathsMap() {
578 Map
<Object
, List
<String
>> propertyPathsMap
= new HashMap
<Object
, List
<String
>>();
579 List
<String
> taxonNodePropertyPaths
= Arrays
.asList(new String
[] {
580 "taxon.name" //$NON-NLS-1$
582 propertyPathsMap
.put("childNodes", taxonNodePropertyPaths
); //$NON-NLS-1$
583 return propertyPathsMap
;
590 public void contextAboutToStop(IMemento memento
, IProgressMonitor monitor
) {
591 // TODO Auto-generated method stub
599 public void contextStop(IMemento memento
, IProgressMonitor monitor
) {
606 public void contextStart(IMemento memento
, IProgressMonitor monitor
) {
607 if(viewer
!=null && viewer
.getControl()!=null && !viewer
.getControl().isDisposed()){
616 public void contextRefresh(IProgressMonitor monitor
) {
623 public void workbenchShutdown(IMemento memento
, IProgressMonitor monitor
) {
628 private void updateView(@UIEventTopic(WorkbenchEventConstants
.REFRESH_NAVIGATOR
)boolean refresh
){