United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-6560955 : JTree: Can't drop a node as last child of a parent in INSERT mode

Details
Type:
Bug
Submit Date:
2007-05-23
Status:
Open
Updated Date:
2017-05-23
Project Name:
JDK
Resolved Date:
Component:
client-libs
OS:
windows_xp
Sub-Component:
javax.swing
CPU:
x86
Priority:
P4
Resolution:
Unresolved
Affected Versions:
6
Targeted Versions:

Related Reports

Sub Tasks

Description
FULL PRODUCT VERSION :
build 1.6.0_01-b06

ADDITIONAL OS VERSION INFORMATION :
Windows XP

A DESCRIPTION OF THE PROBLEM :
When using drag&drop in a JTree in INSERT mode (tree.setDropMode(DropMode.INSERT), then it is not possible to insert a node as the last child. When dragging over the last child, the insertion mark indicates that the node will be inserted as next sibling of the parent container, and this is what occurs.

The only way to insert the node as last child is to drop on the parent container which put the element at the end of its child by default. This is not convenient.

Here is what is think is expected:
- when dragging over the bottom part of the last element: insert just after this element in the same container.
- when dragging over the top part of the next parent sibling, insert before the parent sibling, at the same level of the parent. (This is the actual behavior).

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached code, and drag from the textfield and try to drop on the last color: purple.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The inserted node should be under purple and not up "names".

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------

public class TreeDnDDemo extends JFrame
    implements ActionListener
{

    private DefaultListModel model;
    private int count;
    private JTree tree;
    private JComboBox dropCombo;
    private DefaultTreeModel treeModel;
    
    private static DefaultTreeModel getDefaultTreeModel()
    {
        DefaultMutableTreeNode defaultmutabletreenode = new DefaultMutableTreeNode("things");
        DefaultMutableTreeNode defaultmutabletreenode1 = new DefaultMutableTreeNode("colors");
        defaultmutabletreenode.add(defaultmutabletreenode1);
        defaultmutabletreenode1.add(new DefaultMutableTreeNode("red"));
        defaultmutabletreenode1.add(new DefaultMutableTreeNode("yellow"));
        defaultmutabletreenode1.add(new DefaultMutableTreeNode("green"));
        defaultmutabletreenode1.add(new DefaultMutableTreeNode("blue"));
        defaultmutabletreenode1.add(new DefaultMutableTreeNode("purple"));
        defaultmutabletreenode1 = new DefaultMutableTreeNode("names");
        defaultmutabletreenode.add(defaultmutabletreenode1);
        
        return new DefaultTreeModel(defaultmutabletreenode);
    }

    public TreeDnDDemo()
    {
        super("Drag and Drop Demo");
        model = new DefaultListModel();
        count = 0;
        treeModel = getDefaultTreeModel();
        tree = new JTree(treeModel);
        tree.setBorder(BorderFactory.createEmptyBorder(2, 4, 2, 4));
        tree.getSelectionModel().setSelectionMode(4);
        tree.setDropMode(DropMode.INSERT);
        tree.expandRow(1);
        tree.setTransferHandler(new TransferHandler() {

            public boolean canImport(javax.swing.TransferHandler.TransferSupport transfersupport)
            {
                if(!transfersupport.isDrop())
                    return false;
                if(!transfersupport.isDataFlavorSupported(DataFlavor.stringFlavor))
                {
                    return false;
                } else
                {
                    javax.swing.JTree.DropLocation droplocation = (javax.swing.JTree.DropLocation)transfersupport.getDropLocation();
                    return droplocation.getPath() != null;
                }
            }

            public boolean importData(javax.swing.TransferHandler.TransferSupport transfersupport)
            {
                if(!canImport(transfersupport))
                    return false;
                javax.swing.JTree.DropLocation droplocation = (javax.swing.JTree.DropLocation)transfersupport.getDropLocation();
                TreePath treepath = droplocation.getPath();
                int i = droplocation.getChildIndex();
                String s;
                try
                {
                    s = (String)transfersupport.getTransferable().getTransferData(DataFlavor.stringFlavor);
                }
                catch(UnsupportedFlavorException unsupportedflavorexception)
                {
                    return false;
                }
                catch(IOException ioexception)
                {
                    return false;
                }
                if(i == -1)
                    i = tree.getModel().getChildCount(treepath.getLastPathComponent());
                DefaultMutableTreeNode defaultmutabletreenode = new DefaultMutableTreeNode(s);
                DefaultMutableTreeNode defaultmutabletreenode1 = (DefaultMutableTreeNode)treepath.getLastPathComponent();
                treeModel.insertNodeInto(defaultmutabletreenode, defaultmutabletreenode1, i);
                tree.makeVisible(treepath.pathByAddingChild(defaultmutabletreenode));
                tree.scrollRectToVisible(tree.getPathBounds(treepath.pathByAddingChild(defaultmutabletreenode)));
                model.removeAllElements();
                model.insertElementAt((new StringBuilder()).append("String ").append(++count).toString(), 0);
                return true;
            }

            
        });
        JList jlist = new JList(model);
        jlist.setFocusable(false);
        jlist.setPrototypeCellValue("String 0123456789");
        model.insertElementAt((new StringBuilder()).append("String ").append(count).toString(), 0);
        jlist.setDragEnabled(true);
        jlist.setBorder(BorderFactory.createLoweredBevelBorder());
        JPanel jpanel = new JPanel();
        jpanel.setLayout(new BoxLayout(jpanel, 0));
        JPanel jpanel1 = new JPanel();
        jpanel1.add(new JLabel("Drag from here:"));
        jpanel1.add(jlist);
        jpanel.add(Box.createHorizontalStrut(4));
        jpanel.add(Box.createGlue());
        jpanel.add(jpanel1);
        jpanel.add(Box.createGlue());
        jpanel.add(Box.createHorizontalStrut(4));
        getContentPane().add(jpanel, "North");
        getContentPane().add(new JScrollPane(tree), "Center");
        dropCombo = new JComboBox(new String[] {
            "USE_SELECTION", "ON", "INSERT", "ON_OR_INSERT"
        });
        dropCombo.setSelectedItem("INSERT");
        dropCombo.addActionListener(this);
        jpanel = new JPanel();
        jpanel.setLayout(new BoxLayout(jpanel, 0));
        jpanel1 = new JPanel();
        jpanel1.add(new JLabel("Drop mode:"));
        jpanel1.add(dropCombo);
        jpanel.add(Box.createHorizontalStrut(4));
        jpanel.add(Box.createGlue());
        jpanel.add(jpanel1);
        jpanel.add(Box.createGlue());
        jpanel.add(Box.createHorizontalStrut(4));
        getContentPane().add(jpanel, "South");
        getContentPane().setPreferredSize(new Dimension(228, 326));
    }

    public void actionPerformed(ActionEvent actionevent)
    {
        Object obj = dropCombo.getSelectedItem();
        if(obj == "USE_SELECTION")
            tree.setDropMode(DropMode.USE_SELECTION);
        else
        if(obj == "ON")
            tree.setDropMode(DropMode.ON);
        else
        if(obj == "INSERT")
            tree.setDropMode(DropMode.INSERT);
        else
        if(obj == "ON_OR_INSERT")
            tree.setDropMode(DropMode.ON_OR_INSERT);
    }

    public static void main(String args[])
    {
        
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
        }
        
        SwingUtilities.invokeLater(new Runnable() {

            public void run()
            {
                TreeDnDDemo treednddemo = new TreeDnDDemo();
                treednddemo.setDefaultCloseOperation(3);
                treednddemo.pack();
                treednddemo.setLocationRelativeTo(null);
                treednddemo.setVisible(true);
            }

        });
    }


}

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

CUSTOMER SUBMITTED WORKAROUND :
Unfortunately, JTree.dropLocationForPoint() is package protected and can't be overriden for a fix.

                                    

Comments
EVALUATION

This is a known limitation and something we have plans to resolve.
                                     
2007-05-24



Hardware and Software, Engineered to Work Together