diff --git a/openpdf/src/main/java/com/lowagie/text/HeaderFooter.java b/openpdf/src/main/java/com/lowagie/text/HeaderFooter.java index 5b4e8b181..9faa5d805 100644 --- a/openpdf/src/main/java/com/lowagie/text/HeaderFooter.java +++ b/openpdf/src/main/java/com/lowagie/text/HeaderFooter.java @@ -49,81 +49,105 @@ package com.lowagie.text; +import java.util.ArrayList; +import java.util.List; + +import com.lowagie.text.pdf.PdfPTable; /** - * A HeaderFooter-object is a Rectangle with text - * that can be put above and/or below every page. - *

- * Example: - *

+ * A HeaderFooter-object is a Rectangle with text that can be put above and/or below every
+ * page.
+ * 

+ * Example:

+ * + *
  * HeaderFooter header = new HeaderFooter(new Phrase("This is a header."), false);
  * HeaderFooter footer = new HeaderFooter(new Phrase("This is page "), new Phrase("."));
  * document.setHeader(header);
  * document.setFooter(footer);
- * 
+ *
+ * + *
*/ public class HeaderFooter extends Rectangle { - + // membervariables - -/** Does the page contain a pagenumber? */ + + /** + * Does the page contain a pagenumber? + */ private boolean numbered; - -/** This is the Phrase that comes before the pagenumber. */ + + /** + * This is the Phrase that comes before the pagenumber. + */ private Phrase before = null; - -/** This is number of the page. */ + + /** + * This is number of the page. + */ private int pageN; - -/** This is the Phrase that comes after the pagenumber. */ + + /** + * This is the Phrase that comes after the pagenumber. + */ private Phrase after = null; - -/** This is alignment of the header/footer. */ + + /** + * This is alignment of the header/footer. + */ private int alignment; - + + /** + * This is the List containing non-text Element. + */ + private java.util.List specialContent = null; + + /** + * This is the padding of height of header/footer. + */ + private float padding; + // constructors - -/** - * Constructs a HeaderFooter-object. - * - * @param before the Phrase before the pagenumber - * @param after the Phrase before the pagenumber - */ - + + /** + * Constructs a HeaderFooter-object. + * + * @param before the Phrase before the pagenumber + * @param after the Phrase before the pagenumber + */ public HeaderFooter(Phrase before, Phrase after) { super(0, 0, 0, 0); setBorder(TOP + BOTTOM); setBorderWidth(1); - + numbered = true; this.before = before; this.after = after; } - -/** - * Constructs a Header-object with a pagenumber at the end. - * - * @param before the Phrase before the pagenumber - * @param numbered page will be numbered if true - */ - + + /** + * Constructs a Header-object with a pagenumber at the end. + * + * @param before the Phrase before the pagenumber + * @param numbered page will be numbered if true + */ public HeaderFooter(Phrase before, boolean numbered) { super(0, 0, 0, 0); setBorder(TOP + BOTTOM); setBorderWidth(1); - + this.numbered = numbered; this.before = before; } -/** - * Constructs a Header-object with a pagenumber at the beginning. - * - * @param numbered page will be numbered if true - * @param after the Phrase after the pagenumber - */ - + /** + * Constructs a Header-object with a pagenumber at the beginning. + * + * @param numbered page will be numbered if true + * @param after the Phrase after the pagenumber + */ public HeaderFooter(boolean numbered, Phrase after) { super(0, 0, 0, 0); setBorder(TOP + BOTTOM); @@ -133,82 +157,133 @@ public HeaderFooter(boolean numbered, Phrase after) { this.after = after; } -/** - * Constructs a Header-object with only a pagenumber. - * - * @param numbered true if the page has to be numbered - */ - + /** + * Constructs a Header-object with only a pagenumber. + * + * @param numbered true if the page has to be numbered + */ public HeaderFooter(boolean numbered) { this(null, true); this.numbered = numbered; } // methods - -/** - * Checks if the HeaderFooter contains a page number. - * - * @return true if the page has to be numbered - */ - + + /** + * Checks if the HeaderFooter contains a page number. + * + * @return true if the page has to be numbered + */ public boolean isNumbered() { return numbered; } - -/** - * Gets the part that comes before the pageNumber. - * - * @return a Phrase - */ - + + /** + * Gets the part that comes before the pageNumber. + * + * @return a Phrase + */ public Phrase getBefore() { return before; } - -/** - * Gets the part that comes after the pageNumber. - * - * @return a Phrase - */ - + + /** + * Gets the part that comes after the pageNumber. + * + * @return a Phrase + */ public Phrase getAfter() { return after; } - -/** - * Sets the page number. - * - * @param pageN the new page number - */ - + + /** + * Sets the page number. + * + * @param pageN the new page number + */ public void setPageNumber(int pageN) { this.pageN = pageN; } - -/** - * Sets the alignment. - * - * @param alignment the new alignment - */ - + + /** + * Sets the alignment. + * + * @param alignment the new alignment + */ public void setAlignment(int alignment) { this.alignment = alignment; } + /** + * Gets padding of height of header/footer. + * + * @return the padding of height + */ + public float getPadding() { + return padding; + } + + /** + * Sets padding of height of header/footer. + * + * @param padding the new padding of height + */ + public void setPadding(float padding) { + this.padding = padding; + } + + /** + * Increases current padding by adding new value into it + * + * @param augment the new value + */ + public void addPadding(float augment) { + padding += augment; + } + + /** + * Adds non-text Element into specialContent + * + * @param element the new non-text Element + */ + public void addSpecialContent(Element element) { + if (specialContent == null) { + specialContent = new ArrayList<>(); + } + specialContent.add(element); + } + + /** + * Gets specialContent + * + * @return specialContent + */ + public List getSpecialContent() { + return specialContent; + } + // methods to retrieve the membervariables - -/** - * Gets the Paragraph that can be used as header or footer. - * - * @return a Paragraph - */ - + + /** + * Gets the Paragraph that can be used as header or footer. + * + * @return a Paragraph + */ public Paragraph paragraph() { Paragraph paragraph; + if (before != null) { paragraph = new Paragraph(before.getLeading()); paragraph.add(before); + + // Adding a Paragraph to another Paraghraph adds a newline that needs to be removed in headers and footers + if (before instanceof Paragraph + && + paragraph.size() >= 2 + && + "\n".equals(paragraph.get(paragraph.size() - 1).toString())) { + paragraph.remove(paragraph.size() - 1); + } } else { paragraph = new Paragraph(); } @@ -221,10 +296,13 @@ public Paragraph paragraph() { paragraph.addSpecial(new Chunk(String.valueOf(pageN))); } } + if (after != null) { paragraph.addSpecial(after); } + paragraph.setAlignment(alignment); + return paragraph; } @@ -232,6 +310,7 @@ private Font getFont() { if (before != null) { return before.getFont(); } + if (after != null) { return after.getFont(); } @@ -242,11 +321,9 @@ private Font getFont() { /** * Gets the alignment of this HeaderFooter. * - * @return alignment + * @return alignment */ - - public int alignment() { - return alignment; - } - + public int alignment() { + return alignment; + } } \ No newline at end of file diff --git a/openpdf/src/main/java/com/lowagie/text/Rectangle.java b/openpdf/src/main/java/com/lowagie/text/Rectangle.java index c1238d0af..d93a2719b 100644 --- a/openpdf/src/main/java/com/lowagie/text/Rectangle.java +++ b/openpdf/src/main/java/com/lowagie/text/Rectangle.java @@ -55,13 +55,13 @@ /** * A Rectangle is the representation of a geometric figure. - * + * * Rectangles support constant width borders using * {@link #setBorderWidth(float)}and {@link #setBorder(int)}. They also support * borders that vary in width/color on each side using methods like * {@link #setBorderWidthLeft(float)}or * {@link #setBorderColorLeft(java.awt.Color)}. - * + * * @see Element * @see Table * @see Cell @@ -69,904 +69,913 @@ */ public class Rectangle implements Element { - // CONSTANTS: + // CONSTANTS: + + /** This is the value that will be used as undefined . */ + public static final int UNDEFINED = -1; + + /** This represents one side of the border of the Rectangle. */ + public static final int TOP = 1; + + /** This represents one side of the border of the Rectangle. */ + public static final int BOTTOM = 2; + + /** This represents one side of the border of the Rectangle. */ + public static final int LEFT = 4; + + /** This represents one side of the border of the Rectangle. */ + public static final int RIGHT = 8; + + /** This represents a rectangle without borders. */ + public static final int NO_BORDER = 0; + + /** This represents a type of border. */ + public static final int BOX = TOP + BOTTOM + LEFT + RIGHT; + + // MEMBER VARIABLES: + + /** the lower left x-coordinate. */ + protected float llx; + + /** the lower left y-coordinate. */ + protected float lly; + + /** the upper right x-coordinate. */ + protected float urx; + + /** the upper right y-coordinate. */ + protected float ury; + + protected float aFloat; + + /** The rotation of the Rectangle */ + protected int rotation = 0; + + /** This is the color of the background of this rectangle. */ + protected Color backgroundColor = null; + + /** This represents the status of the 4 sides of the rectangle. */ + protected int border = UNDEFINED; + + /** Whether variable width/color borders are used. */ + protected boolean useVariableBorders = false; + + /** This is the width of the border around this rectangle. */ + protected float borderWidth = UNDEFINED; + + /** The width of the left border of this rectangle. */ + protected float borderWidthLeft = UNDEFINED; + + /** The width of the right border of this rectangle. */ + protected float borderWidthRight = UNDEFINED; + + /** The width of the top border of this rectangle. */ + protected float borderWidthTop = UNDEFINED; + + /** The width of the bottom border of this rectangle. */ + protected float borderWidthBottom = UNDEFINED; + + /** The color of the border of this rectangle. */ + protected Color borderColor = null; + + /** The color of the left border of this rectangle. */ + protected Color borderColorLeft = null; + + /** The color of the right border of this rectangle. */ + protected Color borderColorRight = null; + + /** The color of the top border of this rectangle. */ + protected Color borderColorTop = null; + + /** The color of the bottom border of this rectangle. */ + protected Color borderColorBottom = null; + + // CONSTRUCTORS: + + /** + * Constructs a Rectangle -object. + * + * @param llx + * lower left x + * @param lly + * lower left y + * @param urx + * upper right x + * @param ury + * upper right y + */ + public Rectangle(float llx, float lly, float urx, float ury) { + this.llx = llx; + this.lly = lly; + this.urx = urx; + this.ury = ury; + } + + /** + * Constructs a Rectangle -object starting from the origin (0, + * 0). + * + * @param urx + * upper right x + * @param ury + * upper right y + */ + public Rectangle(float urx, float ury) { + this(0, 0, urx, ury); + } + + // OJO... Modificacion de + // flopez------------------------------------------------- + /** + * Constructs a Rectangle -object. + * + * @param llx + * lower left x + * @param lly + * lower left y + * @param urx + * upper right x + * @param ury + * upper right y + * @param rotation + * 0, 90, 180, or 270 grades + */ + public Rectangle(float llx, float lly, float urx, float ury, int rotation) { + this(llx, lly, urx, ury); + setRotation(rotation); + } + + /** + * Constructs a Rectangle -object starting from the origin (0, + * 0). + * + * @param urx + * upper right x + * @param ury + * upper right y + * @param rotation + * 0, 90, 180, or 270 grades + */ + public Rectangle(float urx, float ury, int rotation) { + this(0, 0, urx, ury); + setRotation(rotation); + } + + /** + * Sets the rotation of the rectangle. Valid values are 0, 90, 180, and 270. + * + * @param rotation + * the new rotation value + * @since iText 5.0.6 + */ + public void setRotation(final int rotation) { + int mod = rotation % 360; + if ((mod == 90) || (mod == 180) || (mod == 270)) { + this.rotation = mod; + } else { + this.rotation = 0; + } + } + + // ****************************************************************************** + + /** + * Constructs a Rectangle -object. + * + * @param rect + * another Rectangle + */ + public Rectangle(Rectangle rect) { + this(rect.llx, rect.lly, rect.urx, rect.ury); + cloneNonPositionParameters(rect); + } - /** This is the value that will be used as undefined . */ - public static final int UNDEFINED = -1; + // IMPLEMENTATION OF THE ELEMENT INTERFACE:e + + /** + * Processes the element by adding it (or the different parts) to an + * ElementListener. + * + * @param listener + * an ElementListener + * @return true if the element was processed successfully + */ + @Override + public boolean process(ElementListener listener) { + try { + return listener.add(this); + } catch (DocumentException de) { + return false; + } + } - /** This represents one side of the border of the Rectangle. */ - public static final int TOP = 1; + /** + * Gets the type of the text element. + * + * @return a type + */ + @Override + public int type() { + return Element.RECTANGLE; + } - /** This represents one side of the border of the Rectangle. */ - public static final int BOTTOM = 2; + /** + * Gets all the chunks in this element. + * + * @return an ArrayList + */ + @Override + public ArrayList getChunks() { + return new ArrayList<>(); + } - /** This represents one side of the border of the Rectangle. */ - public static final int LEFT = 4; + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + @Override + public boolean isContent() { + return true; + } - /** This represents one side of the border of the Rectangle. */ - public static final int RIGHT = 8; + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + @Override + public boolean isNestable() { + return false; + } - /** This represents a rectangle without borders. */ - public static final int NO_BORDER = 0; + // METHODS TO GET/SET THE DIMENSIONS: - /** This represents a type of border. */ - public static final int BOX = TOP + BOTTOM + LEFT + RIGHT; + /** + * Sets the lower left x-coordinate. + * + * @param llx + * the new value + */ + public void setLeft(float llx) { + this.llx = llx; + } - // MEMBER VARIABLES: + /** + * Returns the lower left x-coordinate. + * + * @return the lower left x-coordinate + */ + public float getLeft() { + return llx; + } - /** the lower left x-coordinate. */ - protected float llx; - - /** the lower left y-coordinate. */ - protected float lly; - - /** the upper right x-coordinate. */ - protected float urx; - - /** the upper right y-coordinate. */ - protected float ury; - - /** The rotation of the Rectangle */ - protected int rotation = 0; - - /** This is the color of the background of this rectangle. */ - protected Color backgroundColor = null; - - /** This represents the status of the 4 sides of the rectangle. */ - protected int border = UNDEFINED; - - /** Whether variable width/color borders are used. */ - protected boolean useVariableBorders = false; - - /** This is the width of the border around this rectangle. */ - protected float borderWidth = UNDEFINED; - - /** The width of the left border of this rectangle. */ - protected float borderWidthLeft = UNDEFINED; - - /** The width of the right border of this rectangle. */ - protected float borderWidthRight = UNDEFINED; - - /** The width of the top border of this rectangle. */ - protected float borderWidthTop = UNDEFINED; - - /** The width of the bottom border of this rectangle. */ - protected float borderWidthBottom = UNDEFINED; - - /** The color of the border of this rectangle. */ - protected Color borderColor = null; - - /** The color of the left border of this rectangle. */ - protected Color borderColorLeft = null; - - /** The color of the right border of this rectangle. */ - protected Color borderColorRight = null; - - /** The color of the top border of this rectangle. */ - protected Color borderColorTop = null; - - /** The color of the bottom border of this rectangle. */ - protected Color borderColorBottom = null; - - // CONSTRUCTORS: - - /** - * Constructs a Rectangle -object. - * - * @param llx - * lower left x - * @param lly - * lower left y - * @param urx - * upper right x - * @param ury - * upper right y - */ - public Rectangle(float llx, float lly, float urx, float ury) { - this.llx = llx; - this.lly = lly; - this.urx = urx; - this.ury = ury; - } - - /** - * Constructs a Rectangle -object starting from the origin (0, - * 0). - * - * @param urx - * upper right x - * @param ury - * upper right y - */ - public Rectangle(float urx, float ury) { - this(0, 0, urx, ury); - } - - // OJO... Modificacion de - // flopez------------------------------------------------- - /** - * Constructs a Rectangle -object. - * - * @param llx - * lower left x - * @param lly - * lower left y - * @param urx - * upper right x - * @param ury - * upper right y - * @param rotation - * 0, 90, 180, or 270 grades - */ - public Rectangle(float llx, float lly, float urx, float ury, int rotation) { - this(llx, lly, urx, ury); - setRotation(rotation); - } - - /** - * Constructs a Rectangle -object starting from the origin (0, - * 0). - * - * @param urx - * upper right x - * @param ury - * upper right y - * @param rotation - * 0, 90, 180, or 270 grades - */ - public Rectangle(float urx, float ury, int rotation) { - this(0, 0, urx, ury); - setRotation(rotation); - } - - /** - * Sets the rotation of the rectangle. Valid values are 0, 90, 180, and 270. - * - * @param rotation - * the new rotation value - * @since iText 5.0.6 - */ - public void setRotation(final int rotation) { - int mod = rotation % 360; - if ((mod == 90) || (mod == 180) || (mod == 270)) { - this.rotation = mod; - } else { - this.rotation = 0; - } - } - - // ****************************************************************************** - - /** - * Constructs a Rectangle -object. - * - * @param rect - * another Rectangle - */ - public Rectangle(Rectangle rect) { - this(rect.llx, rect.lly, rect.urx, rect.ury); - cloneNonPositionParameters(rect); - } - - // IMPLEMENTATION OF THE ELEMENT INTERFACE:e - - /** - * Processes the element by adding it (or the different parts) to an - * ElementListener. - * - * @param listener - * an ElementListener - * @return true if the element was processed successfully - */ - @Override - public boolean process(ElementListener listener) { - try { - return listener.add(this); - } catch (DocumentException de) { - return false; - } - } - - /** - * Gets the type of the text element. - * - * @return a type - */ - @Override - public int type() { - return Element.RECTANGLE; - } - - /** - * Gets all the chunks in this element. - * - * @return an ArrayList - */ - @Override - public ArrayList getChunks() { - return new ArrayList<>(); - } - - /** - * @see com.lowagie.text.Element#isContent() - * @since iText 2.0.8 - */ - @Override - public boolean isContent() { - return true; - } - - /** - * @see com.lowagie.text.Element#isNestable() - * @since iText 2.0.8 - */ - @Override - public boolean isNestable() { - return false; - } - - // METHODS TO GET/SET THE DIMENSIONS: - - /** - * Sets the lower left x-coordinate. - * - * @param llx - * the new value - */ - public void setLeft(float llx) { - this.llx = llx; - } - - /** - * Returns the lower left x-coordinate. - * - * @return the lower left x-coordinate - */ - public float getLeft() { - return llx; - } - - /** - * Returns the lower left x-coordinate, considering a given margin. - * - * @param margin - * a margin - * @return the lower left x-coordinate - */ - public float getLeft(float margin) { - return llx + margin; - } - - /** - * Sets the upper right x-coordinate. - * - * @param urx - * the new value - */ - public void setRight(float urx) { - this.urx = urx; - } - - /** - * Returns the upper right x-coordinate. - * - * @return the upper right x-coordinate - */ - public float getRight() { - return urx; - } - - /** - * Returns the upper right x-coordinate, considering a given margin. - * - * @param margin - * a margin - * @return the upper right x-coordinate - */ - public float getRight(float margin) { - return urx - margin; - } - - /** - * Returns the width of the rectangle. - * - * @return the width - */ - public float getWidth() { - return urx - llx; - } - - /** - * Sets the upper right y-coordinate. - * - * @param ury - * the new value - */ - public void setTop(float ury) { - this.ury = ury; - } - - /** - * Returns the upper right y-coordinate. - * - * @return the upper right y-coordinate - */ - public float getTop() { - return ury; - } - - /** - * Returns the upper right y-coordinate, considering a given margin. - * - * @param margin - * a margin - * @return the upper right y-coordinate - */ - public float getTop(float margin) { - return ury - margin; - } - - /** - * Sets the lower left y-coordinate. - * - * @param lly - * the new value - */ - public void setBottom(float lly) { - this.lly = lly; - } - - /** - * Returns the lower left y-coordinate. - * - * @return the lower left y-coordinate - */ - public float getBottom() { - return lly; - } - - /** - * Returns the lower left y-coordinate, considering a given margin. - * - * @param margin - * a margin - * @return the lower left y-coordinate - */ - public float getBottom(float margin) { - return lly + margin; - } - - /** - * Returns the height of the rectangle. - * - * @return the height - */ - public float getHeight() { - return ury - lly; - } - - /** - * Normalizes the rectangle. Switches lower left with upper right if - * necessary. - */ - public void normalize() { - if (llx > urx) { - float a = llx; - llx = urx; - urx = a; - } - if (lly > ury) { - float a = lly; - lly = ury; - ury = a; - } - } - - // METHODS TO GET/SET THE ROTATION: - - /** - * Gets the rotation of the rectangle - * - * @return a rotation value - */ - public int getRotation() { - return rotation; - } - - /** - * Rotates the rectangle. Swaps the values of llx and lly and of urx and ury. - * - * @return the rotated Rectangle - */ - public Rectangle rotate() { - Rectangle rect = new Rectangle(lly, llx, ury, urx); - rect.rotation = rotation + 90; - rect.rotation %= 360; - return rect; - } - - // METHODS TO GET/SET THE BACKGROUND COLOR: - - /** - * Gets the backgroundcolor. - * - * @return a Color - */ - public Color getBackgroundColor() { - return backgroundColor; - } - - /** - * Sets the backgroundcolor of the rectangle. - * - * @param backgroundColor - * a Color - */ - - public void setBackgroundColor(Color backgroundColor) { - this.backgroundColor = backgroundColor; - } - - /** - * Gets the grayscale. - * - * @return the grayscale color of the background or 0 if the background has no - * grayscale color. - */ - public float getGrayFill() { - if (backgroundColor instanceof GrayColor) - return ((GrayColor) backgroundColor).getGray(); - return 0; - } - - /** - * Sets the the background color to a grayscale value. - * - * @param value - * the new grayscale value - */ - public void setGrayFill(float value) { - backgroundColor = new GrayColor(value); - } - - // METHODS TO GET/SET THE BORDER: - - /** - * Returns the exact type of the border. - * - * @return a value - */ - public int getBorder() { - return border; - } - - /** - * Indicates whether some type of border is set. - * - * @return a boolean - */ - public boolean hasBorders() { - switch (border) { - case UNDEFINED: - case NO_BORDER: - return false; - default: - return borderWidth > 0 || borderWidthLeft > 0 || borderWidthRight > 0 - || borderWidthTop > 0 || borderWidthBottom > 0; - } - } - - /** - * Indicates whether the specified type of border is set. - * - * @param type - * the type of border - * @return a boolean - */ - public boolean hasBorder(int type) { - if (border == UNDEFINED) - return false; - return (border & type) == type; - } - - /** - * Enables/Disables the border on the specified sides. The border is specified - * as an integer bitwise combination of the constants: - * LEFT, RIGHT, TOP, BOTTOM. - * - * @see #enableBorderSide(int) - * @see #disableBorderSide(int) - * @param border - * the new value - */ - public void setBorder(int border) { - this.border = border; - } - - /** - * Indicates whether variable width borders are being used. Returns true if - * setBorderWidthLeft, setBorderWidthRight, - * setBorderWidthTop, or setBorderWidthBottom has been called. - * - * @return true if variable width borders are in use - */ - public boolean isUseVariableBorders() { - return useVariableBorders; - } - - /** - * Sets a parameter indicating if the rectangle has variable borders - * - * @param useVariableBorders - * indication if the rectangle has variable borders - */ - public void setUseVariableBorders(boolean useVariableBorders) { - this.useVariableBorders = useVariableBorders; - } - - /** - * Enables the border on the specified side. - * - * @param side - * the side to enable. One of LEFT, RIGHT, TOP, BOTTOM - */ - public void enableBorderSide(int side) { - if (border == UNDEFINED) - border = 0; - border |= side; - } - - /** - * Disables the border on the specified side. - * - * @param side - * the side to disable. One of LEFT, RIGHT, TOP, BOTTOM - */ - public void disableBorderSide(int side) { - if (border == UNDEFINED) - border = 0; - border &= ~side; - } - - // METHODS TO GET/SET THE BORDER WIDTH: - - /** - * Gets the borderwidth. - * - * @return a value - */ - public float getBorderWidth() { - return borderWidth; - } - - /** - * Sets the borderwidth of the table. - * - * @param borderWidth - * the new value - */ - public void setBorderWidth(float borderWidth) { - this.borderWidth = borderWidth; - } - - /** - * Helper function returning the border width of a specific side. - * - * @param variableWidthValue - * a variable width (could be undefined) - * @param side - * the border you want to check - * @return the variableWidthValue if not undefined, otherwise the borderWidth - */ - private float getVariableBorderWidth(float variableWidthValue, int side) { - if ((border & side) != 0) - return variableWidthValue != UNDEFINED ? variableWidthValue : borderWidth; - return 0; - } - - /** - * Helper function updating the border flag for a side based on the specified - * width. A width of 0 will disable the border on that side. Any other width - * enables it. - * - * @param width - * width of border - * @param side - * border side constant - */ - private void updateBorderBasedOnWidth(float width, int side) { - useVariableBorders = true; - if (width > 0) - enableBorderSide(side); - else - disableBorderSide(side); - } - - /** - * Gets the width of the left border. - * - * @return a width - */ - public float getBorderWidthLeft() { - return getVariableBorderWidth(borderWidthLeft, LEFT); - } - - /** - * Sets the width of the left border. - * - * @param borderWidthLeft - * a width - */ - public void setBorderWidthLeft(float borderWidthLeft) { - this.borderWidthLeft = borderWidthLeft; - updateBorderBasedOnWidth(borderWidthLeft, LEFT); - } - - /** - * Gets the width of the right border. - * - * @return a width - */ - public float getBorderWidthRight() { - return getVariableBorderWidth(borderWidthRight, RIGHT); - } - - /** - * Sets the width of the right border. - * - * @param borderWidthRight - * a width - */ - public void setBorderWidthRight(float borderWidthRight) { - this.borderWidthRight = borderWidthRight; - updateBorderBasedOnWidth(borderWidthRight, RIGHT); - } - - /** - * Gets the width of the top border. - * - * @return a width - */ - public float getBorderWidthTop() { - return getVariableBorderWidth(borderWidthTop, TOP); - } - - /** - * Sets the width of the top border. - * - * @param borderWidthTop - * a width - */ - public void setBorderWidthTop(float borderWidthTop) { - this.borderWidthTop = borderWidthTop; - updateBorderBasedOnWidth(borderWidthTop, TOP); - } - - /** - * Gets the width of the bottom border. - * - * @return a width - */ - public float getBorderWidthBottom() { - return getVariableBorderWidth(borderWidthBottom, BOTTOM); - } - - /** - * Sets the width of the bottom border. - * - * @param borderWidthBottom - * a width - */ - public void setBorderWidthBottom(float borderWidthBottom) { - this.borderWidthBottom = borderWidthBottom; - updateBorderBasedOnWidth(borderWidthBottom, BOTTOM); - } - - // METHODS TO GET/SET THE BORDER COLOR: - - /** - * Gets the color of the border. - * - * @return a Color - */ - public Color getBorderColor() { - return borderColor; - } - - /** - * Sets the color of the border. - * - * @param borderColor - * a Color - */ - public void setBorderColor(Color borderColor) { - this.borderColor = borderColor; - } - - /** - * Gets the color of the left border. - * - * @return a Color - */ - public Color getBorderColorLeft() { - if (borderColorLeft == null) - return borderColor; - return borderColorLeft; - } - - /** - * Sets the color of the left border. - * - * @param borderColorLeft - * a Color - */ - public void setBorderColorLeft(Color borderColorLeft) { - this.borderColorLeft = borderColorLeft; - } - - /** - * Gets the color of the right border. - * - * @return a Color - */ - public Color getBorderColorRight() { - if (borderColorRight == null) - return borderColor; - return borderColorRight; - } - - /** - * Sets the color of the right border. - * - * @param borderColorRight - * a Color - */ - public void setBorderColorRight(Color borderColorRight) { - this.borderColorRight = borderColorRight; - } - - /** - * Gets the color of the top border. - * - * @return a Color - */ - public Color getBorderColorTop() { - if (borderColorTop == null) - return borderColor; - return borderColorTop; - } - - /** - * Sets the color of the top border. - * - * @param borderColorTop - * a Color - */ - public void setBorderColorTop(Color borderColorTop) { - this.borderColorTop = borderColorTop; - } - - /** - * Gets the color of the bottom border. - * - * @return a Color - */ - public Color getBorderColorBottom() { - if (borderColorBottom == null) - return borderColor; - return borderColorBottom; - } - - /** - * Sets the color of the bottom border. - * - * @param borderColorBottom - * a Color - */ - public void setBorderColorBottom(Color borderColorBottom) { - this.borderColorBottom = borderColorBottom; - } - - // SPECIAL METHODS: - - /** - * Gets a Rectangle that is altered to fit on the page. - * - * @param top - * the top position - * @param bottom - * the bottom position - * @return a Rectangle - */ - public Rectangle rectangle(float top, float bottom) { - Rectangle tmp = new Rectangle(this); - if (getTop() > top) { - tmp.setTop(top); - tmp.disableBorderSide(TOP); - } - if (getBottom() < bottom) { - tmp.setBottom(bottom); - tmp.disableBorderSide(BOTTOM); - } - return tmp; - } - - /** - * Copies each of the parameters, except the position, from a - * Rectangle object - * - * @param rect - * Rectangle to copy from - */ - public void cloneNonPositionParameters(Rectangle rect) { - this.rotation = rect.rotation; - this.backgroundColor = rect.backgroundColor; - this.border = rect.border; - this.useVariableBorders = rect.useVariableBorders; - this.borderWidth = rect.borderWidth; - this.borderWidthLeft = rect.borderWidthLeft; - this.borderWidthRight = rect.borderWidthRight; - this.borderWidthTop = rect.borderWidthTop; - this.borderWidthBottom = rect.borderWidthBottom; - this.borderColor = rect.borderColor; - this.borderColorLeft = rect.borderColorLeft; - this.borderColorRight = rect.borderColorRight; - this.borderColorTop = rect.borderColorTop; - this.borderColorBottom = rect.borderColorBottom; - } - - /** - * Copies each of the parameters, except the position, from a - * Rectangle object if the value is set there - * - * @param rect - * Rectangle to copy from - */ - public void softCloneNonPositionParameters(Rectangle rect) { - if (rect.rotation != 0) - this.rotation = rect.rotation; - if (rect.backgroundColor != null) - this.backgroundColor = rect.backgroundColor; - if (rect.border != UNDEFINED) - this.border = rect.border; - if (useVariableBorders) - this.useVariableBorders = rect.useVariableBorders; - if (rect.borderWidth != UNDEFINED) - this.borderWidth = rect.borderWidth; - if (rect.borderWidthLeft != UNDEFINED) - this.borderWidthLeft = rect.borderWidthLeft; - if (rect.borderWidthRight != UNDEFINED) - this.borderWidthRight = rect.borderWidthRight; - if (rect.borderWidthTop != UNDEFINED) - this.borderWidthTop = rect.borderWidthTop; - if (rect.borderWidthBottom != UNDEFINED) - this.borderWidthBottom = rect.borderWidthBottom; - if (rect.borderColor != null) - this.borderColor = rect.borderColor; - if (rect.borderColorLeft != null) - this.borderColorLeft = rect.borderColorLeft; - if (rect.borderColorRight != null) - this.borderColorRight = rect.borderColorRight; - if (rect.borderColorTop != null) - this.borderColorTop = rect.borderColorTop; - if (rect.borderColorBottom != null) - this.borderColorBottom = rect.borderColorBottom; - } - - /** - * @return a String representation of the rectangle - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - StringBuilder buf = new StringBuilder("Rectangle: "); - buf.append(getWidth()); - buf.append('x'); - buf.append(getHeight()); - buf.append(" (rot: "); - buf.append(rotation); - buf.append(" degrees)"); - return buf.toString(); - } + /** + * Returns the lower left x-coordinate, considering a given margin. + * + * @param margin + * a margin + * @return the lower left x-coordinate + */ + public float getLeft(float margin) { + return llx + margin; + } + + /** + * Sets the upper right x-coordinate. + * + * @param urx + * the new value + */ + public void setRight(float urx) { + this.urx = urx; + } + + /** + * Returns the upper right x-coordinate. + * + * @return the upper right x-coordinate + */ + public float getRight() { + return urx; + } + + /** + * Returns the upper right x-coordinate, considering a given margin. + * + * @param margin + * a margin + * @return the upper right x-coordinate + */ + public float getRight(float margin) { + return urx - margin; + } + + /** + * Returns the width of the rectangle. + * + * @return the width + */ + public float getWidth() { + return urx - llx; + } + + /** + * Sets the upper right y-coordinate. + * + * @param ury + * the new value + */ + public void setTop(float ury) { + this.ury = ury; + } + + /** + * Returns the upper right y-coordinate. + * + * @return the upper right y-coordinate + */ + public float getTop() { + return ury; + } + + /** + * Returns the upper right y-coordinate, considering a given margin. + * + * @param margin + * a margin + * @return the upper right y-coordinate + */ + public float getTop(float margin) { + return ury - margin; + } + + public float getRelativeTop(){ + return aFloat; + } + + public void setRelativeTop(float relativeTop){ + this.aFloat = relativeTop; + } + /** + * Sets the lower left y-coordinate. + * + * @param lly + * the new value + */ + public void setBottom(float lly) { + this.lly = lly; + } + + /** + * Returns the lower left y-coordinate. + * + * @return the lower left y-coordinate + */ + public float getBottom() { + return lly; + } + + /** + * Returns the lower left y-coordinate, considering a given margin. + * + * @param margin + * a margin + * @return the lower left y-coordinate + */ + public float getBottom(float margin) { + return lly + margin; + } + + /** + * Returns the height of the rectangle. + * + * @return the height + */ + public float getHeight() { + return ury - lly; + } + + /** + * Normalizes the rectangle. Switches lower left with upper right if + * necessary. + */ + public void normalize() { + if (llx > urx) { + float a = llx; + llx = urx; + urx = a; + } + if (lly > ury) { + float a = lly; + lly = ury; + ury = a; + } + } + + // METHODS TO GET/SET THE ROTATION: + + /** + * Gets the rotation of the rectangle + * + * @return a rotation value + */ + public int getRotation() { + return rotation; + } + + /** + * Rotates the rectangle. Swaps the values of llx and lly and of urx and ury. + * + * @return the rotated Rectangle + */ + public Rectangle rotate() { + Rectangle rect = new Rectangle(lly, llx, ury, urx); + rect.rotation = rotation + 90; + rect.rotation %= 360; + return rect; + } + + // METHODS TO GET/SET THE BACKGROUND COLOR: + + /** + * Gets the backgroundcolor. + * + * @return a Color + */ + public Color getBackgroundColor() { + return backgroundColor; + } + + /** + * Sets the backgroundcolor of the rectangle. + * + * @param backgroundColor + * a Color + */ + + public void setBackgroundColor(Color backgroundColor) { + this.backgroundColor = backgroundColor; + } + + /** + * Gets the grayscale. + * + * @return the grayscale color of the background or 0 if the background has no + * grayscale color. + */ + public float getGrayFill() { + if (backgroundColor instanceof GrayColor) + return ((GrayColor) backgroundColor).getGray(); + return 0; + } + + /** + * Sets the the background color to a grayscale value. + * + * @param value + * the new grayscale value + */ + public void setGrayFill(float value) { + backgroundColor = new GrayColor(value); + } + + // METHODS TO GET/SET THE BORDER: + + /** + * Returns the exact type of the border. + * + * @return a value + */ + public int getBorder() { + return border; + } + + /** + * Indicates whether some type of border is set. + * + * @return a boolean + */ + public boolean hasBorders() { + switch (border) { + case UNDEFINED: + case NO_BORDER: + return false; + default: + return borderWidth > 0 || borderWidthLeft > 0 || borderWidthRight > 0 + || borderWidthTop > 0 || borderWidthBottom > 0; + } + } + + /** + * Indicates whether the specified type of border is set. + * + * @param type + * the type of border + * @return a boolean + */ + public boolean hasBorder(int type) { + if (border == UNDEFINED) + return false; + return (border & type) == type; + } + + /** + * Enables/Disables the border on the specified sides. The border is specified + * as an integer bitwise combination of the constants: + * LEFT, RIGHT, TOP, BOTTOM. + * + * @see #enableBorderSide(int) + * @see #disableBorderSide(int) + * @param border + * the new value + */ + public void setBorder(int border) { + this.border = border; + } + + /** + * Indicates whether variable width borders are being used. Returns true if + * setBorderWidthLeft, setBorderWidthRight, + * setBorderWidthTop, or setBorderWidthBottom has been called. + * + * @return true if variable width borders are in use + */ + public boolean isUseVariableBorders() { + return useVariableBorders; + } + + /** + * Sets a parameter indicating if the rectangle has variable borders + * + * @param useVariableBorders + * indication if the rectangle has variable borders + */ + public void setUseVariableBorders(boolean useVariableBorders) { + this.useVariableBorders = useVariableBorders; + } + + /** + * Enables the border on the specified side. + * + * @param side + * the side to enable. One of LEFT, RIGHT, TOP, BOTTOM + */ + public void enableBorderSide(int side) { + if (border == UNDEFINED) + border = 0; + border |= side; + } + + /** + * Disables the border on the specified side. + * + * @param side + * the side to disable. One of LEFT, RIGHT, TOP, BOTTOM + */ + public void disableBorderSide(int side) { + if (border == UNDEFINED) + border = 0; + border &= ~side; + } + + // METHODS TO GET/SET THE BORDER WIDTH: + + /** + * Gets the borderwidth. + * + * @return a value + */ + public float getBorderWidth() { + return borderWidth; + } + + /** + * Sets the borderwidth of the table. + * + * @param borderWidth + * the new value + */ + public void setBorderWidth(float borderWidth) { + this.borderWidth = borderWidth; + } + + /** + * Helper function returning the border width of a specific side. + * + * @param variableWidthValue + * a variable width (could be undefined) + * @param side + * the border you want to check + * @return the variableWidthValue if not undefined, otherwise the borderWidth + */ + private float getVariableBorderWidth(float variableWidthValue, int side) { + if ((border & side) != 0) + return variableWidthValue != UNDEFINED ? variableWidthValue : borderWidth; + return 0; + } + + /** + * Helper function updating the border flag for a side based on the specified + * width. A width of 0 will disable the border on that side. Any other width + * enables it. + * + * @param width + * width of border + * @param side + * border side constant + */ + private void updateBorderBasedOnWidth(float width, int side) { + useVariableBorders = true; + if (width > 0) + enableBorderSide(side); + else + disableBorderSide(side); + } + + /** + * Gets the width of the left border. + * + * @return a width + */ + public float getBorderWidthLeft() { + return getVariableBorderWidth(borderWidthLeft, LEFT); + } + + /** + * Sets the width of the left border. + * + * @param borderWidthLeft + * a width + */ + public void setBorderWidthLeft(float borderWidthLeft) { + this.borderWidthLeft = borderWidthLeft; + updateBorderBasedOnWidth(borderWidthLeft, LEFT); + } + + /** + * Gets the width of the right border. + * + * @return a width + */ + public float getBorderWidthRight() { + return getVariableBorderWidth(borderWidthRight, RIGHT); + } + + /** + * Sets the width of the right border. + * + * @param borderWidthRight + * a width + */ + public void setBorderWidthRight(float borderWidthRight) { + this.borderWidthRight = borderWidthRight; + updateBorderBasedOnWidth(borderWidthRight, RIGHT); + } + + /** + * Gets the width of the top border. + * + * @return a width + */ + public float getBorderWidthTop() { + return getVariableBorderWidth(borderWidthTop, TOP); + } + + /** + * Sets the width of the top border. + * + * @param borderWidthTop + * a width + */ + public void setBorderWidthTop(float borderWidthTop) { + this.borderWidthTop = borderWidthTop; + updateBorderBasedOnWidth(borderWidthTop, TOP); + } + + /** + * Gets the width of the bottom border. + * + * @return a width + */ + public float getBorderWidthBottom() { + return getVariableBorderWidth(borderWidthBottom, BOTTOM); + } + + /** + * Sets the width of the bottom border. + * + * @param borderWidthBottom + * a width + */ + public void setBorderWidthBottom(float borderWidthBottom) { + this.borderWidthBottom = borderWidthBottom; + updateBorderBasedOnWidth(borderWidthBottom, BOTTOM); + } + + // METHODS TO GET/SET THE BORDER COLOR: + + /** + * Gets the color of the border. + * + * @return a Color + */ + public Color getBorderColor() { + return borderColor; + } + + /** + * Sets the color of the border. + * + * @param borderColor + * a Color + */ + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + /** + * Gets the color of the left border. + * + * @return a Color + */ + public Color getBorderColorLeft() { + if (borderColorLeft == null) + return borderColor; + return borderColorLeft; + } + + /** + * Sets the color of the left border. + * + * @param borderColorLeft + * a Color + */ + public void setBorderColorLeft(Color borderColorLeft) { + this.borderColorLeft = borderColorLeft; + } + + /** + * Gets the color of the right border. + * + * @return a Color + */ + public Color getBorderColorRight() { + if (borderColorRight == null) + return borderColor; + return borderColorRight; + } + + /** + * Sets the color of the right border. + * + * @param borderColorRight + * a Color + */ + public void setBorderColorRight(Color borderColorRight) { + this.borderColorRight = borderColorRight; + } + + /** + * Gets the color of the top border. + * + * @return a Color + */ + public Color getBorderColorTop() { + if (borderColorTop == null) + return borderColor; + return borderColorTop; + } + + /** + * Sets the color of the top border. + * + * @param borderColorTop + * a Color + */ + public void setBorderColorTop(Color borderColorTop) { + this.borderColorTop = borderColorTop; + } + + /** + * Gets the color of the bottom border. + * + * @return a Color + */ + public Color getBorderColorBottom() { + if (borderColorBottom == null) + return borderColor; + return borderColorBottom; + } + + /** + * Sets the color of the bottom border. + * + * @param borderColorBottom + * a Color + */ + public void setBorderColorBottom(Color borderColorBottom) { + this.borderColorBottom = borderColorBottom; + } + + // SPECIAL METHODS: + + /** + * Gets a Rectangle that is altered to fit on the page. + * + * @param top + * the top position + * @param bottom + * the bottom position + * @return a Rectangle + */ + public Rectangle rectangle(float top, float bottom) { + Rectangle tmp = new Rectangle(this); + if (getTop() > top) { + tmp.setTop(top); + tmp.disableBorderSide(TOP); + } + if (getBottom() < bottom) { + tmp.setBottom(bottom); + tmp.disableBorderSide(BOTTOM); + } + return tmp; + } + + /** + * Copies each of the parameters, except the position, from a + * Rectangle object + * + * @param rect + * Rectangle to copy from + */ + public void cloneNonPositionParameters(Rectangle rect) { + this.rotation = rect.rotation; + this.backgroundColor = rect.backgroundColor; + this.border = rect.border; + this.useVariableBorders = rect.useVariableBorders; + this.borderWidth = rect.borderWidth; + this.borderWidthLeft = rect.borderWidthLeft; + this.borderWidthRight = rect.borderWidthRight; + this.borderWidthTop = rect.borderWidthTop; + this.borderWidthBottom = rect.borderWidthBottom; + this.borderColor = rect.borderColor; + this.borderColorLeft = rect.borderColorLeft; + this.borderColorRight = rect.borderColorRight; + this.borderColorTop = rect.borderColorTop; + this.borderColorBottom = rect.borderColorBottom; + } + + /** + * Copies each of the parameters, except the position, from a + * Rectangle object if the value is set there + * + * @param rect + * Rectangle to copy from + */ + public void softCloneNonPositionParameters(Rectangle rect) { + if (rect.rotation != 0) + this.rotation = rect.rotation; + if (rect.backgroundColor != null) + this.backgroundColor = rect.backgroundColor; + if (rect.border != UNDEFINED) + this.border = rect.border; + if (useVariableBorders) + this.useVariableBorders = rect.useVariableBorders; + if (rect.borderWidth != UNDEFINED) + this.borderWidth = rect.borderWidth; + if (rect.borderWidthLeft != UNDEFINED) + this.borderWidthLeft = rect.borderWidthLeft; + if (rect.borderWidthRight != UNDEFINED) + this.borderWidthRight = rect.borderWidthRight; + if (rect.borderWidthTop != UNDEFINED) + this.borderWidthTop = rect.borderWidthTop; + if (rect.borderWidthBottom != UNDEFINED) + this.borderWidthBottom = rect.borderWidthBottom; + if (rect.borderColor != null) + this.borderColor = rect.borderColor; + if (rect.borderColorLeft != null) + this.borderColorLeft = rect.borderColorLeft; + if (rect.borderColorRight != null) + this.borderColorRight = rect.borderColorRight; + if (rect.borderColorTop != null) + this.borderColorTop = rect.borderColorTop; + if (rect.borderColorBottom != null) + this.borderColorBottom = rect.borderColorBottom; + } + + /** + * @return a String representation of the rectangle + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + StringBuilder buf = new StringBuilder("Rectangle: "); + buf.append(getWidth()); + buf.append('x'); + buf.append(getHeight()); + buf.append(" (rot: "); + buf.append(rotation); + buf.append(" degrees)"); + return buf.toString(); + } } \ No newline at end of file diff --git a/openpdf/src/main/java/com/lowagie/text/pdf/PdfDocument.java b/openpdf/src/main/java/com/lowagie/text/pdf/PdfDocument.java index b3274956f..f320b2117 100644 --- a/openpdf/src/main/java/com/lowagie/text/pdf/PdfDocument.java +++ b/openpdf/src/main/java/com/lowagie/text/pdf/PdfDocument.java @@ -567,7 +567,7 @@ public boolean add(Element element) throws DocumentException { PdfPageEvent pageEvent = writer.getPageEvent(); boolean hasTitle = section.isNotAddedYet() - && section.getTitle() != null; + && section.getTitle() != null; // if the section is a chapter, we begin a new page if (section.isTriggerNewPage()) { @@ -676,17 +676,22 @@ public boolean add(Element element) throws DocumentException { break; } case Element.PTABLE: { - PdfPTable ptable = (PdfPTable)element; + PdfPTable ptable = (PdfPTable) element; if (ptable.size() <= ptable.getHeaderRows()) break; //nothing to do - // before every table, we add a new line and flush all lines - ensureNewLine(); - flushLines(); + if(isDoFooter) { + delayTableAddition(ptable); + } else { + // before every table, we add a new line and flush all lines + ensureNewLine(); + flushLines(); + + addPTable(ptable); + pageEmpty = false; + newLine(); + } - addPTable(ptable); - pageEmpty = false; - newLine(); break; } case Element.MULTI_COLUMN_TEXT: { @@ -713,15 +718,15 @@ public boolean add(Element element) throws DocumentException { break; } else if (element instanceof Table) { try { - PdfPTable ptable = ((Table)element).createPdfPTable(); - if (ptable.size() <= ptable.getHeaderRows()) - break; //nothing to do - // before every table, we add a new line and flush all lines - ensureNewLine(); - flushLines(); - addPTable(ptable); - pageEmpty = false; - break; + PdfPTable ptable = ((Table)element).createPdfPTable(); + if (ptable.size() <= ptable.getHeaderRows()) + break; //nothing to do + // before every table, we add a new line and flush all lines + ensureNewLine(); + flushLines(); + addPTable(ptable); + pageEmpty = false; + break; } catch(BadElementException bee) { // constructing the PdfTable @@ -745,7 +750,12 @@ public boolean add(Element element) throws DocumentException { case Element.IMGRAW: case Element.IMGTEMPLATE: { //carriageReturn(); suggestion by Marc Campforts - add((Image) element); + if(isDoFooter){ + addDelay((Image) element); + }else{ + add((Image) element); + } + break; } case Element.YMARK: { @@ -777,37 +787,45 @@ public boolean add(Element element) throws DocumentException { } } + + /** + * Integrate a paragraph into a table, so it can be a whole. + *

Note: This is not a table with square, it's just like the paragraph, but + * it cannot be separated. + * @param paragraph the {@code Paragraph} incoming paragraphs to be consolidated + * @return {@code PdfPTable} the whole which will be used later + */ static PdfPTable createInOneCell(Paragraph paragraph) { PdfPTable table = new PdfPTable(1); table.setWidthPercentage(100f); - PdfPCell cell = new PdfPCell(); cell.setBorder(Table.NO_BORDER); cell.setPadding(0); - - for (int i=0; i(boxSize); if (pageSize.getBackgroundColor() != null - || pageSize.hasBorders() - || pageSize.getBorderColor() != null) { + || pageSize.hasBorders() + || pageSize.getBorderColor() != null) { add(pageSize); } @@ -1301,7 +1319,7 @@ protected void carriageReturn() { public float getVerticalPosition(boolean ensureNewLine) { // ensuring that a new line has been started. if (ensureNewLine) { - ensureNewLine(); + ensureNewLine(); } return top() - currentHeight - indentation.indentTop; } @@ -1313,14 +1331,14 @@ public float getVerticalPosition(boolean ensureNewLine) { * Ensures that a new line has been started. */ protected void ensureNewLine() { - try { - if ((lastElementType == Element.PHRASE) || - (lastElementType == Element.CHUNK)) { - newLine(); - flushLines(); - } - } catch (DocumentException ex) { - throw new ExceptionConverter(ex); + try { + if ((lastElementType == Element.PHRASE) || + (lastElementType == Element.CHUNK)) { + newLine(); + flushLines(); + } + } catch (DocumentException ex) { + throw new ExceptionConverter(ex); } } @@ -1401,7 +1419,7 @@ void writeLineToContent(PdfLine line, PdfContentByte text, PdfContentByte graphi int lineLen; boolean isJustified; float hangingCorrection = 0; - float hScale = 1; + float hScale; float lastHScale = Float.NaN; float baseWordSpacing = 0; float baseCharacterSpacing = 0; @@ -1515,9 +1533,9 @@ else if (isJustified) { float[] extra = (float[]) bgr[1]; graphics.rectangle(xMarker - extra[0], - yMarker + descender - extra[1] + chunk.getTextRise(), - width - subtract + extra[0] + extra[2], - ascender - descender + extra[1] + extra[3]); + yMarker + descender - extra[1] + chunk.getTextRise(), + width - subtract + extra[0] + extra[2], + ascender - descender + extra[1] + extra[3]); graphics.fill(); graphics.setGrayFill(0); @@ -1530,7 +1548,7 @@ else if (isJustified) { if (nextChunk == null) subtract += hangingCorrection; Object[][] unders = (Object[][]) chunk.getAttribute(Chunk.UNDERLINE); - Color scolor = null; + Color scolor; for (Object[] obj : unders) { scolor = (Color) obj[0]; float[] ps = (float[]) obj[1]; @@ -2487,7 +2505,7 @@ protected void add(Image image) throws DocumentException { if (image == imageWait) imageWait = null; boolean textwrap = (image.getAlignment() & Image.TEXTWRAP) == Image.TEXTWRAP - && !((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE); + && !((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE); boolean underlying = (image.getAlignment() & Image.UNDERLYING) == Image.UNDERLYING; float diff = leading / 2; if (textwrap) { @@ -2526,7 +2544,120 @@ protected void add(Image image) throws DocumentException { } } -// [M4] Adding a PdfPTable + /** + * write non-text Element into document + */ + + protected void flushSpecial() { + if(footer.getSpecialContent() == null){ + return; + } + for (Element element : footer.getSpecialContent()) { + switch (element.type()) { + case Element.JPEG: + case Element.JPEG2000: + case Element.JBIG2: + case Element.IMGRAW: + case Element.IMGTEMPLATE: { + Image image = (Image) element; + boolean textwrap = (image.getAlignment() & Image.TEXTWRAP) == Image.TEXTWRAP + && !((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE); + float diff = leading / 2; + if (textwrap) { + diff += leading; + } + float lowerleft = footer.getTop() - image.getRelativeTop() - image.getScaledHeight() - diff; + + float[] matrix = image.matrix(); + float startPosition = indentLeft() - matrix[4]; + if ((image.getAlignment() & Image.RIGHT) == Image.RIGHT) + startPosition = indentRight() - image.getScaledWidth() - matrix[4]; + if ((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE) + startPosition = indentLeft() + ((indentRight() - indentLeft() - image.getScaledWidth()) / 2) - matrix[4]; + if (image.hasAbsoluteX()) startPosition = image.getAbsoluteX(); + + if (!textwrap) { + if ((image.getAlignment() & Image.RIGHT) == Image.RIGHT) + startPosition -= image.getIndentationRight(); + else if ((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE) + startPosition += image.getIndentationLeft() - image.getIndentationRight(); + else startPosition += image.getIndentationLeft(); + } + graphics.addImage(image, matrix[0], matrix[1], matrix[2], matrix[3], startPosition, lowerleft - matrix[5]); + break; + } + case Element.PTABLE: + PdfPTable pdfPTable = (PdfPTable) element; + + ColumnText columnText = new ColumnText(writer.getDirectContent()); + columnText.addElement(pdfPTable); + + columnText.setSimpleColumn(indentLeft(), footer.getBottom(), indentRight(), footer.getTop()); + columnText.go(); + + break; + } + } + footer.setPadding(0); + } + + /** + * Occupies space for Image that will be added later instead of now + * + * @param image the new Image + */ + + protected void addDelay(Image image) { + if (image.hasAbsoluteY()) { + System.out.println("Warning: absoluteY of image is invalid in footer"); + } + + image.setRelativeTop(currentHeight); // set the offset relative to the top + image.setAlignment(image.getAlignment() | footer.alignment()); + footer.addSpecialContent(image); + + // add indentation for text + boolean textwrap = (image.getAlignment() & Image.TEXTWRAP) == Image.TEXTWRAP + && !((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE); + boolean underlying = (image.getAlignment() & Image.UNDERLYING) == Image.UNDERLYING; + float diff = leading / 2; + if (textwrap) { + if (imageEnd < 0 || imageEnd < currentHeight + image.getScaledHeight() + diff) { + imageEnd = currentHeight + image.getScaledHeight() + diff; + } + if ((image.getAlignment() & Image.RIGHT) == Image.RIGHT) { + // indentation suggested by Pelikan Stephan + indentation.imageIndentRight += image.getScaledWidth() + image.getIndentationLeft(); + } else { + // indentation suggested by Pelikan Stephan + indentation.imageIndentLeft += image.getScaledWidth() + image.getIndentationRight(); + } + } + // move text + if (!(textwrap || underlying)) { + currentHeight += image.getScaledHeight() + diff; + flushLines(); + text.moveText(0, -(image.getScaledHeight() + diff)); + newLine(); + } else { + footer.addPadding(image.getScaledHeight() + diff); + } + } + + /** + * Occupies space for PdfPTable that will be added later instead of now + * + * @param table the new PdfPTable + */ + protected void delayTableAddition(PdfPTable table) { + setTableWidth(table); + final float footerPadding = table.getTotalHeight() - (0.75f * leading); + + footer.addSpecialContent(table); + footer.addPadding(footerPadding); + } + + // [M4] Adding a PdfPTable /** Adds a PdfPTable to the document. * @param ptable the PdfPTable to be added to the document. @@ -2580,14 +2711,18 @@ void addPTable(PdfPTable ptable) throws DocumentException { */ boolean fitsPage(PdfPTable table, float margin) { + setTableWidth(table); + // ensuring that a new line has been started. + ensureNewLine(); + return table.getTotalHeight() + ((currentHeight > 0) ? table.spacingBefore() : 0f) + <= indentTop() - currentHeight - indentBottom() - margin; + } + + private void setTableWidth(final PdfPTable table) { if (!table.isLockedWidth()) { float totalWidth = (indentRight() - indentLeft()) * table.getWidthPercentage() / 100; table.setTotalWidth(totalWidth); } - // ensuring that a new line has been started. - ensureNewLine(); - return table.getTotalHeight() + ((currentHeight > 0) ? table.spacingBefore() : 0f) - <= indentTop() - currentHeight - indentBottom() - margin; } // [M4'] Adding a Table @@ -3072,7 +3207,7 @@ protected void renderCells(RenderingContext ctx, java.util.List cells, boolean h // we paint the borders of the cells Rectangle cellRect = cell.rectangle(tableRect.getTop(), indentBottom); - //cellRect.setBottom(cellRect.bottom()); + //cellRect.setBottom(cellRect.bottom()); if (cellRect.getHeight() > 0) { ctx.lostTableBottom = indentBottom; ctx.cellGraphics.rectangle(cellRect); @@ -3102,8 +3237,12 @@ float bottom(Table table) { } // [M5] header/footer + /** This is the flag meaning whether document is creating footer. */ + private boolean isDoFooter = false; + protected void doFooter() throws DocumentException { if (footer == null) return; + isDoFooter = true; // Begin added by Edgar Leonardo Prieto Perilla // Avoid footer indentation float tmpIndentLeft = indentation.indentLeft; @@ -3129,11 +3268,12 @@ protected void doFooter() throws DocumentException { text.moveText(left(), indentBottom()); flushLines(); text.moveText(-left(), -bottom()); - footer.setTop(bottom(currentHeight)); + footer.setTop(bottom(Math.max(footer.getPadding(), currentHeight))); footer.setBottom(bottom() - (0.75f * leading)); footer.setLeft(left()); footer.setRight(right()); graphics.rectangle(footer); + flushSpecial(); indentation.indentBottom = currentHeight + leading * 2; currentHeight = 0; // Begin added by Edgar Leonardo Prieto Perilla @@ -3145,6 +3285,7 @@ protected void doFooter() throws DocumentException { indentation.imageIndentRight = tmpImageIndentRight; // End added: Bonf (Marc Schneider) 2003-07-29 // End added by Edgar Leonardo Prieto Perilla + isDoFooter = false; } protected void doHeader() throws DocumentException { @@ -3190,4 +3331,4 @@ protected void doHeader() throws DocumentException { // End added: Bonf (Marc Schneider) 2003-07-29 // End Added by Edgar Leonardo Prieto Perilla } -} +} \ No newline at end of file diff --git a/openpdf/src/test/java/com/lowagie/text/FooterTableTest.java b/openpdf/src/test/java/com/lowagie/text/FooterTableTest.java new file mode 100644 index 000000000..06278212f --- /dev/null +++ b/openpdf/src/test/java/com/lowagie/text/FooterTableTest.java @@ -0,0 +1,62 @@ +package com.lowagie.text; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Objects; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.lowagie.text.pdf.PdfPTable; +import com.lowagie.text.pdf.PdfWriter; + +public class FooterTableTest { + @Test + public void imageLeftAlignmentPositionTest() throws IOException { + Document document = new Document(PageSize.A4); + PdfWriter.getInstance(document, new FileOutputStream("footer-table-test.pdf")); + + Image jpg = Image.getInstance(Objects.requireNonNull(getClass().getClassLoader().getResource("GitHub-Mark-32px.png"))); + jpg.setAlignment(Image.RIGHT); + + PdfPTable table = new PdfPTable(3); + table.getDefaultCell().setBorder(Table.NO_BORDER); + table.addCell("1.1"); + table.addCell("1.2"); + table.addCell("1.3"); + table.addCell("2.1"); + table.addCell(new Phrase("center")); + table.addCell("2.3"); + table.addCell("3.1"); + table.addCell("3.2"); + table.addCell("3.3"); + + Paragraph footerParagraph = new Paragraph(); + footerParagraph.add(jpg); + footerParagraph.add(table); + + HeaderFooter footer = new HeaderFooter(footerParagraph, false); + document.setFooter(footer); + + document.open(); + document.add(new Paragraph("This is fixed smellbusters test.")); + document.add(new Paragraph("Jon line")); + document.newPage(); + document.add(new Paragraph("second")); + document.newPage(); + document.add(new Paragraph("third")); + document.close(); + + float tableHeight = table.getTotalHeight(); + float footerTop = footer.getTop(); + float tableBottom = footerTop - table.getTotalHeight(); + Assertions.assertEquals(48.0, tableHeight); + Assertions.assertEquals(76.0, footerTop); + Assertions.assertEquals(28.0, tableBottom); + } + + public static void main(String[] args) throws IOException { + FooterTableTest test = new FooterTableTest(); + test.imageLeftAlignmentPositionTest(); + } +} \ No newline at end of file diff --git a/openpdf/src/test/java/com/lowagie/text/pdf/FooterImageTest.java b/openpdf/src/test/java/com/lowagie/text/pdf/FooterImageTest.java new file mode 100644 index 000000000..faa0b5bda --- /dev/null +++ b/openpdf/src/test/java/com/lowagie/text/pdf/FooterImageTest.java @@ -0,0 +1,158 @@ +package com.lowagie.text.pdf; + +import com.lowagie.text.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Objects; + +class FooterImageTest { + @Test + void onlyTextFooterUpperBoundTest() throws IOException { + Document document = new Document(PageSize.A4); + PdfWriter.getInstance(document, new FileOutputStream("footer-only-text.pdf")); + + Paragraph footerParagraph = new Paragraph(); + String test = "This is a smellbusters test."; + String footerstr = "footer"; + footerParagraph.add(footerstr); + HeaderFooter footer = new HeaderFooter(footerParagraph, false); + document.setFooter(footer); + + document.open(); + document.add(new Paragraph(test)); + document.close(); + Assertions.assertEquals(52.0, footer.getTop()); + } + + @Test + void imageLeftAlignmentPositionTest() throws IOException { + Document document = new Document(PageSize.A4); + Image jpg = Image.getInstance(Objects.requireNonNull(getClass().getClassLoader().getResource("GitHub-Mark-32px.png"))); + PdfWriter.getInstance(document, new FileOutputStream("footer-image-left.pdf")); + + Paragraph footerParagraph = new Paragraph(); + String test = "This is a smellbusters line."; + String footerstr = "footer"; + footerParagraph.add(jpg); + footerParagraph.add(footerstr); + HeaderFooter footer = new HeaderFooter(footerParagraph, false); + document.setFooter(footer); + + document.open(); + document.add(new Paragraph(test)); + document.close(); + + float footerTop = footer.getTop(); + float imageBottom = footerTop - jpg.getRelativeTop() - jpg.getScaledHeight(); + float imageIndentLeft = document.left() - jpg.matrix()[4]; + Assertions.assertEquals(92.0, footerTop); + Assertions.assertEquals(60.0, imageBottom); + Assertions.assertEquals(36.0, imageIndentLeft); + } + + @Test + void imageRightAlignmentPositionTest() throws IOException { + Document document = new Document(PageSize.A4); + Image jpg = Image.getInstance(Objects.requireNonNull(getClass().getClassLoader().getResource("GitHub-Mark-32px.png"))); + PdfWriter.getInstance(document, new FileOutputStream("footer-image-right.pdf")); + jpg.setAlignment(Element.ALIGN_RIGHT); + + Paragraph footerParagraph = new Paragraph(); + String test = "This is a smellbusters line."; + footerParagraph.add(jpg); + HeaderFooter footer = new HeaderFooter(footerParagraph, false); + document.setFooter(footer); + + document.open(); + document.add(new Paragraph(test)); + document.close(); + + float footerTop = footer.getTop(); + float imageBottom = footerTop - jpg.getRelativeTop() - jpg.getScaledHeight(); + float imageIndentRight = document.right() - jpg.getScaledWidth() - jpg.matrix()[4]; + imageIndentRight -= jpg.getIndentationRight(); + Assertions.assertEquals(76.0, footerTop); + Assertions.assertEquals(44.0, imageBottom); + Assertions.assertEquals(527.0, imageIndentRight); + } + + @Test + void centerUnderlyingPositionTest() throws IOException { + Document document = new Document(PageSize.A4); + Image jpg = Image.getInstance(Objects.requireNonNull(getClass().getClassLoader().getResource("GitHub-Mark-32px.png"))); + jpg.setAlignment(Image.UNDERLYING); + + PdfWriter.getInstance(document, new FileOutputStream("footer-image-center.pdf")); + + Paragraph footerParagraph = new Paragraph(); + String test = "This is a test smellbusters."; + footerParagraph.add(jpg); + HeaderFooter footer = new HeaderFooter(footerParagraph, true); + footer.setAlignment(Element.ALIGN_CENTER); + document.setFooter(footer); + + document.open(); + document.add(new Paragraph(test)); + document.close(); + + float footerTop = footer.getTop(); + float imageBottom = footerTop - jpg.getRelativeTop() - jpg.getScaledHeight(); + float imageIndentLeft = document.left() + (document.right() - document.left() - jpg.getScaledWidth()) / 2; + imageIndentLeft -= jpg.getIndentationRight() + jpg.matrix()[4]; + Assertions.assertEquals(76.0, footerTop); + Assertions.assertEquals(44.0, imageBottom); + Assertions.assertEquals(281.5, imageIndentLeft); + } + + @Test + void multiplePageWithImageAndNumberTest() throws IOException { + Document document = new Document(PageSize.A4); + Image jpg = Image.getInstance(Objects.requireNonNull(getClass().getClassLoader().getResource("GitHub-Mark-32px.png"))); + jpg.setAlignment(Image.UNDERLYING); + + PdfWriter.getInstance(document, new FileOutputStream("footer-image-multiple-pages.pdf")); + + Paragraph footerParagraph = new Paragraph(); + String test = "Smellbusters manual."; + footerParagraph.add(jpg); + HeaderFooter footer = new HeaderFooter(footerParagraph, true); + footer.setAlignment(Element.ALIGN_CENTER); + document.setFooter(footer); + + document.open(); + for (int i = 0; i < 100; i++) { + document.add(new Paragraph(test)); + } + document.close(); + + float footerTop = footer.getTop(); + float imageBottom = footerTop - jpg.getRelativeTop() - jpg.getScaledHeight(); + float imageIndentLeft = document.left() + (document.right() - document.left() - jpg.getScaledWidth()) / 2; + imageIndentLeft -= jpg.getIndentationRight() + jpg.matrix()[4]; + Assertions.assertEquals(76.0, footerTop); + Assertions.assertEquals(44.0, imageBottom); + Assertions.assertEquals(281.5, imageIndentLeft); + + } + + public static void main(String[] args) throws IOException { + FooterImageTest test = new FooterImageTest(); + + + test.onlyTextFooterUpperBoundTest(); + + + test.imageLeftAlignmentPositionTest(); + + test.imageRightAlignmentPositionTest(); + + + test.centerUnderlyingPositionTest(); + + test.multiplePageWithImageAndNumberTest(); + + } +} \ No newline at end of file diff --git a/openpdf/src/test/resources/GitHub-Mark-32px.png b/openpdf/src/test/resources/GitHub-Mark-32px.png new file mode 100644 index 000000000..8b25551a9 Binary files /dev/null and b/openpdf/src/test/resources/GitHub-Mark-32px.png differ diff --git a/pom.xml b/pom.xml index 1f7bea9ad..90cf5ebbd 100644 --- a/pom.xml +++ b/pom.xml @@ -308,20 +308,6 @@ ${maven-repository-plugin.version} - - org.apache.maven.plugins - maven-gpg-plugin - ${maven-gpg-plugin.version} - - - sign-artifacts - verify - - sign - - - - org.sonatype.plugins nexus-staging-maven-plugin