package eu.etaxonomy.taxeditor.editor.view.derivate;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import org.eclipse.jface.util.LocalSelectionTransfer;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeNode;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Tree;
-import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.IEditorSite;
-import org.eclipse.ui.PartInitException;
-import org.eclipse.ui.part.EditorPart;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.ISaveablePart2;
+import org.eclipse.ui.IWorkbenchPart;
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
-import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
import eu.etaxonomy.cdm.api.service.IOccurrenceService;
import eu.etaxonomy.cdm.api.service.molecular.ISequenceService;
import eu.etaxonomy.cdm.model.common.CdmBase;
import eu.etaxonomy.cdm.model.molecular.Sequence;
import eu.etaxonomy.cdm.model.molecular.SingleRead;
+import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
+import eu.etaxonomy.cdm.model.taxon.Taxon;
import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
-import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
+import eu.etaxonomy.taxeditor.editor.EditorUtil;
+import eu.etaxonomy.taxeditor.editor.Messages;
+import eu.etaxonomy.taxeditor.editor.MultiPageTaxonEditor;
+import eu.etaxonomy.taxeditor.editor.view.derivate.searchFilter.DerivateSearchCompositeController;
+import eu.etaxonomy.taxeditor.model.IContextListener;
import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
import eu.etaxonomy.taxeditor.model.IPartContentHasFactualData;
import eu.etaxonomy.taxeditor.model.IPartContentHasMedia;
import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
-import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
+import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
import eu.etaxonomy.taxeditor.store.CdmStore;
+import eu.etaxonomy.taxeditor.view.AbstractCdmViewPart;
import eu.etaxonomy.taxeditor.view.derivateSearch.DerivateContentProvider;
import eu.etaxonomy.taxeditor.view.derivateSearch.DerivateLabelProvider;
* Displays the derivate hierarchy of the specimen specified in the editor input.
*
*/
-public class DerivateView extends EditorPart implements IPartContentHasFactualData, IDirtyMarkable,
- IConversationEnabled, IPartContentHasDetails, IPartContentHasSupplementalData, IPartContentHasMedia,
- ISelectionChangedListener, IPostOperationEnabled {
-
- public static final String ID = "eu.etaxonomy.taxeditor.editor.view.derivate.DerivateView";
+public class DerivateView extends AbstractCdmViewPart implements IPartContentHasFactualData, ISaveablePart2,
+ IPartContentHasDetails, IPartContentHasSupplementalData, IPartContentHasMedia, IContextListener {
+ public static final String ID = "eu.etaxonomy.taxeditor.editor.view.derivate.DerivateView"; //$NON-NLS-1$
+
+ public static final String YOU_NEED_TO_SAVE_BEFORE_PERFORMING_THIS_ACTION = Messages.DerivateView_YOU_NEED_TO_SAVE;
+ public static final String VIEW_HAS_UNSAVED_CHANGES = Messages.DerivateView_UNSAVED_CHANGES;
+
+ private static final List<String> SPECIMEN_INIT_STRATEGY = Arrays.asList(new String[] {
+ "descriptions",
+ "annotations",
+ "markers",
+ "credits",
+ "extensions",
+ "rights",
+ "sources",
+ "derivationEvents.derivatives.annotations",
+ "derivationEvents.derivatives.markers",
+ "derivationEvents.derivatives.credits",
+ "derivationEvents.derivatives.extensions",
+ "derivationEvents.derivatives.rights",
+ "derivationEvents.derivatives.sources"
+ });
private ConversationHolder conversation;
private ISelection selection = null;
+
+ private DerivateContentProvider contentProvider;
+
+ private DerivateSearchCompositeController derivateSearchCompositeController;
+
+ /**
+ * A map with keys being the derivative entities belonging to the {@link UUID}s passed to the constructor
+ * and values being the root elements of the hierarchy (may be the same objects as the derivative entities)
+ */
+ private Map<SpecimenOrObservationBase<?>, SpecimenOrObservationBase<?>> derivateToRootEntityMap;
+
+ /**
+ * The set of root elements
+ */
+ private Set<SpecimenOrObservationBase<?>> rootElements;
+
+ private ICdmEntitySession cdmEntitySession;
+
+ /**
+ * <code>true</code> if this view is listening to selection changes
+ */
+ private boolean listenToSelectionChange;
+
/**
* Default constructor
*/
public DerivateView() {
+ init();
+ }
+
+ /**
+ *
+ */
+ private void init() {
+ this.derivateToRootEntityMap = new HashMap<SpecimenOrObservationBase<?>, SpecimenOrObservationBase<?>>();
+ this.rootElements = new HashSet<SpecimenOrObservationBase<?>>();
+
+ if (CdmStore.isActive() && conversation == null) {
+ conversation = CdmStore.createConversation();
+ }
+ if (CdmStore.isActive()) {
+ cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
+ }
+ //listen to context changes
+ CdmStore.getContextManager().addContextListener(this);
}
@Override
public void createPartControl(Composite parent) {
+
+ parent.setLayout(new GridLayout());
+
+ //---search and filter---
+ derivateSearchCompositeController = new DerivateSearchCompositeController(parent, this);
+ derivateSearchCompositeController.setEnabled(CdmStore.isActive());
+ GridData gridDataSearchBar = new GridData();
+ gridDataSearchBar.horizontalAlignment = GridData.FILL;
+ gridDataSearchBar.grabExcessHorizontalSpace = true;
+ derivateSearchCompositeController.setLayoutData(gridDataSearchBar);
+
+ //---tree viewer---
viewer = new TreeViewer(new Tree(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION));
- viewer.setContentProvider(new DerivateContentProvider());
+ GridData gridDataTree = new GridData();
+ gridDataTree.horizontalAlignment = GridData.FILL;
+ gridDataTree.verticalAlignment = GridData.FILL;
+ gridDataTree.grabExcessVerticalSpace = true;
+ gridDataTree.grabExcessHorizontalSpace = true;
+ viewer.getTree().setLayoutData(gridDataTree);
+ contentProvider = new DerivateContentProvider();
+ viewer.setContentProvider(contentProvider);
labelProvider = new DerivateLabelProvider();
labelProvider.setConversation(conversation);
viewer.setLabelProvider(labelProvider);
viewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
// Propagate selection from viewer
getSite().setSelectionProvider(viewer);
+
//listen to selection changes
- viewer.addSelectionChangedListener(this);
+ selectionService = getSite().getWorkbenchWindow().getSelectionService();
+ selectionService.addSelectionListener(this);
//create context menu
MenuManager menuManager = new MenuManager();
Menu menu = menuManager.createContextMenu(control);
control.setMenu(menu);
- generateMultiLinkSingleReads();
- labelProvider.setMultiLinkSingleReads(multiLinkSingleReads);
- IEditorInput editorInput = getEditorInput();
- viewer.setInput(((DerivateViewEditorInput) editorInput).getRootUUIDs());
- //set selection to selected derivate if only one was selected
- if(editorInput instanceof DerivateViewEditorInput){
- Set<UUID> derivateUUIDs = ((DerivateViewEditorInput) editorInput).getDerivateUUIDs();
- if(derivateUUIDs.size()==1){
- SpecimenOrObservationBase<?> specimen = CdmStore.getService(IOccurrenceService.class).load(derivateUUIDs.iterator().next());
- if(specimen!=null){
- viewer.setSelection(new StructuredSelection(new TreeNode(specimen)));
- }
- }
- }
+ //init tree
+ updateRootEntities();
//add drag'n'drop support
Transfer[] transfers = new Transfer[] {LocalSelectionTransfer.getTransfer(),};
viewer.addDropSupport(dndOperations, transfers, new DerivateDropListener(this));
}
+ public void updateRootEntities() {
+ updateRootEntities(null);
+ }
+
+ public void updateRootEntities(Collection<UUID> derivativeUuids) {
+ if(conversation!=null){
+ if (!conversation.isBound()) {
+ conversation.bind();
+ }
+ /*
+ * If the active session is not the session of the Derivate Editor then we will
+ * save it, bind temporarily to our session and rebind to the original session.
+ * This happens e.g. if a selection change happens in the taxon editor and
+ * "Link with editor" is enabled. The selection change event and thus the
+ * loading in updateRootEntities() happens in the session of the taxon
+ * editor.
+ */
+ ICdmEntitySession previousCdmEntitySession = CdmStore.getCurrentSessionManager().getActiveSession();
+ if(cdmEntitySession != null) {
+ cdmEntitySession.bind();
+ }
+
+ if(derivativeUuids!=null){
+ this.derivateToRootEntityMap = new HashMap<SpecimenOrObservationBase<?>, SpecimenOrObservationBase<?>>();
+ this.rootElements = new HashSet<SpecimenOrObservationBase<?>>();
+ for (UUID uuid : derivativeUuids) {
+ SpecimenOrObservationBase<?> derivate = CdmStore.getService(IOccurrenceService.class).load(uuid, SPECIMEN_INIT_STRATEGY);
+ if(derivate instanceof FieldUnit){
+ derivateToRootEntityMap.put(derivate, derivate);
+ }
+ else {
+ SpecimenOrObservationBase<?> topMostDerivate = EditorUtil.getTopMostDerivate(derivate);
+ if(topMostDerivate!=null){
+ derivateToRootEntityMap.put(derivate, topMostDerivate);
+ }
+ else{
+ derivateToRootEntityMap.put(derivate, derivate);
+ }
+ }
+ }
+ for (SpecimenOrObservationBase<?> specimen : derivateToRootEntityMap.values()) {
+ rootElements.add(specimen);
+ }
+ }
+ viewer.setInput(rootElements);
+ refreshTree();
+ previousCdmEntitySession.bind();
+ }
+ }
+
@Override
public void doSave(IProgressMonitor monitor) {
- String taskName = "Saving hierarchy";
- if(getEditorInput() instanceof DerivateViewEditorInput){
- DerivateViewEditorInput derivateViewEditorInput = (DerivateViewEditorInput) getEditorInput();
- taskName += " "+derivateViewEditorInput.getName();
- }
+ String taskName = Messages.DerivateView_SAVING_HIERARCHY;
monitor.beginTask(taskName, 3);
if (!conversation.isBound()) {
conversation.bind();
// commit the conversation and start a new transaction immediately
conversation.commit(true);
+
+ if(CdmStore.getCurrentSessionManager().isRemoting()) {
+ CdmStore.getService(IOccurrenceService.class).merge(new ArrayList<SpecimenOrObservationBase>(rootElements), true);
+ }
monitor.worked(1);
this.setDirty(false);
@Override
public String getTitleToolTip() {
- if(getEditorInput() instanceof DerivateViewEditorInput){
- DerivateViewEditorInput derivateViewEditorInput = (DerivateViewEditorInput) getEditorInput();
- return derivateViewEditorInput.getName();
- }
- return "Derivative Editor";
- }
-
- @Override
- public void init(IEditorSite site, IEditorInput input) throws PartInitException {
- setSite(site);
- setInput(input);
- if(input instanceof DerivateViewEditorInput){
- DerivateViewEditorInput derivateViewEditorInput = (DerivateViewEditorInput) input;
- conversation = derivateViewEditorInput.getConversationHolder();
- setPartName(derivateViewEditorInput.getName());
- }
+ return Messages.DerivateView_DERIVATIVE_EDITOR;
}
@Override
public void setFocus() {
viewer.getControl().setFocus();
//make sure to bind again if maybe in another view the conversation was unbound
- if(!conversation.isBound()){
+ if(conversation!=null && !conversation.isBound()){
conversation.bind();
}
+ if(cdmEntitySession != null) {
+ cdmEntitySession.bind();
+ }
}
@Override
/**
* @return the viewer
*/
+ @Override
public TreeViewer getViewer() {
return viewer;
}
changed(null);
}
+ @Override
+ public Map<Object, List<String>> getPropertyPathsMap() {
+ List<String> specimenPropertyPaths = Arrays.asList(new String[] {
+ "descriptions",
+ "derivationEvents.derivates",
+ "annotations",
+ "markers",
+ "credits",
+ "extensions",
+ "rights",
+ "sources"
+ });
+ Map<Object, List<String>> specimenPropertyPathMap =
+ new HashMap<Object, List<String>>();
+ specimenPropertyPathMap.put(SpecimenOrObservationBase.class,specimenPropertyPaths);
+ return specimenPropertyPathMap;
+ }
+
/**
* Refreshes the derivate hierarchy tree and expands the tree
* to show and select the given object.
viewer.refresh();
}
+ //FIXME:Remoting hack to make this work for remoting
+ //This should actually be resolved using remoting post operations
+ public void remove(Object obj) {
+ rootElements.remove(obj);
+ viewer.setInput(rootElements);
+ }
+
private void generateMultiLinkSingleReads() {
Set<SingleRead> multiLinkSingleReads = new HashSet<SingleRead>();
for(Entry<SingleRead, Collection<Sequence>> entry:CdmStore.getService(ISequenceService.class).getSingleReadSequencesMap().entrySet()){
return this.multiLinkSingleReads;
}
- @Override
- public void selectionChanged(SelectionChangedEvent event) {
- this.selection = event.getSelection();
- }
-
public ISelection getSelection() {
return selection;
}
return true;
}
+
@Override
public boolean canAttachMedia() {
return true;
}
+ public void removeHierarchy(SpecimenOrObservationBase<?> specimenOrObservationBase) {
+ SpecimenOrObservationBase<?> rootElement = derivateToRootEntityMap.remove(specimenOrObservationBase);
+ rootElements.remove(rootElement);
+ }
+
+ public void addHierarchy(FieldUnit fieldUnit) {
+ rootElements.add(fieldUnit);
+ derivateToRootEntityMap.put(fieldUnit, fieldUnit);
+ }
+
+ @Override
+ public ICdmEntitySession getCdmEntitySession() {
+ return cdmEntitySession;
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ if(conversation!=null){
+ conversation.close();
+ }
+ if(cdmEntitySession != null) {
+ cdmEntitySession.dispose();
+ }
+ }
+
+ @Override
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ if(listenToSelectionChange && selection instanceof IStructuredSelection){
+ Object selectedElement = ((IStructuredSelection) selection).getFirstElement();
+ if(selectedElement instanceof Taxon){
+ Collection<SpecimenOrObservationBase> fieldUnits = CdmStore.getService(IOccurrenceService.class).listFieldUnitsByAssociatedTaxon((Taxon) selectedElement, null, null);
+ Collection<UUID> uuids = new HashSet<UUID>();
+ for (SpecimenOrObservationBase specimenOrObservationBase : fieldUnits) {
+ uuids.add(specimenOrObservationBase.getUuid());
+ }
+ updateRootEntities(uuids);
+ }
+ }
+ if(part instanceof MultiPageTaxonEditor){
+ Taxon taxon = ((MultiPageTaxonEditor) part).getTaxon();
+ derivateSearchCompositeController.setTaxon(taxon);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<SpecimenOrObservationBase<?>> getRootEntities() {
+ return new ArrayList<SpecimenOrObservationBase<?>>(rootElements);
+ }
+
+ @Override
+ public void createViewer(Composite parent) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean isSaveOnCloseNeeded() {
+ return isDirty();
+ }
+
+ @Override
+ public int promptToSaveOnClose() {
+ return ISaveablePart2.DEFAULT;
+ }
+
+ public void toggleListenToSelectionChange() {
+ listenToSelectionChange = !listenToSelectionChange;
+ derivateSearchCompositeController.setEnabled(!listenToSelectionChange);
+ derivateSearchCompositeController.setTaxon(null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void contextAboutToStop(IMemento memento, IProgressMonitor monitor) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void contextStop(IMemento memento, IProgressMonitor monitor) {
+ derivateSearchCompositeController.setEnabled(false);
+ viewer.setInput(null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void contextStart(IMemento memento, IProgressMonitor monitor) {
+ init();
+ derivateSearchCompositeController.setEnabled(!listenToSelectionChange);
+ refreshTree();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void contextRefresh(IProgressMonitor monitor) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void workbenchShutdown(IMemento memento, IProgressMonitor monitor) {
+ }
+
}