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

JTree Transferable object differs on drag/import

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P4 P4
    • None
    • 6
    • client-libs

      FULL PRODUCT VERSION :
      java version "1.6.0_05"
      Java(TM) SE Runtime Environment (build 1.6.0_05-b13)
      Java HotSpot(TM) Client VM (build 10.0-b19, mixed mode, sharing)

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

      A DESCRIPTION OF THE PROBLEM :
      When dragging a DefaultMutableTreeNode that implements Transferable inside of a JTree (local), the Transferable retrieved inside of importData, is not the "same" object that was exported with createTransferable.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Using the code posted below, drag the JTree node with name "choco" onto itself.


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      I would expect that the Transferable containers be the same. The one created during export, should be the one given during import.
      ACTUAL -
      Note the output, the hashcodes on the Transferables do not verify (though as side note, the contents of their getUserObject functions do).

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.awt.datatransfer.DataFlavor;
      import java.awt.datatransfer.Transferable;
      import java.awt.datatransfer.UnsupportedFlavorException;
      import javax.swing.*;
      import javax.swing.event.*;
      import javax.swing.tree.DefaultMutableTreeNode;
      import javax.swing.tree.DefaultTreeModel;
      import javax.swing.tree.TreePath;
      import java.io.*;


      /**
       * Dragging and dropping chocolate milk onto default category should remove
       * the node from its parent, but it doesn't. *puzzle*
       */
      public class Test extends JFrame{
      private static final long serialVersionUID = 1L;

      private static Category root;

      static{
      root = new Category( "root category" );

      Category milk = new Category( "milk" );
      Category cmilk = new Category( "chocolate milk" );
      Category choco = new Category( "choco" );

      String test = "ATEST";

      choco.setUserObject( test );

      milk.add( cmilk );
      root.add( milk );
      root.add( choco );
      }


      public static void main( String args[]) throws Exception {
      JFrame f = new JFrame();
      f.setSize( 400, 400 );
      f.getContentPane().add( new JScrollPane( new TestTree() ) );
      f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
      f.setVisible( true );
      }


      /**
      * Our tree
      */
      private static final class TestTree extends JTree {
      private static final long serialVersionUID = 1L;

      private DefaultTreeModel model;
      private TreePath selectedPath;
      private Category originalTransferable;

      public TestTree(){
      model = new DefaultTreeModel( root );
      setModel( model );
      setDragEnabled( true );
      setTransferHandler( new TreeNodeTransferHandler() );
      setDropMode( DropMode.ON_OR_INSERT );

      addTreeSelectionListener( new TreeSelectionListener() {
      public void valueChanged( TreeSelectionEvent e ){
      TreePath path = e.getNewLeadSelectionPath();

      if( path != null ){
      selectedPath = path;
      }
      }
      });
      }

      private class TreeNodeTransferHandler extends TransferHandler {
      private static final long serialVersionUID = 1L;


      public boolean importData( TransferSupport info ) {
      if( !canImport(info) )
      return false;

      try{
      // fetch the drop location
      JTree.DropLocation dl = (JTree.DropLocation)info.getDropLocation();
      TreePath path = dl.getPath();
      Category dragged = (Category)info.getTransferable().getTransferData( Category.categoryFlavor );
      Category target = (Category)path.getLastPathComponent();

      System.out.println(
      " --> Original transferable hashcode : " +
      originalTransferable.hashCode() +
      "\n --> Actual transferable hashcode : " +
      ((Category)info.getTransferable().getTransferData( Category.categoryFlavor )).hashCode()
      );

      System.out.println(
      " --> Original transferable hashcode : " +
      originalTransferable.getUserObject().hashCode() +
      "\n --> Actual transferable hashcode : " +
      ((Category)info.getTransferable().getTransferData( Category.categoryFlavor )).getUserObject().hashCode()
      );


      System.out.println( "droppped " + dragged + " onto " + target );
      ((Category)dragged.getParent()).removeSubcategory( dragged, model );

      return true;
      }
      catch( Exception x ){
      x.printStackTrace();
      }
      return false;

      }

      public int getSourceActions( JComponent c ){
      return TransferHandler.MOVE;
      }

      @Override
      protected Transferable createTransferable( JComponent c ){
      if( c.equals( TestTree.this ) ){
      if( selectedPath != null && !((Category)selectedPath.getLastPathComponent()).isRoot() ){
      originalTransferable = (Category)selectedPath.getLastPathComponent();
      return originalTransferable;
      }
      }
      return null;
      }

      public boolean canImport( TransferSupport info ){
      if( !info.isDrop() )
      return false;

      if( !info.isDataFlavorSupported( Category.categoryFlavor ) )
      return false;

      JTree.DropLocation dl = (JTree.DropLocation)info.getDropLocation();

      if( dl == null || dl.getPath() == null )
      return false;

      Object transferdata = null;
      try{
      transferdata = info.getTransferable().getTransferData( Category.categoryFlavor );
      }
      catch( Exception e ){
      e.printStackTrace();
      }


      // can't drop a null node, nor can a node be dropped onto itself
      return dl.getPath().getLastPathComponent() != null
      && dl.getPath().getLastPathComponent() != transferdata;
      }

      }
      }


      /**
      * Dummy node object
      */
      private static final class Category extends DefaultMutableTreeNode implements Transferable{
      private static final long serialVersionUID = 1L;
      public static final DataFlavor categoryFlavor = new DataFlavor( Category.class, "Category" );
      public static final DataFlavor[] transferDataFlavors = new DataFlavor[]{ categoryFlavor };

      private String title;

      public Category( String t ){
      title = t;
      }

      @Override
      public String toString() {
      return title;
      }

      @Override
      public Object getTransferData(DataFlavor flavor)
      throws UnsupportedFlavorException, IOException {
      if( flavor.equals( categoryFlavor ) )
      return this;

      return null;
      }

      @Override
      public DataFlavor[] getTransferDataFlavors() {
      return transferDataFlavors;
      }

      @Override
      public boolean isDataFlavorSupported(DataFlavor flavor) {
      return flavor.equals( categoryFlavor );
      }

      /**
      * Remove a child category from this category
      * @param n
      */
      public void removeSubcategory( final Category n, final DefaultTreeModel model ){
      int[] childIndex = new int[1];
      Object[] removedArray = new Object[1];
      childIndex[0] = getIndex( n );
      removedArray[0] = n;
      remove( n );
      model.nodesWereRemoved( this, childIndex, removedArray );
      }
      }
      }

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

            Unassigned Unassigned
            ndcosta Nelson Dcosta (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Imported:
              Indexed: