/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.
*/
/**
* 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
*/
private boolean isLayouted = false;
/*
* The text component to print.
*/
/*
* The FontRenderContext to layout and print with
*/
/**
* Special text component used to print to the printer.
*/
/**
* 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
*/
/**
* 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
*/
/**
* 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}
*/
final MessageFormat headerFormat,
final MessageFormat footerFormat) {
if (textComponent instanceof JEditorPane
//for document with frames we create one printable per
//frame and merge them with the CompoundPrintable.
new ArrayList<CountingPrintable>();
}
return new CompoundPrintable(printables);
} else {
return new TextComponentPrintable(textComponent,
}
}
/**
* 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
*/
boolean ret = false;
if (document instanceof HTMLDocument) {
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
*/
//the frames have not been created yet.
//let's trigger the frames creation.
}
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
*/
if (c instanceof FrameEditorPaneTag
&& c instanceof JEditorPane ) { //it should be always JEditorPane
} else {
if (c instanceof Container) {
}
}
}
}
/**
* Triggers the frames creation for {@code JEditorPane}
*
* @param editor the {@code JEditorPane} to create frames for
*/
new Runnable() {
public void run() {
final int WIDTH = 500;
final int HEIGHT = 500;
//the values do not matter
//we only need to get frames created
};
};
if (SwingUtilities.isEventDispatchThread()) {
} else {
try {
} 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
*/
this.textComponentToPrint = textComponent;
this.headerFormat = headerFormat;
this.footerFormat = footerFormat;
this.pagesMetrics =
}
/**
* 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
*/
if (SwingUtilities.isEventDispatchThread()) {
return createPrintShellOnEDT(textComponent);
} else {
new FutureTask<JTextComponent>(
new Callable<JTextComponent>() {
return createPrintShellOnEDT(textComponent);
}
});
try {
return futureCreateShell.get();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
}
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
}
throw new AssertionError(cause);
}
}
}
assert SwingUtilities.isEventDispatchThread();
if (textComponent instanceof JTextField) {
ret =
new JTextField() {
{
}
? super.getFontMetrics(font)
}
};
} else if (textComponent instanceof JTextArea) {
ret =
new JTextArea() {
{
}
? super.getFontMetrics(font)
}
};
} else if (textComponent instanceof JTextPane) {
ret =
new JTextPane() {
? super.getFontMetrics(font)
}
public EditorKit getEditorKit() {
} else {
return super.getEditorKit();
}
}
};
} else if (textComponent instanceof JEditorPane) {
ret =
new JEditorPane() {
? super.getFontMetrics(font)
}
public EditorKit getEditorKit() {
} else {
return super.getEditorKit();
}
}
};
}
//want to occupy the whole width and height by text
//set properties from the component to print
if (ret instanceof JEditorPane) {
}
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
*/
final PageFormat pf,
final int pageIndex) throws PrinterException {
if (!isLayouted) {
if (graphics instanceof Graphics2D) {
}
}
int ret;
if (!SwingUtilities.isEventDispatchThread()) {
}
};
try {
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
if (cause instanceof PrinterException) {
throw (PrinterException)cause;
} else if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else {
throw new RuntimeException(cause);
}
}
} else {
}
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.
*/
final PageFormat pf,
final int pageIndex) throws PrinterException {
assert SwingUtilities.isEventDispatchThread();
//handle header and footer
//Printable page enumeration is 0 base. We need 1 based.
if (headerFormat != null) {
}
if (footerFormat != null) {
}
}
- borderInsets.bottom);
return NO_SUCH_PAGE;
}
//want to clip only vertically
int xStart = 0;
}
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();
if (document instanceof AbstractDocument) {
try {
needReadLock = true;
// 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
*/
new Runnable() {
public void run() {
}
});
} catch (InterruptedException ignore) {
}
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
*/
if (!SwingUtilities.isEventDispatchThread()) {
return null;
}
};
/*
* We need to release document's readlock while printShell is
* initializing
*/
try {
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else {
throw new RuntimeException(cause);
}
} finally {
}
} else {
}
isLayouted = true;
}
/**
* The EDT part of layout method.
*
* This method is to be called on the EDT only.
*/
assert SwingUtilities.isEventDispatchThread();
//need to have big value but smaller than MAX_VALUE otherwise
//printing goes south due to overflow somewhere
//need to use JViewport since text is layouted to the viewPort width
//otherwise it will be layouted to the maximum text width
//JTextField is a special case
//it layouts text in the middle by Y
if (printShell instanceof JTextField) {
size =
}
}
/**
* 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
*/
// add one page to the pageMetrics
: 0;
int rowIndex;
for (rowIndex = 0;
<= pageHeight;
rowIndex++) {
}
if (rowIndex == 0) {
// can not fit a single row
// need to split
} else {
rowIndex--;
for (int i = 0; i <= rowIndex; i++) {
}
}
}
}
/**
* 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() {
i++) {
try {
if (height != 0
/*
* 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;
}
}
} catch (BadLocationException e) {
assert false;
}
}
/*
* Merge all intersected segments.
*/
}
} else {
}
}
}
}
/**
* Class to represent segment of integers.
* we do not call it Segment to avoid confusion with
* javax.swing.text.Segment
*/
final int start;
final int end;
}
}
if (obj instanceof IntegerSegment) {
} else {
return false;
}
}
public int hashCode() {
// from the "Effective Java: Programming Language Guide"
int result = 17;
return result;
}
}
}
}