1 package eu
.etaxonomy
.taxeditor
.editor
.view
.derivate
;
3 import java
.util
.ArrayList
;
4 import java
.util
.Arrays
;
5 import java
.util
.Collection
;
6 import java
.util
.HashMap
;
7 import java
.util
.HashSet
;
11 import java
.util
.UUID
;
13 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
14 import org
.eclipse
.jface
.action
.MenuManager
;
15 import org
.eclipse
.jface
.util
.LocalSelectionTransfer
;
16 import org
.eclipse
.jface
.viewers
.AbstractTreeViewer
;
17 import org
.eclipse
.jface
.viewers
.ISelection
;
18 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
19 import org
.eclipse
.jface
.viewers
.StructuredSelection
;
20 import org
.eclipse
.jface
.viewers
.TreeNode
;
21 import org
.eclipse
.jface
.viewers
.TreeSelection
;
22 import org
.eclipse
.jface
.viewers
.TreeViewer
;
23 import org
.eclipse
.swt
.SWT
;
24 import org
.eclipse
.swt
.dnd
.DND
;
25 import org
.eclipse
.swt
.dnd
.Transfer
;
26 import org
.eclipse
.swt
.layout
.GridData
;
27 import org
.eclipse
.swt
.layout
.GridLayout
;
28 import org
.eclipse
.swt
.widgets
.Composite
;
29 import org
.eclipse
.swt
.widgets
.Control
;
30 import org
.eclipse
.swt
.widgets
.Menu
;
31 import org
.eclipse
.swt
.widgets
.Tree
;
32 import org
.eclipse
.ui
.IEditorInput
;
33 import org
.eclipse
.ui
.IEditorPart
;
34 import org
.eclipse
.ui
.IEditorSite
;
35 import org
.eclipse
.ui
.IMemento
;
36 import org
.eclipse
.ui
.ISelectionListener
;
37 import org
.eclipse
.ui
.ISelectionService
;
38 import org
.eclipse
.ui
.IWorkbenchPart
;
39 import org
.eclipse
.ui
.PartInitException
;
40 import org
.eclipse
.ui
.part
.EditorPart
;
42 import eu
.etaxonomy
.cdm
.api
.conversation
.ConversationHolder
;
43 import eu
.etaxonomy
.cdm
.api
.conversation
.IConversationEnabled
;
44 import eu
.etaxonomy
.cdm
.api
.service
.IOccurrenceService
;
45 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
46 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
47 import eu
.etaxonomy
.cdm
.model
.molecular
.SingleRead
;
48 import eu
.etaxonomy
.cdm
.model
.occurrence
.FieldUnit
;
49 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
50 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
51 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
52 import eu
.etaxonomy
.cdm
.persistence
.hibernate
.CdmDataChangeMap
;
53 import eu
.etaxonomy
.taxeditor
.editor
.EditorUtil
;
54 import eu
.etaxonomy
.taxeditor
.editor
.Messages
;
55 import eu
.etaxonomy
.taxeditor
.editor
.MultiPageTaxonEditor
;
56 import eu
.etaxonomy
.taxeditor
.editor
.view
.derivate
.searchFilter
.DerivateSearchCompositeController
;
57 import eu
.etaxonomy
.taxeditor
.model
.IContextListener
;
58 import eu
.etaxonomy
.taxeditor
.model
.IDirtyMarkable
;
59 import eu
.etaxonomy
.taxeditor
.model
.IPartContentHasDetails
;
60 import eu
.etaxonomy
.taxeditor
.model
.IPartContentHasFactualData
;
61 import eu
.etaxonomy
.taxeditor
.model
.IPartContentHasMedia
;
62 import eu
.etaxonomy
.taxeditor
.model
.IPartContentHasSupplementalData
;
63 import eu
.etaxonomy
.taxeditor
.operation
.IPostOperationEnabled
;
64 import eu
.etaxonomy
.taxeditor
.session
.ICdmEntitySession
;
65 import eu
.etaxonomy
.taxeditor
.session
.ICdmEntitySessionEnabled
;
66 import eu
.etaxonomy
.taxeditor
.store
.CdmStore
;
67 import eu
.etaxonomy
.taxeditor
.view
.derivateSearch
.DerivateContentProvider
;
68 import eu
.etaxonomy
.taxeditor
.view
.derivateSearch
.DerivateLabelProvider
;
71 * Displays the derivate hierarchy of the specimen specified in the editor input.
74 public class DerivateView
extends EditorPart
implements IPartContentHasFactualData
, IConversationEnabled
,
75 ICdmEntitySessionEnabled
, IDirtyMarkable
, IPostOperationEnabled
, IPartContentHasDetails
, IPartContentHasSupplementalData
, IPartContentHasMedia
,
76 IContextListener
, ISelectionListener
{
77 public static final String ID
= "eu.etaxonomy.taxeditor.editor.view.derivate.DerivateView"; //$NON-NLS-1$
79 public static final String YOU_NEED_TO_SAVE_BEFORE_PERFORMING_THIS_ACTION
= Messages
.DerivateView_YOU_NEED_TO_SAVE
;
80 public static final String VIEW_HAS_UNSAVED_CHANGES
= Messages
.DerivateView_UNSAVED_CHANGES
;
82 private static final List
<String
> SPECIMEN_INIT_STRATEGY
= Arrays
.asList(new String
[] {
90 "derivationEvents.derivatives.annotations",
91 "derivationEvents.derivatives.markers",
92 "derivationEvents.derivatives.credits",
93 "derivationEvents.derivatives.extensions",
94 "derivationEvents.derivatives.rights",
95 "derivationEvents.derivatives.sources"
98 private ConversationHolder conversation
;
100 private TreeViewer viewer
;
102 private boolean isDirty
;
104 private final int dndOperations
= DND
.DROP_MOVE
;
106 private DerivateLabelProvider labelProvider
;
108 private DerivateContentProvider contentProvider
;
110 private DerivateSearchCompositeController derivateSearchCompositeController
;
113 * A map with keys being the derivative entities belonging to the {@link UUID}s passed to the constructor
114 * and values being the root elements of the hierarchy (may be the same objects as the derivative entities)
116 private Map
<SpecimenOrObservationBase
<?
>, SpecimenOrObservationBase
<?
>> derivateToRootEntityMap
;
119 * The set of root elements
121 private Set
<SpecimenOrObservationBase
<?
>> rootElements
;
123 private ICdmEntitySession cdmEntitySession
;
126 * <code>true</code> if this view is listening to selection changes
128 private boolean listenToSelectionChange
;
130 private Taxon selectedTaxon
;
132 private ISelectionService selectionService
;
135 * Default constructor
137 public DerivateView() {
145 public void init(IEditorSite site
, IEditorInput input
) throws PartInitException
{
147 this.setInput(input
);
148 this.derivateToRootEntityMap
= new HashMap
<SpecimenOrObservationBase
<?
>, SpecimenOrObservationBase
<?
>>();
149 this.rootElements
= new HashSet
<SpecimenOrObservationBase
<?
>>();
151 if (CdmStore
.isActive() && conversation
== null) {
152 conversation
= CdmStore
.createConversation();
154 if (CdmStore
.isActive()) {
155 cdmEntitySession
= CdmStore
.getCurrentSessionManager().newSession(this, true);
157 //listen to context changes
158 CdmStore
.getContextManager().addContextListener(this);
162 public void createPartControl(Composite parent
) {
164 parent
.setLayout(new GridLayout());
166 //---search and filter---
167 derivateSearchCompositeController
= new DerivateSearchCompositeController(parent
, this);
168 GridData gridDataSearchBar
= new GridData();
169 gridDataSearchBar
.horizontalAlignment
= GridData
.FILL
;
170 gridDataSearchBar
.grabExcessHorizontalSpace
= true;
171 derivateSearchCompositeController
.setLayoutData(gridDataSearchBar
);
172 derivateSearchCompositeController
.setEnabled(CdmStore
.isActive());
175 viewer
= new TreeViewer(new Tree(parent
, SWT
.MULTI
| SWT
.H_SCROLL
| SWT
.V_SCROLL
| SWT
.FULL_SELECTION
));
176 GridData gridDataTree
= new GridData();
177 gridDataTree
.horizontalAlignment
= GridData
.FILL
;
178 gridDataTree
.verticalAlignment
= GridData
.FILL
;
179 gridDataTree
.grabExcessVerticalSpace
= true;
180 gridDataTree
.grabExcessHorizontalSpace
= true;
181 viewer
.getTree().setLayoutData(gridDataTree
);
182 contentProvider
= new DerivateContentProvider();
183 viewer
.setContentProvider(contentProvider
);
184 labelProvider
= new DerivateLabelProvider();
185 labelProvider
.setConversation(conversation
);
186 viewer
.setLabelProvider(labelProvider
);
187 viewer
.setAutoExpandLevel(AbstractTreeViewer
.ALL_LEVELS
);
188 viewer
.getTree().setEnabled(CdmStore
.isActive());
189 // Propagate selection from viewer
190 getSite().setSelectionProvider(viewer
);
192 //listen to selection changes
193 selectionService
= getSite().getWorkbenchWindow().getSelectionService();
194 selectionService
.addSelectionListener(this);
196 //create context menu
197 MenuManager menuManager
= new MenuManager();
198 getSite().registerContextMenu(menuManager
, viewer
);
199 Control control
= viewer
.getControl();
200 Menu menu
= menuManager
.createContextMenu(control
);
201 control
.setMenu(menu
);
204 updateRootEntities();
206 getEditorSite().getActionBars().getStatusLineManager().setMessage("");
208 //add drag'n'drop support
209 Transfer
[] transfers
= new Transfer
[] {LocalSelectionTransfer
.getTransfer(),};
210 viewer
.addDragSupport(dndOperations
, transfers
, new DerivateDragListener(this));
211 viewer
.addDropSupport(dndOperations
, transfers
, new DerivateDropListener(this));
214 public void updateRootEntities() {
215 updateRootEntities((Collection
)null);
218 public void updateRootEntities(Collection
<UUID
> derivativeUuids
) {
219 if(conversation
!=null){
220 if (!conversation
.isBound()) {
224 * If the active session is not the session of the Derivative Editor
225 * then we will save the active session for later, bind temporarily
226 * to our session and rebind to the original session when we are
227 * done. This happens e.g. if a selection change happens in the
228 * taxon editor and "Link with editor" is enabled. The selection
229 * change event and thus the loading in updateRootEntities() happens
230 * in the session of the taxon editor.
232 ICdmEntitySession previousCdmEntitySession
= CdmStore
.getCurrentSessionManager().getActiveSession();
233 if(cdmEntitySession
!= null) {
234 cdmEntitySession
.bind();
237 List
<SpecimenOrObservationBase
> derivates
= null;
238 if(derivativeUuids
!=null){
239 this.derivateToRootEntityMap
= new HashMap
<SpecimenOrObservationBase
<?
>, SpecimenOrObservationBase
<?
>>();
240 this.rootElements
= new HashSet
<SpecimenOrObservationBase
<?
>>();
241 derivates
= CdmStore
.getService(IOccurrenceService
.class).load(new ArrayList(derivativeUuids
), SPECIMEN_INIT_STRATEGY
);
243 updateRootEntities(derivates
);
244 previousCdmEntitySession
.bind();
249 public void updateRootEntities(List
<SpecimenOrObservationBase
> derivates
) {
252 this.derivateToRootEntityMap
= new HashMap
<SpecimenOrObservationBase
<?
>, SpecimenOrObservationBase
<?
>>();
253 this.rootElements
= new HashSet
<SpecimenOrObservationBase
<?
>>();
254 for (SpecimenOrObservationBase derivate
: derivates
) {
256 if(derivate
instanceof FieldUnit
){
257 derivateToRootEntityMap
.put(derivate
, derivate
);
260 SpecimenOrObservationBase
<?
> topMostDerivate
= EditorUtil
.getTopMostDerivate(derivate
);
261 if(topMostDerivate
!=null){
262 derivateToRootEntityMap
.put(derivate
, topMostDerivate
);
265 derivateToRootEntityMap
.put(derivate
, derivate
);
269 for (SpecimenOrObservationBase
<?
> specimen
: derivateToRootEntityMap
.values()) {
270 rootElements
.add(specimen
);
273 labelProvider
.initCache(rootElements
);
274 viewer
.setInput(rootElements
);
276 getEditorSite().getActionBars().getStatusLineManager().setMessage(rootElements
.size() +" derivative hierarchies found");
281 public void doSave(IProgressMonitor monitor
) {
282 String taskName
= Messages
.DerivateView_SAVING_HIERARCHY
;
283 monitor
.beginTask(taskName
, 3);
284 if (!conversation
.isBound()) {
289 // commit the conversation and start a new transaction immediately
290 conversation
.commit(true);
292 if(CdmStore
.getCurrentSessionManager().isRemoting()) {
293 CdmStore
.getService(IOccurrenceService
.class).merge(new ArrayList
<SpecimenOrObservationBase
>(rootElements
), true);
297 this.setDirty(false);
300 firePropertyChange(PROP_DIRTY
);
305 public void doSaveAs() {
309 public String
getTitleToolTip() {
310 return Messages
.DerivateView_DERIVATIVE_EDITOR
;
314 public boolean isDirty() {
319 * @param isDirty the isDirty to set
321 public void setDirty(boolean isDirty
) {
322 this.isDirty
= isDirty
;
326 public boolean isSaveAsAllowed() {
331 public void setFocus() {
332 viewer
.getControl().setFocus();
333 //make sure to bind again if maybe in another view the conversation was unbound
334 if(conversation
!=null && !conversation
.isBound()){
337 if(cdmEntitySession
!= null) {
338 cdmEntitySession
.bind();
343 public void update(CdmDataChangeMap changeEvents
) {
347 public ConversationHolder
getConversationHolder() {
352 public void changed(Object element
) {
354 firePropertyChange(IEditorPart
.PROP_DIRTY
);
355 viewer
.update(new TreeNode(element
), null);
359 public void forceDirty() {
364 public Map
<Object
, List
<String
>> getPropertyPathsMap() {
365 List
<String
> specimenPropertyPaths
= Arrays
.asList(new String
[] {
367 "derivationEvents.derivates",
375 Map
<Object
, List
<String
>> specimenPropertyPathMap
=
376 new HashMap
<Object
, List
<String
>>();
377 specimenPropertyPathMap
.put(SpecimenOrObservationBase
.class,specimenPropertyPaths
);
378 return specimenPropertyPathMap
;
382 * Refreshes the derivate hierarchy tree and expands the tree
383 * to show and select the given object.
385 * @param expandTo the object to which the tree should be expanded
387 public void refreshTree(Object expandTo
){
389 TreeSelection selection
= (TreeSelection
) viewer
.getSelection();
390 viewer
.expandToLevel(selection
.getFirstElement(), 1);
391 viewer
.setSelection(new StructuredSelection(new TreeNode(expandTo
)));
395 * Refreshes the derivate hierarchy tree
397 public void refreshTree(){
401 //FIXME:Remoting hack to make this work for remoting
402 //This should actually be resolved using remoting post operations
403 public void remove(Object obj
) {
404 rootElements
.remove(obj
);
405 viewer
.setInput(rootElements
);
409 * @return a set of {@link SingleRead}s that have multiple parents
411 public Set
<SingleRead
> getMultiLinkSingleReads() {
412 return DerivateLabelProvider
.getMultiLinkSingleReads();
415 public Object
getSelectionInput() {
416 return selectedTaxon
;
419 public DerivateLabelProvider
getLabelProvider() {
420 return labelProvider
;
424 public boolean postOperation(CdmBase objectAffectedByOperation
) {
426 if(objectAffectedByOperation
!=null){
427 changed(objectAffectedByOperation
);
433 public boolean onComplete() {
439 public boolean canAttachMedia() {
443 public void addFieldUnit(FieldUnit fieldUnit
) {
444 rootElements
.add(fieldUnit
);
445 derivateToRootEntityMap
.put(fieldUnit
, fieldUnit
);
449 public ICdmEntitySession
getCdmEntitySession() {
450 return cdmEntitySession
;
454 public void dispose() {
456 if(conversation
!=null){
457 conversation
.close();
459 if(cdmEntitySession
!= null) {
460 cdmEntitySession
.dispose();
465 public void selectionChanged(IWorkbenchPart part
, ISelection selection
) {
466 if(viewer
.getTree().isDisposed()){
469 if(listenToSelectionChange
){
470 if(part
instanceof MultiPageTaxonEditor
){
471 selectedTaxon
= ((MultiPageTaxonEditor
) part
).getTaxon();
473 else if(selection
instanceof IStructuredSelection
){
474 Object selectedElement
= ((IStructuredSelection
) selection
).getFirstElement();
475 if(selectedElement
instanceof CdmBase
){
476 if(((CdmBase
) selectedElement
).isInstanceOf(TaxonNode
.class)){
477 selectedTaxon
= HibernateProxyHelper
.deproxy(selectedElement
, TaxonNode
.class).getTaxon();
479 else if(((CdmBase
) selectedElement
).isInstanceOf(Taxon
.class)){
480 selectedTaxon
= HibernateProxyHelper
.deproxy(selectedElement
, Taxon
.class);
484 if(selectedTaxon
!=null){
485 Collection
<SpecimenOrObservationBase
> fieldUnits
= CdmStore
.getService(IOccurrenceService
.class).listFieldUnitsByAssociatedTaxon(selectedTaxon
, null, null);
486 Collection
<UUID
> uuids
= new HashSet
<UUID
>();
487 for (SpecimenOrObservationBase specimenOrObservationBase
: fieldUnits
) {
488 uuids
.add(specimenOrObservationBase
.getUuid());
490 updateRootEntities(uuids
);
491 setPartName("Derivative Editor: " + selectedTaxon
.getName());
496 public TreeViewer
getViewer() {
504 public List
<SpecimenOrObservationBase
<?
>> getRootEntities() {
505 return new ArrayList
<SpecimenOrObservationBase
<?
>>(rootElements
);
508 public void toggleListenToSelectionChange() {
509 listenToSelectionChange
= !listenToSelectionChange
;
510 derivateSearchCompositeController
.setEnabled(!listenToSelectionChange
);
511 if(!listenToSelectionChange
){
512 selectedTaxon
= null;
513 setPartName("Derivative Editor");
515 else if(selectedTaxon
==null){
516 setPartName("Derivative Editor [no taxon selected]");
520 public boolean isListenToSelectionChange(){
521 return listenToSelectionChange
;
528 public void contextAboutToStop(IMemento memento
, IProgressMonitor monitor
) {
535 public void contextStop(IMemento memento
, IProgressMonitor monitor
) {
536 derivateSearchCompositeController
.setEnabled(false);
537 if(!viewer
.getTree().isDisposed()) {
538 viewer
.getTree().setEnabled(false);
539 viewer
.setInput(null);
547 public void contextStart(IMemento memento
, IProgressMonitor monitor
) {
548 derivateSearchCompositeController
.setEnabled(!listenToSelectionChange
);
549 viewer
.getTree().setEnabled(true);
557 public void contextRefresh(IProgressMonitor monitor
) {
564 public void workbenchShutdown(IMemento memento
, IProgressMonitor monitor
) {