/* * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */package sun.swing.text; import java.awt.ComponentOrientation;import java.awt.Dimension;import java.awt.Font;import java.awt.FontMetrics;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.Insets;import java.awt.Rectangle;import java.awt.Component;import java.awt.Container;import java.awt.font.FontRenderContext;import java.awt.print.PageFormat;import java.awt.print.Printable;import java.awt.print.PrinterException;import java.text.MessageFormat;import java.util.ArrayList;import java.util.Collections;import java.util.List;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;import java.util.concurrent.atomic.AtomicReference; import javax.swing.BorderFactory;import javax.swing.CellRendererPane;import javax.swing.JTextField;import javax.swing.JTextArea;import javax.swing.JEditorPane;import javax.swing.JViewport;import javax.swing.JScrollPane;import javax.swing.JTextPane;import javax.swing.SwingUtilities;import javax.swing.border.Border;import javax.swing.border.TitledBorder;import javax.swing.text.BadLocationException;import javax.swing.text.JTextComponent;import javax.swing.text.Document;import javax.swing.text.EditorKit;import javax.swing.text.AbstractDocument;import javax.swing.text.html.HTMLDocument;import javax.swing.text.html.HTML; import sun.font.FontDesignMetrics; import sun.swing.text.html.FrameEditorPaneTag; /** * An implementation of {@code Printable} to print {@code JTextComponent} with * the header and footer. * * <h1> * WARNING: this class is to be used in * javax.swing.text.JTextComponent only. * </h1> * * <p> * The implementation creates a new {@code JTextComponent} ({@code printShell}) * to print the content using the {@code Document}, {@code EditorKit} and * rendering-affecting properties from the original {@code JTextComponent}. * * <p> * {@code printShell} is laid out on the first {@code print} invocation. * * <p> * This class can be used on any thread. Part of the implementation is executed * on the EDT though. * * @author Igor Kushnirskiy * * @since 1.6 */public class TextComponentPrintable implements CountingPrintable { private static final int LIST_SIZE = 1000; private boolean isLayouted = false; /* * The text component to print. */ private final JTextComponent textComponentToPrint; /* * The FontRenderContext to layout and print with */ private final AtomicReference<FontRenderContext> frc = new AtomicReference<FontRenderContext>(null); /** * Special text component used to print to the printer. */ private final JTextComponent printShell; private final MessageFormat headerFormat; private final MessageFormat footerFormat; private static final float HEADER_FONT_SIZE = 18.0f; private static final float FOOTER_FONT_SIZE = 12.0f; private final Font headerFont; private final Font footerFont; /** * stores metrics for the unhandled rows. The only metrics we need are * yStart and yEnd when row is handled by updatePagesMetrics it is removed * from the list. Thus the head of the list is the fist row to handle. * * sorted */ private final List<IntegerSegment> rowsMetrics; /** * thread-safe list for storing pages metrics. The only metrics we need are * yStart and yEnd. * It has to be thread-safe since metrics are calculated on * the printing thread and accessed on the EDT thread. * * sorted */ private final List<IntegerSegment> pagesMetrics; /** * Returns {@code TextComponentPrintable} to print {@code textComponent}. * * @param textComponent {@code JTextComponent} to print * @param headerFormat the page header, or {@code null} for none * @param footerFormat the page footer, or {@code null} for none * @return {@code TextComponentPrintable} to print {@code textComponent} */ public static Printable getPrintable(final JTextComponent textComponent, final MessageFormat headerFormat, final MessageFormat footerFormat) { if (textComponent instanceof JEditorPane && isFrameSetDocument(textComponent.getDocument())) { //for document with frames we create one printable per //frame and merge them with the CompoundPrintable. List<JEditorPane> frames = getFrames((JEditorPane) textComponent); List<CountingPrintable> printables = new ArrayList<CountingPrintable>(); for (JEditorPane frame : frames) { printables.add((CountingPrintable) getPrintable(frame, headerFormat, footerFormat)); } return new CompoundPrintable(printables); } else { return new TextComponentPrintable(textComponent, headerFormat, footerFormat); } } /** * Checks whether the document has frames. Only HTMLDocument might * have frames. * * @param document the {@code Document} to check * @return {@code true} if the {@code document} has frames */ private static boolean isFrameSetDocument(final Document document) { boolean ret = false; if (document instanceof HTMLDocument) { HTMLDocument htmlDocument = (HTMLDocument)document; if (htmlDocument.getIterator(HTML.Tag.FRAME).isValid()) { ret = true; } } return ret; } /** * Returns frames under the {@code editor}. * The frames are created if necessary. * * @param editor the {@JEditorPane} to find the frames for * @return list of all frames */ private static List<JEditorPane> getFrames(final JEditorPane editor) { List<JEditorPane> list = new ArrayList<JEditorPane>(); getFrames(editor, list); if (list.size() == 0) { //the frames have not been created yet. //let's trigger the frames creation. createFrames(editor); getFrames(editor, list); } return list; } /** * Adds all {@code JEditorPanes} under {@code container} tagged by {@code * FrameEditorPaneTag} to the {@code list}. It adds only top * level {@code JEditorPanes}. For instance if there is a frame * inside the frame it will return the top frame only. * * @param c the container to find all frames under * @param list {@code List} to append the results too */ private static void getFrames(final Container container, List<JEditorPane> list) { for (Component c : container.getComponents()) { if (c instanceof FrameEditorPaneTag && c instanceof JEditorPane ) { //it should be always JEditorPane list.add((JEditorPane) c); } else { if (c instanceof Container) { getFrames((Container) c, list); } } } } /** * Triggers the frames creation for {@code JEditorPane} * * @param editor the {@code JEditorPane} to create frames for */ private static void createFrames(final JEditorPane editor) { Runnable doCreateFrames = new Runnable() { public void run() { final int WIDTH = 500; final int HEIGHT = 500; CellRendererPane rendererPane = new CellRendererPane(); rendererPane.add(editor); //the values do not matter //we only need to get frames created rendererPane.setSize(WIDTH, HEIGHT); }; }; if (SwingUtilities.isEventDispatchThread()) { doCreateFrames.run(); } else { try { SwingUtilities.invokeAndWait(doCreateFrames); } catch (Exception e) { if (e instanceof RuntimeException) { throw (RuntimeException) e; } else { throw new RuntimeException(e); } } } } /** * Constructs {@code TextComponentPrintable} to print {@code JTextComponent} * {@code textComponent} with {@code headerFormat} and {@code footerFormat}. * * @param textComponent {@code JTextComponent} to print * @param headerFormat the page header or {@code null} for none * @param footerFormat the page footer or {@code null} for none */ private TextComponentPrintable(JTextComponent textComponent, MessageFormat headerFormat, MessageFormat footerFormat) { this.textComponentToPrint = textComponent; this.headerFormat = headerFormat; this.footerFormat = footerFormat; headerFont = textComponent.getFont().deriveFont(Font.BOLD, HEADER_FONT_SIZE); footerFont = textComponent.getFont().deriveFont(Font.PLAIN, FOOTER_FONT_SIZE); this.pagesMetrics = Collections.synchronizedList(new ArrayList<IntegerSegment>()); this.rowsMetrics = new ArrayList<IntegerSegment>(LIST_SIZE); this.printShell = createPrintShell(textComponent); } /** * creates a printShell. * It creates closest text component to {@code textComponent} * which uses {@code frc} from the {@code TextComponentPrintable} * for the {@code getFontMetrics} method. * * @param textComponent {@code JTextComponent} to create a * printShell for * @return the print shell */ private JTextComponent createPrintShell(final JTextComponent textComponent) { if (SwingUtilities.isEventDispatchThread()) { return createPrintShellOnEDT(textComponent); } else { FutureTask<JTextComponent> futureCreateShell = new FutureTask<JTextComponent>( new Callable<JTextComponent>() { public JTextComponent call() throws Exception { return createPrintShellOnEDT(textComponent); } }); SwingUtilities.invokeLater(futureCreateShell); try { return futureCreateShell.get(); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (ExecutionException e) { Throwable cause = e.getCause(); if (cause instanceof Error) { throw (Error) cause; } if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } throw new AssertionError(cause); } } } private JTextComponent createPrintShellOnEDT(final JTextComponent textComponent) { assert SwingUtilities.isEventDispatchThread(); JTextComponent ret = null; if (textComponent instanceof JTextField) { ret = new JTextField() { { setHorizontalAlignment( ((JTextField) textComponent).getHorizontalAlignment()); } @Override public FontMetrics getFontMetrics(Font font) { return (frc.get() == null) ? super.getFontMetrics(font) : FontDesignMetrics.getMetrics(font, frc.get()); } }; } else if (textComponent instanceof JTextArea) { ret = new JTextArea() { { JTextArea textArea = (JTextArea) textComponent; setLineWrap(textArea.getLineWrap()); setWrapStyleWord(textArea.getWrapStyleWord()); setTabSize(textArea.getTabSize()); } @Override public FontMetrics getFontMetrics(Font font) { return (frc.get() == null) ? super.getFontMetrics(font) : FontDesignMetrics.getMetrics(font, frc.get()); } }; } else if (textComponent instanceof JTextPane) { ret = new JTextPane() { @Override public FontMetrics getFontMetrics(Font font) { return (frc.get() == null) ? super.getFontMetrics(font) : FontDesignMetrics.getMetrics(font, frc.get()); } @Override public EditorKit getEditorKit() { if (getDocument() == textComponent.getDocument()) { return ((JTextPane) textComponent).getEditorKit(); } else { return super.getEditorKit(); } } }; } else if (textComponent instanceof JEditorPane) { ret = new JEditorPane() { @Override public FontMetrics getFontMetrics(Font font) { return (frc.get() == null) ? super.getFontMetrics(font) : FontDesignMetrics.getMetrics(font, frc.get()); } @Override public EditorKit getEditorKit() { if (getDocument() == textComponent.getDocument()) { return ((JEditorPane) textComponent).getEditorKit(); } else { return super.getEditorKit(); } } }; } //want to occupy the whole width and height by text ret.setBorder(null); //set properties from the component to print ret.setOpaque(textComponent.isOpaque()); ret.setEditable(textComponent.isEditable()); ret.setEnabled(textComponent.isEnabled()); ret.setFont(textComponent.getFont()); ret.setBackground(textComponent.getBackground()); ret.setForeground(textComponent.getForeground()); ret.setComponentOrientation( textComponent.getComponentOrientation()); if (ret instanceof JEditorPane) { ret.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, textComponent.getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES)); ret.putClientProperty(JEditorPane.W3C_LENGTH_UNITS, textComponent.getClientProperty(JEditorPane.W3C_LENGTH_UNITS)); ret.putClientProperty("charset", textComponent.getClientProperty("charset")); } ret.setDocument(textComponent.getDocument()); return ret; } /** * Returns the number of pages in this printable. * <p> * This number is defined only after {@code print} returns NO_SUCH_PAGE. * * @return the number of pages. */ public int getNumberOfPages() { return pagesMetrics.size(); } /** * See Printable.print for the API description. * * There are two parts in the implementation. * First part (print) is to be called on the printing thread. * Second part (printOnEDT) is to be called on the EDT only. * * print triggers printOnEDT */ public int print(final Graphics graphics, final PageFormat pf, final int pageIndex) throws PrinterException { if (!isLayouted) { if (graphics instanceof Graphics2D) { frc.set(((Graphics2D)graphics).getFontRenderContext()); } layout((int)Math.floor(pf.getImageableWidth())); calculateRowsMetrics(); } int ret; if (!SwingUtilities.isEventDispatchThread()) { Callable<Integer> doPrintOnEDT = new Callable<Integer>() { public Integer call() throws Exception { return printOnEDT(graphics, pf, pageIndex); } }; FutureTask<Integer> futurePrintOnEDT = new FutureTask<Integer>(doPrintOnEDT); SwingUtilities.invokeLater(futurePrintOnEDT); try { ret = futurePrintOnEDT.get(); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (ExecutionException e) { Throwable cause = e.getCause(); if (cause instanceof PrinterException) { throw (PrinterException)cause; } else if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } else { throw new RuntimeException(cause); } } } else { ret = printOnEDT(graphics, pf, pageIndex); } return ret; } /** * The EDT part of the print method. *Lines 1–500 of 839. Load more
/* * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.swing.text; import java.awt.ComponentOrientation; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.Rectangle; import java.awt.Component; import java.awt.Container; import java.awt.font.FontRenderContext; import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; import java.util.concurrent.atomic.AtomicReference; import javax.swing.BorderFactory; import javax.swing.CellRendererPane; import javax.swing.JTextField; import javax.swing.JTextArea; import javax.swing.JEditorPane; import javax.swing.JViewport; import javax.swing.JScrollPane; import javax.swing.JTextPane; import javax.swing.SwingUtilities; import javax.swing.border.Border; import javax.swing.border.TitledBorder; import javax.swing.text.BadLocationException; import javax.swing.text.JTextComponent; import javax.swing.text.Document; import javax.swing.text.EditorKit; import javax.swing.text.AbstractDocument; import javax.swing.text.html.HTMLDocument; import javax.swing.text.html.HTML; import sun.font.FontDesignMetrics; import sun.swing.text.html.FrameEditorPaneTag; /** * An implementation of {@code Printable} to print {@code JTextComponent} with * the header and footer. * * <h1> * WARNING: this class is to be used in * javax.swing.text.JTextComponent only. * </h1> * * <p> * The implementation creates a new {@code JTextComponent} ({@code printShell}) * to print the content using the {@code Document}, {@code EditorKit} and * rendering-affecting properties from the original {@code JTextComponent}. * * <p> * {@code printShell} is laid out on the first {@code print} invocation. * * <p> * This class can be used on any thread. Part of the implementation is executed * on the EDT though. * * @author Igor Kushnirskiy * * @since 1.6 */ public class TextComponentPrintable implements CountingPrintable { private static final int LIST_SIZE = 1000; private boolean isLayouted = false; /* * The text component to print. */ private final JTextComponent textComponentToPrint; /* * The FontRenderContext to layout and print with */ private final AtomicReference<FontRenderContext> frc = new AtomicReference<FontRenderContext>(null); /** * Special text component used to print to the printer. */ private final JTextComponent printShell; private final MessageFormat headerFormat; private final MessageFormat footerFormat; private static final float HEADER_FONT_SIZE = 18.0f; private static final float FOOTER_FONT_SIZE = 12.0f; private final Font headerFont; private final Font footerFont; /** * stores metrics for the unhandled rows. The only metrics we need are * yStart and yEnd when row is handled by updatePagesMetrics it is removed * from the list. Thus the head of the list is the fist row to handle. * * sorted */ private final List<IntegerSegment> rowsMetrics; /** * thread-safe list for storing pages metrics. The only metrics we need are * yStart and yEnd. * It has to be thread-safe since metrics are calculated on * the printing thread and accessed on the EDT thread. * * sorted */ private final List<IntegerSegment> pagesMetrics; /** * Returns {@code TextComponentPrintable} to print {@code textComponent}. * * @param textComponent {@code JTextComponent} to print * @param headerFormat the page header, or {@code null} for none * @param footerFormat the page footer, or {@code null} for none * @return {@code TextComponentPrintable} to print {@code textComponent} */ public static Printable getPrintable(final JTextComponent textComponent, final MessageFormat headerFormat, final MessageFormat footerFormat) { if (textComponent instanceof JEditorPane && isFrameSetDocument(textComponent.getDocument())) { //for document with frames we create one printable per //frame and merge them with the CompoundPrintable. List<JEditorPane> frames = getFrames((JEditorPane) textComponent); List<CountingPrintable> printables = new ArrayList<CountingPrintable>(); for (JEditorPane frame : frames) { printables.add((CountingPrintable) getPrintable(frame, headerFormat, footerFormat)); } return new CompoundPrintable(printables); } else { return new TextComponentPrintable(textComponent, headerFormat, footerFormat); } } /** * Checks whether the document has frames. Only HTMLDocument might * have frames. * * @param document the {@code Document} to check * @return {@code true} if the {@code document} has frames */ private static boolean isFrameSetDocument(final Document document) { boolean ret = false; if (document instanceof HTMLDocument) { HTMLDocument htmlDocument = (HTMLDocument)document; if (htmlDocument.getIterator(HTML.Tag.FRAME).isValid()) { ret = true; } } return ret; } /** * Returns frames under the {@code editor}. * The frames are created if necessary. * * @param editor the {@JEditorPane} to find the frames for * @return list of all frames */ private static List<JEditorPane> getFrames(final JEditorPane editor) { List<JEditorPane> list = new ArrayList<JEditorPane>(); getFrames(editor, list); if (list.size() == 0) { //the frames have not been created yet. //let's trigger the frames creation. createFrames(editor); getFrames(editor, list); } return list; } /** * Adds all {@code JEditorPanes} under {@code container} tagged by {@code * FrameEditorPaneTag} to the {@code list}. It adds only top * level {@code JEditorPanes}. For instance if there is a frame * inside the frame it will return the top frame only. * * @param c the container to find all frames under * @param list {@code List} to append the results too */ private static void getFrames(final Container container, List<JEditorPane> list) { for (Component c : container.getComponents()) { if (c instanceof FrameEditorPaneTag && c instanceof JEditorPane ) { //it should be always JEditorPane list.add((JEditorPane) c); } else { if (c instanceof Container) { getFrames((Container) c, list); } } } } /** * Triggers the frames creation for {@code JEditorPane} * * @param editor the {@code JEditorPane} to create frames for */ private static void createFrames(final JEditorPane editor) { Runnable doCreateFrames = new Runnable() { public void run() { final int WIDTH = 500; final int HEIGHT = 500; CellRendererPane rendererPane = new CellRendererPane(); rendererPane.add(editor); //the values do not matter //we only need to get frames created rendererPane.setSize(WIDTH, HEIGHT); }; }; if (SwingUtilities.isEventDispatchThread()) { doCreateFrames.run(); } else { try { SwingUtilities.invokeAndWait(doCreateFrames); } catch (Exception e) { if (e instanceof RuntimeException) { throw (RuntimeException) e; } else { throw new RuntimeException(e); } } } } /** * Constructs {@code TextComponentPrintable} to print {@code JTextComponent} * {@code textComponent} with {@code headerFormat} and {@code footerFormat}. * * @param textComponent {@code JTextComponent} to print * @param headerFormat the page header or {@code null} for none * @param footerFormat the page footer or {@code null} for none */ private TextComponentPrintable(JTextComponent textComponent, MessageFormat headerFormat, MessageFormat footerFormat) { this.textComponentToPrint = textComponent; this.headerFormat = headerFormat; this.footerFormat = footerFormat; headerFont = textComponent.getFont().deriveFont(Font.BOLD, HEADER_FONT_SIZE); footerFont = textComponent.getFont().deriveFont(Font.PLAIN, FOOTER_FONT_SIZE); this.pagesMetrics = Collections.synchronizedList(new ArrayList<IntegerSegment>()); this.rowsMetrics = new ArrayList<IntegerSegment>(LIST_SIZE); this.printShell = createPrintShell(textComponent); } /** * creates a printShell. * It creates closest text component to {@code textComponent} * which uses {@code frc} from the {@code TextComponentPrintable} * for the {@code getFontMetrics} method. * * @param textComponent {@code JTextComponent} to create a * printShell for * @return the print shell */ private JTextComponent createPrintShell(final JTextComponent textComponent) { if (SwingUtilities.isEventDispatchThread()) { return createPrintShellOnEDT(textComponent); } else { FutureTask<JTextComponent> futureCreateShell = new FutureTask<JTextComponent>( new Callable<JTextComponent>() { public JTextComponent call() throws Exception { return createPrintShellOnEDT(textComponent); } }); SwingUtilities.invokeLater(futureCreateShell); try { return futureCreateShell.get(); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (ExecutionException e) { Throwable cause = e.getCause(); if (cause instanceof Error) { throw (Error) cause; } if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } throw new AssertionError(cause); } } } private JTextComponent createPrintShellOnEDT(final JTextComponent textComponent) { assert SwingUtilities.isEventDispatchThread(); JTextComponent ret = null; if (textComponent instanceof JTextField) { ret = new JTextField() { { setHorizontalAlignment( ((JTextField) textComponent).getHorizontalAlignment()); } @Override public FontMetrics getFontMetrics(Font font) { return (frc.get() == null) ? super.getFontMetrics(font) : FontDesignMetrics.getMetrics(font, frc.get()); } }; } else if (textComponent instanceof JTextArea) { ret = new JTextArea() { { JTextArea textArea = (JTextArea) textComponent; setLineWrap(textArea.getLineWrap()); setWrapStyleWord(textArea.getWrapStyleWord()); setTabSize(textArea.getTabSize()); } @Override public FontMetrics getFontMetrics(Font font) { return (frc.get() == null) ? super.getFontMetrics(font) : FontDesignMetrics.getMetrics(font, frc.get()); } }; } else if (textComponent instanceof JTextPane) { ret = new JTextPane() { @Override public FontMetrics getFontMetrics(Font font) { return (frc.get() == null) ? super.getFontMetrics(font) : FontDesignMetrics.getMetrics(font, frc.get()); } @Override public EditorKit getEditorKit() { if (getDocument() == textComponent.getDocument()) { return ((JTextPane) textComponent).getEditorKit(); } else { return super.getEditorKit(); } } }; } else if (textComponent instanceof JEditorPane) { ret = new JEditorPane() { @Override public FontMetrics getFontMetrics(Font font) { return (frc.get() == null) ? super.getFontMetrics(font) : FontDesignMetrics.getMetrics(font, frc.get()); } @Override public EditorKit getEditorKit() { if (getDocument() == textComponent.getDocument()) { return ((JEditorPane) textComponent).getEditorKit(); } else { return super.getEditorKit(); } } }; } //want to occupy the whole width and height by text ret.setBorder(null); //set properties from the component to print ret.setOpaque(textComponent.isOpaque()); ret.setEditable(textComponent.isEditable()); ret.setEnabled(textComponent.isEnabled()); ret.setFont(textComponent.getFont()); ret.setBackground(textComponent.getBackground()); ret.setForeground(textComponent.getForeground()); ret.setComponentOrientation( textComponent.getComponentOrientation()); if (ret instanceof JEditorPane) { ret.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, textComponent.getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES)); ret.putClientProperty(JEditorPane.W3C_LENGTH_UNITS, textComponent.getClientProperty(JEditorPane.W3C_LENGTH_UNITS)); ret.putClientProperty("charset", textComponent.getClientProperty("charset")); } ret.setDocument(textComponent.getDocument()); return ret; } /** * Returns the number of pages in this printable. * <p> * This number is defined only after {@code print} returns NO_SUCH_PAGE. * * @return the number of pages. */ public int getNumberOfPages() { return pagesMetrics.size(); } /** * See Printable.print for the API description. * * There are two parts in the implementation. * First part (print) is to be called on the printing thread. * Second part (printOnEDT) is to be called on the EDT only. * * print triggers printOnEDT */ public int print(final Graphics graphics, final PageFormat pf, final int pageIndex) throws PrinterException { if (!isLayouted) { if (graphics instanceof Graphics2D) { frc.set(((Graphics2D)graphics).getFontRenderContext()); } layout((int)Math.floor(pf.getImageableWidth())); calculateRowsMetrics(); } int ret; if (!SwingUtilities.isEventDispatchThread()) { Callable<Integer> doPrintOnEDT = new Callable<Integer>() { public Integer call() throws Exception { return printOnEDT(graphics, pf, pageIndex); } }; FutureTask<Integer> futurePrintOnEDT = new FutureTask<Integer>(doPrintOnEDT); SwingUtilities.invokeLater(futurePrintOnEDT); try { ret = futurePrintOnEDT.get(); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (ExecutionException e) { Throwable cause = e.getCause(); if (cause instanceof PrinterException) { throw (PrinterException)cause; } else if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } else { throw new RuntimeException(cause); } } } else { ret = printOnEDT(graphics, pf, pageIndex); } return ret; } /** * The EDT part of the print method. *