Reputation: 3823
I am currently experimenting with drag&drop using Java 7 Update 21.
My target operating systems are:
The requirements are:
drag files from the filesystem and drop it to my Java application (making a copy of the file to a temporary directory) -> works for Linux & MacOSX & Windows
drag e-mails from Thunderbird and drop them to my Java application (saving them as complete *.eml file on the filesystem)
The following code works with simple file drops to my application for Windows, MacOSX and Ubuntu. A further requirement is to drop e-mails from Thunderbird to my Java application (the mail is automatically converted to an *.eml file and stored to disk). This also works fine for Windows but I get a "Data Flavor not supported exception" in Ubuntu and MacOSX...
EDIT: I tried it with OpenJDK 7 on Ubuntu, but with that, even normal file drops doesn't work. Only with the JDK version of Oracle.
Does somebody has an idea how to fix / achieve that?
Many thanks in advance!
Here's a simple executeable sample:
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDropEvent;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.List;
public class DragDropTest extends javax.swing.JFrame {
public DragDropTest() {
initComponents();
initDragAndDrop();
}
private void initDragAndDrop() {
this.setDropTarget(new DropTarget(){
@Override
public synchronized void drop(DropTargetDropEvent dtde) {
try {
Transferable transfer = dtde.getTransferable();
if(transfer.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
List objects = (List)transfer.getTransferData(DataFlavor.javaFileListFlavor);
for(Object object : objects) {
if(object instanceof File) {
File source = (File)object;
File dest = new File(System.getProperty("user.home")+File.separator+source.getName());
Files.copy(Paths.get(source.getAbsolutePath()), Paths.get(dest.getAbsolutePath()), StandardCopyOption.REPLACE_EXISTING);
System.out.println("File copied from "+source.getAbsolutePath()+" to "+dest.getAbsolutePath());
}
}
} else if(transfer.isDataFlavorSupported(DataFlavor.stringFlavor)) {
dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
String type = (String)transfer.getTransferData(DataFlavor.stringFlavor);
System.err.println("Data flavor not supported: "+type);
} else {
System.err.println("Data flavor not supported.");
}
} catch(UnsupportedFlavorException ex) {
System.err.println(ex.getMessage());
} catch(IOException ex) {
System.err.println(ex.getMessage());
} catch(Exception ex) {
System.err.println(ex.getMessage());
} finally {
dtde.dropComplete(true);
}
}
});
}
@SuppressWarnings("unchecked")
private void initComponents() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("Drag & Drop");
setResizable(false);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 200, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 200, Short.MAX_VALUE)
);
pack();
}
public static void main(String args[]) {
new DragDropTest().setVisible(true);
}
}
Upvotes: 9
Views: 7862
Reputation: 3823
Here's a work-around how I finally solved the problem for the moment.
Required libraries: Apache Commons I/O and Java Mail API
The following is the drop event implementation:
scrDocuments.setDropTarget(new DropTarget() {
@Override
public synchronized void drop(DropTargetDropEvent evt) {
try {
Transferable transfer = evt.getTransferable();
if(transfer.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
List objects = (List)transfer.getTransferData(DataFlavor.javaFileListFlavor);
for(Object object : objects) {
if(object instanceof File) {
File file = (File)object;
// store file ...
}
}
} else {
try {
String url = fetchURL(evt, transfer);
ImapMessage eml = new ImapMessage(url);
File file = eml.fetchMessage();
// store file ...
} catch(Exception ex) {
System.err.println(ex.getMessage());
}
}
} catch(Exception ex) {
System.err.println(ex.getMessage());
} finally {
evt.dropComplete(true);
}
}
});
private String fetchURL(DropTargetDropEvent evt, Transferable transfer) throws IOException, UnsupportedEncodingException, UnsupportedFlavorException {
for(DataFlavor flavor : transfer.getTransferDataFlavors()) {
if(flavor.isRepresentationClassInputStream()) {
if(flavor.getHumanPresentableName().equals("application/x-moz-file-promise-url")) {
evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
BufferedReader reader = new BufferedReader(new InputStreamReader((InputStream)transfer.getTransferData(flavor), "ISO-8859-1"));
String fAddress = reader.readLine();
reader.close();
return fAddress;
}
}
}
throw new IOException("No transferable object or stream found.");
}
And the following class looks-up the imap server and fetches the mail:
public class ImapMessage {
private String authority;
private String protocol;
private String host;
private int port;
private String username;
private String password;
private String foldername;
private long msgid;
private String filename;
private Message message;
public ImapMessage(String url) throws IOException, MessagingException {
parseURL(decodeURL(url));
}
@Override
public String toString() {
return "protocol: "+protocol+"\n"+
"host: "+host+"\n"+
"port: "+port+"\n"+
"username: "+username+"\n"+
"password: "+password+"\n"+
"folder: "+foldername+"\n"+
"msgid: "+msgid+"\n"+
"filename: "+filename;
}
private String decodeURL(String url) throws IOException {
if(url!=null && !url.isEmpty()) {
String newurl = "";
for(int i=0; i<url.length(); i+=2) {
newurl+=url.substring(i, i+1);
}
newurl = StringUtils.replace(newurl, "%3E", ">");
newurl = StringUtils.replace(newurl, "%20", " ");
return newurl;
} else {
throw new IOException("The given URL is empty or invalid.");
}
}
private void parseURL(String url) throws IOException, MalformedURLException {
if(url!=null && !url.isEmpty()) {
//<editor-fold defaultstate="collapsed" desc="Parse Protocol">
if(url.startsWith("imaps")) {
url = StringUtils.replace(url, "imaps", "http", 1);
protocol = "imaps";
} else if(url.startsWith("imap")) {
url = StringUtils.replace(url, "imap", "http", 1);
protocol = "imap";
} else {
throw new IOException("Unsupported protocol: "+url.substring(0, url.indexOf("://")));
}
try {
URL newurl = new URL(url);
String path = newurl.getPath();
String query = newurl.getQuery();
authority = newurl.getAuthority();
host = newurl.getHost();
port = newurl.getPort();
username = newurl.getUserInfo();
password = "provide your password here";
foldername = path.substring(path.indexOf(">/")+2, path.lastIndexOf(">"));
msgid = Long.parseLong(path.substring(path.lastIndexOf(">")+1, path.length()));
filename = query.substring(query.indexOf("=")+1, query.length());
} catch (MalformedURLException ex) {
throw ex;
}
} else {
throw new IOException("The given URL is empty or invalid.");
}
}
public File fetchMessage() throws IOException, FileNotFoundException, MessagingException {
Store store = null;
Folder folder = null;
File filepath = new File("/destination/directory");
try {
Properties props = System.getProperties();
props.setProperty("mail.store.protocol", protocol);
Session session = Session.getDefaultInstance(props, null);
// session.setDebug(true);
store = session.getStore(protocol);
store.connect(host, port, username, password);
folder = store.getFolder(foldername);
folder.open(Folder.READ_ONLY);
UIDFolder ufolder = (UIDFolder)folder;
message = ufolder.getMessageByUID(msgid);
if(message!=null) {
File file = null;
if(filename.equals("null")) {
file = new File(filepath.getAbsolutePath()+File.separator+Long.toString(System.nanoTime())+".eml");
} else {
file = new File(filepath.getAbsolutePath()+File.separator+filename);
}
message.writeTo(new FileOutputStream(file));
return file;
} else {
throw new MessagingException("The requested e-mail could not be found on the mail server.");
}
} catch(Exception ex) {
throw ex;
} finally {
if(folder!=null) {
folder.close(true);
}
if(store!=null) {
store.close();
}
}
}
}
Upvotes: 0
Reputation: 94
I guess the following link will give you idea about the problem :-
http://softwareisart.blogspot.in/2011/11/drag-and-drop-of-complex-custom-objects.html
Upvotes: 1
Reputation: 439
Actually the problem is not in your Java code... It's a bug in ubuntu itself while Ubuntu Unity doesn't support Drag and Drop across two Windows (In your application between Mozilla Thunderbird and Java App). while it's possible to a drag and drop a file from the file system to a window..
To confirm this try to drag a mail file from Thunderbird to a browser windows as Gmail Attachment,,, it will not work.
To keep up with this bug review Bug updates in Ubuntu Bugs Launchpad from: https://bugs.launchpad.net/unity/+bug/995039
Upvotes: 6
Reputation: 25150
Instead of throwing, why not print out what data flavors you get on the transferable, and see if there is one you can use. Something like,
else {
for(DataFlavor f : transfer.getTransferDataFlavors()) {
System.out.println("flavor f:" + f + " type:" + f.getMimeType() + " javaClas:" + f.getDefaultRepresentationClass());
}
}
Given the output of that, there is a good chance you can see how to save it to a file.
Upvotes: 5