JDK-4833971 : JTree nodes which implement Drag&Drop and Mouse Event act incorrect
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.3.1_06
  • Priority: P3
  • Status: Closed
  • Resolution: Cannot Reproduce
  • OS: linux_redhat_6.2
  • CPU: x86
  • Submitted: 2003-03-18
  • Updated: 2003-03-25
  • Resolved: 2003-03-25
Related Reports
Relates :  
Description
OS: Red Hat Linux 6.2J Second Edition
Desktop environment: GNOME
J2SE version: 1.3.1_06

JTree nodes which implement Drag&Drop and Mouse Event act incorrect.
When RIGHT click JTree node, drag&drop event runs. 
Drag&Drop event should occur only when we keep finger on left button of a mouse.

We observed this problem with Red Hat Linux, and the behavior seems
fine with Windows2000.

Procedure to reproduce the problem:
1) run the sample program (MainFrame.class)
2) right click one of JTree node
3) Drag&Drop event runs

Behavior of Windows and RedHat Linux is different and behavior of
Windows2000 seems correct.


Sample code 1: TreeTest.java
===================================================================
import javax.swing.*;
import javax.swing.tree.TreeSelectionModel;
import javax.swing.tree.*;
import javax.swing.event.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.dnd.*;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.DataFlavor;

public class TreeTest extends JTree implements DragGestureListener,
                                               DragSourceListener,
                                               DropTargetListener,
                                               Transferable,
                                               MouseListener{

    public TreeTest(TreeNode top){
        super(top);
        super.addMouseListener(this);
        DragSource dragSource = DragSource.getDefaultDragSource();
        dragSource.createDefaultDragGestureRecognizer(this,
                DnDConstants.ACTION_COPY_OR_MOVE,
                this);
        new DropTarget(this,
                DnDConstants.ACTION_COPY_OR_MOVE,
                this);

    }


    public void dragGestureRecognized(DragGestureEvent e){
        int selRow = getRowForLocation((int)e.getDragOrigin().getX(),
                (int)e.getDragOrigin().getY());

        if(selRow != -1){
            TreePath selPath 
                = getPathForLocation((int)e.getDragOrigin().getX(),
                                     (int)e.getDragOrigin().getY());
            e.startDrag(DragSource.DefaultCopyDrop, this , this);
        }
    }

    public Object getTransferData(DataFlavor flavor){
        return new Object();
    }


    public DataFlavor[] getTransferDataFlavors(){
        DataFlavor objFlavor = new DataFlavor("application/x-java-object", "Object");
        DataFlavor[] f = new DataFlavor[1];
        f[0] = objFlavor;
        return f;
    }

    public boolean isDataFlavorSupported(DataFlavor flavor){
        if (flavor.getHumanPresentableName().equals("Object")){
            return true;
        }else{
            return false;
        }
    }



    public void dragEnter(DropTargetDragEvent dtde){}
    public void dragExit(DropTargetEvent dte){}
    public void dragOver(DropTargetDragEvent dtde){}
    public void drop(DropTargetDropEvent dtde){}
    public void dropActionChanged(DropTargetDragEvent dtde){}

    public void mouseClicked(MouseEvent e){}
    public void mouseEntered(MouseEvent e){}
    public void mouseExited(MouseEvent e){}
    public void mousePressed(MouseEvent e){

        int modify = e.getModifiers();
        if( (modify & MouseEvent.BUTTON1_MASK) != MouseEvent.BUTTON1_MASK ) {
            int selRow = getRowForLocation(e.getX(), e.getY());
            if (selRow != -1){
                TreePath selPath = getPathForLocation(e.getX(), e.getY());
                setSelectionPath(selPath);
                JPopupMenu projectMenu = new JPopupMenu();
                JMenuItem createPalette = new JMenuItem("test1");
                JMenuItem setProperty = new JMenuItem("test2");
                projectMenu.add(createPalette);
                projectMenu.add(setProperty);
                projectMenu.show(e.getComponent(), e.getX(), e.getY());
            }
        }
    }
    public void mouseReleased(MouseEvent e){}


    public void dragDropEnd(DragSourceDropEvent dsde){}
    public void dragEnter(DragSourceDragEvent dsde){}
    public void dragExit(DragSourceEvent dse){}
    public void dragOver(DragSourceDragEvent dsde){}
    public void dropActionChanged(DragSourceDragEvent dsde){}


}
===================================================================


Sample code 2: MainFrame.java
===================================================================
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.event.TreeSelectionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.tree.TreeSelectionModel;
import java.net.URL;
import java.io.IOException;
import javax.swing.JEditorPane;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JFrame;
import java.awt.*;
import java.awt.event.*;

