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
.model
.application
.ui
.basic
.MPart
;
37 import org
.eclipse
.e4
.ui
.model
.application
.ui
.menu
.MToolBar
;
38 import org
.eclipse
.e4
.ui
.model
.application
.ui
.menu
.MToolBarElement
;
39 import org
.eclipse
.e4
.ui
.model
.application
.ui
.menu
.impl
.HandledToolItemImpl
;
40 import org
.eclipse
.e4
.ui
.services
.EMenuService
;
41 import org
.eclipse
.e4
.ui
.workbench
.modeling
.EModelService
;
42 import org
.eclipse
.e4
.ui
.workbench
.modeling
.EPartService
;
43 import org
.eclipse
.e4
.ui
.workbench
.modeling
.ESelectionService
;
44 import org
.eclipse
.jface
.util
.LocalSelectionTransfer
;
45 import org
.eclipse
.jface
.viewers
.IElementComparer
;
46 import org
.eclipse
.jface
.viewers
.ISelection
;
47 import org
.eclipse
.jface
.viewers
.ISelectionChangedListener
;
48 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
49 import org
.eclipse
.jface
.viewers
.StructuredSelection
;
50 import org
.eclipse
.jface
.viewers
.TreePath
;
51 import org
.eclipse
.jface
.viewers
.TreeViewer
;
52 import org
.eclipse
.swt
.SWT
;
53 import org
.eclipse
.swt
.dnd
.DND
;
54 import org
.eclipse
.swt
.dnd
.Transfer
;
55 import org
.eclipse
.swt
.layout
.FillLayout
;
56 import org
.eclipse
.swt
.widgets
.Composite
;
57 import org
.eclipse
.swt
.widgets
.Tree
;
58 import org
.eclipse
.ui
.IMemento
;
60 import eu
.etaxonomy
.cdm
.api
.application
.CdmApplicationState
;
61 import eu
.etaxonomy
.cdm
.api
.application
.CdmChangeEvent
;
62 import eu
.etaxonomy
.cdm
.api
.application
.ICdmChangeListener
;
63 import eu
.etaxonomy
.cdm
.api
.conversation
.ConversationHolder
;
64 import eu
.etaxonomy
.cdm
.api
.conversation
.IConversationEnabled
;
65 import eu
.etaxonomy
.cdm
.api
.service
.IClassificationService
;
66 import eu
.etaxonomy
.cdm
.api
.service
.TaxonNodeDtoByNameComparator
;
67 import eu
.etaxonomy
.cdm
.api
.service
.TaxonNodeDtoByRankAndNameComparator
;
68 import eu
.etaxonomy
.cdm
.api
.service
.TaxonNodeDtoNaturalComparator
;
69 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
70 import eu
.etaxonomy
.cdm
.model
.common
.ICdmBase
;
71 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
72 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
73 import eu
.etaxonomy
.cdm
.persistence
.dto
.TaxonNodeDto
;
74 import eu
.etaxonomy
.cdm
.persistence
.hibernate
.CdmDataChangeMap
;
75 import eu
.etaxonomy
.taxeditor
.editor
.ITaxonEditor
;
76 import eu
.etaxonomy
.taxeditor
.editor
.name
.e4
.TaxonNameEditorE4
;
77 import eu
.etaxonomy
.taxeditor
.event
.WorkbenchEventConstants
;
78 import eu
.etaxonomy
.taxeditor
.model
.AbstractUtility
;
79 import eu
.etaxonomy
.taxeditor
.model
.DataChangeBridge
;
80 import eu
.etaxonomy
.taxeditor
.model
.IContextListener
;
81 import eu
.etaxonomy
.taxeditor
.model
.IDataChangeBehavior
;
82 import eu
.etaxonomy
.taxeditor
.navigation
.AppModelId
;
83 import eu
.etaxonomy
.taxeditor
.navigation
.NavigationUtil
;
84 import eu
.etaxonomy
.taxeditor
.navigation
.l10n
.Messages
;
85 import eu
.etaxonomy
.taxeditor
.navigation
.navigator
.EmptyRoot
;
86 import eu
.etaxonomy
.taxeditor
.navigation
.navigator
.Root
;
87 import eu
.etaxonomy
.taxeditor
.navigation
.navigator
.TaxonNodeNavigatorComparator
;
88 import eu
.etaxonomy
.taxeditor
.operation
.IPostOperationEnabled
;
89 import eu
.etaxonomy
.taxeditor
.preference
.PreferencesUtil
;
90 import eu
.etaxonomy
.taxeditor
.session
.ICdmEntitySession
;
91 import eu
.etaxonomy
.taxeditor
.session
.ICdmEntitySessionEnabled
;
92 import eu
.etaxonomy
.taxeditor
.store
.CdmStore
;
93 import eu
.etaxonomy
.taxeditor
.store
.LoginManager
;
94 import eu
.etaxonomy
.taxeditor
.ui
.element
.LayoutConstants
;
95 import eu
.etaxonomy
.taxeditor
.workbench
.part
.ICollapsableExpandable
;
103 public class TaxonNavigatorE4
implements
104 IPostOperationEnabled
, IConversationEnabled
, Observer
,
105 ICdmEntitySessionEnabled
, ICdmChangeListener
, IContextListener
,
106 ICollapsableExpandable
{
108 private static final String RESTORING_TAXON_NAVIGATOR
= Messages
.TaxonNavigator_RESTORE
;
110 private static final String TREE_PATH
= "treepath"; //$NON-NLS-1$
112 private static final String TREE_PATHS
= "treepaths"; //$NON-NLS-1$
114 private final int dndOperations
= DND
.DROP_MOVE
;
116 private ConversationHolder conversation
;
118 private ICdmEntitySession cdmEntitySession
;
120 private IDataChangeBehavior dataChangeBehavior
;
124 private TreeViewer viewer
;
127 private ESelectionService selService
;
130 private UISynchronize sync
;
132 private ISelectionChangedListener selectionChangedListener
;
134 private UndoContext undoContext
;
137 private MApplication application
;
140 private EModelService modelService
;
143 private EPartService partService
;
145 private boolean linkWithTaxon
= false;
148 public TaxonNavigatorE4() {
149 undoContext
= new UndoContext();
150 CdmStore
.getContextManager().addContextListener(this);
154 private void create(Composite parent
, EMenuService menuService
){
155 FillLayout layout
= new FillLayout();
156 layout
.marginHeight
= 0;
157 layout
.marginWidth
= 0;
158 layout
.type
= SWT
.VERTICAL
;
160 parent
.setLayout(layout
);
161 viewer
= new TreeViewer(new Tree(parent
, SWT
.H_SCROLL
| SWT
.V_SCROLL
| SWT
.FULL_SELECTION
| SWT
.MULTI
));
162 viewer
.getControl().setLayoutData(LayoutConstants
.FILL());
164 viewer
.setContentProvider(new TaxonNavigatorContentProviderE4());
165 viewer
.setLabelProvider(new TaxonNavigatorLabelProviderE4());
166 viewer
.addDoubleClickListener(event
->{
167 ISelection selection
= event
.getSelection();
168 if(selection
instanceof IStructuredSelection
){
169 Object firstElement
= ((IStructuredSelection
) selection
).getFirstElement();
170 if(firstElement
instanceof ICdmBase
){
171 NavigationUtil
.openEditor((ICdmBase
) firstElement
, viewer
.getControl().getShell(), modelService
, partService
, application
);
173 if(firstElement
instanceof TaxonNodeDto
){
174 NavigationUtil
.openEditor((TaxonNodeDto
) firstElement
, viewer
.getControl().getShell(), modelService
, partService
, application
);
179 //propagate selection
180 selectionChangedListener
= (event
-> selService
.setSelection(event
.getSelection()));
181 viewer
.addSelectionChangedListener(selectionChangedListener
);
183 //create context menu
184 menuService
.registerContextMenu(viewer
.getControl(), AppModelId
.POPUPMENU_EU_ETAXONOMY_TAXEDITOR_NAVIGATOR_POPUPMENU_TAXONNAVIGATOR
);
186 //add drag'n'drop support
187 Transfer
[] transfers
= new Transfer
[] {LocalSelectionTransfer
.getTransfer()};
188 viewer
.addDragSupport(dndOperations
, transfers
, new TreeNodeDragListenerE4(viewer
));
189 viewer
.addDropSupport(dndOperations
, transfers
, new TreeNodeDropAdapterE4(this));
198 protected void updateSyncButton() {
199 MPart viewPart
= partService
.findPart(AppModelId
.PARTDESCRIPTOR_EU_ETAXONOMY_TAXEDITOR_NAVIGATION_NAVIGATOR
);
201 MToolBar toolBar
= viewPart
.getToolbar();
203 List
<MToolBarElement
> toolBarElements
= toolBar
.getChildren();
205 MToolBarElement upperHandledMenuItem
= toolBarElements
.get(1);
206 if (upperHandledMenuItem
instanceof HandledToolItemImpl
){
207 ((HandledToolItemImpl
)upperHandledMenuItem
).setSelected(linkWithTaxon
);
213 protected IAdaptable
getInitialInput() {
214 Comparator
<TaxonNodeDto
> comparator
;
215 if (PreferencesUtil
.getSortNodesNaturally()){
216 comparator
= new TaxonNodeDtoNaturalComparator();
217 } else if (PreferencesUtil
.getSortNodesStrictlyAlphabetically()){
218 comparator
= new TaxonNodeDtoByNameComparator();
220 comparator
= new TaxonNodeDtoByRankAndNameComparator();
223 TaxonNodeNavigatorComparator viewerComparator
= new TaxonNodeNavigatorComparator(comparator
);
224 viewer
.setComparator(viewerComparator
);
225 viewer
.setComparer(new IElementComparer() {
228 public int hashCode(Object element
) {
229 if (element
instanceof TaxonNodeDto
){
230 TaxonNodeDto nodeDto
= (TaxonNodeDto
)element
;
232 String s
= nodeDto
.getUuid().toString();
236 return element
.hashCode();
238 return element
.toString().hashCode();
243 public boolean equals(Object element1
, Object element2
) {
244 if (element1
instanceof TaxonNodeDto
&& element2
instanceof TaxonNodeDto
){
245 TaxonNodeDto node1
= (TaxonNodeDto
)element1
;
246 TaxonNodeDto node2
= (TaxonNodeDto
)element2
;
247 return (node1
.getUuid().equals(node2
.getUuid()));
249 return element1
.equals(element2
);
255 if (CdmStore
.isActive()) {
257 // TODO when closing and reopening the taxon navigator
258 // we do not preserve state. Closing the view, in contrary to
259 // closing the whole application
260 // should be handled by the state manager too
261 root
= new Root(conversation
);
265 return new EmptyRoot();
269 if (CdmStore
.isActive() && conversation
== null) {
270 conversation
= CdmStore
.createConversation();
271 conversation
.registerForDataStoreChanges(TaxonNavigatorE4
.this);
273 if (CdmStore
.isActive()) {
274 cdmEntitySession
= CdmStore
.getCurrentSessionManager().newSession(this, true);
275 CdmApplicationState
.getCurrentDataChangeService().register(this);
277 CdmStore
.getLoginManager().addObserver(this);
278 viewer
.setInput(getInitialInput());
281 //Link with taxon selection
284 public void updateCurrentTaxon(@UIEventTopic(WorkbenchEventConstants
.CURRENT_ACTIVE_EDITOR
)ITaxonEditor editor
){
285 if(linkWithTaxon
&& editor
!=null){
287 TaxonNodeDto taxonNode
= null;
288 if(editor
.getTaxon()!=null && editor
.getTaxon().getTaxonNodes()!=null){
289 if (editor
instanceof TaxonNameEditorE4
){
290 taxonNode
= new TaxonNodeDto( ((TaxonNameEditorE4
)editor
).getEditorInput().getTaxonNode());
292 taxonNode
= new TaxonNodeDto(editor
.getTaxon().getTaxonNodes().iterator().next());
294 viewer
.reveal(taxonNode
);
295 viewer
.setSelection(new StructuredSelection(taxonNode
));
300 public void setLinkWithTaxon(boolean linkWithTaxon
) {
301 this.linkWithTaxon
= linkWithTaxon
;
304 public boolean isLinkWithTaxon() {
305 return linkWithTaxon
;
309 * Refresh this navigators viewer
311 public void refresh() {
312 if(getConversationHolder() != null){
313 getConversationHolder().bind();
314 //FIXME : Need to make sure this is a stable fix (ticket 3822)
315 if(!getConversationHolder().isCompleted()){
316 getConversationHolder().commit();
319 if(!viewer
.getTree().isDisposed()){
326 * Refresh this navigators viewer
328 public void refresh(Set
<?
> objects
) {
329 for(Object obj
: objects
) {
336 * Refresh this navigators viewer
338 public void refresh(Object object
) {
339 viewer
.refresh(object
);
344 * Removes all content
346 public void clear() {
347 viewer
.setInput(new EmptyRoot());
350 private void restore(IMemento memento
, IProgressMonitor monitor
) {
351 root
= new Root(conversation
);
352 if (memento
== null) {
353 viewer
.setInput(root
);
357 Set
<TreePath
> treePaths
= new HashSet
<TreePath
>();
358 IMemento
[] treePathMementos
= null;
360 IMemento treePathsMemento
= memento
.getChild(TREE_PATHS
);
362 if (treePathsMemento
!= null) {
363 treePathMementos
= treePathsMemento
.getChildren(TREE_PATH
);
364 mementoWork
= treePathMementos
.length
;
366 // begin the monitor with steps for all tree paths and steps for
368 // conversation s.o., refreshing the tree and setting the paths
369 IProgressMonitor subProgressMonitor
= AbstractUtility
370 .getSubProgressMonitor(monitor
, 1);
372 subProgressMonitor
.beginTask(RESTORING_TAXON_NAVIGATOR
,
373 1 + mementoWork
+ 5);
374 subProgressMonitor
.subTask(RESTORING_TAXON_NAVIGATOR
);
375 subProgressMonitor
.worked(1);
377 conversation
= CdmStore
.createConversation();
378 subProgressMonitor
.worked(1);
379 conversation
.registerForDataStoreChanges(TaxonNavigatorE4
.this);
380 subProgressMonitor
.worked(1);
381 viewer
.setInput(root
);
382 subProgressMonitor
.worked(1);
384 subProgressMonitor
.worked(1);
386 if (treePathMementos
!= null && treePathMementos
.length
> 0) {
387 for (IMemento treePathMemento
: treePathMementos
) {
388 TreePath treePath
= createTreePathFromString(treePathMemento
390 if (!subProgressMonitor
.isCanceled() && treePath
!= null) {
391 treePaths
.add(treePath
);
392 subProgressMonitor
.worked(1);
396 if (treePaths
.size() > 0) {
397 TaxonNavigatorE4
.this.viewer
.setExpandedTreePaths(
398 treePaths
.toArray(new TreePath
[0]));
399 subProgressMonitor
.worked(1);
401 subProgressMonitor
.done();
404 private TreePath
createTreePathFromString(String string
) {
406 List
<CdmBase
> pathList
= new ArrayList
<CdmBase
>();
408 if (string
.length() == 0) {
412 for (String uuid
: string
.split(" ")) { //$NON-NLS-1$
413 CdmBase cdmBaseObject
= CdmStore
.getService(
414 IClassificationService
.class).getTaxonNodeByUuid(
415 UUID
.fromString(uuid
));
416 if (cdmBaseObject
== null) {
417 // is this a tree uuid?
418 cdmBaseObject
= CdmStore
.getService(
419 IClassificationService
.class).load(
420 UUID
.fromString(uuid
));
422 if (cdmBaseObject
== null) {
426 pathList
.add(cdmBaseObject
);
428 return new TreePath(pathList
.toArray());
435 public void collapse() {
436 viewer
.collapseAll();
443 public void expand() {
448 public ConversationHolder
getConversationHolder() {
454 public void dispose() {
455 dataChangeBehavior
= null;
456 if (conversation
!= null) {
457 conversation
.unregisterForDataStoreChanges(this);
458 conversation
.close();
460 if(cdmEntitySession
!= null) {
461 cdmEntitySession
.dispose();
462 cdmEntitySession
= null;
464 if(CdmApplicationState
.getCurrentDataChangeService() != null) {
465 CdmApplicationState
.getCurrentDataChangeService().unregister(this);
471 public void setFocus() {
472 if (getConversationHolder() != null) {
473 getConversationHolder().bind();
475 if(cdmEntitySession
!= null) {
476 cdmEntitySession
.bind();
480 public UISynchronize
getSync() {
484 public TreeViewer
getViewer() {
488 public UndoContext
getUndoContext() {
494 public boolean postOperation(CdmBase objectAffectedByOperation
) {
500 public boolean onComplete() {
505 public void update(Observable o
, Object arg
) {
506 if(o
instanceof LoginManager
){
513 public void update(CdmDataChangeMap changeEvents
) {
514 if (dataChangeBehavior
== null) {
515 dataChangeBehavior
= new TaxonNavigatorDataChangeBehaviorE4(this);
518 DataChangeBridge
.handleDataChange(changeEvents
, dataChangeBehavior
);
524 public ICdmEntitySession
getCdmEntitySession() {
525 return cdmEntitySession
;
529 public List
<TaxonNodeDto
> getRootEntities() {
531 return root
.getParentBeans();
537 public void onChange(CdmChangeEvent event
) {
539 for(CdmBase cb
: event
.getChangedObjects()) {
540 if(cb
instanceof TaxonNode
) {
541 TaxonNode tn
= (TaxonNode
)cb
;
542 if(tn
.getTaxon() == null) {
543 viewer
.refresh(tn
.getClassification());
547 } else if (cb
instanceof Classification
) {
554 public Map
<Object
, List
<String
>> getPropertyPathsMap() {
555 Map
<Object
, List
<String
>> propertyPathsMap
= new HashMap
<Object
, List
<String
>>();
556 List
<String
> taxonNodePropertyPaths
= Arrays
.asList(new String
[] {
557 "taxon.name" //$NON-NLS-1$
559 propertyPathsMap
.put("childNodes", taxonNodePropertyPaths
); //$NON-NLS-1$
560 return propertyPathsMap
;
567 public void contextAboutToStop(IMemento memento
, IProgressMonitor monitor
) {
568 // TODO Auto-generated method stub
576 public void contextStop(IMemento memento
, IProgressMonitor monitor
) {
583 public void contextStart(IMemento memento
, IProgressMonitor monitor
) {
584 if(viewer
!=null && viewer
.getControl()!=null && !viewer
.getControl().isDisposed()){
593 public void contextRefresh(IProgressMonitor monitor
) {
600 public void workbenchShutdown(IMemento memento
, IProgressMonitor monitor
) {
605 private void updateView(@UIEventTopic(WorkbenchEventConstants
.REFRESH_NAVIGATOR
)boolean refresh
){