Source Code Cross Referenced for ColumnText.java in  » PDF » pdf-itext » com » lowagie » text » pdf » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » PDF » pdf itext » com.lowagie.text.pdf 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $Id: ColumnText.java 2742 2007-05-08 13:04:56Z blowagie $
0003:         * $Name$
0004:         *
0005:         * Copyright 2001, 2002 by Paulo Soares.
0006:         *
0007:         * The contents of this file are subject to the Mozilla Public License Version 1.1
0008:         * (the "License"); you may not use this file except in compliance with the License.
0009:         * You may obtain a copy of the License at http://www.mozilla.org/MPL/
0010:         *
0011:         * Software distributed under the License is distributed on an "AS IS" basis,
0012:         * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0013:         * for the specific language governing rights and limitations under the License.
0014:         *
0015:         * The Original Code is 'iText, a free JAVA-PDF library'.
0016:         *
0017:         * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
0018:         * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
0019:         * All Rights Reserved.
0020:         * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
0021:         * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
0022:         *
0023:         * Contributor(s): all the names of the contributors are added in the source code
0024:         * where applicable.
0025:         *
0026:         * Alternatively, the contents of this file may be used under the terms of the
0027:         * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
0028:         * provisions of LGPL are applicable instead of those above.  If you wish to
0029:         * allow use of your version of this file only under the terms of the LGPL
0030:         * License and not to allow others to use your version of this file under
0031:         * the MPL, indicate your decision by deleting the provisions above and
0032:         * replace them with the notice and other provisions required by the LGPL.
0033:         * If you do not delete the provisions above, a recipient may use your version
0034:         * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
0035:         *
0036:         * This library is free software; you can redistribute it and/or modify it
0037:         * under the terms of the MPL as stated above or under the terms of the GNU
0038:         * Library General Public License as published by the Free Software Foundation;
0039:         * either version 2 of the License, or any later version.
0040:         *
0041:         * This library is distributed in the hope that it will be useful, but WITHOUT
0042:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
0043:         * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
0044:         * details.
0045:         *
0046:         * If you didn't download this code from the following link, you should check if
0047:         * you aren't using an obsolete version:
0048:         * http://www.lowagie.com/iText/
0049:         */
0050:
0051:        package com.lowagie.text.pdf;
0052:
0053:        import java.util.ArrayList;
0054:        import java.util.Iterator;
0055:        import java.util.LinkedList;
0056:        import java.util.Stack;
0057:
0058:        import com.lowagie.text.Chunk;
0059:        import com.lowagie.text.DocumentException;
0060:        import com.lowagie.text.Element;
0061:        import com.lowagie.text.ExceptionConverter;
0062:        import com.lowagie.text.Image;
0063:        import com.lowagie.text.ListItem;
0064:        import com.lowagie.text.Paragraph;
0065:        import com.lowagie.text.Phrase;
0066:        import com.lowagie.text.SimpleTable;
0067:
0068:        /**
0069:         * Formats text in a columnwise form. The text is bound
0070:         * on the left and on the right by a sequence of lines. This allows the column
0071:         * to have any shape, not only rectangular.
0072:         * <P>
0073:         * Several parameters can be set like the first paragraph line indent and
0074:         * extra space between paragraphs.
0075:         * <P>
0076:         * A call to the method <CODE>go</CODE> will return one of the following
0077:         * situations: the column ended or the text ended.
0078:         * <P>
0079:         * I the column ended, a new column definition can be loaded with the method
0080:         * <CODE>setColumns</CODE> and the method <CODE>go</CODE> can be called again.
0081:         * <P>
0082:         * If the text ended, more text can be loaded with <CODE>addText</CODE>
0083:         * and the method <CODE>go</CODE> can be called again.<BR>
0084:         * The only limitation is that one or more complete paragraphs must be loaded
0085:         * each time.
0086:         * <P>
0087:         * Full bidirectional reordering is supported. If the run direction is
0088:         * <CODE>PdfWriter.RUN_DIRECTION_RTL</CODE> the meaning of the horizontal
0089:         * alignments and margins is mirrored.
0090:         * @author Paulo Soares (psoares@consiste.pt)
0091:         */
0092:
0093:        public class ColumnText {
0094:            /** Eliminate the arabic vowels */
0095:            public static final int AR_NOVOWEL = ArabicLigaturizer.ar_novowel;
0096:            /** Compose the tashkeel in the ligatures. */
0097:            public static final int AR_COMPOSEDTASHKEEL = ArabicLigaturizer.ar_composedtashkeel;
0098:            /** Do some extra double ligatures. */
0099:            public static final int AR_LIG = ArabicLigaturizer.ar_lig;
0100:            /**
0101:             * Digit shaping option: Replace European digits (U+0030...U+0039) by Arabic-Indic digits.
0102:             */
0103:            public static final int DIGITS_EN2AN = ArabicLigaturizer.DIGITS_EN2AN;
0104:
0105:            /**
0106:             * Digit shaping option: Replace Arabic-Indic digits by European digits (U+0030...U+0039).
0107:             */
0108:            public static final int DIGITS_AN2EN = ArabicLigaturizer.DIGITS_AN2EN;
0109:
0110:            /**
0111:             * Digit shaping option:
0112:             * Replace European digits (U+0030...U+0039) by Arabic-Indic digits
0113:             * if the most recent strongly directional character
0114:             * is an Arabic letter (its Bidi direction value is RIGHT_TO_LEFT_ARABIC).
0115:             * The initial state at the start of the text is assumed to be not an Arabic,
0116:             * letter, so European digits at the start of the text will not change.
0117:             * Compare to DIGITS_ALEN2AN_INIT_AL.
0118:             */
0119:            public static final int DIGITS_EN2AN_INIT_LR = ArabicLigaturizer.DIGITS_EN2AN_INIT_LR;
0120:
0121:            /**
0122:             * Digit shaping option:
0123:             * Replace European digits (U+0030...U+0039) by Arabic-Indic digits
0124:             * if the most recent strongly directional character
0125:             * is an Arabic letter (its Bidi direction value is RIGHT_TO_LEFT_ARABIC).
0126:             * The initial state at the start of the text is assumed to be an Arabic,
0127:             * letter, so European digits at the start of the text will change.
0128:             * Compare to DIGITS_ALEN2AN_INT_LR.
0129:             */
0130:            public static final int DIGITS_EN2AN_INIT_AL = ArabicLigaturizer.DIGITS_EN2AN_INIT_AL;
0131:
0132:            /**
0133:             * Digit type option: Use Arabic-Indic digits (U+0660...U+0669).
0134:             */
0135:            public static final int DIGIT_TYPE_AN = ArabicLigaturizer.DIGIT_TYPE_AN;
0136:
0137:            /**
0138:             * Digit type option: Use Eastern (Extended) Arabic-Indic digits (U+06f0...U+06f9).
0139:             */
0140:            public static final int DIGIT_TYPE_AN_EXTENDED = ArabicLigaturizer.DIGIT_TYPE_AN_EXTENDED;
0141:
0142:            protected int runDirection = PdfWriter.RUN_DIRECTION_DEFAULT;
0143:
0144:            /** the space char ratio */
0145:            public static final float GLOBAL_SPACE_CHAR_RATIO = 0;
0146:
0147:            /** Initial value of the status. */
0148:            public static final int START_COLUMN = 0;
0149:
0150:            /** Signals that there is no more text available. */
0151:            public static final int NO_MORE_TEXT = 1;
0152:
0153:            /** Signals that there is no more column. */
0154:            public static final int NO_MORE_COLUMN = 2;
0155:
0156:            /** The column is valid. */
0157:            protected static final int LINE_STATUS_OK = 0;
0158:
0159:            /** The line is out the column limits. */
0160:            protected static final int LINE_STATUS_OFFLIMITS = 1;
0161:
0162:            /** The line cannot fit this column position. */
0163:            protected static final int LINE_STATUS_NOLINE = 2;
0164:
0165:            /** Upper bound of the column. */
0166:            protected float maxY;
0167:
0168:            /** Lower bound of the column. */
0169:            protected float minY;
0170:
0171:            protected float leftX;
0172:
0173:            protected float rightX;
0174:
0175:            /** The column alignment. Default is left alignment. */
0176:            protected int alignment = Element.ALIGN_LEFT;
0177:
0178:            /** The left column bound. */
0179:            protected ArrayList leftWall;
0180:
0181:            /** The right column bound. */
0182:            protected ArrayList rightWall;
0183:
0184:            /** The chunks that form the text. */
0185:            //    protected ArrayList chunks = new ArrayList();
0186:            protected BidiLine bidiLine;
0187:
0188:            /** The current y line location. Text will be written at this line minus the leading. */
0189:            protected float yLine;
0190:
0191:            /** The leading for the current line. */
0192:            protected float currentLeading = 16;
0193:
0194:            /** The fixed text leading. */
0195:            protected float fixedLeading = 16;
0196:
0197:            /** The text leading that is multiplied by the biggest font size in the line. */
0198:            protected float multipliedLeading = 0;
0199:
0200:            /** The <CODE>PdfContent</CODE> where the text will be written to. */
0201:            protected PdfContentByte canvas;
0202:
0203:            protected PdfContentByte[] canvases;
0204:
0205:            /** The line status when trying to fit a line to a column. */
0206:            protected int lineStatus;
0207:
0208:            /** The first paragraph line indent. */
0209:            protected float indent = 0;
0210:
0211:            /** The following paragraph lines indent. */
0212:            protected float followingIndent = 0;
0213:
0214:            /** The right paragraph lines indent. */
0215:            protected float rightIndent = 0;
0216:
0217:            /** The extra space between paragraphs. */
0218:            protected float extraParagraphSpace = 0;
0219:
0220:            /** The width of the line when the column is defined as a simple rectangle. */
0221:            protected float rectangularWidth = -1;
0222:
0223:            protected boolean rectangularMode = false;
0224:            /** Holds value of property spaceCharRatio. */
0225:            private float spaceCharRatio = GLOBAL_SPACE_CHAR_RATIO;
0226:
0227:            private boolean lastWasNewline = true;
0228:
0229:            /** Holds value of property linesWritten. */
0230:            private int linesWritten;
0231:
0232:            private float firstLineY;
0233:            private boolean firstLineYDone = false;
0234:
0235:            /** Holds value of property arabicOptions. */
0236:            private int arabicOptions = 0;
0237:
0238:            protected float descender;
0239:
0240:            protected boolean composite = false;
0241:
0242:            protected ColumnText compositeColumn;
0243:
0244:            protected LinkedList compositeElements;
0245:
0246:            protected int listIdx = 0;
0247:
0248:            private boolean splittedRow;
0249:
0250:            protected Phrase waitPhrase;
0251:
0252:            /** if true, first line height is adjusted so that the max ascender touches the top */
0253:            private boolean useAscender = false;
0254:
0255:            /**
0256:             * Creates a <CODE>ColumnText</CODE>.
0257:             * @param canvas the place where the text will be written to. Can
0258:             * be a template.
0259:             */
0260:            public ColumnText(PdfContentByte canvas) {
0261:                this .canvas = canvas;
0262:            }
0263:
0264:            /** Creates an independent duplicated of the instance <CODE>org</CODE>.
0265:             * @param org the original <CODE>ColumnText</CODE>
0266:             * @return the duplicated
0267:             */
0268:            public static ColumnText duplicate(ColumnText org) {
0269:                ColumnText ct = new ColumnText(null);
0270:                ct.setACopy(org);
0271:                return ct;
0272:            }
0273:
0274:            /** Makes this instance an independent copy of <CODE>org</CODE>.
0275:             * @param org the original <CODE>ColumnText</CODE>
0276:             * @return itself
0277:             */
0278:            public ColumnText setACopy(ColumnText org) {
0279:                setSimpleVars(org);
0280:                if (org.bidiLine != null)
0281:                    bidiLine = new BidiLine(org.bidiLine);
0282:                return this ;
0283:            }
0284:
0285:            protected void setSimpleVars(ColumnText org) {
0286:                maxY = org.maxY;
0287:                minY = org.minY;
0288:                alignment = org.alignment;
0289:                leftWall = null;
0290:                if (org.leftWall != null)
0291:                    leftWall = new ArrayList(org.leftWall);
0292:                rightWall = null;
0293:                if (org.rightWall != null)
0294:                    rightWall = new ArrayList(org.rightWall);
0295:                yLine = org.yLine;
0296:                currentLeading = org.currentLeading;
0297:                fixedLeading = org.fixedLeading;
0298:                multipliedLeading = org.multipliedLeading;
0299:                canvas = org.canvas;
0300:                canvases = org.canvases;
0301:                lineStatus = org.lineStatus;
0302:                indent = org.indent;
0303:                followingIndent = org.followingIndent;
0304:                rightIndent = org.rightIndent;
0305:                extraParagraphSpace = org.extraParagraphSpace;
0306:                rectangularWidth = org.rectangularWidth;
0307:                rectangularMode = org.rectangularMode;
0308:                spaceCharRatio = org.spaceCharRatio;
0309:                lastWasNewline = org.lastWasNewline;
0310:                linesWritten = org.linesWritten;
0311:                arabicOptions = org.arabicOptions;
0312:                runDirection = org.runDirection;
0313:                descender = org.descender;
0314:                composite = org.composite;
0315:                splittedRow = org.splittedRow;
0316:                if (org.composite) {
0317:                    compositeElements = new LinkedList(org.compositeElements);
0318:                    if (splittedRow) {
0319:                        PdfPTable table = (PdfPTable) compositeElements
0320:                                .getFirst();
0321:                        compositeElements.set(0, new PdfPTable(table));
0322:                    }
0323:                    if (org.compositeColumn != null)
0324:                        compositeColumn = duplicate(org.compositeColumn);
0325:                }
0326:                listIdx = org.listIdx;
0327:                firstLineY = org.firstLineY;
0328:                leftX = org.leftX;
0329:                rightX = org.rightX;
0330:                firstLineYDone = org.firstLineYDone;
0331:                waitPhrase = org.waitPhrase;
0332:                useAscender = org.useAscender;
0333:                filledWidth = org.filledWidth;
0334:            }
0335:
0336:            private void addWaitingPhrase() {
0337:                if (bidiLine == null && waitPhrase != null) {
0338:                    bidiLine = new BidiLine();
0339:                    for (Iterator j = waitPhrase.getChunks().iterator(); j
0340:                            .hasNext();) {
0341:                        bidiLine.addChunk(new PdfChunk((Chunk) j.next(), null));
0342:                    }
0343:                    waitPhrase = null;
0344:                }
0345:            }
0346:
0347:            /**
0348:             * Adds a <CODE>Phrase</CODE> to the current text array.
0349:             * Will not have any effect if addElement() was called before.
0350:             * @param phrase the text
0351:             */
0352:            public void addText(Phrase phrase) {
0353:                if (phrase == null || composite)
0354:                    return;
0355:                addWaitingPhrase();
0356:                if (bidiLine == null) {
0357:                    waitPhrase = phrase;
0358:                    return;
0359:                }
0360:                for (Iterator j = phrase.getChunks().iterator(); j.hasNext();) {
0361:                    bidiLine.addChunk(new PdfChunk((Chunk) j.next(), null));
0362:                }
0363:            }
0364:
0365:            /**
0366:             * Replaces the current text array with this <CODE>Phrase</CODE>.
0367:             * Anything added previously with addElement() is lost.
0368:             * @param phrase the text
0369:             */
0370:            public void setText(Phrase phrase) {
0371:                bidiLine = null;
0372:                composite = false;
0373:                compositeColumn = null;
0374:                compositeElements = null;
0375:                listIdx = 0;
0376:                splittedRow = false;
0377:                waitPhrase = phrase;
0378:            }
0379:
0380:            /**
0381:             * Adds a <CODE>Chunk</CODE> to the current text array.
0382:             * Will not have any effect if addElement() was called before.
0383:             * @param chunk the text
0384:             */
0385:            public void addText(Chunk chunk) {
0386:                if (chunk == null || composite)
0387:                    return;
0388:                addText(new Phrase(chunk));
0389:            }
0390:
0391:            /**
0392:             * Adds an element. Elements supported are <CODE>Paragraph</CODE>,
0393:             * <CODE>List</CODE>, <CODE>PdfPTable</CODE>, <CODE>Image</CODE> and
0394:             * <CODE>Graphic</CODE>.
0395:             * <p>
0396:             * It removes all the text placed with <CODE>addText()</CODE>.
0397:             * @param element the <CODE>Element</CODE>
0398:             */
0399:            public void addElement(Element element) {
0400:                if (element == null)
0401:                    return;
0402:                if (element instanceof  Image) {
0403:                    Image img = (Image) element;
0404:                    PdfPTable t = new PdfPTable(1);
0405:                    float w = img.getWidthPercentage();
0406:                    if (w == 0) {
0407:                        t.setTotalWidth(img.getScaledWidth());
0408:                        t.setLockedWidth(true);
0409:                    } else
0410:                        t.setWidthPercentage(w);
0411:                    t.setSpacingAfter(img.getSpacingAfter());
0412:                    t.setSpacingBefore(img.getSpacingBefore());
0413:                    switch (img.getAlignment()) {
0414:                    case Image.LEFT:
0415:                        t.setHorizontalAlignment(Element.ALIGN_LEFT);
0416:                        break;
0417:                    case Image.RIGHT:
0418:                        t.setHorizontalAlignment(Element.ALIGN_RIGHT);
0419:                        break;
0420:                    default:
0421:                        t.setHorizontalAlignment(Element.ALIGN_CENTER);
0422:                        break;
0423:                    }
0424:                    PdfPCell c = new PdfPCell(img, true);
0425:                    c.setPadding(0);
0426:                    c.setBorder(img.getBorder());
0427:                    c.setBorderColor(img.getBorderColor());
0428:                    c.setBorderWidth(img.getBorderWidth());
0429:                    c.setBackgroundColor(img.getBackgroundColor());
0430:                    t.addCell(c);
0431:                    element = t;
0432:                }
0433:                if (element.type() == Element.CHUNK) {
0434:                    element = new Paragraph((Chunk) element);
0435:                } else if (element.type() == Element.PHRASE) {
0436:                    element = new Paragraph((Phrase) element);
0437:                }
0438:                if (element instanceof  SimpleTable) {
0439:                    try {
0440:                        element = ((SimpleTable) element).createPdfPTable();
0441:                    } catch (DocumentException e) {
0442:                        throw new IllegalArgumentException(
0443:                                "Element not allowed.");
0444:                    }
0445:                } else if (element.type() != Element.PARAGRAPH
0446:                        && element.type() != Element.LIST
0447:                        && element.type() != Element.PTABLE)
0448:                    throw new IllegalArgumentException("Element not allowed.");
0449:                if (!composite) {
0450:                    composite = true;
0451:                    compositeElements = new LinkedList();
0452:                    bidiLine = null;
0453:                    waitPhrase = null;
0454:                }
0455:                compositeElements.add(element);
0456:            }
0457:
0458:            /**
0459:             * Converts a sequence of lines representing one of the column bounds into
0460:             * an internal format.
0461:             * <p>
0462:             * Each array element will contain a <CODE>float[4]</CODE> representing
0463:             * the line x = ax + b.
0464:             * @param cLine the column array
0465:             * @return the converted array
0466:             */
0467:            protected ArrayList convertColumn(float cLine[]) {
0468:                if (cLine.length < 4)
0469:                    throw new RuntimeException("No valid column line found.");
0470:                ArrayList cc = new ArrayList();
0471:                for (int k = 0; k < cLine.length - 2; k += 2) {
0472:                    float x1 = cLine[k];
0473:                    float y1 = cLine[k + 1];
0474:                    float x2 = cLine[k + 2];
0475:                    float y2 = cLine[k + 3];
0476:                    if (y1 == y2)
0477:                        continue;
0478:                    // x = ay + b
0479:                    float a = (x1 - x2) / (y1 - y2);
0480:                    float b = x1 - a * y1;
0481:                    float r[] = new float[4];
0482:                    r[0] = Math.min(y1, y2);
0483:                    r[1] = Math.max(y1, y2);
0484:                    r[2] = a;
0485:                    r[3] = b;
0486:                    cc.add(r);
0487:                    maxY = Math.max(maxY, r[1]);
0488:                    minY = Math.min(minY, r[0]);
0489:                }
0490:                if (cc.isEmpty())
0491:                    throw new RuntimeException("No valid column line found.");
0492:                return cc;
0493:            }
0494:
0495:            /**
0496:             * Finds the intersection between the <CODE>yLine</CODE> and the column. It will
0497:             * set the <CODE>lineStatus</CODE> apropriatly.
0498:             * @param wall the column to intersect
0499:             * @return the x coordinate of the intersection
0500:             */
0501:            protected float findLimitsPoint(ArrayList wall) {
0502:                lineStatus = LINE_STATUS_OK;
0503:                if (yLine < minY || yLine > maxY) {
0504:                    lineStatus = LINE_STATUS_OFFLIMITS;
0505:                    return 0;
0506:                }
0507:                for (int k = 0; k < wall.size(); ++k) {
0508:                    float r[] = (float[]) wall.get(k);
0509:                    if (yLine < r[0] || yLine > r[1])
0510:                        continue;
0511:                    return r[2] * yLine + r[3];
0512:                }
0513:                lineStatus = LINE_STATUS_NOLINE;
0514:                return 0;
0515:            }
0516:
0517:            /**
0518:             * Finds the intersection between the <CODE>yLine</CODE> and the two
0519:             * column bounds. It will set the <CODE>lineStatus</CODE> apropriatly.
0520:             * @return a <CODE>float[2]</CODE>with the x coordinates of the intersection
0521:             */
0522:            protected float[] findLimitsOneLine() {
0523:                float x1 = findLimitsPoint(leftWall);
0524:                if (lineStatus == LINE_STATUS_OFFLIMITS
0525:                        || lineStatus == LINE_STATUS_NOLINE)
0526:                    return null;
0527:                float x2 = findLimitsPoint(rightWall);
0528:                if (lineStatus == LINE_STATUS_NOLINE)
0529:                    return null;
0530:                return new float[] { x1, x2 };
0531:            }
0532:
0533:            /**
0534:             * Finds the intersection between the <CODE>yLine</CODE>,
0535:             * the <CODE>yLine-leading</CODE>and the two
0536:             * column bounds. It will set the <CODE>lineStatus</CODE> apropriatly.
0537:             * @return a <CODE>float[4]</CODE>with the x coordinates of the intersection
0538:             */
0539:            protected float[] findLimitsTwoLines() {
0540:                boolean repeat = false;
0541:                for (;;) {
0542:                    if (repeat && currentLeading == 0)
0543:                        return null;
0544:                    repeat = true;
0545:                    float x1[] = findLimitsOneLine();
0546:                    if (lineStatus == LINE_STATUS_OFFLIMITS)
0547:                        return null;
0548:                    yLine -= currentLeading;
0549:                    if (lineStatus == LINE_STATUS_NOLINE) {
0550:                        continue;
0551:                    }
0552:                    float x2[] = findLimitsOneLine();
0553:                    if (lineStatus == LINE_STATUS_OFFLIMITS)
0554:                        return null;
0555:                    if (lineStatus == LINE_STATUS_NOLINE) {
0556:                        yLine -= currentLeading;
0557:                        continue;
0558:                    }
0559:                    if (x1[0] >= x2[1] || x2[0] >= x1[1])
0560:                        continue;
0561:                    return new float[] { x1[0], x1[1], x2[0], x2[1] };
0562:                }
0563:            }
0564:
0565:            /**
0566:             * Sets the columns bounds. Each column bound is described by a
0567:             * <CODE>float[]</CODE> with the line points [x1,y1,x2,y2,...].
0568:             * The array must have at least 4 elements.
0569:             * @param leftLine the left column bound
0570:             * @param rightLine the right column bound
0571:             */
0572:            public void setColumns(float leftLine[], float rightLine[]) {
0573:                maxY = -10e20f;
0574:                minY = 10e20f;
0575:                rightWall = convertColumn(rightLine);
0576:                leftWall = convertColumn(leftLine);
0577:                rectangularWidth = -1;
0578:                rectangularMode = false;
0579:            }
0580:
0581:            /**
0582:             * Simplified method for rectangular columns.
0583:             * @param phrase a <CODE>Phrase</CODE>
0584:             * @param llx the lower left x corner
0585:             * @param lly the lower left y corner
0586:             * @param urx the upper right x corner
0587:             * @param ury the upper right y corner
0588:             * @param leading the leading
0589:             * @param alignment the column alignment
0590:             */
0591:            public void setSimpleColumn(Phrase phrase, float llx, float lly,
0592:                    float urx, float ury, float leading, int alignment) {
0593:                addText(phrase);
0594:                setSimpleColumn(llx, lly, urx, ury, leading, alignment);
0595:            }
0596:
0597:            /**
0598:             * Simplified method for rectangular columns.
0599:             * @param llx the lower left x corner
0600:             * @param lly the lower left y corner
0601:             * @param urx the upper right x corner
0602:             * @param ury the upper right y corner
0603:             * @param leading the leading
0604:             * @param alignment the column alignment
0605:             */
0606:            public void setSimpleColumn(float llx, float lly, float urx,
0607:                    float ury, float leading, int alignment) {
0608:                setLeading(leading);
0609:                this .alignment = alignment;
0610:                setSimpleColumn(llx, lly, urx, ury);
0611:            }
0612:
0613:            /**
0614:             * Simplified method for rectangular columns.
0615:             * @param llx
0616:             * @param lly
0617:             * @param urx
0618:             * @param ury
0619:             */
0620:            public void setSimpleColumn(float llx, float lly, float urx,
0621:                    float ury) {
0622:                leftX = Math.min(llx, urx);
0623:                maxY = Math.max(lly, ury);
0624:                minY = Math.min(lly, ury);
0625:                rightX = Math.max(llx, urx);
0626:                yLine = maxY;
0627:                rectangularWidth = rightX - leftX;
0628:                if (rectangularWidth < 0)
0629:                    rectangularWidth = 0;
0630:                rectangularMode = true;
0631:            }
0632:
0633:            /**
0634:             * Sets the leading to fixed
0635:             * @param leading the leading
0636:             */
0637:            public void setLeading(float leading) {
0638:                fixedLeading = leading;
0639:                multipliedLeading = 0;
0640:            }
0641:
0642:            /**
0643:             * Sets the leading fixed and variable. The resultant leading will be
0644:             * fixedLeading+multipliedLeading*maxFontSize where maxFontSize is the
0645:             * size of the bigest font in the line.
0646:             * @param fixedLeading the fixed leading
0647:             * @param multipliedLeading the variable leading
0648:             */
0649:            public void setLeading(float fixedLeading, float multipliedLeading) {
0650:                this .fixedLeading = fixedLeading;
0651:                this .multipliedLeading = multipliedLeading;
0652:            }
0653:
0654:            /**
0655:             * Gets the fixed leading
0656:             * @return the leading
0657:             */
0658:            public float getLeading() {
0659:                return fixedLeading;
0660:            }
0661:
0662:            /**
0663:             * Gets the variable leading
0664:             * @return the leading
0665:             */
0666:            public float getMultipliedLeading() {
0667:                return multipliedLeading;
0668:            }
0669:
0670:            /**
0671:             * Sets the yLine. The line will be written to yLine-leading.
0672:             * @param yLine the yLine
0673:             */
0674:            public void setYLine(float yLine) {
0675:                this .yLine = yLine;
0676:            }
0677:
0678:            /**
0679:             * Gets the yLine.
0680:             * @return the yLine
0681:             */
0682:            public float getYLine() {
0683:                return yLine;
0684:            }
0685:
0686:            /**
0687:             * Sets the alignment.
0688:             * @param alignment the alignment
0689:             */
0690:            public void setAlignment(int alignment) {
0691:                this .alignment = alignment;
0692:            }
0693:
0694:            /**
0695:             * Gets the alignment.
0696:             * @return the alignment
0697:             */
0698:            public int getAlignment() {
0699:                return alignment;
0700:            }
0701:
0702:            /**
0703:             * Sets the first paragraph line indent.
0704:             * @param indent the indent
0705:             */
0706:            public void setIndent(float indent) {
0707:                this .indent = indent;
0708:                lastWasNewline = true;
0709:            }
0710:
0711:            /**
0712:             * Gets the first paragraph line indent.
0713:             * @return the indent
0714:             */
0715:            public float getIndent() {
0716:                return indent;
0717:            }
0718:
0719:            /**
0720:             * Sets the following paragraph lines indent.
0721:             * @param indent the indent
0722:             */
0723:            public void setFollowingIndent(float indent) {
0724:                this .followingIndent = indent;
0725:                lastWasNewline = true;
0726:            }
0727:
0728:            /**
0729:             * Gets the following paragraph lines indent.
0730:             * @return the indent
0731:             */
0732:            public float getFollowingIndent() {
0733:                return followingIndent;
0734:            }
0735:
0736:            /**
0737:             * Sets the right paragraph lines indent.
0738:             * @param indent the indent
0739:             */
0740:            public void setRightIndent(float indent) {
0741:                this .rightIndent = indent;
0742:                lastWasNewline = true;
0743:            }
0744:
0745:            /**
0746:             * Gets the right paragraph lines indent.
0747:             * @return the indent
0748:             */
0749:            public float getRightIndent() {
0750:                return rightIndent;
0751:            }
0752:
0753:            /**
0754:             * Outputs the lines to the document. It is equivalent to <CODE>go(false)</CODE>.
0755:             * @return returns the result of the operation. It can be <CODE>NO_MORE_TEXT</CODE>
0756:             * and/or <CODE>NO_MORE_COLUMN</CODE>
0757:             * @throws DocumentException on error
0758:             */
0759:            public int go() throws DocumentException {
0760:                return go(false);
0761:            }
0762:
0763:            /**
0764:             * Outputs the lines to the document. The output can be simulated.
0765:             * @param simulate <CODE>true</CODE> to simulate the writting to the document
0766:             * @return returns the result of the operation. It can be <CODE>NO_MORE_TEXT</CODE>
0767:             * and/or <CODE>NO_MORE_COLUMN</CODE>
0768:             * @throws DocumentException on error
0769:             */
0770:            public int go(boolean simulate) throws DocumentException {
0771:                if (composite)
0772:                    return goComposite(simulate);
0773:                addWaitingPhrase();
0774:                if (bidiLine == null)
0775:                    return NO_MORE_TEXT;
0776:                descender = 0;
0777:                linesWritten = 0;
0778:                boolean dirty = false;
0779:                float ratio = spaceCharRatio;
0780:                Object currentValues[] = new Object[2];
0781:                PdfFont currentFont = null;
0782:                Float lastBaseFactor = new Float(0);
0783:                currentValues[1] = lastBaseFactor;
0784:                PdfDocument pdf = null;
0785:                PdfContentByte graphics = null;
0786:                PdfContentByte text = null;
0787:                firstLineY = Float.NaN;
0788:                int localRunDirection = PdfWriter.RUN_DIRECTION_NO_BIDI;
0789:                if (runDirection != PdfWriter.RUN_DIRECTION_DEFAULT)
0790:                    localRunDirection = runDirection;
0791:                if (canvas != null) {
0792:                    graphics = canvas;
0793:                    pdf = canvas.getPdfDocument();
0794:                    text = canvas.getDuplicate();
0795:                } else if (!simulate)
0796:                    throw new NullPointerException(
0797:                            "ColumnText.go with simulate==false and text==null.");
0798:                if (!simulate) {
0799:                    if (ratio == GLOBAL_SPACE_CHAR_RATIO)
0800:                        ratio = text.getPdfWriter().getSpaceCharRatio();
0801:                    else if (ratio < 0.001f)
0802:                        ratio = 0.001f;
0803:                }
0804:                float firstIndent = 0;
0805:
0806:                int status = 0;
0807:                if (rectangularMode) {
0808:                    for (;;) {
0809:                        firstIndent = (lastWasNewline ? indent
0810:                                : followingIndent);
0811:                        if (rectangularWidth <= firstIndent + rightIndent) {
0812:                            status = NO_MORE_COLUMN;
0813:                            if (bidiLine.isEmpty())
0814:                                status |= NO_MORE_TEXT;
0815:                            break;
0816:                        }
0817:                        if (bidiLine.isEmpty()) {
0818:                            status = NO_MORE_TEXT;
0819:                            break;
0820:                        }
0821:                        PdfLine line = bidiLine.processLine(rectangularWidth
0822:                                - firstIndent - rightIndent, alignment,
0823:                                localRunDirection, arabicOptions);
0824:                        if (line == null) {
0825:                            status = NO_MORE_TEXT;
0826:                            break;
0827:                        }
0828:                        float maxSize = line.getMaxSizeSimple();
0829:                        if (isUseAscender() && Float.isNaN(firstLineY)) {
0830:                            currentLeading = line.getAscender();
0831:                        } else {
0832:                            currentLeading = fixedLeading + maxSize
0833:                                    * multipliedLeading;
0834:                        }
0835:                        if (yLine > maxY || yLine - currentLeading < minY) {
0836:                            status = NO_MORE_COLUMN;
0837:                            bidiLine.restore();
0838:                            break;
0839:                        }
0840:                        yLine -= currentLeading;
0841:                        if (!simulate && !dirty) {
0842:                            text.beginText();
0843:                            dirty = true;
0844:                        }
0845:                        if (Float.isNaN(firstLineY)) {
0846:                            firstLineY = yLine;
0847:                        }
0848:                        updateFilledWidth(rectangularWidth - line.widthLeft());
0849:                        if (!simulate) {
0850:                            currentValues[0] = currentFont;
0851:                            text.setTextMatrix(
0852:                                    leftX
0853:                                            + (line.isRTL() ? rightIndent
0854:                                                    : firstIndent)
0855:                                            + line.indentLeft(), yLine);
0856:                            pdf.writeLineToContent(line, text, graphics,
0857:                                    currentValues, ratio);
0858:                            currentFont = (PdfFont) currentValues[0];
0859:                        }
0860:                        lastWasNewline = line.isNewlineSplit();
0861:                        yLine -= line.isNewlineSplit() ? extraParagraphSpace
0862:                                : 0;
0863:                        ++linesWritten;
0864:                        descender = line.getDescender();
0865:                    }
0866:                } else {
0867:                    currentLeading = fixedLeading;
0868:                    for (;;) {
0869:                        firstIndent = (lastWasNewline ? indent
0870:                                : followingIndent);
0871:                        float yTemp = yLine;
0872:                        float xx[] = findLimitsTwoLines();
0873:                        if (xx == null) {
0874:                            status = NO_MORE_COLUMN;
0875:                            if (bidiLine.isEmpty())
0876:                                status |= NO_MORE_TEXT;
0877:                            yLine = yTemp;
0878:                            break;
0879:                        }
0880:                        if (bidiLine.isEmpty()) {
0881:                            status = NO_MORE_TEXT;
0882:                            yLine = yTemp;
0883:                            break;
0884:                        }
0885:                        float x1 = Math.max(xx[0], xx[2]);
0886:                        float x2 = Math.min(xx[1], xx[3]);
0887:                        if (x2 - x1 <= firstIndent + rightIndent)
0888:                            continue;
0889:                        if (!simulate && !dirty) {
0890:                            text.beginText();
0891:                            dirty = true;
0892:                        }
0893:                        PdfLine line = bidiLine.processLine(x2 - x1
0894:                                - firstIndent - rightIndent, alignment,
0895:                                localRunDirection, arabicOptions);
0896:                        if (line == null) {
0897:                            status = NO_MORE_TEXT;
0898:                            yLine = yTemp;
0899:                            break;
0900:                        }
0901:                        if (!simulate) {
0902:                            currentValues[0] = currentFont;
0903:                            text.setTextMatrix(
0904:                                    x1
0905:                                            + (line.isRTL() ? rightIndent
0906:                                                    : firstIndent)
0907:                                            + line.indentLeft(), yLine);
0908:                            pdf.writeLineToContent(line, text, graphics,
0909:                                    currentValues, ratio);
0910:                            currentFont = (PdfFont) currentValues[0];
0911:                        }
0912:                        lastWasNewline = line.isNewlineSplit();
0913:                        yLine -= line.isNewlineSplit() ? extraParagraphSpace
0914:                                : 0;
0915:                        ++linesWritten;
0916:                        descender = line.getDescender();
0917:                    }
0918:                }
0919:                if (dirty) {
0920:                    text.endText();
0921:                    canvas.add(text);
0922:                }
0923:                return status;
0924:            }
0925:
0926:            /**
0927:             * Sets the extra space between paragraphs.
0928:             * @return the extra space between paragraphs
0929:             */
0930:            public float getExtraParagraphSpace() {
0931:                return extraParagraphSpace;
0932:            }
0933:
0934:            /**
0935:             * Sets the extra space between paragraphs.
0936:             * @param extraParagraphSpace the extra space between paragraphs
0937:             */
0938:            public void setExtraParagraphSpace(float extraParagraphSpace) {
0939:                this .extraParagraphSpace = extraParagraphSpace;
0940:            }
0941:
0942:            /**
0943:             * Clears the chunk array. A call to <CODE>go()</CODE> will always return
0944:             * NO_MORE_TEXT.
0945:             */
0946:            public void clearChunks() {
0947:                if (bidiLine != null)
0948:                    bidiLine.clearChunks();
0949:            }
0950:
0951:            /** Gets the space/character extra spacing ratio for
0952:             * fully justified text.
0953:             * @return the space/character extra spacing ratio
0954:             */
0955:            public float getSpaceCharRatio() {
0956:                return spaceCharRatio;
0957:            }
0958:
0959:            /** Sets the ratio between the extra word spacing and the extra character spacing
0960:             * when the text is fully justified.
0961:             * Extra word spacing will grow <CODE>spaceCharRatio</CODE> times more than extra character spacing.
0962:             * If the ratio is <CODE>PdfWriter.NO_SPACE_CHAR_RATIO</CODE> then the extra character spacing
0963:             * will be zero.
0964:             * @param spaceCharRatio the ratio between the extra word spacing and the extra character spacing
0965:             */
0966:            public void setSpaceCharRatio(float spaceCharRatio) {
0967:                this .spaceCharRatio = spaceCharRatio;
0968:            }
0969:
0970:            /** Sets the run direction. 
0971:             * @param runDirection the run direction
0972:             */
0973:            public void setRunDirection(int runDirection) {
0974:                if (runDirection < PdfWriter.RUN_DIRECTION_DEFAULT
0975:                        || runDirection > PdfWriter.RUN_DIRECTION_RTL)
0976:                    throw new RuntimeException("Invalid run direction: "
0977:                            + runDirection);
0978:                this .runDirection = runDirection;
0979:            }
0980:
0981:            /** Gets the run direction.
0982:             * @return the run direction
0983:             */
0984:            public int getRunDirection() {
0985:                return runDirection;
0986:            }
0987:
0988:            /** Gets the number of lines written.
0989:             * @return the number of lines written
0990:             */
0991:            public int getLinesWritten() {
0992:                return this .linesWritten;
0993:            }
0994:
0995:            /** Gets the arabic shaping options.
0996:             * @return the arabic shaping options
0997:             */
0998:            public int getArabicOptions() {
0999:                return this .arabicOptions;
1000:            }
1001:
1002:            /** Sets the arabic shaping options. The option can be AR_NOVOWEL,
1003:             * AR_COMPOSEDTASHKEEL and AR_LIG.
1004:             * @param arabicOptions the arabic shaping options
1005:             */
1006:            public void setArabicOptions(int arabicOptions) {
1007:                this .arabicOptions = arabicOptions;
1008:            }
1009:
1010:            /** Gets the biggest descender value of the last line written.
1011:             * @return the biggest descender value of the last line written
1012:             */
1013:            public float getDescender() {
1014:                return descender;
1015:            }
1016:
1017:            /** Gets the width that the line will occupy after writing.
1018:             * Only the width of the first line is returned.
1019:             * @param phrase the <CODE>Phrase</CODE> containing the line
1020:             * @param runDirection the run direction
1021:             * @param arabicOptions the options for the arabic shaping
1022:             * @return the width of the line
1023:             */
1024:            public static float getWidth(Phrase phrase, int runDirection,
1025:                    int arabicOptions) {
1026:                ColumnText ct = new ColumnText(null);
1027:                ct.addText(phrase);
1028:                ct.addWaitingPhrase();
1029:                PdfLine line = ct.bidiLine.processLine(20000,
1030:                        Element.ALIGN_LEFT, runDirection, arabicOptions);
1031:                if (line == null)
1032:                    return 0;
1033:                else
1034:                    return 20000 - line.widthLeft();
1035:            }
1036:
1037:            /** Gets the width that the line will occupy after writing.
1038:             * Only the width of the first line is returned.
1039:             * @param phrase the <CODE>Phrase</CODE> containing the line
1040:             * @return the width of the line
1041:             */
1042:            public static float getWidth(Phrase phrase) {
1043:                return getWidth(phrase, PdfWriter.RUN_DIRECTION_NO_BIDI, 0);
1044:            }
1045:
1046:            /** Shows a line of text. Only the first line is written.
1047:             * @param canvas where the text is to be written to
1048:             * @param alignment the alignment. It is not influenced by the run direction
1049:             * @param phrase the <CODE>Phrase</CODE> with the text
1050:             * @param x the x reference position
1051:             * @param y the y reference position
1052:             * @param rotation the rotation to be applied in degrees counterclockwise
1053:             * @param runDirection the run direction
1054:             * @param arabicOptions the options for the arabic shaping
1055:             */
1056:            public static void showTextAligned(PdfContentByte canvas,
1057:                    int alignment, Phrase phrase, float x, float y,
1058:                    float rotation, int runDirection, int arabicOptions) {
1059:                if (alignment != Element.ALIGN_LEFT
1060:                        && alignment != Element.ALIGN_CENTER
1061:                        && alignment != Element.ALIGN_RIGHT)
1062:                    alignment = Element.ALIGN_LEFT;
1063:                canvas.saveState();
1064:                ColumnText ct = new ColumnText(canvas);
1065:                if (rotation == 0) {
1066:                    if (alignment == Element.ALIGN_LEFT)
1067:                        ct.setSimpleColumn(phrase, x, y - 1, 20000 + x, y + 2,
1068:                                2, alignment);
1069:                    else if (alignment == Element.ALIGN_RIGHT)
1070:                        ct.setSimpleColumn(phrase, x - 20000, y - 1, x, y + 2,
1071:                                2, alignment);
1072:                    else
1073:                        ct.setSimpleColumn(phrase, x - 20000, y - 1, x + 20000,
1074:                                y + 2, 2, alignment);
1075:                } else {
1076:                    double alpha = rotation * Math.PI / 180.0;
1077:                    float cos = (float) Math.cos(alpha);
1078:                    float sin = (float) Math.sin(alpha);
1079:                    canvas.concatCTM(cos, sin, -sin, cos, x, y);
1080:                    if (alignment == Element.ALIGN_LEFT)
1081:                        ct.setSimpleColumn(phrase, 0, -1, 20000, 2, 2,
1082:                                alignment);
1083:                    else if (alignment == Element.ALIGN_RIGHT)
1084:                        ct.setSimpleColumn(phrase, -20000, -1, 0, 2, 2,
1085:                                alignment);
1086:                    else
1087:                        ct.setSimpleColumn(phrase, -20000, -1, 20000, 2, 2,
1088:                                alignment);
1089:                }
1090:                if (runDirection == PdfWriter.RUN_DIRECTION_RTL) {
1091:                    if (alignment == Element.ALIGN_LEFT)
1092:                        alignment = Element.ALIGN_RIGHT;
1093:                    else if (alignment == Element.ALIGN_RIGHT)
1094:                        alignment = Element.ALIGN_LEFT;
1095:                }
1096:                ct.setAlignment(alignment);
1097:                ct.setArabicOptions(arabicOptions);
1098:                ct.setRunDirection(runDirection);
1099:                try {
1100:                    ct.go();
1101:                } catch (DocumentException e) {
1102:                    throw new ExceptionConverter(e);
1103:                }
1104:                canvas.restoreState();
1105:            }
1106:
1107:            /** Shows a line of text. Only the first line is written.
1108:             * @param canvas where the text is to be written to
1109:             * @param alignment the alignment
1110:             * @param phrase the <CODE>Phrase</CODE> with the text
1111:             * @param x the x reference position
1112:             * @param y the y reference position
1113:             * @param rotation the rotation to be applied in degrees counterclockwise
1114:             */
1115:            public static void showTextAligned(PdfContentByte canvas,
1116:                    int alignment, Phrase phrase, float x, float y,
1117:                    float rotation) {
1118:                showTextAligned(canvas, alignment, phrase, x, y, rotation,
1119:                        PdfWriter.RUN_DIRECTION_NO_BIDI, 0);
1120:            }
1121:
1122:            protected int goComposite(boolean simulate)
1123:                    throws DocumentException {
1124:                if (!rectangularMode)
1125:                    throw new DocumentException(
1126:                            "Irregular columns are not supported in composite mode.");
1127:                linesWritten = 0;
1128:                descender = 0;
1129:                boolean firstPass = true;
1130:                main_loop: while (true) {
1131:                    if (compositeElements.isEmpty())
1132:                        return NO_MORE_TEXT;
1133:                    Element element = (Element) compositeElements.getFirst();
1134:                    if (element.type() == Element.PARAGRAPH) {
1135:                        Paragraph para = (Paragraph) element;
1136:                        int status = 0;
1137:                        for (int keep = 0; keep < 2; ++keep) {
1138:                            float lastY = yLine;
1139:                            boolean createHere = false;
1140:                            if (compositeColumn == null) {
1141:                                compositeColumn = new ColumnText(canvas);
1142:                                compositeColumn
1143:                                        .setUseAscender(firstPass ? useAscender
1144:                                                : false);
1145:                                compositeColumn.setAlignment(para
1146:                                        .getAlignment());
1147:                                compositeColumn.setIndent(para
1148:                                        .getIndentationLeft()
1149:                                        + para.getFirstLineIndent());
1150:                                compositeColumn.setExtraParagraphSpace(para
1151:                                        .getExtraParagraphSpace());
1152:                                compositeColumn.setFollowingIndent(para
1153:                                        .getIndentationLeft());
1154:                                compositeColumn.setRightIndent(para
1155:                                        .getIndentationRight());
1156:                                compositeColumn.setLeading(para.getLeading(),
1157:                                        para.getMultipliedLeading());
1158:                                compositeColumn.setRunDirection(runDirection);
1159:                                compositeColumn.setArabicOptions(arabicOptions);
1160:                                compositeColumn
1161:                                        .setSpaceCharRatio(spaceCharRatio);
1162:                                compositeColumn.addText(para);
1163:                                if (!firstPass) {
1164:                                    yLine -= para.spacingBefore();
1165:                                }
1166:                                createHere = true;
1167:                            }
1168:                            compositeColumn.leftX = leftX;
1169:                            compositeColumn.rightX = rightX;
1170:                            compositeColumn.yLine = yLine;
1171:                            compositeColumn.rectangularWidth = rectangularWidth;
1172:                            compositeColumn.rectangularMode = rectangularMode;
1173:                            compositeColumn.minY = minY;
1174:                            compositeColumn.maxY = maxY;
1175:                            boolean keepCandidate = (para.getKeepTogether()
1176:                                    && createHere && !firstPass);
1177:                            status = compositeColumn.go(simulate
1178:                                    || (keepCandidate && keep == 0));
1179:                            updateFilledWidth(compositeColumn.filledWidth);
1180:                            if ((status & NO_MORE_TEXT) == 0 && keepCandidate) {
1181:                                compositeColumn = null;
1182:                                yLine = lastY;
1183:                                return NO_MORE_COLUMN;
1184:                            }
1185:                            if (simulate || !keepCandidate)
1186:                                break;
1187:                            if (keep == 0) {
1188:                                compositeColumn = null;
1189:                                yLine = lastY;
1190:                            }
1191:                        }
1192:                        firstPass = false;
1193:                        yLine = compositeColumn.yLine;
1194:                        linesWritten += compositeColumn.linesWritten;
1195:                        descender = compositeColumn.descender;
1196:                        if ((status & NO_MORE_TEXT) != 0) {
1197:                            compositeColumn = null;
1198:                            compositeElements.removeFirst();
1199:                            yLine -= para.spacingAfter();
1200:                        }
1201:                        if ((status & NO_MORE_COLUMN) != 0) {
1202:                            return NO_MORE_COLUMN;
1203:                        }
1204:                    } else if (element.type() == Element.LIST) {
1205:                        com.lowagie.text.List list = (com.lowagie.text.List) element;
1206:                        ArrayList items = list.getItems();
1207:                        ListItem item = null;
1208:                        float listIndentation = list.getIndentationLeft();
1209:                        int count = 0;
1210:                        Stack stack = new Stack();
1211:                        for (int k = 0; k < items.size(); ++k) {
1212:                            Object obj = items.get(k);
1213:                            if (obj instanceof  ListItem) {
1214:                                if (count == listIdx) {
1215:                                    item = (ListItem) obj;
1216:                                    break;
1217:                                } else
1218:                                    ++count;
1219:                            } else if (obj instanceof  com.lowagie.text.List) {
1220:                                stack.push(new Object[] { list, new Integer(k),
1221:                                        new Float(listIndentation) });
1222:                                list = (com.lowagie.text.List) obj;
1223:                                items = list.getItems();
1224:                                listIndentation += list.getIndentationLeft();
1225:                                k = -1;
1226:                                continue;
1227:                            }
1228:                            if (k == items.size() - 1) {
1229:                                if (!stack.isEmpty()) {
1230:                                    Object objs[] = (Object[]) stack.pop();
1231:                                    list = (com.lowagie.text.List) objs[0];
1232:                                    items = list.getItems();
1233:                                    k = ((Integer) objs[1]).intValue();
1234:                                    listIndentation = ((Float) objs[2])
1235:                                            .floatValue();
1236:                                }
1237:                            }
1238:                        }
1239:                        int status = 0;
1240:                        for (int keep = 0; keep < 2; ++keep) {
1241:                            float lastY = yLine;
1242:                            boolean createHere = false;
1243:                            if (compositeColumn == null) {
1244:                                if (item == null) {
1245:                                    listIdx = 0;
1246:                                    compositeElements.removeFirst();
1247:                                    continue main_loop;
1248:                                }
1249:                                compositeColumn = new ColumnText(canvas);
1250:                                compositeColumn
1251:                                        .setUseAscender(firstPass ? useAscender
1252:                                                : false);
1253:                                compositeColumn.setAlignment(item
1254:                                        .getAlignment());
1255:                                compositeColumn.setIndent(item
1256:                                        .getIndentationLeft()
1257:                                        + listIndentation
1258:                                        + item.getFirstLineIndent());
1259:                                compositeColumn.setExtraParagraphSpace(item
1260:                                        .getExtraParagraphSpace());
1261:                                compositeColumn
1262:                                        .setFollowingIndent(compositeColumn
1263:                                                .getIndent());
1264:                                compositeColumn.setRightIndent(item
1265:                                        .getIndentationRight()
1266:                                        + list.getIndentationRight());
1267:                                compositeColumn.setLeading(item.getLeading(),
1268:                                        item.getMultipliedLeading());
1269:                                compositeColumn.setRunDirection(runDirection);
1270:                                compositeColumn.setArabicOptions(arabicOptions);
1271:                                compositeColumn
1272:                                        .setSpaceCharRatio(spaceCharRatio);
1273:                                compositeColumn.addText(item);
1274:                                if (!firstPass) {
1275:                                    yLine -= item.spacingBefore();
1276:                                }
1277:                                createHere = true;
1278:                            }
1279:                            compositeColumn.leftX = leftX;
1280:                            compositeColumn.rightX = rightX;
1281:                            compositeColumn.yLine = yLine;
1282:                            compositeColumn.rectangularWidth = rectangularWidth;
1283:                            compositeColumn.rectangularMode = rectangularMode;
1284:                            compositeColumn.minY = minY;
1285:                            compositeColumn.maxY = maxY;
1286:                            boolean keepCandidate = (item.getKeepTogether()
1287:                                    && createHere && !firstPass);
1288:                            status = compositeColumn.go(simulate
1289:                                    || (keepCandidate && keep == 0));
1290:                            updateFilledWidth(compositeColumn.filledWidth);
1291:                            if ((status & NO_MORE_TEXT) == 0 && keepCandidate) {
1292:                                compositeColumn = null;
1293:                                yLine = lastY;
1294:                                return NO_MORE_COLUMN;
1295:                            }
1296:                            if (simulate || !keepCandidate)
1297:                                break;
1298:                            if (keep == 0) {
1299:                                compositeColumn = null;
1300:                                yLine = lastY;
1301:                            }
1302:                        }
1303:                        firstPass = false;
1304:                        yLine = compositeColumn.yLine;
1305:                        linesWritten += compositeColumn.linesWritten;
1306:                        descender = compositeColumn.descender;
1307:                        if (!Float.isNaN(compositeColumn.firstLineY)
1308:                                && !compositeColumn.firstLineYDone) {
1309:                            if (!simulate)
1310:                                showTextAligned(
1311:                                        canvas,
1312:                                        Element.ALIGN_LEFT,
1313:                                        new Phrase(item.getListSymbol()),
1314:                                        compositeColumn.leftX + listIndentation,
1315:                                        compositeColumn.firstLineY, 0);
1316:                            compositeColumn.firstLineYDone = true;
1317:                        }
1318:                        if ((status & NO_MORE_TEXT) != 0) {
1319:                            compositeColumn = null;
1320:                            ++listIdx;
1321:                            yLine -= item.spacingAfter();
1322:                        }
1323:                        if ((status & NO_MORE_COLUMN) != 0) {
1324:                            return NO_MORE_COLUMN;
1325:                        }
1326:                    } else if (element.type() == Element.PTABLE) {
1327:                        if (yLine < minY || yLine > maxY)
1328:                            return NO_MORE_COLUMN;
1329:                        PdfPTable table = (PdfPTable) element;
1330:                        if (table.size() <= table.getHeaderRows()) {
1331:                            compositeElements.removeFirst();
1332:                            continue;
1333:                        }
1334:                        float yTemp = yLine;
1335:                        float yLineWrite = yLine;
1336:                        if (!firstPass && listIdx == 0) {
1337:                            yTemp -= table.spacingBefore();
1338:                            yLineWrite = yTemp;
1339:                        }
1340:                        currentLeading = 0;
1341:                        if (yTemp < minY || yTemp > maxY)
1342:                            return NO_MORE_COLUMN;
1343:                        float x1 = leftX;
1344:                        float tableWidth;
1345:                        if (table.isLockedWidth()) {
1346:                            tableWidth = table.getTotalWidth();
1347:                            updateFilledWidth(tableWidth);
1348:                        } else {
1349:                            tableWidth = rectangularWidth
1350:                                    * table.getWidthPercentage() / 100f;
1351:                            table.setTotalWidth(tableWidth);
1352:                        }
1353:                        int k;
1354:                        boolean skipHeader = (!firstPass
1355:                                && table.isSkipFirstHeader() && listIdx <= table
1356:                                .getHeaderRows());
1357:                        if (!skipHeader) {
1358:                            yTemp -= table.getHeaderHeight();
1359:                            if (yTemp < minY || yTemp > maxY) {
1360:                                if (firstPass) {
1361:                                    compositeElements.removeFirst();
1362:                                    continue;
1363:                                }
1364:                                return NO_MORE_COLUMN;
1365:                            }
1366:                        }
1367:                        if (listIdx < table.getHeaderRows())
1368:                            listIdx = table.getHeaderRows();
1369:                        for (k = listIdx; k < table.size(); ++k) {
1370:                            float rowHeight = table.getRowHeight(k);
1371:                            if (yTemp - rowHeight < minY)
1372:                                break;
1373:                            yTemp -= rowHeight;
1374:                        }
1375:                        if (k < table.size()) {
1376:                            if (table.isSplitRows()
1377:                                    && (!table.isSplitLate() || (k == listIdx && firstPass))) {
1378:                                if (!splittedRow) {
1379:                                    splittedRow = true;
1380:                                    table = new PdfPTable(table);
1381:                                    compositeElements.set(0, table);
1382:                                    ArrayList rows = table.getRows();
1383:                                    for (int i = table.getHeaderRows(); i < listIdx; ++i)
1384:                                        rows.set(i, null);
1385:                                }
1386:                                float h = yTemp - minY;
1387:                                PdfPRow newRow = table.getRow(k).splitRow(h);
1388:                                if (newRow == null) {
1389:                                    if (k == listIdx)
1390:                                        return NO_MORE_COLUMN;
1391:                                } else {
1392:                                    yTemp = minY;
1393:                                    table.getRows().add(++k, newRow);
1394:                                }
1395:                            } else if (!table.isSplitRows() && k == listIdx
1396:                                    && firstPass) {
1397:                                compositeElements.removeFirst();
1398:                                splittedRow = false;
1399:                                continue;
1400:                            } else if (k == listIdx
1401:                                    && !firstPass
1402:                                    && (!table.isSplitRows() || table
1403:                                            .isSplitLate())) {
1404:                                return NO_MORE_COLUMN;
1405:                            }
1406:                        }
1407:                        firstPass = false;
1408:                        if (!simulate) {
1409:                            switch (table.getHorizontalAlignment()) {
1410:                            case Element.ALIGN_LEFT:
1411:                                break;
1412:                            case Element.ALIGN_RIGHT:
1413:                                x1 += rectangularWidth - tableWidth;
1414:                                break;
1415:                            default:
1416:                                x1 += (rectangularWidth - tableWidth) / 2f;
1417:                            }
1418:                            int realHeaderRows = table.getHeaderRows();
1419:                            int footerRows = table.getFooterRows();
1420:                            if (footerRows > realHeaderRows)
1421:                                footerRows = realHeaderRows;
1422:                            realHeaderRows -= footerRows;
1423:                            PdfPTable nt = PdfPTable.shallowCopy(table);
1424:                            ArrayList rows = table.getRows();
1425:                            ArrayList sub = nt.getRows();
1426:                            if (!skipHeader) {
1427:                                for (int j = 0; j < realHeaderRows; ++j)
1428:                                    sub.add(rows.get(j));
1429:                            } else
1430:                                nt.setHeaderRows(footerRows);
1431:                            for (int j = listIdx; j < k; ++j)
1432:                                sub.add(rows.get(j));
1433:                            for (int j = 0; j < footerRows; ++j)
1434:                                sub.add(rows.get(j + realHeaderRows));
1435:                            float rowHeight = 0;
1436:                            if (table.isExtendLastRow()) {
1437:                                PdfPRow last = (PdfPRow) sub.get(sub.size() - 1
1438:                                        - footerRows);
1439:                                rowHeight = last.getMaxHeights();
1440:                                last.setMaxHeights(yTemp - minY + rowHeight);
1441:                                yTemp = minY;
1442:                            }
1443:                            if (canvases != null)
1444:                                nt.writeSelectedRows(0, -1, x1, yLineWrite,
1445:                                        canvases);
1446:                            else
1447:                                nt.writeSelectedRows(0, -1, x1, yLineWrite,
1448:                                        canvas);
1449:                            if (table.isExtendLastRow()) {
1450:                                PdfPRow last = (PdfPRow) sub.get(sub.size() - 1
1451:                                        - footerRows);
1452:                                last.setMaxHeights(rowHeight);
1453:                            }
1454:                        } else if (table.isExtendLastRow()
1455:                                && minY > PdfPRow.BOTTOM_LIMIT)
1456:                            yTemp = minY;
1457:                        yLine = yTemp;
1458:                        if (k >= table.size()) {
1459:                            yLine -= table.spacingAfter();
1460:                            compositeElements.removeFirst();
1461:                            splittedRow = false;
1462:                            listIdx = 0;
1463:                        } else {
1464:                            if (splittedRow) {
1465:                                ArrayList rows = table.getRows();
1466:                                for (int i = listIdx; i < k; ++i)
1467:                                    rows.set(i, null);
1468:                            }
1469:                            listIdx = k;
1470:                            return NO_MORE_COLUMN;
1471:                        }
1472:                    } else
1473:                        compositeElements.removeFirst();
1474:                }
1475:            }
1476:
1477:            /**
1478:             * Gets the canvas.
1479:             * @return a PdfContentByte.
1480:             */
1481:            public PdfContentByte getCanvas() {
1482:                return canvas;
1483:            }
1484:
1485:            /**
1486:             * Sets the canvas.
1487:             * @param canvas
1488:             */
1489:            public void setCanvas(PdfContentByte canvas) {
1490:                this .canvas = canvas;
1491:                this .canvases = null;
1492:                if (compositeColumn != null)
1493:                    compositeColumn.setCanvas(canvas);
1494:            }
1495:
1496:            /**
1497:             * Sets the canvases.
1498:             * @param canvases
1499:             */
1500:            public void setCanvases(PdfContentByte[] canvases) {
1501:                this .canvases = canvases;
1502:                this .canvas = canvases[PdfPTable.TEXTCANVAS];
1503:                if (compositeColumn != null)
1504:                    compositeColumn.setCanvases(canvases);
1505:            }
1506:
1507:            /**
1508:             * Gets the canvases.
1509:             * @return an array of PdfContentByte
1510:             */
1511:            public PdfContentByte[] getCanvases() {
1512:                return canvases;
1513:            }
1514:
1515:            /**
1516:             * Checks if UseAscender is enabled/disabled.
1517:             * @return true is the adjustment of the first line height is based on max ascender.
1518:             */
1519:            public boolean isUseAscender() {
1520:                return useAscender;
1521:            }
1522:
1523:            /**
1524:             * Enables/Disables adjustment of first line height based on max ascender.
1525:             * @param use enable adjustment if true
1526:             */
1527:            public void setUseAscender(boolean use) {
1528:                useAscender = use;
1529:            }
1530:
1531:            /**
1532:             * Checks the status variable and looks if there's still some text.
1533:             */
1534:            public static boolean hasMoreText(int status) {
1535:                return (status & ColumnText.NO_MORE_TEXT) == 0;
1536:            }
1537:
1538:            /**
1539:             * Holds value of property filledWidth.
1540:             */
1541:            private float filledWidth;
1542:
1543:            /**
1544:             * Gets the real width used by the largest line.
1545:             * @return the real width used by the largest line
1546:             */
1547:            public float getFilledWidth() {
1548:
1549:                return this .filledWidth;
1550:            }
1551:
1552:            /**
1553:             * Sets the real width used by the largest line. Only used to set it
1554:             * to zero to start another measurement.
1555:             * @param filledWidth the real width used by the largest line
1556:             */
1557:            public void setFilledWidth(float filledWidth) {
1558:
1559:                this .filledWidth = filledWidth;
1560:            }
1561:
1562:            /**
1563:             * Replaces the <CODE>filledWidth</CODE> if greater than the existing one.
1564:             * @param w the new <CODE>filledWidth</CODE> if greater than the existing one
1565:             */
1566:            public void updateFilledWidth(float w) {
1567:                if (w > filledWidth)
1568:                    filledWidth = w;
1569:            }
1570:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.