public class MainFrame extends JFrame {


    public MainFrame() {
        super("MainFrame");
        DefaultMutableTreeNode top = new DefaultMutableTreeNode("Top");
        createNodes(top);
        TreeTest tree = new TreeTest(top);
        JScrollPane treeView = new JScrollPane(tree);
        getContentPane().add(treeView, BorderLayout.CENTER);
    }


    private void createNodes(DefaultMutableTreeNode top) {
        DefaultMutableTreeNode test1 = null;
        DefaultMutableTreeNode test2 = null;
        DefaultMutableTreeNode test3 = null;
        DefaultMutableTreeNode test4 = null;
        DefaultMutableTreeNode test5 = null;
        test1 = new DefaultMutableTreeNode("test1");
        test2 = new DefaultMutableTreeNode("test2");
        test3 = new DefaultMutableTreeNode("test3");
        test4 = new DefaultMutableTreeNode("test4");
        test5 = new DefaultMutableTreeNode("test5");
        top.add(test1);
        top.add(test2);
        top.add(test3);
        top.add(test4);
        top.add(test5);
    }

    public static void main(String[] args) {
        JFrame frame = new MainFrame();
 
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });  
 
        frame.pack();
        frame.setVisible(true);
    }
}

===================================================================

Comments
EVALUATION Note: As of 1.4.0, this is not the recommended way to use DnD with Swing components. AWT's DragGestureRecognizers don't interact well with Swing's selection listeners. See the following on how to correctly use DnD with Swing as of 1.4.0: http://java.sun.com/j2se/1.4.1/docs/guide/swing/1.4/dnd.html This being said, it appears that the user is complaining about the drag recognizer created by createDefaultDragGestureRecognizer responding to either left or right mouse button events. Re-assigning to AWT DnD. ###@###.### 2003-03-18 Name: dsR10078 Date: 03/19/2003 The observed behavior is as follows: On Windows: the drag is initiated with any mouse button. On X11 (Solaris/Linux): the drag is not initiated with the right mouse button. The problem is not a bug as this is the behavior of platform-specififc default drag gesture recognizers. The reason for the difference in behavior is that historically right-mouse button drag was uncommon for X11 applications, while it is widely used on Windows. Any change in this behavior could break existing applications and thus is undesirable. If the application needs a different behavior, it can use a custom drag gesture recognizer that implements the desired behavior. The following code is an example of a custom drag gesture recognizer that initiates a drag operation only on the left mouse button drag: ------------------------------------------------------------------------ [...] DragSource dragSource = DragSource.getDefaultDragSource(); new CustomDragGestureRecognizer(dragSource, this, DnDConstants.ACTION_COPY_OR_MOVE, this, 3); new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, this); [...] class CustomDragGestureRecognizer extends MouseDragGestureRecognizer { final int motionThreshold; public CustomDragGestureRecognizer(DragSource ds, Component c, int act, DragGestureListener dgl, int motionThreshold) { super(ds, c, act, dgl); this.motionThreshold = motionThreshold; } public void mousePressed(MouseEvent e) { resetRecognizer(); if (e.getButton() == MouseEvent.BUTTON1) { appendEvent(e); } } public void mouseReleased(MouseEvent e) { resetRecognizer(); } public void mouseDragged(MouseEvent e) { if (getTriggerEvent() != null) { // gesture pending if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) { appendEvent(e); final MouseEvent trigger = (MouseEvent)getTriggerEvent(); final Point origin = trigger.getPoint(); final Point current = e.getPoint(); final int dx = Math.abs(origin.x - current.x); final int dy = Math.abs(origin.y - current.y); // If the mouse motion threshold is exceeded fire a drag // gesture event. if (dx > motionThreshold || dy > motionThreshold) { fireDragGestureRecognized(DnDConstants.ACTION_COPY, origin); } } else { // Cancel drag gesture recognition if the middle mouse // button is released. resetRecognizer(); } } } } ------------------------------------------------------------------------ ###@###.### 2003-03-19 ====================================================================== Name: dsR10078 Date: 03/24/2003 The behavior described in the evaluation above applies only to 1.4.0 and later releases. The problem documented in the bug description exists only in 1.3.1. It was described in the evaluation for 4494085 and fixed in JDK 1.4.0. So it is not reproducible since 1.4.0. This report is left open for the convenience of CTE. ###@###.### 2003-03-24 ====================================================================== The customer is not planning to raise an escalation, and the problem is not reproducible in 1.4.x, so I am closing this report. ###@###.### 2003-03-24
24-03-2003