001: /*
002: *
003: * Copyright 2002 by Paulo Soares.
004: *
005: * The contents of this file are subject to the Mozilla Public License Version 1.1
006: * (the "License"); you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
008: *
009: * Software distributed under the License is distributed on an "AS IS" basis,
010: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
011: * for the specific language governing rights and limitations under the License.
012: *
013: * The Original Code is 'iText, a free JAVA-PDF library'.
014: *
015: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
016: * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
017: * All Rights Reserved.
018: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
019: * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
020: *
021: * Contributor(s): all the names of the contributors are added in the source code
022: * where applicable.
023: *
024: * Alternatively, the contents of this file may be used under the terms of the
025: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
026: * provisions of LGPL are applicable instead of those above. If you wish to
027: * allow use of your version of this file only under the terms of the LGPL
028: * License and not to allow others to use your version of this file under
029: * the MPL, indicate your decision by deleting the provisions above and
030: * replace them with the notice and other provisions required by the LGPL.
031: * If you do not delete the provisions above, a recipient may use your version
032: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
033: *
034: * This library is free software; you can redistribute it and/or modify it
035: * under the terms of the MPL as stated above or under the terms of the GNU
036: * Library General Public License as published by the Free Software Foundation;
037: * either version 2 of the License, or any later version.
038: *
039: * This library is distributed in the hope that it will be useful, but WITHOUT
040: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
041: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
042: * details.
043: *
044: * If you didn't download this code from the following link, you should check if
045: * you aren't using an obsolete version:
046: * http://www.lowagie.com/iText/
047: */
048: package com.lowagie.text.pdf;
049:
050: import java.awt.Color;
051: import java.util.ArrayList;
052: import java.util.Iterator;
053:
054: import com.lowagie.text.Chunk;
055: import com.lowagie.text.Element;
056: import com.lowagie.text.Phrase;
057:
058: /** Writes text vertically. Note that the naming is done according
059: * to horizontal text although it referrs to vertical text.
060: * A line with the alignment Element.LEFT_ALIGN will actually
061: * be top aligned.
062: */
063: public class VerticalText {
064:
065: /** Signals that there are no more text available. */
066: public static final int NO_MORE_TEXT = 1;
067:
068: /** Signals that there is no more column. */
069: public static final int NO_MORE_COLUMN = 2;
070:
071: /** The chunks that form the text. */
072: protected ArrayList chunks = new ArrayList();
073:
074: /** The <CODE>PdfContent</CODE> where the text will be written to. */
075: protected PdfContentByte text;
076:
077: /** The column alignment. Default is left alignment. */
078: protected int alignment = Element.ALIGN_LEFT;
079:
080: /** Marks the chunks to be eliminated when the line is written. */
081: protected int currentChunkMarker = -1;
082:
083: /** The chunk created by the splitting. */
084: protected PdfChunk currentStandbyChunk;
085:
086: /** The chunk created by the splitting. */
087: protected String splittedChunkText;
088:
089: /** The leading
090: */
091: protected float leading;
092:
093: /** The X coordinate.
094: */
095: protected float startX;
096:
097: /** The Y coordinate.
098: */
099: protected float startY;
100:
101: /** The maximum number of vertical lines.
102: */
103: protected int maxLines;
104:
105: /** The height of the text.
106: */
107: protected float height;
108:
109: /** Creates new VerticalText
110: * @param text the place where the text will be written to. Can
111: * be a template.
112: */
113: public VerticalText(PdfContentByte text) {
114: this .text = text;
115: }
116:
117: /**
118: * Adds a <CODE>Phrase</CODE> to the current text array.
119: * @param phrase the text
120: */
121: public void addText(Phrase phrase) {
122: for (Iterator j = phrase.getChunks().iterator(); j.hasNext();) {
123: chunks.add(new PdfChunk((Chunk) j.next(), null));
124: }
125: }
126:
127: /**
128: * Adds a <CODE>Chunk</CODE> to the current text array.
129: * @param chunk the text
130: */
131: public void addText(Chunk chunk) {
132: chunks.add(new PdfChunk(chunk, null));
133: }
134:
135: /** Sets the layout.
136: * @param startX the top right X line position
137: * @param startY the top right Y line position
138: * @param height the height of the lines
139: * @param maxLines the maximum number of lines
140: * @param leading the separation between the lines
141: */
142: public void setVerticalLayout(float startX, float startY,
143: float height, int maxLines, float leading) {
144: this .startX = startX;
145: this .startY = startY;
146: this .height = height;
147: this .maxLines = maxLines;
148: setLeading(leading);
149: }
150:
151: /** Sets the separation between the vertical lines.
152: * @param leading the vertical line separation
153: */
154: public void setLeading(float leading) {
155: this .leading = leading;
156: }
157:
158: /** Gets the separation between the vertical lines.
159: * @return the vertical line separation
160: */
161: public float getLeading() {
162: return leading;
163: }
164:
165: /**
166: * Creates a line from the chunk array.
167: * @param width the width of the line
168: * @return the line or null if no more chunks
169: */
170: protected PdfLine createLine(float width) {
171: if (chunks.isEmpty())
172: return null;
173: splittedChunkText = null;
174: currentStandbyChunk = null;
175: PdfLine line = new PdfLine(0, width, alignment, 0);
176: String total;
177: for (currentChunkMarker = 0; currentChunkMarker < chunks.size(); ++currentChunkMarker) {
178: PdfChunk original = (PdfChunk) (chunks
179: .get(currentChunkMarker));
180: total = original.toString();
181: currentStandbyChunk = line.add(original);
182: if (currentStandbyChunk != null) {
183: splittedChunkText = original.toString();
184: original.setValue(total);
185: return line;
186: }
187: }
188: return line;
189: }
190:
191: /**
192: * Normalizes the list of chunks when the line is accepted.
193: */
194: protected void shortenChunkArray() {
195: if (currentChunkMarker < 0)
196: return;
197: if (currentChunkMarker >= chunks.size()) {
198: chunks.clear();
199: return;
200: }
201: PdfChunk split = (PdfChunk) (chunks.get(currentChunkMarker));
202: split.setValue(splittedChunkText);
203: chunks.set(currentChunkMarker, currentStandbyChunk);
204: for (int j = currentChunkMarker - 1; j >= 0; --j)
205: chunks.remove(j);
206: }
207:
208: /**
209: * Outputs the lines to the document. It is equivalent to <CODE>go(false)</CODE>.
210: * @return returns the result of the operation. It can be <CODE>NO_MORE_TEXT</CODE>
211: * and/or <CODE>NO_MORE_COLUMN</CODE>
212: */
213: public int go() {
214: return go(false);
215: }
216:
217: /**
218: * Outputs the lines to the document. The output can be simulated.
219: * @param simulate <CODE>true</CODE> to simulate the writting to the document
220: * @return returns the result of the operation. It can be <CODE>NO_MORE_TEXT</CODE>
221: * and/or <CODE>NO_MORE_COLUMN</CODE>
222: */
223: public int go(boolean simulate) {
224: boolean dirty = false;
225: PdfContentByte graphics = null;
226: if (text != null) {
227: graphics = text.getDuplicate();
228: } else if (!simulate)
229: throw new NullPointerException(
230: "VerticalText.go with simulate==false and text==null.");
231: int status = 0;
232: for (;;) {
233: if (maxLines <= 0) {
234: status = NO_MORE_COLUMN;
235: if (chunks.isEmpty())
236: status |= NO_MORE_TEXT;
237: break;
238: }
239: if (chunks.isEmpty()) {
240: status = NO_MORE_TEXT;
241: break;
242: }
243: PdfLine line = createLine(height);
244: if (!simulate && !dirty) {
245: text.beginText();
246: dirty = true;
247: }
248: shortenChunkArray();
249: if (!simulate) {
250: text.setTextMatrix(startX, startY - line.indentLeft());
251: writeLine(line, text, graphics);
252: }
253: --maxLines;
254: startX -= leading;
255: }
256: if (dirty) {
257: text.endText();
258: text.add(graphics);
259: }
260: return status;
261: }
262:
263: void writeLine(PdfLine line, PdfContentByte text,
264: PdfContentByte graphics) {
265: PdfFont currentFont = null;
266: PdfChunk chunk;
267: for (Iterator j = line.iterator(); j.hasNext();) {
268: chunk = (PdfChunk) j.next();
269:
270: if (chunk.font().compareTo(currentFont) != 0) {
271: currentFont = chunk.font();
272: text.setFontAndSize(currentFont.getFont(), currentFont
273: .size());
274: }
275: Color color = chunk.color();
276: if (color != null)
277: text.setColorFill(color);
278: text.showText(chunk.toString());
279: if (color != null)
280: text.resetRGBColorFill();
281: }
282: }
283:
284: /** Sets the new text origin.
285: * @param startX the X coordinate
286: * @param startY the Y coordinate
287: */
288: public void setOrigin(float startX, float startY) {
289: this .startX = startX;
290: this .startY = startY;
291: }
292:
293: /** Gets the X coordinate where the next line will be writen. This value will change
294: * after each call to <code>go()</code>.
295: * @return the X coordinate
296: */
297: public float getOriginX() {
298: return startX;
299: }
300:
301: /** Gets the Y coordinate where the next line will be writen.
302: * @return the Y coordinate
303: */
304: public float getOriginY() {
305: return startY;
306: }
307:
308: /** Gets the maximum number of available lines. This value will change
309: * after each call to <code>go()</code>.
310: * @return Value of property maxLines.
311: */
312: public int getMaxLines() {
313: return maxLines;
314: }
315:
316: /** Sets the maximum number of lines.
317: * @param maxLines the maximum number of lines
318: */
319: public void setMaxLines(int maxLines) {
320: this .maxLines = maxLines;
321: }
322:
323: /** Gets the height of the line
324: * @return the height
325: */
326: public float getHeight() {
327: return height;
328: }
329:
330: /** Sets the height of the line
331: * @param height the new height
332: */
333: public void setHeight(float height) {
334: this .height = height;
335: }
336:
337: /**
338: * Sets the alignment.
339: * @param alignment the alignment
340: */
341: public void setAlignment(int alignment) {
342: this .alignment = alignment;
343: }
344:
345: /**
346: * Gets the alignment.
347: * @return the alignment
348: */
349: public int getAlignment() {
350: return alignment;
351: }
352: }
|