/** * Copyright (C) 2011 Steve McLeod (http://stackoverflow.com/users/2959/steve-mcleod) * * Source: * http://stackoverflow.com/questions/7745087 * * License: http://creativecommons.org/licenses/by-sa/3.0/ */ package org.languagetool.gui; import javax.swing.*; import javax.swing.text.MutableAttributeSet; import javax.swing.text.html.HTML; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.parser.ParserDelegator; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; import java.io.Reader; import java.io.StringReader; /** * Keep line breaks when copying from JTextPane. */ class RetainLineBreakTransferHandler extends TransferHandler { @Override protected Transferable createTransferable(JComponent c) { final JEditorPane pane = (JEditorPane) c; final String htmlText = pane.getText(); final String plainText = extractText(new StringReader(htmlText)); return new MyTransferable(plainText, htmlText); } private String extractText(Reader reader) { final StringBuilder result = new StringBuilder(); final HTMLEditorKit.ParserCallback parserCallback = new HTMLEditorKit.ParserCallback() { @Override public void handleText(final char[] data, final int pos) { result.append(data); } @Override public void handleStartTag(HTML.Tag tag, MutableAttributeSet attribute, int pos) { } @Override public void handleEndTag(HTML.Tag tag, final int pos) { } @Override public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet a, final int pos) { if (tag.equals(HTML.Tag.BR)) { result.append("\n"); } } @Override public void handleComment(final char[] data, final int pos) { } @Override public void handleError(final String errMsg, final int pos) { } }; try { new ParserDelegator().parse(reader, parserCallback, true); } catch (IOException e) { throw new RuntimeException(e); } return result.toString(); } @Override public void exportToClipboard(JComponent comp, Clipboard clip, int action) throws IllegalStateException { if (action == COPY) { clip.setContents(this.createTransferable(comp), null); } } @Override public int getSourceActions(JComponent c) { return COPY; } } class MyTransferable implements Transferable { private static final DataFlavor[] supportedFlavors; static { try { supportedFlavors = new DataFlavor[]{ new DataFlavor("text/html;class=java.lang.String"), new DataFlavor("text/plain;class=java.lang.String") }; } catch (ClassNotFoundException e) { throw new ExceptionInInitializerError(e); } } private final String plainData; private final String htmlData; public MyTransferable(String plainData, String htmlData) { this.plainData = plainData; this.htmlData = htmlData; } @Override public DataFlavor[] getTransferDataFlavors() { return supportedFlavors; } @Override public boolean isDataFlavorSupported(DataFlavor flavor) { for (DataFlavor supportedFlavor : supportedFlavors) { if (supportedFlavor == flavor) { return true; } } return false; } @Override public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { if (flavor.equals(supportedFlavors[0])) { return htmlData; } if (flavor.equals(supportedFlavors[1])) { return plainData; } throw new UnsupportedFlavorException(flavor); } }