001: /*
002: * (C) Copyright IBM Corp. 1998-2004. All Rights Reserved.
003: *
004: * The program is provided "as is" without any warranty express or
005: * implied, including the warranty of non-infringement and the implied
006: * warranties of merchantibility and fitness for a particular purpose.
007: * IBM will not be liable for any damages suffered by you as a result
008: * of using the Program. In no event will IBM be liable for any
009: * special, indirect or consequential damages or lost profits even if
010: * IBM has been advised of the possibility of their occurrence. IBM
011: * will not be liable for any third party claims against you.
012: */
013: package com.ibm.richtext.print;
014:
015: import com.ibm.richtext.styledtext.MConstText;
016:
017: import com.ibm.richtext.textformat.MFormatter;
018:
019: import com.ibm.richtext.textlayout.attributes.AttributeMap;
020:
021: import java.awt.Color;
022: import java.awt.Graphics;
023: import java.awt.Point;
024: import java.awt.Rectangle;
025:
026: import java.util.Vector;
027:
028: /**
029: * This class's interface is very close to that of the JDK 1.2 Printable
030: * interface, but can execute on JDK 1.1. On 1.2, this class is wrapped
031: * in a real Printable. On 1.1, the PrintContext class uses this class
032: * and a PrintJob for printing.
033: *
034: * Note that this class paginates the text in the first call to print,
035: * or to getPageCount.
036: * After construction, its page size is essentially fixed. This is not
037: * as flexible as the 1.2 classes allow, but it should suffice.
038: */
039: final class MConstTextPrintable {
040:
041: static final String COPYRIGHT = "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
042:
043: static final int PAGE_EXISTS = 0;
044: static final int NO_SUCH_PAGE = 1;
045:
046: private MConstText fText;
047: private AttributeMap fDefaultStyles;
048: private Rectangle fPageRect;
049:
050: // If these two fields are null the text has not been paginated.
051: private MFormatter fFormatter;
052: private Vector fPageStarts;
053:
054: /**
055: * Construct an MConstTextPrintable to print the given text. Each page will fit
056: * into pageRect.
057: */
058: MConstTextPrintable(MConstText text, AttributeMap defaultStyles,
059: Rectangle pageRect) {
060:
061: fText = text;
062: fDefaultStyles = defaultStyles;
063: fPageRect = new Rectangle(pageRect);
064: }
065:
066: private static boolean emptyParagraphAtEndOfText(MConstText text) {
067:
068: if (text.length() > 0) {
069: char ch = text.at(text.length() - 1);
070: return ch == '\n' || ch == '\u2029';
071: } else {
072: return false;
073: }
074: }
075:
076: private void paginate(Graphics graphics) {
077:
078: if (fPageStarts == null) {
079:
080: fFormatter = MFormatter.createFormatter(fText,
081: fDefaultStyles, fPageRect.width, true, graphics);
082:
083: fFormatter.formatToHeight(Integer.MAX_VALUE);
084: fFormatter.stopBackgroundFormatting();
085:
086: fPageStarts = new Vector();
087:
088: int lineCount = fFormatter.getLineCount();
089: if (emptyParagraphAtEndOfText(fText)) {
090: lineCount -= 1;
091: }
092:
093: int startLine = 0;
094: fPageStarts.addElement(new Integer(startLine));
095: int startHeight = 0;
096: final int pageHeight = fPageRect.height;
097:
098: while (startLine < lineCount) {
099:
100: int nextStart = fFormatter.lineAtHeight(startHeight
101: + pageHeight);
102: fPageStarts.addElement(new Integer(nextStart));
103: startHeight = fFormatter.lineGraphicStart(nextStart);
104: startLine = nextStart;
105: }
106: }
107: }
108:
109: /**
110: * Print the given page in the given graphics. Page numbers are
111: * 0-based. The the return value indicates whether
112: * the page number is valid (as in JDK 1.2). Since you can get the page count
113: * directly, there's really no excuse for passing in an invalid page
114: * index.
115: * @param graphics the Graphics to print to
116: * @param pageNumber the 0-based page number. Should be nonnegative and
117: * less than getPageCount()
118: * @return PAGE_EXISTS if the page number is valid, or
119: * NO_SUCH_PAGE otherwise
120: */
121: int print(Graphics graphics, int pageNumber) {
122:
123: paginate(graphics);
124:
125: if (pageNumber < getPageCount(graphics) && pageNumber >= 0) {
126: graphics.setColor(Color.black); // workaround for 1.2 printing bug
127: int startLine = ((Integer) fPageStarts
128: .elementAt(pageNumber)).intValue();
129: int limitLine = ((Integer) fPageStarts
130: .elementAt(pageNumber + 1)).intValue();
131:
132: int topOfPage = fFormatter.lineGraphicStart(startLine);
133: int pageHeight = fFormatter.lineGraphicStart(limitLine)
134: - topOfPage;
135:
136: Point origin = new Point(fPageRect.x, fPageRect.y
137: - topOfPage);
138: Rectangle drawRect = new Rectangle(fPageRect);
139: drawRect.height = pageHeight;
140:
141: fFormatter.draw(graphics, drawRect, origin);
142: return PAGE_EXISTS;
143: } else {
144: return NO_SUCH_PAGE;
145: }
146: }
147:
148: /**
149: * Return the number of pages that can be printed.
150: * @param graphics a Graphics instance representative of those
151: * which will be printed into
152: */
153: int getPageCount(Graphics graphics) {
154:
155: paginate(graphics);
156: return fPageStarts.size() - 1;
157: }
158: }
|