I am looking for a method to perform a drag-and-drop of a file/multiple files onto my application from a unit test. For example selecting some files in Windows Explorer, drag them and drop them on my application.
I am capable of testing drag-and-drop behavior between two components in my application (see below - feel free to indicate if you know a better way), but I have no idea how to do the same when the data has to come from outside my application.
I thought about using the debugger to inspect a 'file' Transferable
when I do the drag-and-drop operation by hand, but there must be a better way then hard-coding a complete Transferable
.
Example of a drag-and-drop test between components
import org.junit.Test;
import javax.swing.Action;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
import java.awt.event.ActionEvent;
import static org.junit.Assert.assertEquals;
public class DragAndDropTest {
@Test
public void dragAndDropBetweenTwoTextFields() {
JTextField firstField = new JTextField();
JTextField secondField = new JTextField();
String testText = "Test text";
firstField.setText( testText );
firstField.selectAll();
Action copyAction = TransferHandler.getCopyAction();
copyAction.actionPerformed( new ActionEvent( firstField, ActionEvent.ACTION_PERFORMED, "Copy" ) );
Action pasteAction = TransferHandler.getPasteAction();
pasteAction.actionPerformed( new ActionEvent( secondField, ActionEvent.ACTION_PERFORMED, "Paste" ) );
assertEquals( "Text is not copied", testText, secondField.getText() );
}
}
Edit
Based on the comments under this question, I have updated my code snippet to 'fake' a drag-and-drop by providing a hard-coded Transferable
. The code also contains a little main program which just creates an empty frame on which you can drop files. The path will then be printed on the console.
On my PC, drag-and-drop of a file does not use the javaFileListFlavor
but the URI flavor.
Previous experiences (see this question) already teached me that the Transferable
a component receives when dragging something from outside the Java application might differ in subtle ways.
So to be completely clear: I want to test the part of my code that extracts the information from the received Transferable
. The 'information-handling' code (e.g. what happens when the application receives the file) can easily be tested without bothering with D&D. I just need to make sure I extract the correct information from the Transferable
, and it is silly to test this with a hard-coded Transferable
.
import org.junit.Test;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.TransferHandler;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import java.util.List;
import static org.junit.Assert.assertEquals;
public class DragAndDropTest {
private static DataFlavor URI_LIST_FLAVOR = null;
static {
try {
URI_LIST_FLAVOR = new DataFlavor( "text/uri-list;class=java.lang.String" );
}
catch ( ClassNotFoundException ignore ) {
}
}
@Test
public void testFileDragAndDrop() throws IOException, UnsupportedFlavorException {
JComponent testComponent = new JPanel();
TestingTransferHandler transferHandler = new TestingTransferHandler();
testComponent.setTransferHandler( transferHandler );
Clipboard clipBoard = new JLabel( ).getToolkit().getSystemClipboard();
Transferable transferable = new Transferable() {
@Override
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{URI_LIST_FLAVOR};
}
@Override
public boolean isDataFlavorSupported( DataFlavor flavor ) {
return flavor == URI_LIST_FLAVOR;
}
@Override
public Object getTransferData( DataFlavor flavor ) throws UnsupportedFlavorException, IOException {
if ( flavor == URI_LIST_FLAVOR ) {
return new String( "file:///home/robins/Desktop/swingx-1.0-javadoc.jar" );
}
throw new UnsupportedFlavorException( flavor );
}
};
clipBoard.setContents( transferable, null );
Action pasteAction = TransferHandler.getPasteAction();
pasteAction.actionPerformed( new ActionEvent( testComponent, ActionEvent.ACTION_PERFORMED, "Paste" ) );
assertEquals( transferable.getTransferData( URI_LIST_FLAVOR ), transferHandler.transferable.getTransferData( URI_LIST_FLAVOR ) );
}
private static class TestingTransferHandler extends TransferHandler{
public Transferable transferable;
@Override
public boolean canImport( TransferSupport support ) {
return true;
}
@Override
public boolean importData( TransferSupport support ) {
transferable = support.getTransferable();
try{
if ( transferable.isDataFlavorSupported( DataFlavor.javaFileListFlavor ) ) {
System.out.println("File list flavor");
List<File> fileList = ( List<File> ) transferable.getTransferData( DataFlavor.javaFileListFlavor );
System.out.println( "fileList = " + fileList );
}
if ( transferable.isDataFlavorSupported( URI_LIST_FLAVOR )){
System.out.println("URI list flavor");
String uriList = ( String ) transferable.getTransferData( URI_LIST_FLAVOR );
System.out.println( "uriList = " + uriList );
}
return true;
} catch ( UnsupportedFlavorException e ) {
return false;
} catch ( IOException e ) {
return false;
}
}
}
public static void main( String[] args ) {
EventQueue.invokeLater( new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame( "TestFrame" );
JPanel contentPane = new JPanel( new BorderLayout( ) );
contentPane.setTransferHandler( new TestingTransferHandler() );
frame.setContentPane( contentPane );
frame.setSize( 200,200 );
frame.setVisible( true );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
} );
}
}