[committed] Drag and drop enhancement

Hi,

I submitted this code one year ago, explanations are still here :

http://www.jmonkeyengine.com/jmeforum/index.php?topic=7336.0



briefly its a small enhancement to the current awt drag n drop and a brand new test class (wich makes too a pretty good gamestates tutorial i think)



and here is a patch against the current trunk on googlecode :



Index: src/com/jmex/awt/swingui/dnd/JMEDragAndDrop.java
===================================================================
--- src/com/jmex/awt/swingui/dnd/JMEDragAndDrop.java   (revision 4107)
+++ src/com/jmex/awt/swingui/dnd/JMEDragAndDrop.java   (working copy)
@@ -165,7 +165,7 @@
         dragComponent.setLocation(p.x - dragComponent.getWidth() / 2, p.y - dragComponent.getHeight() / 2);
         if (dropTargetListener != null) {
             Point p2 = SwingUtilities.convertPoint(desktop.getJDesktop(), p.x, p.y, (Component)dropTargetListener);
-            dropTargetListener.dragOver(new JMEDropTargetEvent(p2, dge.getAction(), this));
+         dropTargetListener.dragOver(new JMEDropTargetEvent(event.getSource(),p2, dge.getAction(), this));
         }
     }
 
@@ -215,7 +215,7 @@
         boolean dropSuccess = false;
         if (dropTargetListener != null) {
             Point p = SwingUtilities.convertPoint((Component)dragSourceListener, e.getX(), e.getY(), (Component)dropTargetListener);
-            JMEDropTargetEvent dte = new JMEDropTargetEvent(p, dge.getAction(), this);
+         JMEDropTargetEvent dte = new JMEDropTargetEvent(e.getSource(),p, dge.getAction(), this);
             dropTargetListener.drop(dte);
             dropSuccess = dte.isCompleted();
         } else {
@@ -244,7 +244,7 @@
         if ( e.getSource() instanceof JMEDropTargetListener ) {
             dropTargetListener = (JMEDropTargetListener) e.getSource();
             Point p = SwingUtilities.convertPoint((Component)dragSourceListener, e.getX(), e.getY(), (Component)dropTargetListener);
-            ( (JMEDropTargetListener)e.getSource() ).dragEnter( new JMEDropTargetEvent(p, dge.getAction(), this ) );
+         ( (JMEDropTargetListener)e.getSource() ).dragEnter( new JMEDropTargetEvent(e.getSource(),p, dge.getAction(), this ) );
         }
         dragSourceListener.dragEnter( new JMEDragSourceEvent( e.getPoint(), dge.getAction(), e.getComponent() ) );
     }
@@ -256,7 +256,7 @@
     public void mouseExited( MouseEvent e ) {
         if ( e.getSource() instanceof JMEDropTargetListener ) {
             dropTargetListener = null;
-            ( (JMEDropTargetListener) e.getSource() ).dragExit( new JMEDropTargetEvent( e.getPoint(), dge.getAction(), this ) );
+            ( (JMEDropTargetListener) e.getSource() ).dragExit( new JMEDropTargetEvent(e.getSource(), e.getPoint(), dge.getAction(), this ) );
         }
         dragSourceListener.dragExit( new JMEDragSourceEvent( e.getPoint(), dge.getAction() ) );
     }
Index: src/com/jmex/awt/swingui/dnd/JMEDropTargetEvent.java
===================================================================
--- src/com/jmex/awt/swingui/dnd/JMEDropTargetEvent.java   (revision 4107)
+++ src/com/jmex/awt/swingui/dnd/JMEDropTargetEvent.java   (working copy)
@@ -34,20 +34,24 @@
 
 import java.awt.Point;
 import java.awt.datatransfer.Transferable;
+import java.util.EventObject;
 
 /**
  * @author Galun
  */
