Merge branch 'release/5.8.0'
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / featuretree / e4 / FeatureTreeEditor.java
index 12819c592f18401a2fe0e5a5173d73c37766450a..a57bdd9b6ae0a79d4d9c039da42db52700eefdbb 100644 (file)
@@ -9,7 +9,6 @@
 
 package eu.etaxonomy.taxeditor.featuretree.e4;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -29,12 +28,17 @@ import org.eclipse.e4.ui.services.EMenuService;
 import org.eclipse.e4.ui.workbench.modeling.EPartService;
 import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
 import org.eclipse.jface.util.LocalSelectionTransfer;
+import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.SWT;
 import org.eclipse.swt.dnd.DND;
 import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
 import org.eclipse.swt.layout.FillLayout;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.ui.IMemento;
@@ -42,24 +46,27 @@ import org.eclipse.ui.IMemento;
 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
 import eu.etaxonomy.cdm.api.service.IFeatureTreeService;
-import eu.etaxonomy.cdm.model.description.FeatureNode;
-import eu.etaxonomy.cdm.model.description.FeatureTree;
+import eu.etaxonomy.cdm.api.service.ITermService;
+import eu.etaxonomy.cdm.model.description.Character;
+import eu.etaxonomy.cdm.model.term.FeatureNode;
+import eu.etaxonomy.cdm.model.term.FeatureTree;
+import eu.etaxonomy.cdm.model.term.TermType;
 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
+import eu.etaxonomy.taxeditor.editor.definedterm.FeatureTreeViewerComparator;
 import eu.etaxonomy.taxeditor.editor.definedterm.TermTransfer;
 import eu.etaxonomy.taxeditor.featuretree.FeatureNodeTransfer;
 import eu.etaxonomy.taxeditor.featuretree.FeatureTreeContentProvider;
 import eu.etaxonomy.taxeditor.featuretree.FeatureTreeLabelProvider;
+import eu.etaxonomy.taxeditor.featuretree.e4.operation.AddFeatureOperation;
 import eu.etaxonomy.taxeditor.model.AbstractUtility;
 import eu.etaxonomy.taxeditor.model.IContextListener;
 import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
 import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
 import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
-import eu.etaxonomy.taxeditor.operation.AbstractPostOperation;
-import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
 import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
-import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
+import eu.etaxonomy.taxeditor.store.AppModelId;
 import eu.etaxonomy.taxeditor.store.CdmStore;
-import eu.etaxonomy.taxeditor.workbench.part.IE4SavablePart;
+import eu.etaxonomy.taxeditor.store.StoreUtil;
 import eu.etaxonomy.taxeditor.workbench.part.IE4ViewerPart;
 
 /**
@@ -68,9 +75,9 @@ import eu.etaxonomy.taxeditor.workbench.part.IE4ViewerPart;
  * @date 06.06.2017
  *
  */
