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