commit f3065796575239dbdc4afab4207bf70d87d72536
Author: Patrick Plitzner <p.plitzner@bgbm.org>
Date:   Fri Oct 26 13:26:48 2018 +0200

    fix #7873 Implement copy&paste for feature nodes in feature tree editor

diff --git a/eu.etaxonomy.taxeditor.store/fragment.e4xmi b/eu.etaxonomy.taxeditor.store/fragment.e4xmi
index d8e5ed7ee..83f925864 100644
--- a/eu.etaxonomy.taxeditor.store/fragment.e4xmi
+++ b/eu.etaxonomy.taxeditor.store/fragment.e4xmi
@@ -15,11 +15,17 @@
       <handlers xmi:id="_hPTxMBezEeiXusClKZjycQ" elementId="eu.etaxonomy.taxeditor.featuretree.e4.handler.AddChildFeatureHandler" contributionURI="bundleclass://eu.etaxonomy.taxeditor.store/eu.etaxonomy.taxeditor.featuretree.e4.handler.AddChildFeatureHandler" command="_aPYxsBezEeiXusClKZjycQ"/>
       <handlers xmi:id="_Bb0TwCFeEeiVXriJfxPIuA" elementId="eu.etaxonomy.taxeditor.featuretree.e4.handler.RemoveFeatureTreeHandlers" contributionURI="bundleclass://eu.etaxonomy.taxeditor.store/eu.etaxonomy.taxeditor.featuretree.e4.handler.RemoveFeatureTreeHandler" command="_3mqzkCFdEeiVXriJfxPIuA"/>
       <handlers xmi:id="_DYhGACHXEeiP8eNo0PEm1g" elementId="eu.etaxonomy.taxeditor.featuretree.e4.handler.CreateFeatureTreeHandler" contributionURI="bundleclass://eu.etaxonomy.taxeditor.store/eu.etaxonomy.taxeditor.featuretree.e4.handler.CreateFeatureTreeHandler" command="_AJtnsCHXEeiP8eNo0PEm1g"/>
+      <handlers xmi:id="_i-FlkNjyEeidDMMI9xTsbQ" elementId="eu.etaxonomy.taxeditor.featuretree.e4.handler.CopyFeatureHandler" contributionURI="bundleclass://eu.etaxonomy.taxeditor.store/eu.etaxonomy.taxeditor.featuretree.e4.handler.CopyFeatureHandler" command="_cMyQ4NjyEeidDMMI9xTsbQ"/>
+      <handlers xmi:id="_tzQ_YNjyEeidDMMI9xTsbQ" elementId="eu.etaxonomy.taxeditor.featuretree.e4.handler.PasteFeatureHandler" contributionURI="bundleclass://eu.etaxonomy.taxeditor.store/eu.etaxonomy.taxeditor.featuretree.e4.handler.PasteFeatureHandler" command="_xDk5kNjyEeidDMMI9xTsbQ"/>
       <menus xsi:type="menu:PopupMenu" xmi:id="__Jwh4GceEee0qLTtA2ZpVQ" elementId="eu.etaxonomy.taxeditor.store.popupmenu.featureTreeEditor">
         <children xsi:type="menu:HandledMenuItem" xmi:id="_GuuM0CHXEeiP8eNo0PEm1g" elementId="eu.etaxonomy.taxeditor.store.handledmenuitem.newfeaturetree" label="%handledmenuitem.label.1" iconURI="platform:/plugin/org.eclipse.ui/icons/full/etool16/new_wiz.png" command="_AJtnsCHXEeiP8eNo0PEm1g"/>
         <children xsi:type="menu:MenuSeparator" xmi:id="_eIB1kCHXEeiP8eNo0PEm1g" elementId="eu.etaxonomy.taxeditor.store.menuseparator.5"/>
         <children xsi:type="menu:HandledMenuItem" xmi:id="_jr4E0Be0EeiXusClKZjycQ" elementId="eu.etaxonomy.taxeditor.store.handledmenuitem.addchildfeature" label="%handledmenuitem.label.2" iconURI="platform:/plugin/eu.etaxonomy.taxeditor.store/icons/add.gif" command="_aPYxsBezEeiXusClKZjycQ"/>
         <children xsi:type="menu:HandledMenuItem" xmi:id="_eWBz0GcjEee0qLTtA2ZpVQ" elementId="eu.etaxonomy.taxeditor.store.handledmenuitem.addFeature" label="%handledmenuitem.label.3" iconURI="platform:/plugin/eu.etaxonomy.taxeditor.store/icons/add.gif" command="_oftL0GceEee0qLTtA2ZpVQ"/>
+        <children xsi:type="menu:MenuSeparator" xmi:id="_XtPjcNjyEeidDMMI9xTsbQ" elementId="eu.etaxonomy.taxeditor.store.menuseparator.8"/>
+        <children xsi:type="menu:HandledMenuItem" xmi:id="_G_IOENj3EeidDMMI9xTsbQ" elementId="eu.etaxonomy.taxeditor.store.handledmenuitem.paste" label="Paste" iconURI="platform:/plugin/eu.etaxonomy.taxeditor.store/icons/paste_edit.png" command="_xDk5kNjyEeidDMMI9xTsbQ"/>
+        <children xsi:type="menu:HandledMenuItem" xmi:id="_QXkWYNjyEeidDMMI9xTsbQ" elementId="eu.etaxonomy.taxeditor.store.handledmenuitem.copy" label="Copy" iconURI="platform:/plugin/eu.etaxonomy.taxeditor.store/icons/copy_edit.png" command="_cMyQ4NjyEeidDMMI9xTsbQ"/>
+        <children xsi:type="menu:MenuSeparator" xmi:id="_So5f0NjyEeidDMMI9xTsbQ" elementId="eu.etaxonomy.taxeditor.store.menuseparator.7"/>
         <children xsi:type="menu:HandledMenuItem" xmi:id="_7vaEcGcqEee0qLTtA2ZpVQ" elementId="eu.etaxonomy.taxeditor.store.handledmenuitem.exportFeatureTree" label="%handledmenuitem.label.4" iconURI="platform:/plugin/eu.etaxonomy.taxeditor.store/icons/export.gif" command="_I_yx4GcqEee0qLTtA2ZpVQ">
           <visibleWhen xsi:type="ui:CoreExpression" xmi:id="_-91IQGcqEee0qLTtA2ZpVQ" coreExpressionId="isShowExperimentalFeatures"/>
         </children>
@@ -135,6 +141,8 @@
     <elements xsi:type="commands:Command" xmi:id="_tPtdwMiIEeiKErB3UVzQug" elementId="eu.etaxonomy.taxeditor.store.open.OpenDistributionStatusWizardAdminHandler" commandName="%command.name.111"/>
     <elements xsi:type="commands:Command" xmi:id="_tRsg8MrcEeiKErB3UVzQug" elementId="eu.etaxonomy.taxeditor.store.open.OpenCommonNameAreaWizardAdminHandler" commandName="%command.name.112"/>
     <elements xsi:type="commands:Command" xmi:id="_nP0XMNhHEeijwMElCRdOhg" elementId="org.eclipse.ui.file.restartWorkbench" commandName="%command.commandname.10"/>
+    <elements xsi:type="commands:Command" xmi:id="_cMyQ4NjyEeidDMMI9xTsbQ" elementId="eu.etaxonomy.taxeditor.store.command.featureTree.copyFeature" commandName="Copy Feature"/>
+    <elements xsi:type="commands:Command" xmi:id="_xDk5kNjyEeidDMMI9xTsbQ" elementId="eu.etaxonomy.taxeditor.store.command.featureTree.pasteFeature" commandName="Paste Feature"/>
   </fragments>
   <fragments xsi:type="fragment:StringModelFragment" xmi:id="_swGH0GhvEee3K4uKJljEYg" featurename="handlers" parentElementId="xpath:/">
     <elements xsi:type="commands:Handler" xmi:id="_rVEdIGcjEee0qLTtA2ZpVQ" elementId="eu.etaxonomy.taxeditor.featuretree.e4.handler.RemoveFeatureHandler" contributionURI="bundleclass://eu.etaxonomy.taxeditor.store/eu.etaxonomy.taxeditor.featuretree.e4.handler.RemoveFeatureHandler" command="_fNBtQGcjEee0qLTtA2ZpVQ"/>