-public class FeatureTreeEditor implements ICdmEntitySessionEnabled, ISelectionChangedListener,
-        IE4ViewerPart, IE4SavablePart, IPartContentHasDetails, IPartContentHasSupplementalData,
-        IContextListener, IConversationEnabled, IDirtyMarkable, IPostOperationEnabled {
+public class FeatureTreeEditor implements IFeatureTreeEditor, ISelectionChangedListener,
+        IE4ViewerPart, IPartContentHasDetails, IPartContentHasSupplementalData,
+        IContextListener, IConversationEnabled, IDirtyMarkable {
 
     private ConversationHolder conversation;
 
@@ -83,21 +90,18 @@ public class FeatureTreeEditor implements ICdmEntitySessionEnabled, ISelectionCh
     private MDirtyable dirty;
 
     @Inject
-    private MPart thisPart;
+    private UISynchronize sync;
 
     @Inject
-    private UISynchronize sync;
+    private MPart thisPart;
 
     private TreeViewer viewer;
 
-    private List<AbstractPostOperation> operations = new ArrayList<>();
-
     @Inject
     public FeatureTreeEditor() {
         CdmStore.getContextManager().addContextListener(this);
     }
 
-       /** {@inheritDoc} */
     @PostConstruct
     public void createControl(Composite parent, EMenuService menuService){
         if (CdmStore.isActive()){
@@ -117,14 +121,53 @@ public class FeatureTreeEditor implements ICdmEntitySessionEnabled, ISelectionCh
                 TermTransfer.getInstance(),
                 LocalSelectionTransfer.getTransfer()};
         viewer.addDragSupport(ops, transfers, new FeatureNodeDragListener(viewer));
-        viewer.addDropSupport(ops, transfers, new FeatureNodeDropAdapter(dirty, viewer));
+        viewer.addDropSupport(ops, transfers, new FeatureTreeDropAdapter(this, viewer, sync));
         viewer.addSelectionChangedListener(this);
+        viewer.getTree().addKeyListener(new KeyAdapter() {
+            @Override
+            public void keyPressed(KeyEvent e) {
+                if(e.stateMask == SWT.MOD1 && e.keyCode == 'c'){
+                    copy(viewer.getStructuredSelection());
+                }
+                else if(e.stateMask == SWT.MOD1 && e.keyCode == 'v'){
+                    paste(viewer.getStructuredSelection());
+                }
+            }
+        });
 
         List<FeatureTree> trees = CdmStore.getService(IFeatureTreeService.class).list(FeatureTree.class, null, null, null, null);
+        viewer.setComparator(new FeatureTreeViewerComparator());
         viewer.setInput(trees);
 
         //create context menu
-        menuService.registerContextMenu(viewer.getControl(), "eu.etaxonomy.taxeditor.store.popupmenu.featureTreeEditor");
+        menuService.registerContextMenu(viewer.getControl(), AppModelId.POPUPMENU_EU_ETAXONOMY_TAXEDITOR_STORE_POPUPMENU_FEATURETREEEDITOR);
+    }
+
+    public void paste(IStructuredSelection selection) {
+        if (StoreUtil.promptCheckIsDirty(this)) {
+            return;
+        }
+
+        ISelection clipBoardSelection = LocalSelectionTransfer.getTransfer().getSelection();
+        Object firstElement = selection.getFirstElement();
+        FeatureNode parentNode = null;
+        if(firstElement instanceof FeatureNode){
+            parentNode = (FeatureNode) firstElement;
+        }
+        else if(firstElement instanceof FeatureTree){
+            parentNode = ((FeatureTree)firstElement).getRoot();
+        }
+        if(parentNode!=null){
+            FeatureNode copiedNode = (FeatureNode) ((IStructuredSelection)clipBoardSelection).getFirstElement();
+
+            AddFeatureOperation operation = new AddFeatureOperation(copiedNode.getTerm().getUuid(), parentNode, this, this);
+            AbstractUtility.executeOperation(operation, sync);
+        }
+
+    }
+
+    public void copy(IStructuredSelection selection) {
+        LocalSelectionTransfer.getTransfer().setSelection(selection);
     }
 
     private void initSession(){
@@ -152,15 +195,11 @@ public class FeatureTreeEditor implements ICdmEntitySessionEnabled, ISelectionCh
            this.dirty.setDirty(isDirty);
        }
 
-       public boolean isDirty(){
+       @Override
+    public boolean isDirty(){
            return dirty.isDirty();
        }
 
-       public void addOperation(AbstractPostOperation operation){
-           operations.add(operation);
-       }
-
-       /** {@inheritDoc} */
        @Override
        public void selectionChanged(SelectionChangedEvent event) {
                //propagate selection
@@ -189,17 +228,11 @@ public class FeatureTreeEditor implements ICdmEntitySessionEnabled, ISelectionCh
            return viewer;
        }
 
-       /**
-        * {@inheritDoc}
-        */
        @Override
        public IStructuredSelection getSelection() {
            return (IStructuredSelection) viewer.getSelection();
        }
 
-       /**
-        * {@inheritDoc}
-        */
        @Override
        public ConversationHolder getConversationHolder() {
            return conversation;
@@ -214,26 +247,30 @@ public class FeatureTreeEditor implements ICdmEntitySessionEnabled, ISelectionCh
 
         // commit the conversation and start a new transaction immediately
         conversation.commit(true);
-        operations.forEach(operation->AbstractUtility.executeOperation(operation, sync));
-        operations.clear();
 
         CdmStore.getService(IFeatureTreeService.class).saveOrUpdate(getRootEntities());
 
-        /*
-         * reload feature trees is needed to update i.e.
-         * temporarily created feature nodes by adding features.
-         * This is related to the current saving strategy which
-         * emulates all changes on the visible feature tree but
-         * the actual change is done when saving via executeOperation()
-         */
+        List<FeatureTree> rootEntities = getRootEntities();
+        for (FeatureTree featureTree : rootEntities) {
+            if(featureTree.getTermType().equals(TermType.Character)){
+                FeatureTree<Character> characterTree = featureTree;
+                //save characters because they can be modified in this editor
+                characterTree.getDistinctFeatures().forEach(character->CdmStore.getService(ITermService.class).merge(character,true));
+            }
+        }
+
+        initializeTrees();
+
+        this.setDirty(false);
+       }
+
+    private void initializeTrees() {
         Object[] expandedElements = viewer.getExpandedElements();
         viewer.getTree().removeAll();
         List<FeatureTree> trees = CdmStore.getService(IFeatureTreeService.class).list(FeatureTree.class, null, null, null, null);
         viewer.setInput(trees);
         viewer.setExpandedElements(expandedElements);
-
-        this.setDirty(false);
-       }
+    }
 
        @PreDestroy
        public void dispose(){
@@ -306,17 +343,21 @@ public class FeatureTreeEditor implements ICdmEntitySessionEnabled, ISelectionCh
         dirty.setDirty(true);
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public boolean postOperation(Object objectAffectedByOperation) {
-        return false;
+        initializeTrees();
+        viewer.refresh();
+        if(objectAffectedByOperation instanceof FeatureNode){
+            FeatureNode node = (FeatureNode)objectAffectedByOperation;
+            viewer.expandToLevel(node.getFeatureTree(), 1);
+        }
+        if(objectAffectedByOperation!=null){
+            StructuredSelection selection = new StructuredSelection(objectAffectedByOperation);
+            viewer.setSelection(selection);
+        }
+        return true;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public boolean onComplete() {
         return false;