JDK-5071874 : Would like DropTargetDragEvent.acceptDrag(int dragOperation, File directory)
  • Type: Enhancement
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2004-07-07
  • Updated: 2006-08-31
  • Resolved: 2006-08-31
Related Reports
Duplicate :  
Description
Name: js151677			Date: 07/07/2004


A DESCRIPTION OF THE REQUEST :
I have a table that is essential a file browser similar to windows explorer.   With both awt DnD and swing DnD implementaions, I get notified that the dragEvent is a move unless the ctrl key is down.  This is not how windows explorer works.  In Windows explorer, dragging from one drive to another is a copy gesture, while dragging and dropping whithin a  drive is a move.  My users are complaining that my UI does not behave the same way as windows explorer and I have no way to work around the problem.    I assume that the reason I am always told this action is a move is because java has no way of knowing where the file will be dropped.

I would like some way to accept a drag of a file object in my dropTarget with an optional arguement to let the dragSource know where the file will be dropped.

Can you please add a new method to accept file objects with an arguement of directory that the file will be dropped in?

JUSTIFICATION :
  To provide a consistent look and feel with windows.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I would like drag and drop of files to behave the same as windows explorer in that some drops are copy actions even though there are no modifier keys down.
ACTUAL -
Currently dropping a file object is always a move unless there are modifier keys.

---------- BEGIN SOURCE ----------
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
import java.awt.dnd.*;
import java.awt.datatransfer.*;
import java.awt.*;

public class TestTableDnD extends JFrame implements DropTargetListener, DragGestureListener, DragSourceListener
{
    private JFrame fFrame;
    private JTable fTable;

    public TestTableDnD()
    {
        fFrame = new JFrame("Test DnD in Table");
        TableModel dataModel = new AbstractTableModel() {
                  public int getColumnCount() { return 10; }
                  public int getRowCount() { return 10;}
                  public Object getValueAt(int row, int col) { return new Integer(row*col); }
              };
          fTable = new JTable(dataModel);
          JScrollPane scrollpane = new JScrollPane(fTable);

        fFrame.getContentPane().add(scrollpane);

        fTable.setDragEnabled(true);
        fTable.setDropTarget(new DropTarget(this, // component
            DnDConstants.ACTION_COPY_OR_MOVE, // actions
            this)); // DropTargetListener
        fTable.setTransferHandler(new FBDefaultTransferHandler());

        fFrame.setSize(300,300);
        fFrame.setVisible(true);


    }
    public static void main(String[] args)
    {
        new TestTableDnD();
    }


    // DragGestureListener implementation begins  -------------------------
    public void dragGestureRecognized(DragGestureEvent dge)
    {
       /* this doesn't matter for test */
    }

    // DragSourceListener implementation begins --------------------------
    // These methods are also part of DragSourceListener.
    // They are invoked at interesting points during the drag, and can be
    // used to perform "drag over" effects, such as changing the drag cursor
    // or drag image.
    public void dragEnter(DragSourceDragEvent dsde)
    {

        Cursor newCursor = null;
        Cursor currentCursor = dsde.getDragSourceContext().getCursor();
        switch (dsde.getUserAction())
        {
            case DnDConstants.ACTION_COPY:
                if (!currentCursor.equals(DragSource.DefaultCopyDrop))
                {
                    newCursor = DragSource.DefaultCopyDrop;
                }
                break;
            case DnDConstants.ACTION_MOVE:
                if (!currentCursor.equals(DragSource.DefaultMoveDrop))
                {
                    newCursor = DragSource.DefaultMoveDrop;
                }
                break;
            default:
                newCursor = DragSource.DefaultCopyDrop;
                break;
        }
        if (newCursor != null)
            dsde.getDragSourceContext().setCursor(newCursor);

    }

    public void dragExit(DragSourceEvent dsde)
    {
        dsde.getDragSourceContext().setCursor(DragSource.DefaultCopyNoDrop);
    }

    public void dragOver(DragSourceDragEvent dsde)
    {
        Cursor newCursor = null;
        Cursor currentCursor = dsde.getDragSourceContext().getCursor();
        switch (dsde.getUserAction())
        {
            case DnDConstants.ACTION_COPY:
                if (!currentCursor.equals(DragSource.DefaultCopyDrop))
                {
                    newCursor = DragSource.DefaultCopyDrop;
                }
                break;
            case DnDConstants.ACTION_MOVE:
                if (!currentCursor.equals(DragSource.DefaultMoveDrop))
                {
                    newCursor = DragSource.DefaultMoveDrop;
                }
                break;
            default:
                newCursor = DragSource.DefaultCopyDrop;
                break;
        }
        if (newCursor != null)
            dsde.getDragSourceContext().setCursor(newCursor);
    }

