• category: swing folder: MinimalHTMLWriter title: JTextPaneのStyledDocumentからhtmlテキストを生成する tags: [JTextPane, StyledDocument, Html, Clipboard] author: aterai pubdate: 2023-06-05T03:07:49+09:00 description: JTextPaneから取得したStyledDocumentをMinimalHTMLWriterで変換してhtmlテキストを生成します。 image: https://drive.google.com/uc?id=1vmydUsUDHmnZMDK1ZRv5Ww-K7NjwCC1F

概要

JTextPaneから取得したStyledDocumentをMinimalHTMLWriterで変換してhtmlテキストを生成します。

サンプルコード

public void copyHtmlTextToClipboard(JTextPane textPane) {
  Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
  int start = textPane.getSelectionStart();
  int end = textPane.getSelectionEnd();
  int length = end - start;
  StyledDocument styledDocument = textPane.getStyledDocument();
  try (OutputStream os = new ByteArrayOutputStream();
       OutputStreamWriter writer = new OutputStreamWriter(os, StandardCharsets.UTF_8)) {
    MinimalHTMLWriter w = new MinimalHTMLWriter(writer, styledDocument, start, length);
    w.write();
    writer.flush();
    String contents = os.toString();
    ParserDelegator delegator = new ParserDelegator();
    StringBuilder plainBuf = new StringBuilder();
    delegator.parse(new StringReader(contents), new HTMLEditorKit.ParserCallback() {
      @Override public void handleText(char[] text, int pos) {
        plainBuf.append(text);
      }
    }, Boolean.TRUE);

    Transferable transferable = new BasicTransferable(plainBuf.toString(), contents);
    clipboard.setContents(transferable, null);
  } catch (IOException | BadLocationException e) {
    UIManager.getLookAndFeel().provideErrorFeedback(textPane);
    e.printStackTrace();
  }
}
View in GitHub: Java, Kotlin

解説

  • copy-to-clipboard
    • DefaultEditorKit.CopyAction()を使用して選択テキストをコピー
    • Ctrl+Cでのコピーと同じ
    • コピー元のJTextPaneにペーストすればDataFlavorapplication/x-java-jvm-local-objectrefに対応しているのでスタイルを維持したテキストになる
    • JEditorPane#setContentType("text/html")を設定してHTMLEditorKitを使用するJEditorPaneにペーストするとスタイルは除去されたテキストになる
  • copy-html-and-text-to-clipboard
    • MinimalHTMLWriterを使用してスタイル付きテキストをHtmlテキストに変換してクリップボードにコピー
      • javax/swing/plaf/basic/BasicTransferable.javaをコピーしてプレーンテキストとHtmlテキストを保持するTransferableを生成してクリップボードにコピー
      • このためJEditorPane#setContentType("text/html")を設定してHTMLEditorKitを使用するJEditorPaneHtmlテキストとしてペーストが可能
      • MinimalHTMLWriterHtml化するとタグ間に空白文字が追加されたり、改行文字が追加・除去される場合がある?
    • HTMLEditorKit#write(Writer out, Document doc, int pos, int len)では、以下のようにHTMLDocumentHTMLWriterで、StyledDocumentMinimalHTMLWriterhtmlテキストに変換しているのでこれを参考にしている
public void write(Writer out, Document doc, int pos, int len)
    throws IOException, BadLocationException {
  if (doc instanceof HTMLDocument) {
    HTMLWriter w = new HTMLWriter(out, (HTMLDocument) doc, pos, len);
    w.write();
  } else if (doc instanceof StyledDocument) {
    MinimalHTMLWriter w = new MinimalHTMLWriter(out, (StyledDocument) doc, pos, len);
    w.write();
  } else {
    super.write(out, doc, pos, len);
  }
}
  • copy-html-to-clipboard
    • copy-html-and-text-to-clipboardと同様にMinimalHTMLWriterを使用してスタイル付きテキストをHtmlテキストに変換し、以下のようなHtmlテキストのみを保持する簡易Transferableを生成してクリップボードにコピー
    • JEditorPane#setContentType("text/html")を設定してHTMLEditorKitを使用するJEditorPaneHtmlテキストとしてペーストが可能だが、コピー元のJTextPaneにペースト不可になる
class HtmlTransferable implements Transferable {
  private final String htmlFormattedText;

  public HtmlTransferable(String htmlFormattedText) {
    this.htmlFormattedText = htmlFormattedText;
  }

  @Override public DataFlavor[] getTransferDataFlavors() {
    return new DataFlavor[] { DataFlavor.allHtmlFlavor };
  }

  @Override public boolean isDataFlavorSupported(DataFlavor flavor) {
    for (DataFlavor supportedFlavor : getTransferDataFlavors()) {
      if (supportedFlavor.equals(flavor)) {
        return true;
      }
    }
    return false;
  }

  @Override public Object getTransferData(DataFlavor flavor)
      throws UnsupportedFlavorException, IOException {
    if (Objects.equals(flavor, DataFlavor.allHtmlFlavor)) {
      return htmlFormattedText;
    }
    throw new UnsupportedFlavorException(flavor);
  }
}

参考リンク

コメント