commit 86fcba2118241803d5550cf84c19d93396050cd3
Author: Patrick Plitzner <p.plitzner@bgbm.org>
Date:   Fri Nov 23 09:30:26 2018 +0100

    ref #7923 Extend drag & drop action for creating characters

diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/descriptiveDataSet/character/CharacterDragListener.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/descriptiveDataSet/character/CharacterDragListener.java
index ad3f958cc..9bacf141c 100644
--- a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/descriptiveDataSet/character/CharacterDragListener.java
+++ b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/descriptiveDataSet/character/CharacterDragListener.java
@@ -8,12 +8,15 @@
 */
 package eu.etaxonomy.taxeditor.editor.descriptiveDataSet.character;
 
-import org.eclipse.jface.viewers.IStructuredSelection;
+import java.util.List;
+
+import org.eclipse.jface.util.LocalSelectionTransfer;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeSelection;
 import org.eclipse.jface.viewers.TreeViewer;
 import org.eclipse.swt.dnd.DragSourceEvent;
 
-import eu.etaxonomy.cdm.model.description.FeatureNode;
-import eu.etaxonomy.taxeditor.featuretree.FeatureNodeTransfer;
+import eu.etaxonomy.cdm.model.description.Character;
 import eu.etaxonomy.taxeditor.featuretree.e4.FeatureNodeDragListener;
 
 /**
@@ -26,27 +29,22 @@ public class CharacterDragListener extends FeatureNodeDragListener {
     private TreeViewer structureViewer;
     private TreeViewer propertyViewer;
 
-    /**
-     * @param propertyViewer
-     */
     public CharacterDragListener(TreeViewer structureViewer, TreeViewer propertyViewer) {
         super(propertyViewer);
         this.structureViewer = structureViewer;
         this.propertyViewer = propertyViewer;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public void dragSetData(DragSourceEvent event) {
-        FeatureNode structure = (FeatureNode) ((IStructuredSelection) structureViewer.getSelection()).getFirstElement();
-        FeatureNode property = (FeatureNode) ((IStructuredSelection) propertyViewer.getSelection()).getFirstElement();
-        FeatureNode[] character = new FeatureNode[2];
-        character[0] = structure;
-        character[1] = property;
-        if (FeatureNodeTransfer.getInstance().isSupportedType(event.dataType)) {
-            event.data = character;
+        TreeSelection structureSelection = (TreeSelection) structureViewer.getSelection();
+        TreeSelection propertySelection = (TreeSelection) propertyViewer.getSelection();
+        if(structureSelection!=null && propertySelection!=null
+                && !structureSelection.isEmpty() && !propertySelection.isEmpty()){
+            //create all possible characters
+            List<Character> characters = CharacterEditor.createCharacters(structureSelection, propertySelection);
+
+            LocalSelectionTransfer.getTransfer().setSelection(new StructuredSelection(characters));
         }
     }
 
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/descriptiveDataSet/character/CharacterDropAdapter.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/descriptiveDataSet/character/CharacterDropAdapter.java
index 47ec20bf1..71f78f1d7 100644
--- a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/descriptiveDataSet/character/CharacterDropAdapter.java
+++ b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/descriptiveDataSet/character/CharacterDropAdapter.java
@@ -8,14 +8,23 @@
 */
 package eu.etaxonomy.taxeditor.editor.descriptiveDataSet.character;
 
+import java.util.Iterator;
+
+import org.eclipse.jface.util.LocalSelectionTransfer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.jface.viewers.ViewerDropAdapter;
+import org.eclipse.swt.dnd.DropTargetEvent;
 import org.eclipse.swt.dnd.TransferData;
 
+import eu.etaxonomy.cdm.api.service.IFeatureNodeService;
 import eu.etaxonomy.cdm.model.description.Character;
 import eu.etaxonomy.cdm.model.description.FeatureNode;
 import eu.etaxonomy.cdm.model.description.FeatureTree;
-import eu.etaxonomy.taxeditor.featuretree.FeatureNodeTransfer;
+import eu.etaxonomy.taxeditor.featuretree.e4.FeatureNodeDropAdapter;
+import eu.etaxonomy.taxeditor.store.CdmStore;
+import eu.etaxonomy.taxeditor.store.StoreUtil;
+import eu.etaxonomy.taxeditor.workbench.part.IE4SavablePart;
 
 /**
  *
@@ -23,49 +32,58 @@ import eu.etaxonomy.taxeditor.featuretree.FeatureNodeTransfer;
  * @date Jun 1, 2017
  *
  */
-public class CharacterDropAdapter extends ViewerDropAdapter {
+public class CharacterDropAdapter extends FeatureNodeDropAdapter {
 
-	protected CharacterDropAdapter(Viewer viewer) {
-	    super(viewer);
+	protected CharacterDropAdapter(IE4SavablePart savablePart, Viewer viewer) {
+	    super(savablePart, viewer);
 	}
 
 	@Override
-	public boolean performDrop(Object data) {
+	protected Object determineTarget(DropTargetEvent event) {
+        return event.item == null ? ((FeatureTree)getViewer().getInput()).getRoot() : event.item.getData();
+	}
 
+	@Override
+	public boolean performDrop(Object data) {
+	    if(StoreUtil.checkDirty(savablePart)){
+	        return false;
+	    }
 	    FeatureNode target = (FeatureNode) getCurrentTarget();
-		int currentLocation = getCurrentLocation();
-		Object[] characterData = (Object[]) data;
-
-		//create new Character
-		if(characterData.length==2){
-		    FeatureNode structureNode = (FeatureNode) characterData[0];
-		    FeatureNode propertyNode = (FeatureNode) characterData[1];
-		    String label = structureNode.getFeature().toString()+" "+propertyNode.getFeature().toString();
-		    Character character = Character.NewInstance(structureNode, propertyNode, null, label, label);
-		    FeatureNode characterNode = FeatureNode.NewInstance(character);
-
-		    if(getViewer().getInput()==null){
-		        //create new feature tree
-		        FeatureTree featureTree = FeatureTree.NewInstance();
-		        getViewer().setInput(featureTree);
-		    }
-            if(target==null){
-                FeatureNode root = ((FeatureTree)getViewer().getInput()).getRoot();
-                root.addChild(characterNode);
-            }
-            else{
-                target.addChild(characterNode);
-            }
-		}
-		getViewer().refresh();
-		return true;
+	    ISelection selection = LocalSelectionTransfer.getTransfer().getSelection();
+	    if(selection!=null
+	            &&selection instanceof IStructuredSelection
+	            ){
+	        IStructuredSelection structuredSelection = (IStructuredSelection)selection;
+	        Iterator iterator = structuredSelection.iterator();
+	        while(iterator.hasNext()){
+	            Object next = iterator.next();
+	            if(next instanceof Character){
+	                Character character = (Character)next;
+	                if(target==null){
+	                    //drop on feature tree
+	                    target = ((FeatureTree)getViewer().getInput()).getRoot();
+	                }
+	                CdmStore.getService(IFeatureNodeService.class).addChildFeatureNode(target.getUuid(), character.getUuid());
+	            }
+	        }
+	        getViewer().refresh();
+	        LocalSelectionTransfer.getTransfer().setSelection(null);
+	        return true;
+	    }
+	    return super.performDrop(data);
 	}
 
 	@Override
 	public boolean validateDrop(Object target, int operation,
-			TransferData transferType) {
-		boolean transferDataIsSupported = FeatureNodeTransfer.getInstance().isSupportedType(transferType);
-		return transferDataIsSupported;
+			TransferData transferData) {
+		LocalSelectionTransfer transfer = LocalSelectionTransfer.getTransfer();
+        boolean valid = true;
+		valid &= transfer.getSelection()!=null
+		        && !transfer.getSelection().isEmpty();
+		if(!valid){
+		    return super.validateDrop(target, operation, transferData);
+		}
+		return valid;
 	}
 
 }
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/descriptiveDataSet/character/CharacterEditor.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/descriptiveDataSet/character/CharacterEditor.java
index af9451c3f..8146ba789 100644
--- a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/descriptiveDataSet/character/CharacterEditor.java
+++ b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/descriptiveDataSet/character/CharacterEditor.java
@@ -155,7 +155,7 @@ public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled,
         formToolkit.adapt(btnAddCharacter, true, true);
 
         characterTreeEditorComposite = addFeatureTreeEditor(composite_3);
-        initFeatureTreeComposite(characterTreeEditorComposite, new FeatureNodeDragListener(characterTreeEditorComposite.getViewer()), new FeatureNodeDropAdapter(dirty, this, characterTreeEditorComposite.getViewer()));
+        initFeatureTreeComposite(characterTreeEditorComposite, new FeatureNodeDragListener(characterTreeEditorComposite.getViewer()), new CharacterDropAdapter(this, characterTreeEditorComposite.getViewer()));
         characterTreeEditorComposite.getLabel_title().setText("Characters");
 
         //add context menu to character viewer//create context menu
@@ -204,22 +204,11 @@ public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled,
                             "You have to select a structure, a property and a feature tree to perform this action.");
                     return;
                 }
-                //get selected structures and properties
-                Iterator<FeatureNode> structureIterator = ((TreeSelection)structureTreeSelection).iterator();
-
-                //create all combinations of structures and properties
-                while(structureIterator.hasNext()){
-                    FeatureNode structureNode = structureIterator.next();
-                    Iterator<FeatureNode> propertiesIterator = ((TreeSelection)propertyTreeSelection).iterator();
-                    while(propertiesIterator.hasNext()){
-                        FeatureNode propertyNode = propertiesIterator.next();
-                        //create new Character
-                        String label = structureNode.getFeature().generateTitle()+" "+propertyNode.getFeature().generateTitle();
-                        Character character = Character.NewInstance(structureNode, propertyNode, "", label, label);
-                        character = HibernateProxyHelper.deproxy(CdmStore.getService(ITermService.class).merge(character), Character.class);
-
-                        addCharacterSorted(character);
-                    }
+                List<Character> characters = createCharacters((TreeSelection)structureTreeSelection, (TreeSelection)propertyTreeSelection);
+                for (Character character : characters) {
+                    //add new Character to feature tree
+                    FeatureNode parent = ((FeatureTree) characterTreeEditorComposite.getViewer().getInput()).getRoot();
+                    CdmStore.getService(IFeatureNodeService.class).addChildFeatureNode(parent.getUuid(), character.getUuid());
                 }
 
                 setDirty();
@@ -228,10 +217,24 @@ public class CharacterEditor implements IFeatureTreeEditor,IConversationEnabled,
         });
     }
 
-    private void addCharacterSorted(Character character){
-        //add new Character to feature tree
-        FeatureNode parent = ((FeatureTree) characterTreeEditorComposite.getViewer().getInput()).getRoot();
-        CdmStore.getService(IFeatureNodeService.class).addChildFeatureNode(parent.getUuid(), character.getUuid());
+    public static List<Character> createCharacters(TreeSelection structureTreeSelection, TreeSelection propertyTreeSelection){
+        List<Character> characters = new ArrayList<>();
+        //get selected structures and properties
+        Iterator<FeatureNode> structureIterator = structureTreeSelection.iterator();
+
+        //create all combinations of structures and properties
+        while(structureIterator.hasNext()){
+            FeatureNode structureNode = structureIterator.next();
+            Iterator<FeatureNode> propertiesIterator = propertyTreeSelection.iterator();
+            while(propertiesIterator.hasNext()){
+                FeatureNode propertyNode = propertiesIterator.next();
+                //create new Character
+                String label = structureNode.getFeature().generateTitle()+" "+propertyNode.getFeature().generateTitle();
+                Character character = Character.NewInstance(structureNode, propertyNode, "", label, label);
+                characters.add(HibernateProxyHelper.deproxy(CdmStore.getService(ITermService.class).save(character), Character.class));
+            }
+        }
+        return characters;
     }
 
     @Override
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 078e9cd5e..afd755af8 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
@@ -13,8 +13,6 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.e4.ui.model.application.ui.MDirtyable;
 import org.eclipse.jface.util.LocalSelectionTransfer;
 import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.TreeViewer;
@@ -34,6 +32,7 @@ import eu.etaxonomy.taxeditor.featuretree.FeatureNodeTransfer;
 import eu.etaxonomy.taxeditor.l10n.Messages;
 import eu.etaxonomy.taxeditor.model.MessagingUtils;
 import eu.etaxonomy.taxeditor.store.CdmStore;
+import eu.etaxonomy.taxeditor.store.StoreUtil;
 import eu.etaxonomy.taxeditor.ui.dialog.selection.TermVocabularySelectionDialog;
 import eu.etaxonomy.taxeditor.view.webimport.termimport.wrapper.OntologyTermWrapper;
 import eu.etaxonomy.taxeditor.workbench.part.IE4SavablePart;
@@ -43,25 +42,18 @@ public class FeatureNodeDropAdapter extends ViewerDropAdapter {
     public static final String SAVE_CHANGES_TITLE = "Unsaved changes";
     public static final String SAVE_CHANGES_MESSAGE = "The editor has unsaved changes. You need to save before performind this operation. Save now?";
 
-    private MDirtyable dirtyable;
-    private IE4SavablePart savablePart;
+    protected IE4SavablePart savablePart;
 
-    public FeatureNodeDropAdapter(MDirtyable dirtyable, IE4SavablePart savablePart, Viewer viewer) {
+    public FeatureNodeDropAdapter(IE4SavablePart savablePart, Viewer viewer) {
 		super(viewer);
-		this.dirtyable = dirtyable;
 		this.savablePart = savablePart;
 	}
 
 	@Override
 	public boolean performDrop(Object data) {
-        if(dirtyable.isDirty()){
-            if(MessagingUtils.confirmDialog(SAVE_CHANGES_TITLE, SAVE_CHANGES_MESSAGE)){
-                savablePart.save(new NullProgressMonitor());
-            }
-            else{
-                return false;
-            }
-        }
+	    if(StoreUtil.checkDirty(savablePart)){
+	        return false;
+	    }
 		Object currentTarget = getCurrentTarget();
 		FeatureNode target = null;
 		if(currentTarget instanceof FeatureTree){
diff --git a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/e4/FeatureTreeEditor.java b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/e4/FeatureTreeEditor.java
index 895cffdfc..3696e3d72 100644
--- a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/e4/FeatureTreeEditor.java
+++ b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/e4/FeatureTreeEditor.java
@@ -105,7 +105,7 @@ public class FeatureTreeEditor implements IFeatureTreeEditor, ISelectionChangedL
                 TermTransfer.getInstance(),
                 LocalSelectionTransfer.getTransfer()};
         viewer.addDragSupport(ops, transfers, new FeatureNodeDragListener(viewer));
-        viewer.addDropSupport(ops, transfers, new FeatureNodeDropAdapter(dirty, this, viewer));
+        viewer.addDropSupport(ops, transfers, new FeatureNodeDropAdapter(this, viewer));
         viewer.addSelectionChangedListener(this);
 
         List<FeatureTree> trees = CdmStore.getService(IFeatureTreeService.class).list(FeatureTree.class, null, null, null, null);
diff --git a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/e4/FeatureTreeEditorComposite.java b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/e4/FeatureTreeEditorComposite.java
index b48349040..972336135 100644
--- a/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/e4/FeatureTreeEditorComposite.java
+++ b/eu.etaxonomy.taxeditor.store/src/main/java/eu/etaxonomy/taxeditor/featuretree/e4/FeatureTreeEditorComposite.java
@@ -8,6 +8,7 @@
 */
 package eu.etaxonomy.taxeditor.featuretree.e4;
 
+import org.eclipse.jface.util.LocalSelectionTransfer;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.TreeViewer;
 import org.eclipse.swt.SWT;
@@ -109,8 +110,11 @@ public class FeatureTreeEditorComposite extends Composite{
         viewer.setLabelProvider(new FeatureTreeLabelProvider());
 
         int ops = DND.DROP_COPY | DND.DROP_MOVE;
-        Transfer[] transfers = new Transfer[] { FeatureNodeTransfer
-                .getInstance(), TermTransfer.getInstance() };
+        Transfer[] transfers = new Transfer[] {
+                FeatureNodeTransfer.getInstance(),
+                TermTransfer.getInstance(),
+                LocalSelectionTransfer.getTransfer()
+                };
         if(dragSourceListener!=null){
             viewer.addDragSupport(ops, transfers, dragSourceListener);
         }
