Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4874092
Votes 1
Synopsis dragEnter/dragExit methods of DragSourceListener fire without reaching target
Category java:dragndrop
Reported Against mantis-beta
Release Fixed 1.5(tiger)
State 10-Fix Delivered, bug
Priority: 3-Medium
Related Bugs 4819437 , 4407521 , 4989414 , 5043688
Submit Date 04-JUN-2003
Description




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

FULL OS VERSION :
Windows XP Professional, Version 2002

A DESCRIPTION OF THE PROBLEM :
dragEnter and dragExit methods of DragSourceListener fire continuously as the dragging action occurs. They should fire only when the drop target is reached, but in 1.4.2-beta it happens even when the drop target is not designated.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile the submitted code. Launch the program (Test.main()). Start dragging action in the displayed window. The debugging output tracing the methods firing continuously will be shown in the console.

Running the same app against 1.4.1 shows dragEnter and dragExit methods firing only when the drag action ends (mouse released).



EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
In the given test case, the dragEnter and dragExit methods should fire only when the mouse is released.
ACTUAL -
The dragEnter and dragExit methods fire continuously, as the mouse drags across the window.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
// file Test.java

import java.awt.*;
import javax.swing.*;

public class Test
{
	private Controller controller;

	public Test()
	{
		controller = new Controller();
	}

	public static void main(String args[])
	{
		try
		{
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
			if (System.getProperty("os.name").startsWith("Windows"))
				UIManager.getDefaults().put("ScrollBar.track",
					new javax.swing.plaf.ColorUIResource (224, 224, 224));
			UIManager.put("ToolTip.font",new Font("SansSerif",Font.PLAIN,10));
		}
		catch (Exception exc) { System.out.println("Error loading L&F: " + exc); }
		new Test();
	}
}

// file Controller.java

import java.awt.*;
import java.awt.dnd.*;
import java.awt.datatransfer.*;
import javax.swing.*;

public class Controller implements DragGestureListener, DragSourceListener, DragSourceMotionListener, Transferable
{
	private JFrame frame;
	private Container contentPane;
	private Rectangle windowRect;
	private Font plainFont, boldFont;
	private TransparentWindow cache;
	private DataFlavor[] dummyDataFlavors = { new DataFlavor(String.class, "") };

	public Controller()
	{
		frame = new JFrame();
		frame.addNotify();
		frame.pack();
		boldFont = new Font("SansSerif",Font.BOLD,18);
		contentPane = frame.getContentPane();
		contentPane.setLayout(null);
		frame.setSize(350, 250);
		frame.validate();
		windowRect = frame.getBounds();
		createViews();
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
		frame.doLayout();
		cache = new TransparentWindow();
	}

	public void createViews()
	{
/*
**		Drag source
*/
		DragSourceLabel dragSource = new DragSourceLabel("Drag from here...");
		dragSource.setFont(boldFont);
		dragSource.setSize(dragSource.getPreferredSize());
		dragSource.setLocation(20, 20);
		contentPane.add(dragSource);
		DragSource ds = DragSource.getDefaultDragSource();
		ds.addDragSourceMotionListener(this);
		DragGestureRecognizer dgr = ds.createDefaultDragGestureRecognizer(dragSource, DnDConstants.ACTION_MOVE, this);
		dragSource.setDragGestureRecognizer(dgr);
/*
**		Drag target
*/
		JLabel dragTarget = new JLabel("...to here");
		dragTarget.setFont(boldFont);
		dragTarget.setSize(dragTarget.getPreferredSize());
		dragTarget.setLocation(contentPane.getWidth() - dragTarget.getWidth() - 20, contentPane.getHeight() - dragTarget.getHeight() - 20);
		contentPane.add(dragTarget);
	}

	public void dragGestureRecognized(DragGestureEvent dge)
	{
		System.out.println("dragGestureRecognized");
		Point location = dge.getDragOrigin();
		SwingUtilities.convertPointToScreen(location, dge.getComponent());
		cache.setLocation(location);
		cache.setVisible(true);
		dge.startDrag(null, this, this);
	}

	public void dragDropEnd(DragSourceDropEvent dsde)
	{
		System.out.println("dragDropEnd");
		cache.setVisible(false);
	}

	public void dropActionChanged(DragSourceDragEvent dsde) {}
	public void dragEnter(DragSourceDragEvent dsde)
	{
		System.out.println("dragEnter");
	}

	public void dragExit(DragSourceEvent dse)
	{
		System.out.println("dragExit");
	}

	public void dragMouseMoved(DragSourceDragEvent dsde)
	{
		Point origin = dsde.getLocation();
		cache.setLocation(origin);
	}

	public void dragOver(DragSourceDragEvent dsde) {}
	public Object getTransferData(DataFlavor flavor) { return null; }
	public DataFlavor[] getTransferDataFlavors() { return (dummyDataFlavors); }
	public boolean isDataFlavorSupported(DataFlavor flavor) { return (true); }
}

// file DragSourceLabel.java

import javax.swing.*;
import java.util.*;
import java.awt.event.*;
import java.awt.dnd.*;

public class DragSourceLabel extends JLabel
{
	protected DragGestureListener dgl;
	protected DragGestureRecognizer dgr;

	public DragSourceLabel(String text)
	{
		super(text);
	}

	public void setDragGestureRecognizer(DragGestureRecognizer dgr)
	{
		this.dgr = dgr;
	}

