/* * @(#)TransferHandlerTest.java * * Copyright (c) 2007-2010 Werner Randelshofer, Immensee, Switzerland. * All rights reserved. * * The copyright of this software is owned by Werner Randelshofer. * You may not use, copy or modify this software, except in * accordance with the license agreement you entered into with * Werner Randelshofer. For details see accompanying license terms. */ package test; import ch.randelshofer.quaqua.QuaquaManager; import java.awt.datatransfer.*; import java.awt.event.*; import java.io.*; import java.util.*; import javax.swing.*; import javax.swing.table.*; /** * TransferHandlerTest. * * @author Werner Randelshofer * @version $Id: TransferHandlerTest.java 363 2010-11-21 17:41:04Z wrandelshofer $ */ public class TransferHandlerTest extends javax.swing.JPanel { static class TableTransferHandler extends TransferHandler { public TableTransferHandler() { } /** * Create a Transferable to use as the source for a data transfer. * * @param c The component holding the data to be transfered. This * argument is provided to enable sharing of TransferHandlers by * multiple components. * @return The representation of the data to be transfered. * */ protected Transferable createTransferable(JComponent c) { if (c instanceof JTable) { JTable table = (JTable) c; int[] rows; int[] cols; if (!table.getRowSelectionAllowed() && !table.getColumnSelectionAllowed()) { return null; } if (!table.getRowSelectionAllowed()) { int rowCount = table.getRowCount(); rows = new int[rowCount]; for (int counter = 0; counter < rowCount; counter++) { rows[counter] = counter; } } else { rows = table.getSelectedRows(); } if (!table.getColumnSelectionAllowed()) { int colCount = table.getColumnCount(); cols = new int[colCount]; for (int counter = 0; counter < colCount; counter++) { cols[counter] = counter; } } else { cols = table.getSelectedColumns(); } if (rows == null || cols == null || rows.length == 0 || cols.length == 0) { return null; } StringBuffer plainBuf = new StringBuffer(); StringBuffer htmlBuf = new StringBuffer(); htmlBuf.append("<html>\n<body>\n<table>\n"); for (int row = 0; row < rows.length; row++) { htmlBuf.append("<tr>\n"); for (int col = 0; col < cols.length; col++) { Object obj = table.getValueAt(rows[row], cols[col]); String val = ((obj == null) ? "" : obj.toString()); plainBuf.append(val + "\t"); htmlBuf.append(" <td>" + val + "</td>\n"); } // we want a newline at the end of each line and not a tab plainBuf.deleteCharAt(plainBuf.length() - 1).append("\n"); htmlBuf.append("</tr>\n"); } // remove the last newline plainBuf.deleteCharAt(plainBuf.length() - 1); htmlBuf.append("</table>\n</body>\n</html>"); return new BasicTransferable(plainBuf.toString(), htmlBuf.toString()); } return null; } public int getSourceActions(JComponent c) { return COPY; } public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) { if (comp instanceof JTable) { for (int i = 0; i < transferFlavors.length; i++) { if (transferFlavors[i].equals(DataFlavor.javaFileListFlavor)) { return true; } } } return false; } /** * Causes a transfer to a component from a clipboard or a * DND drop operation. The <code>Transferable</code> represents * the data to be imported into the component. * * @param comp the component to receive the transfer; this * argument is provided to enable sharing of <code>TransferHandler</code>s * by multiple components * @param t the data to import * @return true if the data was inserted into the component, false otherwise */ public boolean importData(JComponent comp, Transferable t) { JTable table = (JTable) comp; System.out.println("TransferHandler.importData " + comp + " " + t); if (table.getModel() instanceof DefaultTableModel) { DefaultTableModel dtm = (DefaultTableModel) table.getModel(); if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { java.util.List fileList; try { fileList = (java.util.List) t.getTransferData(DataFlavor.javaFileListFlavor); for (Iterator i = fileList.iterator(); i.hasNext();) { File file = (File) i.next(); Object[] rowData = new Object[dtm.getColumnCount()]; switch (rowData.length) { case 0: break; default: // run through case 4: rowData[3] = file.isDirectory() ? "Directory" : "File"; // run through case 3: rowData[2] = new Double(file.length()); // run through case 2: rowData[1] = new Date(file.lastModified()).toString(); // run through case 1: rowData[0] = file.getName(); // run through } dtm.addRow(rowData); } return true; } catch (UnsupportedFlavorException ex) { ex.printStackTrace(); } catch (IOException ex) { ex.printStackTrace(); } } } return false; } } static class BasicTransferable implements Transferable { protected String plainData; protected String htmlData; private static DataFlavor[] htmlFlavors; private static DataFlavor[] stringFlavors; private static DataFlavor[] plainFlavors; static { try { htmlFlavors = new DataFlavor[3]; htmlFlavors[0] = new DataFlavor("text/html;class=java.lang.String"); htmlFlavors[1] = new DataFlavor("text/html;class=java.io.Reader"); htmlFlavors[2] = new DataFlavor("text/html;charset=unicode;class=java.io.InputStream"); plainFlavors = new DataFlavor[3]; plainFlavors[0] = new DataFlavor("text/plain;class=java.lang.String"); plainFlavors[1] = new DataFlavor("text/plain;class=java.io.Reader"); plainFlavors[2] = new DataFlavor("text/plain;charset=unicode;class=java.io.InputStream"); stringFlavors = new DataFlavor[2]; stringFlavors[0] = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType + ";class=java.lang.String"); stringFlavors[1] = DataFlavor.stringFlavor; } catch (ClassNotFoundException cle) { System.err.println("error initializing javax.swing.plaf.basic.BasicTranserable"); } } public BasicTransferable(String plainData, String htmlData) { this.plainData = plainData; this.htmlData = htmlData; } /** * Returns an array of DataFlavor objects indicating the flavors the data * can be provided in. The array should be ordered according to preference * for providing the data (from most richly descriptive to least descriptive). * @return an array of data flavors in which this data can be transferred */ public DataFlavor[] getTransferDataFlavors() { DataFlavor[] richerFlavors = getRicherFlavors(); int nRicher = (richerFlavors != null) ? richerFlavors.length : 0; int nHTML = (isHTMLSupported()) ? htmlFlavors.length : 0; int nPlain = (isPlainSupported()) ? plainFlavors.length : 0; int nString = (isPlainSupported()) ? stringFlavors.length : 0; int nFlavors = nRicher + nHTML + nPlain + nString; DataFlavor[] flavors = new DataFlavor[nFlavors]; // fill in the array int nDone = 0; if (nRicher > 0) { System.arraycopy(richerFlavors, 0, flavors, nDone, nRicher); nDone += nRicher; } if (nHTML > 0) { System.arraycopy(htmlFlavors, 0, flavors, nDone, nHTML); nDone += nHTML; } if (nPlain > 0) { System.arraycopy(plainFlavors, 0, flavors, nDone, nPlain); nDone += nPlain; } if (nString > 0) { System.arraycopy(stringFlavors, 0, flavors, nDone, nString); nDone += nString; } return flavors; } /** * Returns whether or not the specified data flavor is supported for * this object. * @param flavor the requested flavor for the data * @return boolean indicating whether or not the data flavor is supported */ public boolean isDataFlavorSupported(DataFlavor flavor) { DataFlavor[] flavors = getTransferDataFlavors(); for (int i = 0; i < flavors.length; i++) { if (flavors[i].equals(flavor)) { return true; } } return false; } /** * Returns an object which represents the data to be transferred. The class * of the object returned is defined by the representation class of the flavor. * * @param flavor the requested flavor for the data * @see DataFlavor#getRepresentationClass * @exception IOException if the data is no longer available * in the requested flavor. * @exception UnsupportedFlavorException if the requested data flavor is * not supported. */ public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { if (isRicherFlavor(flavor)) { return getRicherData(flavor); } else if (isHTMLFlavor(flavor)) { String data = getHTMLData(); data = (data == null) ? "" : data; if (String.class.equals(flavor.getRepresentationClass())) { return data; } else if (Reader.class.equals(flavor.getRepresentationClass())) { return new StringReader(data); } else if (InputStream.class.equals(flavor.getRepresentationClass())) { String charsetName = flavor.getParameter("charset"); return new ByteArrayInputStream(data.getBytes(charsetName == null ? "UTF-8" : charsetName)); //return new StringBufferInputStream(data); } // fall through to unsupported } else if (isPlainFlavor(flavor)) { String data = getPlainData(); data = (data == null) ? "" : data; if (String.class.equals(flavor.getRepresentationClass())) { return data; } else if (Reader.class.equals(flavor.getRepresentationClass())) { return new StringReader(data); } else if (InputStream.class.equals(flavor.getRepresentationClass())) { String charsetName = flavor.getParameter("charset"); return new ByteArrayInputStream(data.getBytes(charsetName == null ? "UTF-8" : charsetName)); //return new StringBufferInputStream(data); } // fall through to unsupported } else if (isStringFlavor(flavor)) { String data = getPlainData(); data = (data == null) ? "" : data; return data; } throw new UnsupportedFlavorException(flavor); } // --- richer subclass flavors ---------------------------------------------- protected boolean isRicherFlavor(DataFlavor flavor) { DataFlavor[] richerFlavors = getRicherFlavors(); int nFlavors = (richerFlavors != null) ? richerFlavors.length : 0; for (int i = 0; i < nFlavors; i++) { if (richerFlavors[i].equals(flavor)) { return true; } } return false; } /** * Some subclasses will have flavors that are more descriptive than HTML * or plain text. If this method returns a non-null value, it will be * placed at the start of the array of supported flavors. */ protected DataFlavor[] getRicherFlavors() { return null; } protected Object getRicherData(DataFlavor flavor) throws UnsupportedFlavorException { return null; } // --- html flavors ---------------------------------------------------------- /** * Returns whether or not the specified data flavor is an HTML flavor that * is supported. * @param flavor the requested flavor for the data * @return boolean indicating whether or not the data flavor is supported */ protected boolean isHTMLFlavor(DataFlavor flavor) { DataFlavor[] flavors = htmlFlavors; for (int i = 0; i < flavors.length; i++) { if (flavors[i].equals(flavor)) { return true; } } return false; } /** * Should the HTML flavors be offered? If so, the method * getHTMLData should be implemented to provide something reasonable. */ protected boolean isHTMLSupported() { return htmlData != null; } /** * Fetch the data in a text/html format */ protected String getHTMLData() { return htmlData; } // --- plain text flavors ---------------------------------------------------- /** * Returns whether or not the specified data flavor is an plain flavor that * is supported. * @param flavor the requested flavor for the data * @return boolean indicating whether or not the data flavor is supported */ protected boolean isPlainFlavor(DataFlavor flavor) { DataFlavor[] flavors = plainFlavors; for (int i = 0; i < flavors.length; i++) { if (flavors[i].equals(flavor)) { return true; } } return false; } /** * Should the plain text flavors be offered? If so, the method * getPlainData should be implemented to provide something reasonable. */ protected boolean isPlainSupported() { return plainData != null; } /** * Fetch the data in a text/plain format. */ protected String getPlainData() { return plainData; } // --- string flavorss -------------------------------------------------------- /** * Returns whether or not the specified data flavor is a String flavor that * is supported. * @param flavor the requested flavor for the data * @return boolean indicating whether or not the data flavor is supported */ protected boolean isStringFlavor(DataFlavor flavor) { DataFlavor[] flavors = stringFlavors; for (int i = 0; i < flavors.length; i++) { if (flavors[i].equals(flavor)) { return true; } } return false; } } /** * Creates new form TransferHandlerTest */ public TransferHandlerTest() { initComponents(); table.setTransferHandler(new TableTransferHandler()); table.setDragEnabled(true); } public static void main(String[] args) { try { UIManager.setLookAndFeel(QuaquaManager.getLookAndFeel()); UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); } catch (Exception ex) { ex.printStackTrace(); } JFrame f = new JFrame("TransferHandlerText"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.getContentPane().add(new TransferHandlerTest()); f.setVisible(true); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; scrollPane = new javax.swing.JScrollPane(); table = new javax.swing.JTable(); jLabel1 = new javax.swing.JLabel(); jButton1 = new javax.swing.JButton(); setLayout(new java.awt.GridBagLayout()); table.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { {null, null, null, null} }, new String [] { "Name", "Last Modified", "Length", "Kind" } ) { Class[] types = new Class [] { java.lang.String.class, java.lang.String.class, java.lang.Long.class, java.lang.String.class }; boolean[] canEdit = new boolean [] { false, false, false, false }; public Class getColumnClass(int columnIndex) { return types [columnIndex]; } public boolean isCellEditable(int rowIndex, int columnIndex) { return canEdit [columnIndex]; } }); scrollPane.setViewportView(table); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridheight = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(scrollPane, gridBagConstraints); jLabel1.setText("Drag a file into the table."); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 0); add(jLabel1, gridBagConstraints); jButton1.setText("JFileChooser"); jButton1.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { openFileChooser(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridy = 1; add(jButton1, gridBagConstraints); }// </editor-fold>//GEN-END:initComponents private void openFileChooser(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openFileChooser JFileChooser fileChooser; fileChooser = new JFileChooser(); fileChooser.setDragEnabled(true); final JDialog dialog = new JDialog(); dialog.setContentPane(fileChooser); dialog.pack(); dialog.setVisible(true); dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); fileChooser.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { dialog.dispose(); } }); fileChooser.showOpenDialog(this); }//GEN-LAST:event_openFileChooser // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton jButton1; private javax.swing.JLabel jLabel1; private javax.swing.JScrollPane scrollPane; private javax.swing.JTable table; // End of variables declaration//GEN-END:variables }