    public void dropActionChanged(DragSourceDragEvent dsde)
    {
    }

    /**
     * dragDropEnd() is invoked when the drag & drop is completed.
     **/
    public void dragDropEnd(DragSourceDropEvent e)
    {
         /* this doesn't matter for test */
    }
    // DragSourceListener implementation ends  ----------------------------

    // DropTargetListener implementation begins  --------------------------
    public void dragEnter(DropTargetDragEvent dtde)
    {
        if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
        {
            dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
        }
        else
        {
            dtde.rejectDrag();
        }
    }

    public void dragExit(DropTargetEvent dte)
    {
    }

    public void dragOver(DropTargetDragEvent dtde)
    {
        if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
        {
            dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
		    return;   //get out.
	    }
        //if not a file flavor, reject.
	    dtde.rejectDrag();
    }

    public void drop(DropTargetDropEvent dtde)
    {
        if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
        {
            dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);

            if (dtde.getDropAction() == DnDConstants.ACTION_MOVE)
                System.out.println("drop - MOVE");
            else
                System.out.println("drop - COPY");

            //do stuff to drop.  not relevant to test.
            dtde.dropComplete(true);

            return;
        }

        //If there was not a transferable object we are interested in then
        //reject the drop.
        dtde.rejectDrop();
    }

    public void dropActionChanged(DropTargetDragEvent dtde)
    {
    }

    class FBDefaultTransferHandler extends TransferHandler
    {



        public void exportToClipboard(JComponent comp, Clipboard clipboard,
                                      int action)
        {
            // Not important for test example
        }

        public void exportDone(JComponent source,
                               Transferable data,
                               int action)
        {
            cleanup(source, action == MOVE);
        }


        //If the remove argument is true, the drop has been
        //successful and it's time to remove the selected items
        //from the list. If the remove argument is false, it
        //was a Copy operation and the original list is left
        //intact.
        protected void cleanup(JComponent c, boolean remove) {

        }

        /**
         * This is called to paste.  Gets data off the clipboard.
         * @param comp
         * @param t
         * @return successful import
         */
        public boolean importData(JComponent comp, Transferable t)
        {
           // Not important for test example

            return false;
        }

        private DataFlavor getFlavor(DataFlavor[] flavors)
        {

            if (flavors != null)
            {
                for (int counter = 0; counter < flavors.length; counter++)
                {
                    if (flavors[counter].equals(DataFlavor.javaFileListFlavor))
                    {
                        return flavors[counter];
                    }
                }
            }
            return null;
        }

        /**
            * Does the flavor list have a file flavor?
            */
           protected boolean hasFileFlavor(DataFlavor[] flavors) {


            for (int i = 0; i < flavors.length; i++) {
                   if (DataFlavor.javaFileListFlavor.equals(flavors[i])) {
                       return true;
                   }
               }
               return false;
           }

           /**
            * Overridden to include a check for a file flavor.
            */
           public boolean canImport(JComponent c, DataFlavor[] flavors) {
               return hasFileFlavor(flavors);
           }

            public int getSourceActions(JComponent c) {
                    return COPY_OR_MOVE;
           }

           protected Transferable createTransferable(JComponent c) {
               // Not important for test example
               Transferable trans = new StringSelection("");
               return trans;
           }



    }


}

---------- END SOURCE ----------
(Incident Review ID: 284965) 
======================================================================

Comments
EVALUATION This can be closed now that 4869264 is fixed. The decision whether to copy or move should be up to the drop target. It can query the transferable, and if it decides to make it a copy, it can call acceptDrag(COPY).
31-08-2006

EVALUATION The submitter's proposal [Would like DropTargetDragEvent.acceptDrag(int dragOperation, File directory)] is too specific. As of JDK 1.5.0, DropTargetDragEvent has the method getTransferable(), and after the RFE 4869264 (drag & drop action negotiation does not honor the targets supported actions) is implemented, one will be able to achieve the desired functionality. So this issue will be fixed along with 4869264. ###@###.### 2004-08-17
17-08-2004