-public class JMEDropTargetEvent {
-
-    private Point point;
+public class JMEDropTargetEvent extends EventObject {
+   
+   private static final long serialVersionUID = 1L;
+   private Point point;
     private int action;
     private boolean accepted;
     private boolean completed;
     private JMEDragAndDrop dnd;
 
-    JMEDropTargetEvent( Point point, int action, JMEDragAndDrop dnd ) {
-        this.point = point;
+   
+     JMEDropTargetEvent(Object source, Point point, int action, JMEDragAndDrop dnd ) {
+        super(source);
+       this.point = point;
         this.action = action;
         this.dnd = dnd;
     }
Index: src/jmetest/awt/swingui/dnd/TestDnd.java
===================================================================
--- src/jmetest/awt/swingui/dnd/TestDnd.java   (revision 0)
+++ src/jmetest/awt/swingui/dnd/TestDnd.java   (revision 0)
@@ -0,0 +1,238 @@
+package jmetest.awt.swingui.dnd;
+
+import java.awt.Color;
+import java.awt.GridLayout;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.awt.dnd.DnDConstants;
+import java.io.IOException;
+
+import javax.swing.BorderFactory;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JInternalFrame;
+import javax.swing.JLabel;
+
+import com.jme.bounding.BoundingSphere;
+import com.jme.input.KeyboardLookHandler;
+import com.jme.input.MouseInput;
+import com.jme.math.FastMath;
+import com.jme.math.Quaternion;
+import com.jme.math.Vector3f;
+import com.jme.scene.shape.Box;
+import com.jme.system.DisplaySystem;
+import com.jmex.awt.swingui.JMEDesktopState;
+import com.jmex.awt.swingui.dnd.JMEDndException;
+import com.jmex.awt.swingui.dnd.JMEDragAndDrop;
+import com.jmex.awt.swingui.dnd.JMEDragGestureEvent;
+import com.jmex.awt.swingui.dnd.JMEDragGestureListener;
+import com.jmex.awt.swingui.dnd.JMEDragSourceEvent;
+import com.jmex.awt.swingui.dnd.JMEDragSourceListener;
+import com.jmex.awt.swingui.dnd.JMEDropTargetEvent;
+import com.jmex.awt.swingui.dnd.JMEDropTargetListener;
+import com.jmex.awt.swingui.dnd.JMEMouseDragGestureRecognizer;
+import com.jmex.game.StandardGame;
+import com.jmex.game.state.DebugGameState;
+import com.jmex.game.state.GameStateManager;
+
+/**
+ * clean and simple drag and drop test with gamestates
+ *
+ * for making method DndIcon.drop(JMEDropTargetEvent e) work as intended, you have to patch the class
+ * JMEDropTargetEvent to make it extend java.util.EventObject ,
+ *
+ * then add the Source Object in the constructor  like this :
+ *
+ * JMEDropTargetEvent(Object source, Point point, int action, JMEDragAndDrop dnd ) {
+        super(source);
+        ...
+   
+ *  and then update JME classes that instantiate JMEDropTargetEvent
+ *
+ * if you want to test without the swapping with source icon, comment this code in DndIcon.drop(JMEDropTargetEvent e)
+ *  //DndIcon source = (DndIcon) e.getSource();
+   //source.setIcon(this.getIcon());
+ *
+ * @author Nomis
+ *
+ */
+public class TestDnd {
+
+   public static void main(String[] args) {
+      TestDnd test = new TestDnd();
+      StandardGame game = new StandardGame("DND test");
+      game.start();
+
+      TestDnd.MyGameState ingameState = test.new MyGameState();
+      GameStateManager.getInstance().attachChild(ingameState);
+
+      // always updateRenderState or get funky effects
+      ingameState.getRootNode().updateRenderState();
+      // By the way I strongly advise you to comment it to see the funky
+      // effects it's really fun !
+      ingameState.setActive(true);
+
+      TestDnd.MyHudState hudState = test.new MyHudState();
+      hudState.setActive(true);
+      hudState.getRootNode().updateRenderState();
+      GameStateManager.getInstance().attachChild(hudState);
+
+   }
+
+   public class MyGameState extends DebugGameState {
+      private Box box;
+      private Quaternion rotQuat = new Quaternion();
+      private float angle = 0;
+
+      private Vector3f axis = new Vector3f(1, 1, 0.5f);
+
+      public MyGameState() {
+         // keyboard look handler because the mouse is used for the hud
+         super(false);
+         input = new KeyboardLookHandler(DisplaySystem.getDisplaySystem().getRenderer().getCamera(), 15.0f, 0.5f);
+
+         this.box = new Box("my box", new Vector3f(0, 0, 0), 2, 2, 2);
+         box.setModelBound(new BoundingSphere());
+         box.updateModelBound();
+         this.getRootNode().attachChild(box);
+
+         this.axis.normalizeLocal();
+      }
+
+      @Override
+      public void update(float tpf) {
+
+         super.update(tpf);
+         // rotating the box to show there is some 3d behind the UI
+         if (tpf < 1) {
+            angle = angle + (tpf * 25);
+            if (angle > 360) {
+               angle = 0;
+            }
+         }
+         rotQuat.fromAngleNormalAxis(angle * FastMath.DEG_TO_RAD, axis);
+         box.setLocalRotation(rotQuat);
+      }
+   }
+
+   public class MyHudState extends JMEDesktopState {
+
+      public MyHudState() {
+         super();
+      }
+
+      protected void buildUI() {
+
+         new JMEDragAndDrop(this.getDesktop());
+
+         JInternalFrame frame = new JInternalFrame("dnd test", true, true);
+         frame.setLayout(new GridLayout(4, 4));
+
+         Icon icon1 = getResizedIcon("Monkey.jpg");
+         frame.add(new DndIcon(this, icon1));
+         Icon icon2 = getResizedIcon("Monkey.png");
+         frame.add(new DndIcon(this, icon2));
+         Icon icon3 = getResizedIcon("logo.jpg");
+         frame.add(new DndIcon(this, icon3));
+
+         // few empty icons to let you play
+         for (int i = 0; i < 13; i++) {
+            frame.add(new DndIcon(this, null));
+         }
+         frame.setSize(64 * 4, 64 * 4);
+         frame.setLocation(100, 100);
+         frame.setVisible(true);
+         this.getDesktop().getJDesktop().add(frame);
+         MouseInput.get().setCursorVisible(true);
+      }
+
+      private Icon getResizedIcon(String fileName) {
+         ImageIcon icon = new ImageIcon(this.getClass().getResource("/jmetest/data/images/" + fileName));
+         icon.setImage(icon.getImage().getScaledInstance(64, 64, 16));
+         return icon;
+      }
+   }
+
+   /**
+    * DndIcon is the drag source and the drop target, so you can easily drag /
+    * swap icons from different panels
+    *
+    * @author Nomis
+    *
+    */
+   public class DndIcon extends JLabel implements JMEDragGestureListener, JMEDragSourceListener, JMEDropTargetListener {
+
+      private static final long serialVersionUID = 1L;
+
+      private JMEDragAndDrop dndSupport;
+
+      public DndIcon(JMEDesktopState desktopSate, Icon icon) {
+         this.setIcon(icon);
+         this.dndSupport = desktopSate.getDesktop().getDragAndDropSupport();
+         new JMEMouseDragGestureRecognizer(dndSupport, this, DnDConstants.ACTION_COPY_OR_MOVE, this);
+         this.setBorder(BorderFactory.createLineBorder(Color.black));
+      }
+
+      // drop = swap this icon with event's source component icon
+
+      public void drop(JMEDropTargetEvent e) {
+
+         TransferableImage t = (TransferableImage) e.getTransferable();
+
+         Icon icon=null;
+         try {
+            icon = (Icon) t.getTransferData(null);
+         } catch (UnsupportedFlavorException e1) {            
+            e1.printStackTrace();
+         } catch (IOException e1) {            
+            e1.printStackTrace();
+         }
+
+         if (icon != null) {
+            // Set current icon to the source
+            DndIcon source = (DndIcon) e.getSource();
+            source.setIcon(this.getIcon());
+            this.setIcon(icon);
+         }
+
+      }
+
+      public void dragGestureRecognized(JMEDragGestureEvent dge) {
+
+         if (this.getIcon() == null) {
+            // nothing to transfer
+            return;
+         }
+
+         TransferableImage transferable = new TransferableImage(this.getIcon());
+
+         try {
+            dndSupport.startDrag(dge, (ImageIcon) this.getIcon(), transferable, this);
+         } catch (JMEDndException e) {
+            e.printStackTrace();
+         }
+
+      }
+
+      // we don't care for all other events
+
+      public void dragDropEnd(JMEDragSourceEvent e) {
+      }
+
+      public void dragEnter(JMEDragSourceEvent e) {
+      }
+
+      public void dragExit(JMEDragSourceEvent e) {
+      }
+
+      public void dragEnter(JMEDropTargetEvent e) {
+      }
+
+      public void dragExit(JMEDropTargetEvent e) {
+      }
+
+      public void dragOver(JMEDropTargetEvent e) {
+      }
+
+   }
+
+}


i can take a look at it next weekend if no one else is faster :slight_smile:



Could you add [ code ][ /code ] tags around your patch? it makes copying / reading easier.

Nice work Nomis, its committed r4111.

In TestDnd, I added a few comments, removed a few empty lines and removed only the DebugGameState’s MouseHandler, so the Key’s (like F4 or ESC) still work.



Can you add a [committed] to the topic?

Thanks !