1 /*
2  * TransferHandlerTest14.java
3  *
4  * Created on January 15, 2007, 11:44 AM
5  */
6 
7 package test;
8 
9 import ch.randelshofer.quaqua.QuaquaManager;
10 import java.awt.datatransfer.*;
11 import java.awt.event.*;
12 import java.io.*;
13 import java.util.*;
14 import javax.swing.*;
15 import javax.swing.table.*;
16 
17 /**
18  *
19  * @author  werni
20  */
21 public class TransferHandlerTest14 extends javax.swing.JPanel {
22     static class TableTransferHandler extends TransferHandler {
23 
TableTransferHandler()24         public TableTransferHandler() {
25         }
26 
27         /**
28          * Create a Transferable to use as the source for a data transfer.
29          *
30          * @param c  The component holding the data to be transfered.  This
31          *  argument is provided to enable sharing of TransferHandlers by
32          *  multiple components.
33          * @return  The representation of the data to be transfered.
34          *
35          */
createTransferable(JComponent c)36         protected Transferable createTransferable(JComponent c) {
37             if (c instanceof JTable) {
38                 JTable table = (JTable) c;
39                 int[] rows;
40                 int[] cols;
41 
42                 if (!table.getRowSelectionAllowed() && !table.getColumnSelectionAllowed()) {
43                     return null;
44                 }
45 
46                 if (!table.getRowSelectionAllowed()) {
47                     int rowCount = table.getRowCount();
48 
49                     rows = new int[rowCount];
50                     for (int counter = 0; counter < rowCount; counter++) {
51                         rows[counter] = counter;
52                     }
53                 } else {
54                     rows = table.getSelectedRows();
55                 }
56 
57                 if (!table.getColumnSelectionAllowed()) {
58                     int colCount = table.getColumnCount();
59 
60                     cols = new int[colCount];
61                     for (int counter = 0; counter < colCount; counter++) {
62                         cols[counter] = counter;
63                     }
64                 } else {
65                     cols = table.getSelectedColumns();
66                 }
67 
68                 if (rows == null || cols == null || rows.length == 0 || cols.length == 0) {
69                     return null;
70                 }
71 
72                 StringBuffer plainBuf = new StringBuffer();
73                 StringBuffer htmlBuf = new StringBuffer();
74 
75                 htmlBuf.append("<html>\n<body>\n<table>\n");
76 
77                 for (int row = 0; row < rows.length; row++) {
78                     htmlBuf.append("<tr>\n");
79                     for (int col = 0; col < cols.length; col++) {
80                         Object obj = table.getValueAt(rows[row], cols[col]);
81                         String val = ((obj == null) ? "" : obj.toString());
82                         plainBuf.append(val + "\t");
83                         htmlBuf.append("  <td>" + val + "</td>\n");
84                     }
85                     // we want a newline at the end of each line and not a tab
86                     plainBuf.deleteCharAt(plainBuf.length() - 1).append("\n");
87                     htmlBuf.append("</tr>\n");
88                 }
89 
90                 // remove the last newline
91                 plainBuf.deleteCharAt(plainBuf.length() - 1);
92                 htmlBuf.append("</table>\n</body>\n</html>");
93 
94                 return new BasicTransferable(plainBuf.toString(), htmlBuf.toString());
95             }
96 
97             return null;
98         }
99 
getSourceActions(JComponent c)100         public int getSourceActions(JComponent c) {
101             return COPY;
102         }
canImport(JComponent comp, DataFlavor[] transferFlavors)103         public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
104             if (comp instanceof JTable) {
105                 for (int i=0;i < transferFlavors.length; i++) {
106                     if (transferFlavors[i].equals(DataFlavor.javaFileListFlavor)) {
107                         return true;
108                     }
109                 }
110             }
111             return false;
112         }
113         /**
114          * Causes a transfer to a component from a clipboard or a
115          * DND drop operation.  The <code>Transferable</code> represents
116          * the data to be imported into the component.
117          *
118          * @param comp  the component to receive the transfer; this
119          *  argument is provided to enable sharing of <code>TransferHandler</code>s
120          *  by multiple components
121          * @param t     the data to import
122          * @return  true if the data was inserted into the component, false otherwise
123          */
importData(JComponent comp, Transferable t)124         public boolean importData(JComponent comp, Transferable t) {
125             JTable table = (JTable) comp;
126             System.out.println("TransferHandler.importData "+comp+" "+t);
127             if (table.getModel() instanceof DefaultTableModel) {
128                 DefaultTableModel dtm = (DefaultTableModel) table.getModel();
129                 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
130                     java.util.List fileList;
131                     try {
132                         fileList = (java.util.List) t.getTransferData(DataFlavor.javaFileListFlavor);
133                         for (Iterator i=fileList.iterator(); i.hasNext(); ) {
134                             File file = (File) i.next();
135                             Object[] rowData = new Object[dtm.getColumnCount()];
136                             switch (rowData.length) {
137                                 case 0 :
138                                     break;
139                                 default :
140                                     // run through
141                                 case 4 :
142                                     rowData[3] = file.isDirectory() ? "Directory" : "File";
143                                     // run through
144                                 case 3 :
145                                     rowData[2] = new Double(file.length());
146                                     // run through
147                                 case 2 :
148                                     rowData[1] = new Date(file.lastModified()).toString();
149                                     // run through
150                                 case 1 :
151                                     rowData[0] = file.getName();
152                                     // run through
153                             }
154                             dtm.addRow(rowData);
155                         }
156                         return true;
157                     } catch (UnsupportedFlavorException ex) {
158                         ex.printStackTrace();
159                     } catch (IOException ex) {
160                         ex.printStackTrace();
161                     }
162                 }
163             }
164             return false;
165         }
166     }
167 
168     static class BasicTransferable implements Transferable {
169 
170         protected String plainData;
171         protected String htmlData;
172 
173         private static DataFlavor[] htmlFlavors;
174         private static DataFlavor[] stringFlavors;
175         private static DataFlavor[] plainFlavors;
176 
177         static {
178             try {
179                 htmlFlavors = new DataFlavor[3];
180                 htmlFlavors[0] = new DataFlavor("text/html;class=java.lang.String");
181                 htmlFlavors[1] = new DataFlavor("text/html;class=java.io.Reader");
182                 htmlFlavors[2] = new DataFlavor("text/html;charset=unicode;class=java.io.InputStream");
183 
184                 plainFlavors = new DataFlavor[3];
185                 plainFlavors[0] = new DataFlavor("text/plain;class=java.lang.String");
186                 plainFlavors[1] = new DataFlavor("text/plain;class=java.io.Reader");
187                 plainFlavors[2] = new DataFlavor("text/plain;charset=unicode;class=java.io.InputStream");
188 
189                 stringFlavors = new DataFlavor[2];
190                 stringFlavors[0] = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType+";class=java.lang.String");
191                 stringFlavors[1] = DataFlavor.stringFlavor;
192 
193             } catch (ClassNotFoundException cle) {
194                 System.err.println("error initializing javax.swing.plaf.basic.BasicTranserable");
195             }
196         }
197 
BasicTransferable(String plainData, String htmlData)198         public BasicTransferable(String plainData, String htmlData) {
199             this.plainData = plainData;
200             this.htmlData = htmlData;
201         }
202 
203 
204         /**
205          * Returns an array of DataFlavor objects indicating the flavors the data
206          * can be provided in.  The array should be ordered according to preference
207          * for providing the data (from most richly descriptive to least descriptive).
208          * @return an array of data flavors in which this data can be transferred
209          */
getTransferDataFlavors()210         public DataFlavor[] getTransferDataFlavors() {
211             DataFlavor[] richerFlavors = getRicherFlavors();
212             int nRicher = (richerFlavors != null) ? richerFlavors.length : 0;
213             int nHTML = (isHTMLSupported()) ? htmlFlavors.length : 0;
214             int nPlain = (isPlainSupported()) ? plainFlavors.length: 0;
215             int nString = (isPlainSupported()) ? stringFlavors.length : 0;
216             int nFlavors = nRicher + nHTML + nPlain + nString;
217             DataFlavor[] flavors = new DataFlavor[nFlavors];
218 
219             // fill in the array
220             int nDone = 0;
221             if (nRicher > 0) {
222                 System.arraycopy(richerFlavors, 0, flavors, nDone, nRicher);
223                 nDone += nRicher;
224             }
225             if (nHTML > 0) {
226                 System.arraycopy(htmlFlavors, 0, flavors, nDone, nHTML);
227                 nDone += nHTML;
228             }
229             if (nPlain > 0) {
230                 System.arraycopy(plainFlavors, 0, flavors, nDone, nPlain);
231                 nDone += nPlain;
232             }
233             if (nString > 0) {
234                 System.arraycopy(stringFlavors, 0, flavors, nDone, nString);
235                 nDone += nString;
236             }
237             return flavors;
238         }
239 
240         /**
241          * Returns whether or not the specified data flavor is supported for
242          * this object.
243          * @param flavor the requested flavor for the data
244          * @return boolean indicating whether or not the data flavor is supported
245          */
isDataFlavorSupported(DataFlavor flavor)246         public boolean isDataFlavorSupported(DataFlavor flavor) {
247             DataFlavor[] flavors = getTransferDataFlavors();
248             for (int i = 0; i < flavors.length; i++) {
249                 if (flavors[i].equals(flavor)) {
250                     return true;
251                 }
252             }
253             return false;
254         }
255 
256         /**
257          * Returns an object which represents the data to be transferred.  The class
258          * of the object returned is defined by the representation class of the flavor.
259          *
260          * @param flavor the requested flavor for the data
261          * @see DataFlavor#getRepresentationClass
262          * @exception IOException                if the data is no longer available
263          *              in the requested flavor.
264          * @exception UnsupportedFlavorException if the requested data flavor is
265          *              not supported.
266          */
getTransferData(DataFlavor flavor)267         public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
268             DataFlavor[] richerFlavors = getRicherFlavors();
269             if (isRicherFlavor(flavor)) {
270                 return getRicherData(flavor);
271             } else if (isHTMLFlavor(flavor)) {
272                 String data = getHTMLData();
273                 data = (data == null) ? "" : data;
274                 if (String.class.equals(flavor.getRepresentationClass())) {
275                     return data;
276                 } else if (Reader.class.equals(flavor.getRepresentationClass())) {
277                     return new StringReader(data);
278                 } else if (InputStream.class.equals(flavor.getRepresentationClass())) {
279                     return new StringBufferInputStream(data);
280                 }
281                 // fall through to unsupported
282             } else if (isPlainFlavor(flavor)) {
283                 String data = getPlainData();
284                 data = (data == null) ? "" : data;
285                 if (String.class.equals(flavor.getRepresentationClass())) {
286                     return data;
287                 } else if (Reader.class.equals(flavor.getRepresentationClass())) {
288                     return new StringReader(data);
289                 } else if (InputStream.class.equals(flavor.getRepresentationClass())) {
290                     return new StringBufferInputStream(data);
291                 }
292                 // fall through to unsupported
293 
294             } else if (isStringFlavor(flavor)) {
295                 String data = getPlainData();
296                 data = (data == null) ? "" : data;
297                 return data;
298             }
299             throw new UnsupportedFlavorException(flavor);
300         }
301 
302         // --- richer subclass flavors ----------------------------------------------
303 
isRicherFlavor(DataFlavor flavor)304         protected boolean isRicherFlavor(DataFlavor flavor) {
305             DataFlavor[] richerFlavors = getRicherFlavors();
306             int nFlavors = (richerFlavors != null) ? richerFlavors.length : 0;
307             for (int i = 0; i < nFlavors; i++) {
308                 if (richerFlavors[i].equals(flavor)) {
309                     return true;
310                 }
311             }
312             return false;
313         }
314 
315         /**
316          * Some subclasses will have flavors that are more descriptive than HTML
317          * or plain text.  If this method returns a non-null value, it will be
318          * placed at the start of the array of supported flavors.
319          */
getRicherFlavors()320         protected DataFlavor[] getRicherFlavors() {
321             return null;
322         }
323 
getRicherData(DataFlavor flavor)324         protected Object getRicherData(DataFlavor flavor) throws UnsupportedFlavorException {
325             return null;
326         }
327 
328         // --- html flavors ----------------------------------------------------------
329 
330         /**
331          * Returns whether or not the specified data flavor is an HTML flavor that
332          * is supported.
333          * @param flavor the requested flavor for the data
334          * @return boolean indicating whether or not the data flavor is supported
335          */
isHTMLFlavor(DataFlavor flavor)336         protected boolean isHTMLFlavor(DataFlavor flavor) {
337             DataFlavor[] flavors = htmlFlavors;
338             for (int i = 0; i < flavors.length; i++) {
339                 if (flavors[i].equals(flavor)) {
340                     return true;
341                 }
342             }
343             return false;
344         }
345 
346         /**
347          * Should the HTML flavors be offered?  If so, the method
348          * getHTMLData should be implemented to provide something reasonable.
349          */
isHTMLSupported()350         protected boolean isHTMLSupported() {
351             return htmlData != null;
352         }
353 
354         /**
355          * Fetch the data in a text/html format
356          */
getHTMLData()357         protected String getHTMLData() {
358             return htmlData;
359         }
360 
361         // --- plain text flavors ----------------------------------------------------
362 
363         /**
364          * Returns whether or not the specified data flavor is an plain flavor that
365          * is supported.
366          * @param flavor the requested flavor for the data
367          * @return boolean indicating whether or not the data flavor is supported
368          */
isPlainFlavor(DataFlavor flavor)369         protected boolean isPlainFlavor(DataFlavor flavor) {
370             DataFlavor[] flavors = plainFlavors;
371             for (int i = 0; i < flavors.length; i++) {
372                 if (flavors[i].equals(flavor)) {
373                     return true;
374                 }
375             }
376             return false;
377         }
378 
379         /**
380          * Should the plain text flavors be offered?  If so, the method
381          * getPlainData should be implemented to provide something reasonable.
382          */
isPlainSupported()383         protected boolean isPlainSupported() {
384             return plainData != null;
385         }
386 
387         /**
388          * Fetch the data in a text/plain format.
389          */
getPlainData()390         protected String getPlainData() {
391             return plainData;
392         }
393 
394         // --- string flavorss --------------------------------------------------------
395 
396         /**
397          * Returns whether or not the specified data flavor is a String flavor that
398          * is supported.
399          * @param flavor the requested flavor for the data
400          * @return boolean indicating whether or not the data flavor is supported
401          */
isStringFlavor(DataFlavor flavor)402         protected boolean isStringFlavor(DataFlavor flavor) {
403             DataFlavor[] flavors = stringFlavors;
404             for (int i = 0; i < flavors.length; i++) {
405                 if (flavors[i].equals(flavor)) {
406                     return true;
407                 }
408             }
409             return false;
410         }
411     }
412 
413 
414     /**
415      * Creates new form TransferHandlerTest14
416      */
TransferHandlerTest14()417     public TransferHandlerTest14() {
418         initComponents();
419         table.setTransferHandler(new TableTransferHandler());
420         table.setDragEnabled(true);
421     }
422 
main(String[] args)423     public static void main(String[] args) {
424 
425         try {
426             UIManager.setLookAndFeel(QuaquaManager.getLookAndFeel());
427                 UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
428         } catch (Exception ex) {
429             ex.printStackTrace();
430         }
431 
432 
433         JFrame f = new JFrame("TransferHandlerText");
434         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
435         f.getContentPane().add(new TransferHandlerTest14());
436         f.show();
437 
438     }
439 
440     /** This method is called from within the constructor to
441      * initialize the form.
442      * WARNING: Do NOT modify this code. The content of this method is
443      * always regenerated by the Form Editor.
444      */
445     // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
initComponents()446     private void initComponents() {
447         java.awt.GridBagConstraints gridBagConstraints;
448 
449         scrollPane = new javax.swing.JScrollPane();
450         table = new javax.swing.JTable();
451         jLabel1 = new javax.swing.JLabel();
452         jButton1 = new javax.swing.JButton();
453 
454         setLayout(new java.awt.GridBagLayout());
455 
456         table.setModel(new javax.swing.table.DefaultTableModel(
457             new Object [][] {
458                 {null, null, null, null}
459             },
460             new String [] {
461                 "Name", "Last Modified", "Length", "Kind"
462             }
463         ) {
464             Class[] types = new Class [] {
465                 java.lang.String.class, java.lang.String.class, java.lang.Long.class, java.lang.String.class
466             };
467             boolean[] canEdit = new boolean [] {
468                 false, false, false, false
469             };
470 
471             public Class getColumnClass(int columnIndex) {
472                 return types [columnIndex];
473             }
474 
475             public boolean isCellEditable(int rowIndex, int columnIndex) {
476                 return canEdit [columnIndex];
477             }
478         });
479         scrollPane.setViewportView(table);
480 
481         gridBagConstraints = new java.awt.GridBagConstraints();
482         gridBagConstraints.gridheight = java.awt.GridBagConstraints.REMAINDER;
483         gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
484         gridBagConstraints.weightx = 1.0;
485         gridBagConstraints.weighty = 1.0;
486         add(scrollPane, gridBagConstraints);
487 
488         jLabel1.setText("Drag a file into the table.");
489         gridBagConstraints = new java.awt.GridBagConstraints();
490         gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 0);
491         add(jLabel1, gridBagConstraints);
492 
493         jButton1.setText("JFileChooser");
494         jButton1.addActionListener(new java.awt.event.ActionListener() {
495             public void actionPerformed(java.awt.event.ActionEvent evt) {
496                 openFileChooser(evt);
497             }
498         });
499 
500         gridBagConstraints = new java.awt.GridBagConstraints();
501         gridBagConstraints.gridy = 1;
502         add(jButton1, gridBagConstraints);
503 
504     }// </editor-fold>//GEN-END:initComponents
505 
openFileChooser(java.awt.event.ActionEvent evt)506     private void openFileChooser(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openFileChooser
507         JFileChooser fileChooser;
508         fileChooser = new JFileChooser();
509         fileChooser.setDragEnabled(true);
510 
511         final JDialog dialog = new JDialog();
512         dialog.setContentPane(fileChooser);
513         dialog.pack();
514         dialog.setVisible(true);
515         dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
516         fileChooser.addActionListener(new ActionListener() {
517             public void actionPerformed(ActionEvent evt) {
518                 dialog.dispose();
519             }
520         });
521         fileChooser.showOpenDialog(this);
522     }//GEN-LAST:event_openFileChooser
523 
524 
525     // Variables declaration - do not modify//GEN-BEGIN:variables
526     private javax.swing.JButton jButton1;
527     private javax.swing.JLabel jLabel1;
528     private javax.swing.JScrollPane scrollPane;
529     private javax.swing.JTable table;
530     // End of variables declaration//GEN-END:variables
531 
532 }
533