Java 7:如何在Java中实现拖放?

9

我目前正在尝试使用Java 7 Update 21进行拖放实验。

我的目标操作系统是:

  • Windows 7
  • Ubuntu 12.04
  • Mac OSX 10.6 / 10.8

要求如下:

  • 从文件系统中拖动文件并将其放到我的Java应用程序中(将文件复制到临时目录)-> 适用于Linux和MacOSX和Windows

  • 从Thunderbird中拖动电子邮件并将其放到我的Java应用程序中(将其保存为完整的*.eml文件到文件系统中)

以下代码适用于Windows,MacOSX Ubuntu对我的应用程序进行简单的文件拖放。进一步的要求是将来自Thunderbird的电子邮件拖放到我的Java应用程序中(该邮件会自动转换为*.eml文件并存储到磁盘中)。这在Windows上也很好用,但是在Ubuntu和MacOSX中我会得到一个"Data Flavor not supported exception"...

编辑:我已经在Ubuntu上尝试了OpenJDK 7,但即使是正常的文件拖放也无法工作。只有使用Oracle的JDK版本才能正常工作。

有人有想法如何解决/实现吗?

非常感谢!

这里是一个简单的可执行示例:

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);
    }

}
4个回答

6
实际上问题不在你的Java代码中...这是Ubuntu本身的一个bug,因为Ubuntu Unity不支持在两个窗口之间(例如Mozilla Thunderbird和Java应用程序之间)拖放。虽然从文件系统向窗口拖放文件是可能的...
要确认这一点,请尝试将Thunderbird中的邮件文件拖动到浏览器窗口作为Gmail附件,它不起作用。
要跟进此错误,请查看Ubuntu Bugs Launchpad中的错误更新: https://bugs.launchpad.net/unity/+bug/995039

谢谢您的建议。我尝试使用“sudo apt-get purge mousetweaks”来删除Mousetweaks,但它仍然无法正常工作... :-( - salocinx

5

与其抛出异常,为什么不打印出传输数据类型以查看是否存在可用的数据类型。可以采用以下方式:

 else { 
      for(DataFlavor f : transfer.getTransferDataFlavors()) {
             System.out.println("flavor f:" + f + " type:" + f.getMimeType() + " javaClas:" + f.getDefaultRepresentationClass());  
      }
 }

根据这个输出,你很有可能知道如何将其保存到文件中。


1
再进一步,打印出您得到的信息并尝试操作它,也许将所有内容保存到文件中,然后查看.eml文件,尽管我怀疑只有一个会被设置。如果您没有获得任何可用的信息,可能是*nix下Thunderbird的问题。 - tgkprog


0

以下是一个解决方案,我用它来解决了目前的问题。

  1. 如果不支持文件列表格式,请从拖放事件获取 IMAP URL
  2. 使用提供的 IMAP URL 打开 IMAP 连接
  3. 打开 IMAP 存储、IMAP 文件夹,按 UID 搜索邮件,最后提取消息
  4. 转换为 *.eml 格式

所需库:Apache Commons I/OJava Mail API

以下是拖放事件的实现:

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.");
}

以下类查找IMAP服务器并获取邮件:
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();
                }
            }
        }

    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接