diff --git a/eu.etaxonomy.taxeditor.store/icons/copy_edit.png b/eu.etaxonomy.taxeditor.store/icons/copy_edit.png
new file mode 100644
index 000000000..41efe451e
Binary files /dev/null and b/eu.etaxonomy.taxeditor.store/icons/copy_edit.png differ
diff --git a/eu.etaxonomy.taxeditor.store/icons/paste_edit.png b/eu.etaxonomy.taxeditor.store/icons/paste_edit.png
new file mode 100644
index 000000000..dd078d456
Binary files /dev/null and b/eu.etaxonomy.taxeditor.store/icons/paste_edit.png differ
diff --git a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/e4/FeatureNodeDropAdapter.java b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/e4/FeatureNodeDropAdapter.java
index d7aab8683..29000248d 100644
--- a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/e4/FeatureNodeDropAdapter.java
+++ b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/e4/FeatureNodeDropAdapter.java
@@ -19,6 +19,7 @@ import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.TreeViewer;
 import org.eclipse.jface.viewers.Viewer;
 import org.eclipse.jface.viewers.ViewerDropAdapter;
+import org.eclipse.swt.dnd.DND;
 import org.eclipse.swt.dnd.TransferData;
 
 import eu.etaxonomy.cdm.api.service.IFeatureNodeService;
