Name: rmT116609 Date: 11/06/2003
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)
FULL OS VERSION :
Microsoft Windows XP [Version 5.1.2600]
A DESCRIPTION OF THE PROBLEM :
When trying to move rows around in a JTable (by dragging and ropping them). I get an InvalidDnDOperationException with the message "Drag and drop in progress".
This only happens if you try to initiate a drag with the exact row that you just dropped, without changing the selection. The drag and drop will be successful if you try other rows, or you change the selection.
I am pretty sure I am accepting and completing the drop correctly in the drop method of the DropTargetListener.
The exact stack trace is below.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1) Run RowDraggingTable
2) Click & Drag the first row and drop it on the second row (for example)... the rows should swap
3) Click & Drag the new second row anywhere... the exception should occur
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The newly dropped row should be able to be dragged like any other row
ACTUAL -
I get the InvalidDnDOperationException when I try to initiate a drag with the newly dropped row
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.awt.dnd.InvalidDnDOperationException: Drag and drop in progress
at sun.awt.dnd.SunDragSourceContextPeer.setDragDropInProgress(SunDragSourceContextPeer.java:328)
at java.awt.dnd.DragSource.startDrag(DragSource.java:285)
at java.awt.dnd.DragSource.startDrag(DragSource.java:402)
at java.awt.dnd.DragGestureEvent.startDrag(DragGestureEvent.java:201)
at RowDraggingTable.dragGestureRecognized(RowDraggingTable.java:83)
at java.awt.dnd.DragGestureRecognizer.fireDragGestureRecognized(DragGestureRecognizer.java:339)
at sun.awt.windows.WMouseDragGestureRecognizer.mouseDragged(WMouseDragGestureRecognizer.java:205)
at java.awt.AWTEventMulticaster.mouseDragged(AWTEventMulticaster.java:262)
at java.awt.AWTEventMulticaster.mouseDragged(AWTEventMulticaster.java:261)
at java.awt.Component.processMouseMotionEvent(Component.java:5148)
at javax.swing.JComponent.processMouseMotionEvent(JComponent.java:2779)
at java.awt.Component.processEvent(Component.java:4901)
at java.awt.Container.processEvent(Container.java:1569)
at java.awt.Component.dispatchEventImpl(Component.java:3615)
at java.awt.Container.dispatchEventImpl(Container.java:1627)
at java.awt.Component.dispatchEvent(Component.java:3477)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:3483)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3215)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3128)
at java.awt.Container.dispatchEventImpl(Container.java:1613)
at java.awt.Window.dispatchEventImpl(Window.java:1606)
at java.awt.Component.dispatchEvent(Component.java:3477)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:456)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:145)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:137)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:100)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import javax.swing.table.TableModel;
import javax.swing.table.TableColumnModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.*;
import java.awt.dnd.*;
import java.awt.*;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.util.Vector;
import java.util.HashSet;
import java.util.Set;
import java.util.Iterator;
import java.io.IOException;
public class RowDraggingTable extends JTable implements Autoscroll, DropTargetListener, DragGestureListener {
private static final int AUTOSCROLL_MARGIN = 25;
protected Insets autoscrollInsets = new Insets(0, 0, 0, 0);
private Set listeners = new HashSet();
public RowDraggingTable() {
initdrag();
}
public RowDraggingTable(int numRows, int numColumns) {
super(numRows, numColumns);
initdrag();
}
public RowDraggingTable(Object[][] rowData, Object[] columnNames) {
super(rowData, columnNames);
initdrag();
}
public RowDraggingTable(TableModel dm) {
super(dm);
initdrag();
}
public RowDraggingTable(TableModel dm, TableColumnModel cm) {
super(dm, cm);
initdrag();
}
public RowDraggingTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
super(dm, cm, sm);
initdrag();
}
public RowDraggingTable(Vector rowData, Vector columnNames) {
super(rowData, columnNames);
initdrag();
}
private void initdrag() {
setDragEnabled(true);
DragSource.getDefaultDragSource().createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, this);
setDropTarget(new DropTarget(this, DnDConstants.ACTION_MOVE, this));
}
/** Add a listener to tell when a row is dragged to a new spot */
public void addRowDragListener(RowDragListener l) {
listeners.add(l);
}
/** Remove the row drag listener */
public void removeRowDragListener(RowDragListener l) {
listeners.remove(l);
}
public void dragGestureRecognized(DragGestureEvent e) {
if (getDragEnabled() == true) {
int row = getSelectedRow();
if (row > -1) {
if (isEditing() == true) {
getCellEditor().stopCellEditing();
}
try {
e.startDrag(DragSource.DefaultMoveDrop, new IntegerTransfer(row));
} catch (InvalidDnDOperationException dnd) {
for (Iterator it = listeners.iterator(); it.hasNext();) {
RowDragListener l = (RowDragListener) it.next();
l.dropError(this, dnd);
}
}
}
}
}
public void autoscroll(Point location) {
int top = 0;
int left = 0;
int bottom = 0;
int right = 0;
Dimension size = getSize();
Rectangle rect = getVisibleRect();
int bottomEdge = rect.y + rect.height;
int rightEdge = rect.x + rect.width;
if (((location.y - rect.y) <= AUTOSCROLL_MARGIN) && (rect.y > 0)) {
top = AUTOSCROLL_MARGIN;
}
if (((location.x - rect.x) <= AUTOSCROLL_MARGIN) && (rect.x > 0)) {
left = AUTOSCROLL_MARGIN;
}
if (((bottomEdge - location.y) <= AUTOSCROLL_MARGIN) && (bottomEdge < size.height)) {
bottom = AUTOSCROLL_MARGIN;
}
if (((rightEdge - location.x) <= AUTOSCROLL_MARGIN) && (rightEdge < size.width)) {
right = AUTOSCROLL_MARGIN;
}
rect.x += right - left;
rect.y += bottom - top;
scrollRectToVisible(rect);
}
public Insets getAutoscrollInsets() {
Dimension size = getSize();
Rectangle rect = getVisibleRect();
autoscrollInsets.top = rect.y + AUTOSCROLL_MARGIN;
autoscrollInsets.left = rect.x + AUTOSCROLL_MARGIN;
autoscrollInsets.bottom = size.height - (rect.y + rect.height) + AUTOSCROLL_MARGIN;
autoscrollInsets.right = size.width - (rect.x + rect.width) + AUTOSCROLL_MARGIN;
return autoscrollInsets;
}
public void dragEnter(DropTargetDragEvent dtde) {
if (dtde.getDropAction() != DnDConstants.ACTION_MOVE)
dtde.acceptDrag(DnDConstants.ACTION_MOVE);
};
public void dragExit(DropTargetEvent dte) {
}
public void dragOver(DropTargetDragEvent dtde) {
if (dtde.getDropAction() != DnDConstants.ACTION_MOVE)
dtde.acceptDrag(DnDConstants.ACTION_MOVE);
}
public void drop(DropTargetDropEvent dtde) {
DataFlavor df = IntegerTransfer.flavor;
if (dtde.isDataFlavorSupported(df)) {
dtde.acceptDrop(dtde.getDropAction());
Transferable transferable = dtde.getTransferable();
try {
int source_row = ((Integer) transferable.getTransferData(df)).intValue();
int dest_row = rowAtPoint(dtde.getLocation());
//notify...
for (Iterator it = listeners.iterator(); it.hasNext();) {
RowDragListener l = (RowDragListener) it.next();
l.rowDragged(this, source_row, dest_row);
}
dtde.dropComplete(true);
} catch (Exception e) {
for (Iterator it = listeners.iterator(); it.hasNext();) {
RowDragListener l = (RowDragListener) it.next();
l.dropError(this, e);
}
dtde.dropComplete(false);
}
} else {
dtde.rejectDrop();
}
}
public void dropActionChanged(DropTargetDragEvent dtde) {
if (dtde.getDropAction() != DnDConstants.ACTION_MOVE)
dtde.acceptDrag(DnDConstants.ACTION_MOVE);
};
private static class IntegerTransfer implements Transferable {
static DataFlavor flavor = new DataFlavor(Integer.class, "Integer");
private Integer row = null;
public IntegerTransfer(int row) {
this.row = new Integer(row);
}
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{flavor};
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return this.flavor.equals(flavor);
}
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
if (!isDataFlavorSupported(flavor)) throw new UnsupportedFlavorException(flavor);
return row;
}
}
/** Use to listen to drag events from this RowDraggingTable */
public static interface RowDragListener {
/** Called when there is some sort of error while dragging */
void dropError(RowDraggingTable source, Exception e);
/** Called when a drop is complete... it is up to the listener
* to modify the model to reflect any needed changes */
void rowDragged(RowDraggingTable source, int source_row, int dest_row);
}
public static final void main(String[] args) {
JFrame testframe = new JFrame("Test Window");
testframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
testframe.getContentPane().setLayout(new BorderLayout(0, 0));
DefaultTableModel model = new DefaultTableModel(new Object[] {"Col 1", "Col 2"}, 0);
for (int i = 0; i < 100; i++) {
model.addRow(new Object[] {new Integer(i), "Row Data " + i});
}
RowDraggingTable rdt = new RowDraggingTable(model);
rdt.addRowDragListener(new RowDragListener() {
public void dropError(RowDraggingTable source, Exception e) {
e.printStackTrace();
}
public void rowDragged(RowDraggingTable source, int source_row, int dest_row) {
DefaultTableModel model = (DefaultTableModel) source.getModel();
model.moveRow(source_row, source_row, dest_row);
source.getSelectionModel().setSelectionInterval(dest_row, dest_row);
}
});
testframe.getContentPane().add(new JScrollPane(rdt), BorderLayout.CENTER);
testframe.pack();
testframe.setVisible(true);
}
}
---------- END SOURCE ----------
(Incident Review ID: 223420)
======================================================================