feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
73
jdkSrc/jdk8/sun/swing/text/CompoundPrintable.java
Normal file
73
jdkSrc/jdk8/sun/swing/text/CompoundPrintable.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 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.util.*;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.print.*;
|
||||
|
||||
|
||||
/**
|
||||
* Printable to merge multiple printables into one.
|
||||
*
|
||||
* @author Igor Kushnirskiy
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
class CompoundPrintable implements CountingPrintable {
|
||||
private final Queue<CountingPrintable> printables;
|
||||
private int offset = 0;
|
||||
|
||||
public CompoundPrintable(List<CountingPrintable> printables) {
|
||||
this.printables = new LinkedList<CountingPrintable>(printables);
|
||||
}
|
||||
|
||||
public int print(final Graphics graphics,
|
||||
final PageFormat pf,
|
||||
final int pageIndex) throws PrinterException {
|
||||
int ret = NO_SUCH_PAGE;
|
||||
while (printables.peek() != null) {
|
||||
ret = printables.peek().print(graphics, pf, pageIndex - offset);
|
||||
if (ret == PAGE_EXISTS) {
|
||||
break;
|
||||
} else {
|
||||
offset += printables.poll().getNumberOfPages();
|
||||
}
|
||||
}
|
||||
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 offset;
|
||||
}
|
||||
|
||||
}
|
||||
47
jdkSrc/jdk8/sun/swing/text/CountingPrintable.java
Normal file
47
jdkSrc/jdk8/sun/swing/text/CountingPrintable.java
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 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.print.*;
|
||||
|
||||
/**
|
||||
* Printable which counts the number of pages.
|
||||
*
|
||||
* @author Igor Kushnirskiy
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
public interface CountingPrintable extends Printable {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
int getNumberOfPages();
|
||||
}
|
||||
846
jdkSrc/jdk8/sun/swing/text/TextComponentPrintable.java
Normal file
846
jdkSrc/jdk8/sun/swing/text/TextComponentPrintable.java
Normal file
@@ -0,0 +1,846 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2011, 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.*;
|
||||
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 JPasswordField) {
|
||||
ret =
|
||||
new JPasswordField() {
|
||||
{
|
||||
setEchoChar(((JPasswordField) textComponent).getEchoChar());
|
||||
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 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.
|
||||
*
|
||||
* This method is to be called on the EDT only. Layout should be done before
|
||||
* calling this method.
|
||||
*/
|
||||
private int printOnEDT(final Graphics graphics,
|
||||
final PageFormat pf,
|
||||
final int pageIndex) throws PrinterException {
|
||||
assert SwingUtilities.isEventDispatchThread();
|
||||
Border border = BorderFactory.createEmptyBorder();
|
||||
//handle header and footer
|
||||
if (headerFormat != null || footerFormat != null) {
|
||||
//Printable page enumeration is 0 base. We need 1 based.
|
||||
Object[] formatArg = new Object[]{Integer.valueOf(pageIndex + 1)};
|
||||
if (headerFormat != null) {
|
||||
border = new TitledBorder(border,
|
||||
headerFormat.format(formatArg),
|
||||
TitledBorder.CENTER, TitledBorder.ABOVE_TOP,
|
||||
headerFont, printShell.getForeground());
|
||||
}
|
||||
if (footerFormat != null) {
|
||||
border = new TitledBorder(border,
|
||||
footerFormat.format(formatArg),
|
||||
TitledBorder.CENTER, TitledBorder.BELOW_BOTTOM,
|
||||
footerFont, printShell.getForeground());
|
||||
}
|
||||
}
|
||||
Insets borderInsets = border.getBorderInsets(printShell);
|
||||
updatePagesMetrics(pageIndex,
|
||||
(int)Math.floor(pf.getImageableHeight()) - borderInsets.top
|
||||
- borderInsets.bottom);
|
||||
|
||||
if (pagesMetrics.size() <= pageIndex) {
|
||||
return NO_SUCH_PAGE;
|
||||
}
|
||||
|
||||
Graphics2D g2d = (Graphics2D)graphics.create();
|
||||
|
||||
g2d.translate(pf.getImageableX(), pf.getImageableY());
|
||||
border.paintBorder(printShell, g2d, 0, 0,
|
||||
(int)Math.floor(pf.getImageableWidth()),
|
||||
(int)Math.floor(pf.getImageableHeight()));
|
||||
|
||||
g2d.translate(0, borderInsets.top);
|
||||
//want to clip only vertically
|
||||
Rectangle clip = new Rectangle(0, 0,
|
||||
(int) pf.getWidth(),
|
||||
pagesMetrics.get(pageIndex).end
|
||||
- pagesMetrics.get(pageIndex).start + 1);
|
||||
|
||||
g2d.clip(clip);
|
||||
int xStart = 0;
|
||||
if (ComponentOrientation.RIGHT_TO_LEFT ==
|
||||
printShell.getComponentOrientation()) {
|
||||
xStart = (int) pf.getImageableWidth() - printShell.getWidth();
|
||||
}
|
||||
g2d.translate(xStart, - pagesMetrics.get(pageIndex).start);
|
||||
printShell.print(g2d);
|
||||
|
||||
g2d.dispose();
|
||||
|
||||
return Printable.PAGE_EXISTS;
|
||||
}
|
||||
|
||||
|
||||
private boolean needReadLock = false;
|
||||
|
||||
/**
|
||||
* Tries to release document's readlock
|
||||
*
|
||||
* Note: Not to be called on the EDT.
|
||||
*/
|
||||
private void releaseReadLock() {
|
||||
assert ! SwingUtilities.isEventDispatchThread();
|
||||
Document document = textComponentToPrint.getDocument();
|
||||
if (document instanceof AbstractDocument) {
|
||||
try {
|
||||
((AbstractDocument) document).readUnlock();
|
||||
needReadLock = true;
|
||||
} catch (Error ignore) {
|
||||
// readUnlock() might throw StateInvariantError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tries to acquire document's readLock if it was released
|
||||
* in releaseReadLock() method.
|
||||
*
|
||||
* Note: Not to be called on the EDT.
|
||||
*/
|
||||
private void acquireReadLock() {
|
||||
assert ! SwingUtilities.isEventDispatchThread();
|
||||
if (needReadLock) {
|
||||
try {
|
||||
/*
|
||||
* wait until all the EDT events are processed
|
||||
* some of the document changes are asynchronous
|
||||
* we need to make sure we get the lock after those changes
|
||||
*/
|
||||
SwingUtilities.invokeAndWait(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
}
|
||||
});
|
||||
} catch (InterruptedException ignore) {
|
||||
} catch (java.lang.reflect.InvocationTargetException ignore) {
|
||||
}
|
||||
Document document = textComponentToPrint.getDocument();
|
||||
((AbstractDocument) document).readLock();
|
||||
needReadLock = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares {@code printShell} for printing.
|
||||
*
|
||||
* Sets properties from the component to print.
|
||||
* Sets width and FontRenderContext.
|
||||
*
|
||||
* Triggers Views creation for the printShell.
|
||||
*
|
||||
* There are two parts in the implementation.
|
||||
* First part (layout) is to be called on the printing thread.
|
||||
* Second part (layoutOnEDT) is to be called on the EDT only.
|
||||
*
|
||||
* {@code layout} triggers {@code layoutOnEDT}.
|
||||
*
|
||||
* @param width width to layout the text for
|
||||
*/
|
||||
private void layout(final int width) {
|
||||
if (!SwingUtilities.isEventDispatchThread()) {
|
||||
Callable<Object> doLayoutOnEDT = new Callable<Object>() {
|
||||
public Object call() throws Exception {
|
||||
layoutOnEDT(width);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
FutureTask<Object> futureLayoutOnEDT = new FutureTask<Object>(
|
||||
doLayoutOnEDT);
|
||||
|
||||
/*
|
||||
* We need to release document's readlock while printShell is
|
||||
* initializing
|
||||
*/
|
||||
releaseReadLock();
|
||||
SwingUtilities.invokeLater(futureLayoutOnEDT);
|
||||
try {
|
||||
futureLayoutOnEDT.get();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ExecutionException e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof RuntimeException) {
|
||||
throw (RuntimeException) cause;
|
||||
} else if (cause instanceof Error) {
|
||||
throw (Error) cause;
|
||||
} else {
|
||||
throw new RuntimeException(cause);
|
||||
}
|
||||
} finally {
|
||||
acquireReadLock();
|
||||
}
|
||||
} else {
|
||||
layoutOnEDT(width);
|
||||
}
|
||||
|
||||
isLayouted = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The EDT part of layout method.
|
||||
*
|
||||
* This method is to be called on the EDT only.
|
||||
*/
|
||||
private void layoutOnEDT(final int width) {
|
||||
assert SwingUtilities.isEventDispatchThread();
|
||||
//need to have big value but smaller than MAX_VALUE otherwise
|
||||
//printing goes south due to overflow somewhere
|
||||
final int HUGE_INTEGER = Integer.MAX_VALUE - 1000;
|
||||
|
||||
CellRendererPane rendererPane = new CellRendererPane();
|
||||
|
||||
//need to use JViewport since text is layouted to the viewPort width
|
||||
//otherwise it will be layouted to the maximum text width
|
||||
JViewport viewport = new JViewport();
|
||||
viewport.setBorder(null);
|
||||
Dimension size = new Dimension(width, HUGE_INTEGER);
|
||||
|
||||
//JTextField is a special case
|
||||
//it layouts text in the middle by Y
|
||||
if (printShell instanceof JTextField) {
|
||||
size =
|
||||
new Dimension(size.width, printShell.getPreferredSize().height);
|
||||
}
|
||||
printShell.setSize(size);
|
||||
viewport.setComponentOrientation(printShell.getComponentOrientation());
|
||||
viewport.setSize(size);
|
||||
viewport.add(printShell);
|
||||
rendererPane.add(viewport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates pageMetrics for the pages up to the {@code pageIndex} using
|
||||
* {@code rowsMetrics}.
|
||||
* Metrics are stored in the {@code pagesMetrics}.
|
||||
*
|
||||
* @param pageIndex the page to update the metrics for
|
||||
* @param pageHeight the page height
|
||||
*/
|
||||
private void updatePagesMetrics(final int pageIndex, final int pageHeight) {
|
||||
while (pageIndex >= pagesMetrics.size() && !rowsMetrics.isEmpty()) {
|
||||
// add one page to the pageMetrics
|
||||
int lastPage = pagesMetrics.size() - 1;
|
||||
int pageStart = (lastPage >= 0)
|
||||
? pagesMetrics.get(lastPage).end + 1
|
||||
: 0;
|
||||
int rowIndex;
|
||||
for (rowIndex = 0;
|
||||
rowIndex < rowsMetrics.size()
|
||||
&& (rowsMetrics.get(rowIndex).end - pageStart + 1)
|
||||
<= pageHeight;
|
||||
rowIndex++) {
|
||||
}
|
||||
if (rowIndex == 0) {
|
||||
// can not fit a single row
|
||||
// need to split
|
||||
pagesMetrics.add(
|
||||
new IntegerSegment(pageStart, pageStart + pageHeight - 1));
|
||||
} else {
|
||||
rowIndex--;
|
||||
pagesMetrics.add(new IntegerSegment(pageStart,
|
||||
rowsMetrics.get(rowIndex).end));
|
||||
for (int i = 0; i <= rowIndex; i++) {
|
||||
rowsMetrics.remove(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates rowsMetrics for the document. The result is stored
|
||||
* in the {@code rowsMetrics}.
|
||||
*
|
||||
* Two steps process.
|
||||
* First step is to find yStart and yEnd for the every document position.
|
||||
* Second step is to merge all intersected segments ( [yStart, yEnd] ).
|
||||
*/
|
||||
private void calculateRowsMetrics() {
|
||||
final int documentLength = printShell.getDocument().getLength();
|
||||
List<IntegerSegment> documentMetrics = new ArrayList<IntegerSegment>(LIST_SIZE);
|
||||
Rectangle rect;
|
||||
for (int i = 0, previousY = -1, previousHeight = -1; i < documentLength;
|
||||
i++) {
|
||||
try {
|
||||
rect = printShell.modelToView(i);
|
||||
if (rect != null) {
|
||||
int y = (int) rect.getY();
|
||||
int height = (int) rect.getHeight();
|
||||
if (height != 0
|
||||
&& (y != previousY || height != previousHeight)) {
|
||||
/*
|
||||
* we do not store the same value as previous. in our
|
||||
* documents it is often for consequent positons to have
|
||||
* the same modelToView y and height.
|
||||
*/
|
||||
previousY = y;
|
||||
previousHeight = height;
|
||||
documentMetrics.add(new IntegerSegment(y, y + height - 1));
|
||||
}
|
||||
}
|
||||
} catch (BadLocationException e) {
|
||||
assert false;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Merge all intersected segments.
|
||||
*/
|
||||
Collections.sort(documentMetrics);
|
||||
int yStart = Integer.MIN_VALUE;
|
||||
int yEnd = Integer.MIN_VALUE;
|
||||
for (IntegerSegment segment : documentMetrics) {
|
||||
if (yEnd < segment.start) {
|
||||
if (yEnd != Integer.MIN_VALUE) {
|
||||
rowsMetrics.add(new IntegerSegment(yStart, yEnd));
|
||||
}
|
||||
yStart = segment.start;
|
||||
yEnd = segment.end;
|
||||
} else {
|
||||
yEnd = segment.end;
|
||||
}
|
||||
}
|
||||
if (yEnd != Integer.MIN_VALUE) {
|
||||
rowsMetrics.add(new IntegerSegment(yStart, yEnd));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to represent segment of integers.
|
||||
* we do not call it Segment to avoid confusion with
|
||||
* javax.swing.text.Segment
|
||||
*/
|
||||
private static class IntegerSegment implements Comparable<IntegerSegment> {
|
||||
final int start;
|
||||
final int end;
|
||||
|
||||
IntegerSegment(int start, int end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public int compareTo(IntegerSegment object) {
|
||||
int startsDelta = start - object.start;
|
||||
return (startsDelta != 0) ? startsDelta : end - object.end;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof IntegerSegment) {
|
||||
return compareTo((IntegerSegment) obj) == 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// from the "Effective Java: Programming Language Guide"
|
||||
int result = 17;
|
||||
result = 37 * result + start;
|
||||
result = 37 * result + end;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IntegerSegment [" + start + ", " + end + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
36
jdkSrc/jdk8/sun/swing/text/html/FrameEditorPaneTag.java
Normal file
36
jdkSrc/jdk8/sun/swing/text/html/FrameEditorPaneTag.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 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.html;
|
||||
|
||||
|
||||
/**
|
||||
* This interface is used only for tagging
|
||||
* FrameEditorPane in javax.swing.text.html.FrameView.
|
||||
*/
|
||||
|
||||
public interface FrameEditorPaneTag {
|
||||
}
|
||||
Reference in New Issue
Block a user