@@ -99,7 +100,14 @@ public class FeatureNodeDropAdapter extends ViewerDropAdapter {
 		for (Object droppedObject : droppedObjects) {
 		    if(droppedObject instanceof FeatureNode){
 		        FeatureNode droppedNode = (FeatureNode) droppedObject;
-		        CdmStore.getService(IFeatureNodeService.class).moveFeatureNode(droppedNode.getUuid(), target.getUuid(), position);
+		        //move operation
+		        if(getCurrentOperation()==DND.DROP_MOVE){
+		            CdmStore.getService(IFeatureNodeService.class).moveFeatureNode(droppedNode.getUuid(), target.getUuid(), position);
+		        }
+		        //copy operation
+		        else if(getCurrentOperation()==DND.DROP_COPY){
+		            CdmStore.getService(IFeatureNodeService.class).addChildFeatureNode(target.getUuid(), droppedNode.getFeature().getUuid());
+		        }
 		        viewer.reveal(droppedNode);
 		    }
 		    else if(droppedObject instanceof Feature){
diff --git a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/e4/handler/CopyFeatureHandler.java b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/e4/handler/CopyFeatureHandler.java
new file mode 100644
index 000000000..7f6a39267
--- /dev/null
+++ b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/e4/handler/CopyFeatureHandler.java
@@ -0,0 +1,39 @@
+
+package eu.etaxonomy.taxeditor.featuretree.e4.handler;
+
+import javax.inject.Named;
+
+import org.eclipse.e4.core.di.annotations.CanExecute;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.menu.MHandledMenuItem;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.jface.util.LocalSelectionTransfer;
+import org.eclipse.jface.viewers.IStructuredSelection;
+
+import eu.etaxonomy.cdm.model.description.FeatureNode;
+import eu.etaxonomy.taxeditor.featuretree.e4.FeatureTreeEditor;
+
+public class CopyFeatureHandler {
+
+    @Execute
+    public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part,
+            @Named(IServiceConstants.ACTIVE_SELECTION) IStructuredSelection selection){
+        LocalSelectionTransfer.getTransfer().setSelection(selection);
+    }
+
+    @CanExecute
+    public boolean canExecute(@Optional @Named(IServiceConstants.ACTIVE_SELECTION) IStructuredSelection selection,
+            @Named(IServiceConstants.ACTIVE_PART) MPart part,
+            MHandledMenuItem menuItem){
+        boolean canExecute = false;
+        canExecute =part.getObject() instanceof FeatureTreeEditor
+                && selection!=null
+                && selection.size()==1
+                && selection.getFirstElement() instanceof FeatureNode;
+        menuItem.setVisible(canExecute);
+        return canExecute;
+    }
+
+}
\ No newline at end of file
diff --git a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/e4/handler/PasteFeatureHandler.java b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/e4/handler/PasteFeatureHandler.java
new file mode 100644
index 000000000..3c254b738
--- /dev/null
+++ b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/e4/handler/PasteFeatureHandler.java
@@ -0,0 +1,53 @@
+
+package eu.etaxonomy.taxeditor.featuretree.e4.handler;
+
+import javax.inject.Named;
+
+import org.eclipse.e4.core.di.annotations.CanExecute;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.menu.MHandledMenuItem;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.jface.util.LocalSelectionTransfer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+
+import eu.etaxonomy.cdm.api.service.IFeatureNodeService;
+import eu.etaxonomy.cdm.model.description.FeatureNode;
+import eu.etaxonomy.taxeditor.featuretree.e4.FeatureTreeEditor;
+import eu.etaxonomy.taxeditor.store.CdmStore;
+
+public class PasteFeatureHandler {
+
+    @Execute
+    public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part,
+            @Named(IServiceConstants.ACTIVE_SELECTION) IStructuredSelection selection){
+        ISelection clipBoardSelection = LocalSelectionTransfer.getTransfer().getSelection();
+        FeatureTreeEditor editor = (FeatureTreeEditor)part.getObject();
+        FeatureNode parentNode = (FeatureNode) selection.getFirstElement();
+        FeatureNode copiedNode = (FeatureNode) ((IStructuredSelection)clipBoardSelection).getFirstElement();
+
+        CdmStore.getService(IFeatureNodeService.class).addChildFeatureNode(parentNode.getUuid(), copiedNode.getFeature().getUuid());
+
+        editor.getViewer().reveal(copiedNode);
+        editor.setDirty(true);
+        editor.getViewer().refresh();
+    }
+
+    @CanExecute
+    public boolean canExecute(@Optional @Named(IServiceConstants.ACTIVE_SELECTION) IStructuredSelection selection,
+            MHandledMenuItem menuItem){
+        boolean canExecute = false;
+        ISelection transferSelection = LocalSelectionTransfer.getTransfer().getSelection();
+        canExecute = selection!=null
+                && selection.size()==1
+                && selection.getFirstElement() instanceof FeatureNode
+                && transferSelection instanceof IStructuredSelection
+                && ((IStructuredSelection)transferSelection).size()==1
+                && ((IStructuredSelection)transferSelection).getFirstElement() instanceof FeatureNode;
+        menuItem.setVisible(canExecute);
+        return canExecute;
+    }
+
+}
\ No newline at end of file
diff --git a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/model/ImageResources.java b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/model/ImageResources.java
index 543bd78d9..fc8efbaae 100644
--- a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/model/ImageResources.java
+++ b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/model/ImageResources.java
@@ -51,6 +51,8 @@ public class ImageResources {
 	ICONS
 	************************************************************************************** */
 	/** Constant <code>ADD_ICON="add_icon"</code> */
+	public static final String COPY_ICON = "copy_icon";
+	public static final String PASTE_ICON = "paste_icon";
 	public static final String ADD_ICON = "add_icon";
 	public static final String ADD_ICON_GREEN = "add_icon_green";
 	public static final String MIN_ICON = "min_icon";
@@ -280,6 +282,10 @@ public class ImageResources {
 	 * @param registry a {@link org.eclipse.jface.resource.ImageRegistry} object.
 	 */
 	protected void initializeImageRegistry(ImageRegistry registry) {
+	    registerImage(registry, COPY_ICON,
+	            "copy_edit.png");
+	    registerImage(registry, PASTE_ICON,
+	            "paste_edit.png");
 		registerImage(registry, ADD_ICON,
 				"add_no_bg.gif");
 		registerImage(registry, ADD_ICON_GREEN,
