Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6614043

No events posted to AWTEventListeners during native drag

    XMLWordPrintable

Details

    • Bug
    • Resolution: Duplicate
    • P4
    • None
    • 1.4.2
    • client-libs
    • x86
    • windows_xp

    Description

      FULL PRODUCT VERSION :
      java version "1.4.2_01"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_01-b06)
      Java HotSpot(TM) Client VM (build 1.4.2_01-b06, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows XP [Version 5.1.2600]

      A DESCRIPTION OF THE PROBLEM :
      I wrote and maintain a UI testing framework (Abbot) which, among other things, supports recording user actions (for playback, inspection, creating demos, etc). In general, AWTEventListeners are used to track user input and UI state.

      Once a native drag operation has started (i.e. DragGestureListener.startDrag has been called), no events are received by any AWTEventListeners registered with Toolkit.addAWTEventListener until the drag is completed.

      There may be no indication of drag start (other than MOUSE_PRESSED), and there is no indication of drag progress or termination. Different platforms *may* post a MOUSE_EXITED, but this is not reliable.

      These events could easily be generated and posted to the AWT event queue, but are not generically available. There is apparently no way to add a listener to the currently active DragSource (if there were, I could at least fake-post the simulated events myself).

      I consider this a bug rather than a RFE since the event queue produces no output for the duration of the native drag. At the very least the entire lack of MOUSE_RELEASED at the end of the drag is very inconsistent for no good reason.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Set up a native drag/drop scenario (any of the DnD examples will do). Add an AWTEventListener for all events.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      I would expect MOUSE_DRAGGED, MOUSE_ENTERED, and MOUSE_EXITED events for the duration of the drag, as well as MOUSE_RELEASED when it is finished.
      ACTUAL -
      No events are posted for the duration of the native drag.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      // uses junit 3.8.1
      import java.awt.*;
      import java.awt.event.*;
      import java.awt.dnd.*;
      import java.awt.datatransfer.*;
      import javax.swing.*;
      import java.util.*;

      import junit.framework.*;
      import junit.textui.TestRunner;

      public class DragDropTest extends TestCase {

          private class DropLabel extends JLabel {
              /** Target received drag. */
              public volatile boolean dragEntered = false;
              /** Target accepted the drop. */
              public volatile boolean dropAccepted = false;
              private DropTarget dropTarget = null;
              private DropTargetListener dtl = null;
              private boolean acceptDrops = false;
              public DropLabel(String name) { this(name, true); }
              public DropLabel(String name, boolean accept) {
                  super(name);
                  setName("DropLabel");
                  acceptDrops = accept;
                  dtl = new DropTargetListener() {
                      public void dragEnter(DropTargetDragEvent e) {
                          dragEntered = true;
                          if (acceptDrops) {
                              setForeground(Color.blue);
                              paintImmediately(getBounds());
                          }
                      }
                      public void dragOver(DropTargetDragEvent e) {
                          if (acceptDrops)
                              e.acceptDrag(e.getDropAction());
                      }
                      public void dragExit(DropTargetEvent e) {
                          if (acceptDrops) {
                              setForeground(Color.black);
                              paintImmediately(getBounds());
                          }
                      }
                      public void dropActionChanged(DropTargetDragEvent e) {
                          if (acceptDrops)
                              e.acceptDrag(e.getDropAction());
                      }
                      public void drop(DropTargetDropEvent e) {
                          if (acceptDrops) {
                              e.acceptDrop(e.getDropAction());
                              e.dropComplete(true);
                              dropAccepted = true;
                              setForeground(Color.black);
                              paintImmediately(getBounds());
                          }
                      }
                  };
                  dropTarget = new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE,
                                              dtl, true);
              }
          }

          private class DragLabel extends DropLabel {
              private class DragData implements Transferable {
                  public DataFlavor[] getTransferDataFlavors() {
                      return new DataFlavor[] {
                          DataFlavor.stringFlavor
                      };
                  }
                  public boolean isDataFlavorSupported(DataFlavor flavor) {
                      return true;
                  }
                  public Object getTransferData(DataFlavor flavor) {
                      return getName();
                  }
              }
              
              /** Drag gesture was recognized. */
              public volatile boolean dragStarted = false;
              /** Drag has left the building, er, Component. */
              public volatile boolean dragExited = false;
              /** Source registered a successful drop. */
              public volatile boolean dropSuccessful = false;
              /** Source got an indication the drag ended. */
              public volatile boolean dragEnded = false;
              public Exception exception = null;
              private DragGestureListener dgl = null;
              private DragSourceListener dsl = null;
              private DragSource dragSource = null;
              private int acceptedActions = DnDConstants.ACTION_COPY_OR_MOVE;
              public DragLabel(String name) { this(name, true); }
              public DragLabel(String name, final boolean acceptDrops) {
                  super(name, acceptDrops);
                  setName("DragLabel (" + name + ")");
                  dragSource = DragSource.getDefaultDragSource();
                  dgl = new DragGestureListener() {
                      public void dragGestureRecognized(DragGestureEvent e) {
                          if ((e.getDragAction() & acceptedActions) == 0)
                              return;
                          dragStarted = true;
                          try {
                              e.startDrag(acceptDrops
                                          ? DragSource.DefaultCopyDrop
                                          : DragSource.DefaultCopyNoDrop,
                                          new DragData(), dsl);
                              setForeground(Color.red);
                              paintImmediately(getBounds());
                          }
                          catch(InvalidDnDOperationException idoe) {
                              exception = idoe;
                          }
                      }
                  };
                  dsl = new DragSourceListener() {
                      public void dragDropEnd(DragSourceDropEvent e) {
                          dropSuccessful = e.getDropSuccess();
                          dragEnded = true;
                          setForeground(Color.black);
                          paintImmediately(getBounds());
                      }
                      public void dragEnter(DragSourceDragEvent e) {
                      }
                      public void dragOver(DragSourceDragEvent e) {
                      }
                      public void dragExit(DragSourceEvent e) {
                          dragExited = true;
                      }
                      public void dropActionChanged(DragSourceDragEvent e) {
                      }
                  };
                  dragSource.
                      createDefaultDragGestureRecognizer(this, acceptedActions, dgl);
              }
          }

          public void testDragDropEvents() throws Exception {
              Robot robot = new Robot();

              JPanel p = new JPanel();
              JLabel drag = new DragLabel("Drag Me");
              JLabel drop = new DropLabel("Drop On Me");
              p.add(drag);
              p.add(drop);
              JFrame frame = new JFrame("drag/drop");
              frame.setContentPane(p);
              frame.pack();
              frame.show();

              final ArrayList events = new ArrayList();
              Toolkit.getDefaultToolkit().
                  addAWTEventListener(new AWTEventListener() {
                      public void eventDispatched(AWTEvent e) {
                          synchronized(events) {
                              events.add(e);
                          }
                      }
                  }, (InputEvent.MOUSE_EVENT_MASK
                      | InputEvent.MOUSE_MOTION_EVENT_MASK));

              // Drag set up for w32; needs adjustments for OSX or X11
              Point start = drag.getLocationOnScreen();
              robot.mouseMove(start.x + drag.getWidth()/2,
                              start.y + drag.getHeight()/2);
              robot.delay(500);
              robot.waitForIdle();
              synchronized(events) {
                  events.clear();
              }

              robot.mousePress(InputEvent.BUTTON1_MASK);

              Point end = drop.getLocationOnScreen();
              robot.mouseMove(end.x + drop.getWidth()/2,
                              end.y + drop.getHeight()/2);
              robot.delay(200); // required for w32 drop
              robot.waitForIdle();

              // Insert a marker for where the drop occurs
              synchronized(events) {
                  events.add(null);
              }

              robot.mouseRelease(InputEvent.BUTTON1_MASK);
              robot.delay(500);
              robot.waitForIdle();

              // Insert another marker
              synchronized(events) {
                  events.add(null);
              }

              ArrayList snapshot = new ArrayList(events);
              frame.setVisible(false);

              int[] ids = {
                  MouseEvent.MOUSE_PRESSED,
                  MouseEvent.MOUSE_DRAGGED,
                  MouseEvent.MOUSE_EXITED,
                  MouseEvent.MOUSE_ENTERED,
                  MouseEvent.MOUSE_DRAGGED,
                  // Would expect a null here
                  MouseEvent.MOUSE_RELEASED,
                  // Would expect a null here
              };
              for (int i=0;i < ids.length;i++) {
                  MouseEvent me = (MouseEvent)snapshot.get(i);
                  if (me.getID() != ids[i]) {
                      fail("Got unexpected event ID: " + snapshot);
                  }
              }
          }


          public static void main(String[] args) {
              TestRunner.main(new String[] {
                  "-c", DragDropTest.class.getName(),
              });
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      None whatsoever.

      Attachments

        Issue Links

          Activity

            People

              denis Denis Fokin (Inactive)
              dav Andrei Dmitriev (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: