Skip to Main Content

Java SE (Java Platform, Standard Edition)

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Copy and Paste for Excel + Thunderbird + Outlook

600732Jun 8 2011 — edited Jun 18 2011
Hi fellow developers.

I have a JTable, from this JTable I want to copy + paste the data to Excel or Outlook or Thunderbird.

There are many tutorials, about how to copy and paste to Excel, which I have managed to do:
http://www.javaworld.com/javaworld/javatips/jw-javatip77.html

However these work by creating a string with tab seperated columns, which looks horrible in Thunderbird (and I'm assuming Outlook). Its just ugly text.

I notice that when I copy from Excel to thunderbird, it is converted into a wonderful table. Cool. So I want to do the same thing from a JTable. My idea, I'll just copy + paste with html rather than text

So I tried to create my own Transferable for use with a JTable. This is very much inspired by the StringSelection from Java.

I have a DataFlavour for html.
DataFlavor HTML_TEXT = new DataFlavor("text/html;class=java.lang.String");
Now the exciting bit is getTransferData(), here a turn a tab delimited String into an html block
public Object getTransferData(DataFlavor flavor)
        throws UnsupportedFlavorException, IOException
    {
	// JCK Test StringSelection0007: if 'flavor' is null, throw NPE
	if (flavor.equals(STRING_FLAVOUR)) {
	    return data;
	} else if (flavor.equals(PLAIN_TEXT)) {
	    return new StringReader(data == null ? "" : data);
	}else if (flavor.equals(HTML_TEXT)) {
            if (data==null)
                return new StringReader("");
            StringBuilder sb = new StringBuilder(data.length());
            sb.append("<html><page><table>");
            StringTokenizer stLines = new StringTokenizer(data, "\n");
            while (stLines.hasMoreTokens())
            {
                sb.append("<tr>");
                StringTokenizer stTab = new StringTokenizer(stLines.nextToken(), "\t");
                while (stTab.hasMoreTokens())
                {
                    sb.append("<td>"+stTab.nextToken()+"</td>");
                }
                sb.append("</tr>");
            }
            sb.append("</table></page></html>");
//            return "<h1>YAY</h1>";
            return sb.toString();
	} else {
	    throw new UnsupportedFlavorException(flavor);
	}
    }
Now this all works fine, I still get my data in Excel (excel then selects to use the html/text version which has slightly different formating to the tab delimited version.
In Notepad I get the tab delimited version.
But I can no longer get any data into thunderbird. I seems it won't accept my html/text.

How do I produce the same mime type as excel? Excel has fantastic copy/paste functionality into thunderbird.

Any thoughts?

FYI my complete class. The JavaDoc is 100% identical to the StringSelection class from Java and most of the code is very inspired from StringSelection.
public class HtmlSelection implements Transferable, ClipboardOwner {

    private static final DataFlavor STRING_FLAVOUR = DataFlavor.stringFlavor;
    private static final DataFlavor PLAIN_TEXT = DataFlavor.plainTextFlavor;
    private static DataFlavor HTML_TEXT;

    private static final List<DataFlavor> flavours = new ArrayList(Arrays.<DataFlavor>asList(
        STRING_FLAVOUR,
	PLAIN_TEXT
    ));

    static
    {
        try {
            HTML_TEXT = new DataFlavor("text/html;class=java.lang.String");
            flavours.add(HTML_TEXT);
        } catch (ClassNotFoundException ex) {
            ex.printlnStackTrace();
        }
    }

    private String data;

    /**
     * Creates a <code>Transferable</code> capable of transferring
     * the specified <code>String</code>.
     */
    public HtmlSelection(String data) {
        this.data = data;
    }

    /**
     * Returns an array of flavors in which this <code>Transferable</code>
     * can provide the data. <code>DataFlavor.stringFlavor</code>
     * is properly supported.
     * Support for <code>DataFlavor.plainTextFlavor</code> is
     * <b>deprecated</b>.
     *
     * @return an array of length two, whose elements are <code>DataFlavor.
     *         stringFlavor</code> and <code>DataFlavor.plainTextFlavor</code>
     */
    public DataFlavor[] getTransferDataFlavors() {
        // returning flavors itself would allow client code to modify
        // our internal behavior

	return flavours.toArray(new DataFlavor[flavours.size()]);
    }

    /**
     * Returns whether the requested flavor is supported by this
     * <code>Transferable</code>.
     *
     * @param flavor the requested flavor for the data
     * @return true if <code>flavor</code> is equal to
     *   <code>DataFlavor.stringFlavor</code> or
     *   <code>DataFlavor.plainTextFlavor</code>; false if <code>flavor</code>
     *   is not one of the above flavors
     * @throws NullPointerException if flavor is <code>null</code>
     */
    public boolean isDataFlavorSupported(DataFlavor flavor) {
	// JCK Test StringSelection0003: if 'flavor' is null, throw NPE
        for(DataFlavor flv : flavours) {
	    if (flavor.equals(flv)) {
	        return true;
	    }
	}
	return false;
    }

    /**
     * Returns the <code>Transferable</code>'s data in the requested
     * <code>DataFlavor</code> if possible. If the desired flavor is
     * <code>DataFlavor.stringFlavor</code>, or an equivalent flavor,
     * the <code>String</code> representing the selection is
     * returned. If the desired flavor is
     * <code>DataFlavor.plainTextFlavor</code>,
     * or an equivalent flavor, a <code>Reader</code> is returned.
     * <b>Note:</b> The behavior of this method for
     * <code>DataFlavor.plainTextFlavor</code>
     * and equivalent <code>DataFlavor</code>s is inconsistent with the
     * definition of <code>DataFlavor.plainTextFlavor</code>.
     *
     * @param flavor the requested flavor for the data
     * @return the data in the requested flavor, as outlined above
     * @throws UnsupportedFlavorException if the requested data flavor is
     *         not equivalent to either <code>DataFlavor.stringFlavor</code>
     *         or <code>DataFlavor.plainTextFlavor</code>
     * @throws IOException if an IOException occurs while retrieving the data.
     *         By default, StringSelection never throws this exception, but a
     *         subclass may.
     * @throws NullPointerException if flavor is <code>null</code>
     * @see java.io.Reader
     */
    public Object getTransferData(DataFlavor flavor)
        throws UnsupportedFlavorException, IOException
    {
	// JCK Test StringSelection0007: if 'flavor' is null, throw NPE
	if (flavor.equals(STRING_FLAVOUR)) {
	    return data;
	} else if (flavor.equals(PLAIN_TEXT)) {
	    return new StringReader(data == null ? "" : data);
	}else if (flavor.equals(HTML_TEXT)) {
            if (data==null)
                return new StringReader("");
            StringBuilder sb = new StringBuilder(data.length());
            sb.append("<html><page><table>");
            StringTokenizer stLines = new StringTokenizer(data, "\n");
            while (stLines.hasMoreTokens())
            {
                sb.append("<tr>");
                StringTokenizer stTab = new StringTokenizer(stLines.nextToken(), "\t");
                while (stTab.hasMoreTokens())
                {
                    sb.append("<td>"+stTab.nextToken()+"</td>");
                }
                sb.append("</tr>");
            }
            sb.append("</table></page></html>");
//            return "<h1>YAY</h1>";
            return sb.toString();
	} else {
	    throw new UnsupportedFlavorException(flavor);
	}
    }

    public void lostOwnership(Clipboard clipboard, Transferable contents) {
    }

}
Edited by: mac24nz on Jun 8, 2011 3:15 AM
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Jul 16 2011
Added on Jun 8 2011
1 comment
2,003 views