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
;
10 import java
.util
.Map
.Entry
;
12 import java
.util
.UUID
;
14 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
15 import org
.eclipse
.jface
.action
.MenuManager
;
16 import org
.eclipse
.jface
.util
.LocalSelectionTransfer
;
17 import org
.eclipse
.jface
.viewers
.AbstractTreeViewer
;
18 import org
.eclipse
.jface
.viewers
.ISelection
;
19 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
20 import org
.eclipse
.jface
.viewers
.StructuredSelection
;
21 import org
.eclipse
.jface
.viewers
.TreeNode
;
22 import org
.eclipse
.jface
.viewers
.TreeSelection
;
23 import org
.eclipse
.jface
.viewers
.TreeViewer
;
24 import org
.eclipse
.swt
.SWT
;
25 import org
.eclipse
.swt
.dnd
.DND
;
26 import org
.eclipse
.swt
.dnd
.Transfer
;
27 import org
.eclipse
.swt
.layout
.GridData
;
28 import org
.eclipse
.swt
.layout
.GridLayout
;
29 import org
.eclipse
.swt
.widgets
.Composite
;
30 import org
.eclipse
.swt
.widgets
.Control
;
31 import org
.eclipse
.swt
.widgets
.Menu
;
32 import org
.eclipse
.swt
.widgets
.Tree
;
33 import org
.eclipse
.ui
.IEditorPart
;
34 import org
.eclipse
.ui
.IMemento
;
35 import org
.eclipse
.ui
.ISaveablePart2
;
36 import org
.eclipse
.ui
.IWorkbenchPart
;
38 import eu
.etaxonomy
.cdm
.api
.conversation
.ConversationHolder
;
39 import eu
.etaxonomy
.cdm
.api
.service
.IOccurrenceService
;
40 import eu
.etaxonomy
.cdm
.api
.service
.molecular
.ISequenceService
;
41 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
42 import eu
.etaxonomy
.cdm
.model
.molecular
.Sequence
;
43 import eu
.etaxonomy
.cdm
.model
.molecular
.SingleRead
;
44 import eu
.etaxonomy
.cdm
.model
.occurrence
.FieldUnit
;
45 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
46 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
47 import eu
.etaxonomy
.cdm
.persistence
.hibernate
.CdmDataChangeMap
;
48 import eu
.etaxonomy
.taxeditor
.editor
.EditorUtil
;
49 import eu
.etaxonomy
.taxeditor
.editor
.Messages
;
50 import eu
.etaxonomy
.taxeditor
.editor
.view
.derivate
.searchFilter
.DerivateSearchCompositeController
;
51 import eu
.etaxonomy
.taxeditor
.model
.IContextListener
;
52 import eu
.etaxonomy
.taxeditor
.model
.IPartContentHasDetails
;
53 import eu
.etaxonomy
.taxeditor
.model
.IPartContentHasFactualData
;
54 import eu
.etaxonomy
.taxeditor
.model
.IPartContentHasMedia
;
55 import eu
.etaxonomy
.taxeditor
.model
.IPartContentHasSupplementalData
;
56 import eu
.etaxonomy
.taxeditor
.session
.ICdmEntitySession
;
57 import eu
.etaxonomy
.taxeditor
.store
.CdmStore
;
58 import eu
.etaxonomy
.taxeditor
.view
.AbstractCdmViewPart
;
59 import eu
.etaxonomy
.taxeditor
.view
.derivateSearch
.DerivateContentProvider
;
60 import eu
.etaxonomy
.taxeditor
.view
.derivateSearch
.DerivateLabelProvider
;
63 * Displays the derivate hierarchy of the specimen specified in the editor input.
66 public class DerivateView
extends AbstractCdmViewPart
implements IPartContentHasFactualData
, ISaveablePart2
,
67 IPartContentHasDetails
, IPartContentHasSupplementalData
, IPartContentHasMedia
, IContextListener
{
68 public static final String ID
= "eu.etaxonomy.taxeditor.editor.view.derivate.DerivateView"; //$NON-NLS-1$
70 public static final String YOU_NEED_TO_SAVE_BEFORE_PERFORMING_THIS_ACTION
= Messages
.DerivateView_YOU_NEED_TO_SAVE
;
71 public static final String VIEW_HAS_UNSAVED_CHANGES
= Messages
.DerivateView_UNSAVED_CHANGES
;
73 private static final List
<String
> SPECIMEN_INIT_STRATEGY
= Arrays
.asList(new String
[] {
81 "derivationEvents.derivatives.annotations",
82 "derivationEvents.derivatives.markers",
83 "derivationEvents.derivatives.credits",
84 "derivationEvents.derivatives.extensions",
85 "derivationEvents.derivatives.rights",
86 "derivationEvents.derivatives.sources"
89 private ConversationHolder conversation
;
91 private TreeViewer viewer
;
93 private boolean isDirty
;
95 private final int dndOperations
= DND
.DROP_MOVE
;
97 private DerivateLabelProvider labelProvider
;
99 private Set
<SingleRead
> multiLinkSingleReads
;
101 private ISelection selection
= null;
104 private DerivateContentProvider contentProvider
;
106 private DerivateSearchCompositeController derivateSearchCompositeController
;
109 * A map with keys being the derivative entities belonging to the {@link UUID}s passed to the constructor
110 * and values being the root elements of the hierarchy (may be the same objects as the derivative entities)
112 private Map
<SpecimenOrObservationBase
<?
>, SpecimenOrObservationBase
<?
>> derivateToRootEntityMap
;
115 * The set of root elements
117 private Set
<SpecimenOrObservationBase
<?
>> rootElements
;
119 private ICdmEntitySession cdmEntitySession
;
122 * <code>true</code> if this view is listening to selection changes
124 private boolean listenToSelectionChange
;
127 * Default constructor
129 public DerivateView() {
136 private void init() {
137 this.derivateToRootEntityMap
= new HashMap
<SpecimenOrObservationBase
<?
>, SpecimenOrObservationBase
<?
>>();
138 this.rootElements
= new HashSet
<SpecimenOrObservationBase
<?
>>();
140 if (CdmStore
.isActive() && conversation
== null) {
141 conversation
= CdmStore
.createConversation();
143 if (CdmStore
.isActive()) {
144 cdmEntitySession
= CdmStore
.getCurrentSessionManager().newSession(this, true);
146 //listen to context changes
147 CdmStore
.getContextManager().addContextListener(this);
151 public void createPartControl(Composite parent
) {
153 parent
.setLayout(new GridLayout());
155 //---search and filter---
156 derivateSearchCompositeController
= new DerivateSearchCompositeController(parent
, this);
157 derivateSearchCompositeController
.setEnabled(CdmStore
.isActive());
158 GridData gridDataSearchBar
= new GridData();
159 gridDataSearchBar
.horizontalAlignment
= GridData
.FILL
;
160 gridDataSearchBar
.grabExcessHorizontalSpace
= true;
161 derivateSearchCompositeController
.setLayoutData(gridDataSearchBar
);
164 viewer
= new TreeViewer(new Tree(parent
, SWT
.MULTI
| SWT
.H_SCROLL
| SWT
.V_SCROLL
| SWT
.FULL_SELECTION
));
165 GridData gridDataTree
= new GridData();
166 gridDataTree
.horizontalAlignment
= GridData
.FILL
;
167 gridDataTree
.verticalAlignment
= GridData
.FILL
;
168 gridDataTree
.grabExcessVerticalSpace
= true;
169 gridDataTree
.grabExcessHorizontalSpace
= true;
170 viewer
.getTree().setLayoutData(gridDataTree
);
171 contentProvider
= new DerivateContentProvider();
172 viewer
.setContentProvider(contentProvider
);
173 labelProvider
= new DerivateLabelProvider();
174 labelProvider
.setConversation(conversation
);
175 viewer
.setLabelProvider(labelProvider
);
176 viewer
.setAutoExpandLevel(AbstractTreeViewer
.ALL_LEVELS
);
177 // Propagate selection from viewer
178 getSite().setSelectionProvider(viewer
);
180 //listen to selection changes
181 selectionService
= getSite().getWorkbenchWindow().getSelectionService();
182 selectionService
.addSelectionListener(this);
184 //create context menu
185 MenuManager menuManager
= new MenuManager();
186 getSite().registerContextMenu(menuManager
, viewer
);
187 Control control
= viewer
.getControl();
188 Menu menu
= menuManager
.createContextMenu(control
);
189 control
.setMenu(menu
);
192 updateRootEntities();
194 //add drag'n'drop support
195 Transfer
[] transfers
= new Transfer
[] {LocalSelectionTransfer
.getTransfer(),};
196 viewer
.addDragSupport(dndOperations
, transfers
, new DerivateDragListener(this));
197 viewer
.addDropSupport(dndOperations
, transfers
, new DerivateDropListener(this));
200 public void updateRootEntities() {
201 updateRootEntities(null);
204 public void updateRootEntities(Collection
<UUID
> derivativeUuids
) {
205 if(conversation
!=null){
206 if (!conversation
.isBound()) {
210 * If the active session is not the session of the Derivate Editor then we will
211 * save it, bind temporarily to our session and rebind to the original session.
212 * This happens e.g. if a selection change happens in the taxon editor and
213 * "Link with editor" is enabled. The selection change event and thus the
214 * loading in updateRootEntities() happens in the session of the taxon
217 ICdmEntitySession previousCdmEntitySession
= CdmStore
.getCurrentSessionManager().getActiveSession();
218 if(cdmEntitySession
!= null) {
219 cdmEntitySession
.bind();
222 if(derivativeUuids
!=null){
223 this.derivateToRootEntityMap
= new HashMap
<SpecimenOrObservationBase
<?
>, SpecimenOrObservationBase
<?
>>();
224 this.rootElements
= new HashSet
<SpecimenOrObservationBase
<?
>>();
225 for (UUID uuid
: derivativeUuids
) {
226 SpecimenOrObservationBase
<?
> derivate
= CdmStore
.getService(IOccurrenceService
.class).load(uuid
, SPECIMEN_INIT_STRATEGY
);
227 if(derivate
instanceof FieldUnit
){
228 derivateToRootEntityMap
.put(derivate
, derivate
);
231 SpecimenOrObservationBase
<?
> topMostDerivate
= EditorUtil
.getTopMostDerivate(derivate
);
232 if(topMostDerivate
!=null){
233 derivateToRootEntityMap
.put(derivate
, topMostDerivate
);
236 derivateToRootEntityMap
.put(derivate
, derivate
);
240 for (SpecimenOrObservationBase
<?
> specimen
: derivateToRootEntityMap
.values()) {
241 rootElements
.add(specimen
);
244 viewer
.setInput(rootElements
);
246 previousCdmEntitySession
.bind();
251 public void doSave(IProgressMonitor monitor
) {
252 String taskName
= Messages
.DerivateView_SAVING_HIERARCHY
;
253 monitor
.beginTask(taskName
, 3);
254 if (!conversation
.isBound()) {
259 // commit the conversation and start a new transaction immediately
260 conversation
.commit(true);
262 if(CdmStore
.getCurrentSessionManager().isRemoting()) {
263 CdmStore
.getService(IOccurrenceService
.class).merge(new ArrayList
<SpecimenOrObservationBase
>(rootElements
), true);
267 this.setDirty(false);
270 firePropertyChange(PROP_DIRTY
);
275 public void doSaveAs() {
279 public String
getTitleToolTip() {
280 return Messages
.DerivateView_DERIVATIVE_EDITOR
;
284 public boolean isDirty() {
289 * @param isDirty the isDirty to set
291 public void setDirty(boolean isDirty
) {
292 this.isDirty
= isDirty
;
296 public boolean isSaveAsAllowed() {
301 public void setFocus() {
302 viewer
.getControl().setFocus();
303 //make sure to bind again if maybe in another view the conversation was unbound
304 if(conversation
!=null && !conversation
.isBound()){
307 if(cdmEntitySession
!= null) {
308 cdmEntitySession
.bind();
313 public void update(CdmDataChangeMap changeEvents
) {
317 public ConversationHolder
getConversationHolder() {
325 public TreeViewer
getViewer() {
330 public void changed(Object element
) {
332 firePropertyChange(IEditorPart
.PROP_DIRTY
);
337 public void forceDirty() {
342 public Map
<Object
, List
<String
>> getPropertyPathsMap() {
343 List
<String
> specimenPropertyPaths
= Arrays
.asList(new String
[] {
345 "derivationEvents.derivates",
353 Map
<Object
, List
<String
>> specimenPropertyPathMap
=
354 new HashMap
<Object
, List
<String
>>();
355 specimenPropertyPathMap
.put(SpecimenOrObservationBase
.class,specimenPropertyPaths
);
356 return specimenPropertyPathMap
;
360 * Refreshes the derivate hierarchy tree and expands the tree
361 * to show and select the given object.
363 * @param expandTo the object to which the tree should be expanded
365 public void refreshTree(Object expandTo
){
367 TreeSelection selection
= (TreeSelection
) viewer
.getSelection();
368 viewer
.expandToLevel(selection
.getFirstElement(), 1);
369 viewer
.setSelection(new StructuredSelection(new TreeNode(expandTo
)));
373 * Refreshes the derivate hierarchy tree
375 public void refreshTree(){
376 generateMultiLinkSingleReads();
377 labelProvider
.setMultiLinkSingleReads(multiLinkSingleReads
);
381 //FIXME:Remoting hack to make this work for remoting
382 //This should actually be resolved using remoting post operations
383 public void remove(Object obj
) {
384 rootElements
.remove(obj
);
385 viewer
.setInput(rootElements
);
388 private void generateMultiLinkSingleReads() {
389 Set
<SingleRead
> multiLinkSingleReads
= new HashSet
<SingleRead
>();
390 for(Entry
<SingleRead
, Collection
<Sequence
>> entry
:CdmStore
.getService(ISequenceService
.class).getSingleReadSequencesMap().entrySet()){
391 if(entry
.getValue().size()>1){
392 multiLinkSingleReads
.add(entry
.getKey());
395 this.multiLinkSingleReads
= multiLinkSingleReads
;
399 * @return a set of {@link SingleRead}s that have multiple parents
401 public Set
<SingleRead
> getMultiLinkSingleReads() {
402 return this.multiLinkSingleReads
;
405 public ISelection
getSelection() {
409 public DerivateLabelProvider
getLabelProvider() {
410 return labelProvider
;
414 public boolean postOperation(CdmBase objectAffectedByOperation
) {
416 if(objectAffectedByOperation
!=null){
417 changed(objectAffectedByOperation
);
423 public boolean onComplete() {
429 public boolean canAttachMedia() {
433 public void removeHierarchy(SpecimenOrObservationBase
<?
> specimenOrObservationBase
) {
434 SpecimenOrObservationBase
<?
> rootElement
= derivateToRootEntityMap
.remove(specimenOrObservationBase
);
435 rootElements
.remove(rootElement
);
438 public void addHierarchy(FieldUnit fieldUnit
) {
439 rootElements
.add(fieldUnit
);
440 derivateToRootEntityMap
.put(fieldUnit
, fieldUnit
);
444 public ICdmEntitySession
getCdmEntitySession() {
445 return cdmEntitySession
;
449 public void dispose() {
451 if(conversation
!=null){
452 conversation
.close();
454 if(cdmEntitySession
!= null) {
455 cdmEntitySession
.dispose();
460 public void selectionChanged(IWorkbenchPart part
, ISelection selection
) {
461 if(listenToSelectionChange
&& selection
instanceof IStructuredSelection
){
462 Object selectedElement
= ((IStructuredSelection
) selection
).getFirstElement();
463 if(selectedElement
instanceof Taxon
){
464 Collection
<SpecimenOrObservationBase
> fieldUnits
= CdmStore
.getService(IOccurrenceService
.class).listFieldUnitsByAssociatedTaxon((Taxon
) selectedElement
, null, null);
465 Collection
<UUID
> uuids
= new HashSet
<UUID
>();
466 for (SpecimenOrObservationBase specimenOrObservationBase
: fieldUnits
) {
467 uuids
.add(specimenOrObservationBase
.getUuid());
469 updateRootEntities(uuids
);
478 public List
<SpecimenOrObservationBase
<?
>> getRootEntities() {
479 return new ArrayList
<SpecimenOrObservationBase
<?
>>(rootElements
);
483 public void createViewer(Composite parent
) {
484 // TODO Auto-generated method stub
489 public boolean isSaveOnCloseNeeded() {
494 public int promptToSaveOnClose() {
495 return ISaveablePart2
.DEFAULT
;
498 public void toggleListenToSelectionChange() {
499 listenToSelectionChange
= !listenToSelectionChange
;
500 derivateSearchCompositeController
.setEnabled(!listenToSelectionChange
);
507 public void contextAboutToStop(IMemento memento
, IProgressMonitor monitor
) {
514 public void contextStop(IMemento memento
, IProgressMonitor monitor
) {
515 derivateSearchCompositeController
.setEnabled(false);
516 viewer
.setInput(null);
523 public void contextStart(IMemento memento
, IProgressMonitor monitor
) {
525 derivateSearchCompositeController
.setEnabled(!listenToSelectionChange
);
533 public void contextRefresh(IProgressMonitor monitor
) {
540 public void workbenchShutdown(IMemento memento
, IProgressMonitor monitor
) {