	protected void processMouseEvent(MouseEvent e)
	{
		boolean suppressDND = false;
		switch (e.getID())
		{
			case MouseEvent.MOUSE_PRESSED:
				suppressDND = true;
				break;
			case MouseEvent.MOUSE_RELEASED:
				suppressDND = true;
				break;
		}
		if (suppressDND)
		{
			EventListener el[] = getListeners(DragGestureListener.class);
			for (int i = 0; i < el.length; i++)
				dgr.removeDragGestureListener((DragGestureListener) el[i]);
			super.processMouseEvent(e);
			for (int i = 0; i < el.length; i++)
			{
				try { dgr.addDragGestureListener((DragGestureListener) el[i]); }
				catch (TooManyListenersException exc) { System.out.println(exc); }
			}
		}
		else
			super.processMouseEvent(e);
	}
}

// file TransparentWindow.java

import java.awt.*;
import java.awt.image.*;
import javax.swing.*;

public class TransparentWindow extends JWindow
{
	private Container contentPane;
	private BufferedImage currentImage, baseImage;
	private Image tileImage[];
	private Rectangle baseRect, tile[];
	private Point origin, baseOrigin;
	private Robot r;
	private Font boldFont;
	private boolean drawBackgroundOnly;

	public TransparentWindow()
	{
		super(new Frame());
		tileImage = new Image[2];
		tileImage[0] = null;
		tileImage[1] = null;
		baseOrigin = new Point();
		pack();
		setSize(100, 100);
		boldFont = new Font("SansSerif",Font.BOLD,16);
		validate();
		try
		{
			r = new Robot();
		}
		catch (AWTException awe)
		{
			System.out.println("robot excepton occurred");
		}
	}

	protected void grabCurrentImage()
	{
		currentImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
		Graphics g = currentImage.getGraphics();
		drawBackgroundOnly = true;
		paint(g);
		drawBackgroundOnly = false;
		g.dispose();
	}

	public void capture()
	{
		baseRect = getBounds();
		baseImage = r.createScreenCapture(baseRect);
	}

	public void setVisible(boolean flag)
	{
		if (flag)
		{
			capture();
			grabCurrentImage();
		}
		super.setVisible(flag);
	}

	public void setLocation(Point loc)
	{
/*
**		Calculate tiled rectangles
*/
		Rectangle oldFrame = getBounds();
		Rectangle newFrame = new Rectangle(loc.x, loc.y, oldFrame.width, oldFrame.height);
		baseRect = oldFrame.intersection(newFrame);
		tile = SwingUtilities.computeDifference(newFrame, oldFrame);
/*
**		Get base image from the captured ImageBuffer
*/
		if (baseRect.width > 0 && baseRect.height > 0)
			baseImage = currentImage.getSubimage(baseRect.x - oldFrame.x, baseRect.y - oldFrame.y, baseRect.width, baseRect.height);
		else
			baseImage = null;
/*
**		Capture tile images from the screen
*/
		tileImage[0] = null;
		tileImage[1] = null;
		for (int i = 0; i < tile.length; i++)
		{
			if (!tile[i].isEmpty())
				tileImage[i] = r.createScreenCapture(tile[i]);
		}
/*
**		Translate the rectangles to the origin of the new frame
*/
		baseRect.x -= newFrame.x;
		baseRect.y -= newFrame.y;
		for (int i = 0; i < tile.length; i++)
		{
			if (!tile[i].isEmpty())
			{
				tile[i].x -= newFrame.x;
				tile[i].y -= newFrame.y;
			}
		}
		super.setVisible(false);
		super.setLocation(loc);
		grabCurrentImage();
		super.setVisible(true);
	}

	public void paint(Graphics g)
	{
		super.paintComponents(g);
		if (baseImage != null)
			g.drawImage(baseImage, baseRect.x, baseRect.y, null);
		for (int i = 0; i < tile.length; i++)
		{
			if (tileImage[i] != null)
				g.drawImage(tileImage[i], tile[i].x, tile[i].y, null);
		}
		if (drawBackgroundOnly)
			return;
		g.setColor(Color.black);
		g.setFont(boldFont);
		g.drawString("Hello there", 5, 50);
		Rectangle rect = getBounds();
		g.setColor(Color.red);
		g.drawRect(0,0,rect.width - 1,rect.height - 1);
	}
}
---------- END SOURCE ----------

Release Regression From : 1.4.1_03
The above release value was the last known release where this 
bug was known to work. Since then there has been a regression.

(Review ID: 186668) 
======================================================================
Work Around
N/A
Evaluation




Using JDK 1.4.1 build 21, and dragging over and dropping on
the window with no associated DropTarget (as in the provided
test case), the following methods of the DragSourceListener
are invoked:
- on Windows: dragExit
              dragDropEnd
- on Solaris: dragExit
              dragExit
              ...
              dragExit
              dragDropEnd

Using JDK 1.4.2 build 25:
- on Windows and on Solaris: dragExit
                             dragExit
                             ...
                             dragExit
                             dragDropEnd

This behavior change was introduced with the fix 4407521
(Cursor not modified during Drag and Drop).

But as from the fix 4819437 (DragSourceListener.dragExit()
is called unexpectedly) we have the following behavior:
- on Windows: dragExit
              dragDropEnd
- on Solaris: dragDropEnd

According to the javadoc for DragSourceListener.dragExit(),
this method must not be called if there hasn't been
corresponding call of dragEnter().

Therefore Windows implementation must be revised, so that
dragExit isn't called in this scenario.

  xxxxx@xxxxx    2003-06-09
======================================================================
Comments
  
  Include a link with my name & email   


PLEASE NOTE: JDK6 is formerly known as Project Mustang