1 /*
2  * $Id: Document.java 4007 2009-07-07 09:43:40Z blowagie $
3  *
4  * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie.
5  *
6  * The contents of this file are subject to the Mozilla Public License Version 1.1
7  * (the "License"); you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the License.
13  *
14  * The Original Code is 'iText, a free JAVA-PDF library'.
15  *
16  * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
17  * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
18  * All Rights Reserved.
19  * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
20  * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
21  *
22  * Contributor(s): all the names of the contributors are added in the source code
23  * where applicable.
24  *
25  * Alternatively, the contents of this file may be used under the terms of the
26  * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
27  * provisions of LGPL are applicable instead of those above.  If you wish to
28  * allow use of your version of this file only under the terms of the LGPL
29  * License and not to allow others to use your version of this file under
30  * the MPL, indicate your decision by deleting the provisions above and
31  * replace them with the notice and other provisions required by the LGPL.
32  * If you do not delete the provisions above, a recipient may use your version
33  * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
34  *
35  * This library is free software; you can redistribute it and/or modify it
36  * under the terms of the MPL as stated above or under the terms of the GNU
37  * Library General Public License as published by the Free Software Foundation;
38  * either version 2 of the License, or any later version.
39  *
40  * This library is distributed in the hope that it will be useful, but WITHOUT
41  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
42  * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
43  * details.
44  *
45  * If you didn't download this code from the following link, you should check if
46  * you aren't using an obsolete version:
47  * http://www.lowagie.com/iText/
48  */

49
50 package com.lowagie.text;
51
52 import java.text.SimpleDateFormat;
53 import java.util.ArrayList;
54 import java.util.Date;
55 import java.util.Iterator;
56
57 /**
58  * A generic Document class.
59  * <P>
60  * All kinds of Text-elements can be added to a <CODE>HTMLDocument</CODE>.
61  * The <CODE>Document</CODE> signals all the listeners when an element has
62  * been added.
63  * <P>
64  * Remark:
65  * <OL>
66  *     <LI>Once a document is created you can add some meta information.
67  *     <LI>You can also set the headers/footers.
68  *     <LI>You have to open the document before you can write content.
69  * <LI>You can only write content (no more meta-formation!) once a document is
70  * opened.
71  * <LI>When you change the header/footer on a certain page, this will be
72  * effective starting on the next page.
73  * <LI>After closing the document, every listener (as well as its <CODE>
74  * OutputStream</CODE>) is closed too.
75  * </OL>
76  * Example: <BLOCKQUOTE>
77  *
78  * <PRE>// creation of the document with a certain size and certain margins
79  * <STRONG>Document document = new Document(PageSize.A4, 50, 50, 50, 50);
80  * </STRONG> try { 
81  *   // creation of the different writers 
82  *   HtmlWriter.getInstance(<STRONG>document </STRONG>, System.out);
83  *   PdfWriter.getInstance(<STRONG>document </STRONG>, new FileOutputStream("text.pdf"));
84  *   // we add some meta information to the document
85  *   <STRONG>document.addAuthor("Bruno Lowagie"); </STRONG>
86  *   <STRONG>document.addSubject("This is the result of a Test."); </STRONG>
87  *   // we open the document for writing
88  *   <STRONG>document.open(); </STRONG>
89  *   <STRONG>document.add(new Paragraph("Hello world"));</STRONG>
90  *  } catch(DocumentException de) {
91  *   System.err.println(de.getMessage());
92  *  }
93  *  <STRONG>document.close();</STRONG>
94  * </PRE>
95  * 
96  * </BLOCKQUOTE>
97  */

98
99 public class Document implements DocListener {
100     
101     // membervariables
102     /**
103      * This constant may only be changed by Paulo Soares and/or Bruno Lowagie.
104      * @since    2.1.6
105      */

106     private static final String ITEXT = "iText";
107     /**
108      * This constant may only be changed by Paulo Soares and/or Bruno Lowagie.
109      * @since    2.1.6
110      */

111     private static final String RELEASE = "2.1.7";
112     /** This constant may only be changed by Paulo Soares and/or Bruno Lowagie. */
113     private static final String ITEXT_VERSION = ITEXT + " " + RELEASE + " by 1T3XT";
114     
115     /**
116      * Allows the pdf documents to be produced without compression for debugging
117      * purposes.
118      */

119     public static boolean compress = true
120     
121     /**
122      * When true the file access is not done through a memory mapped file. Use it if the file
123      * is too big to be mapped in your address space.
124      */

125     public static boolean plainRandomAccess = false
126  
127     /** Scales the WMF font size. The default value is 0.86. */
128     public static float wmfFontCorrection = 0.86f;
129     
130     /** The DocListener. */
131     private ArrayList listeners = new ArrayList();
132     
133     /** Is the document open or not? */
134     protected boolean open;
135     
136     /** Has the document already been closed? */
137     protected boolean close;
138     
139     // membervariables concerning the layout
140     
141     /** The size of the page. */
142     protected Rectangle pageSize;
143     
144     /** margin in x direction starting from the left */
145     protected float marginLeft = 0;
146     
147     /** margin in x direction starting from the right */
148     protected float marginRight = 0;
149     
150     /** margin in y direction starting from the top */
151     protected float marginTop = 0;
152     
153     /** margin in y direction starting from the bottom */
154     protected float marginBottom = 0;
155     
156     /** mirroring of the left/right margins */
157     protected boolean marginMirroring = false;
158     
159     /**
160      * mirroring of the top/bottom margins
161      * @since    2.1.6
162      */

163     protected boolean marginMirroringTopBottom = false;
164     
165     /** Content of JavaScript onLoad function */
166     protected String javaScript_onLoad = null;
167
168     /** Content of JavaScript onUnLoad function */
169     protected String javaScript_onUnLoad = null;
170
171     /** Style class in HTML body tag */
172     protected String htmlStyleClass = null;
173
174     // headers, footers
175     
176     /** Current pagenumber */
177     protected int pageN = 0;
178     
179     /** This is the textual part of a Page; it can contain a header */
180     protected HeaderFooter header = null;
181     
182     /** This is the textual part of the footer */
183     protected HeaderFooter footer = null;
184     
185     /** This is a chapter number in case ChapterAutoNumber is used. */
186     protected int chapternumber = 0;
187     
188     // constructor
189     
190     /**
191      * Constructs a new <CODE>Document</CODE> -object.
192  */

193     
194     public Document() {
195         this(PageSize.A4);
196     }
197     
198     /**
199      * Constructs a new <CODE>Document</CODE> -object.
200  *
201      * @param pageSize
202      *            the pageSize
203  */

204     
205     public Document(Rectangle pageSize) {
206         this(pageSize, 36, 36, 36, 36);
207     }
208     
209     /**
210      * Constructs a new <CODE>Document</CODE> -object.
211  *
212      * @param pageSize
213      *            the pageSize
214      * @param marginLeft
215      *            the margin on the left
216      * @param marginRight
217      *            the margin on the right
218      * @param marginTop
219      *            the margin on the top
220      * @param marginBottom
221      *            the margin on the bottom
222  */

223     
224     public Document(Rectangle pageSize, float marginLeft, float marginRight,
225             float marginTop, float marginBottom) {
226         this.pageSize = pageSize;
227         this.marginLeft = marginLeft;
228         this.marginRight = marginRight;
229         this.marginTop = marginTop;
230         this.marginBottom = marginBottom;
231     }
232     
233     // listener methods
234     
235     /**
236  * Adds a <CODE>DocListener</CODE> to the <CODE>Document</CODE>.
237  *
238      * @param listener
239      *            the new DocListener.
240  */

241     
242     public void addDocListener(DocListener listener) {
243         listeners.add(listener);
244     }
245     
246     /**
247  * Removes a <CODE>DocListener</CODE> from the <CODE>Document</CODE>.
248  *
249      * @param listener
250      *            the DocListener that has to be removed.
251  */

252     
253     public void removeDocListener(DocListener listener) {
254         listeners.remove(listener);
255     }
256     
257     // methods implementing the DocListener interface
258     
259     /**
260      * Adds an <CODE>Element</CODE> to the <CODE>Document</CODE>.
261  *
262      * @param element
263      *            the <CODE>Element</CODE> to add
264      * @return <CODE>true</CODE> if the element was added, <CODE>false
265      *         </CODE> if not
266      * @throws DocumentException
267      *             when a document isn't open yet, or has been closed
268  */

269     
270     public boolean add(Element element) throws DocumentException {
271         if (close) {
272             throw new DocumentException(
273                 "The document has been closed. You can't add any Elements.");
274         }
275         if (!open && element.isContent()) {
276             throw new DocumentException(
277                 "The document is not open yet; you can only add Meta information.");
278         }
279         boolean success = false;
280         DocListener listener;
281         if (element instanceof ChapterAutoNumber) {
282             chapternumber = ((ChapterAutoNumber)element).setAutomaticNumber(chapternumber);
283         }
284         for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
285             listener = (DocListener) iterator.next();
286             success |= listener.add(element);
287         }
288         if (element instanceof LargeElement) {
289             LargeElement e = (LargeElement)element;
290             if (!e.isComplete())
291                 e.flushContent();
292         }
293         return success;
294     }
295     
296     /**
297  * Opens the document.
298  * <P>
299      * Once the document is opened, you can't write any Header- or
300      * Meta-information anymore. You have to open the document before you can
301      * begin to add content to the body of the document.
302  */

303     
304     public void open() {
305         if (!close) {
306             open = true;
307         }
308         DocListener listener;
309         for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
310             listener = (DocListener) iterator.next();
311             listener.setPageSize(pageSize);
312             listener.setMargins(marginLeft, marginRight, marginTop,
313                     marginBottom);
314             listener.open();
315         }
316     }
317     
318     /**
319  * Sets the pagesize.
320  *
321      * @param pageSize
322      *            the new pagesize
323  * @return    a <CODE>boolean</CODE>
324  */

325     
326     public boolean setPageSize(Rectangle pageSize) {
327         this.pageSize = pageSize;
328         DocListener listener;
329         for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
330             listener = (DocListener) iterator.next();
331             listener.setPageSize(pageSize);
332         }
333         return true;
334     }
335     
336     /**
337  * Sets the margins.
338  *
339      * @param marginLeft
340      *            the margin on the left
341      * @param marginRight
342      *            the margin on the right
343      * @param marginTop
344      *            the margin on the top
345      * @param marginBottom
346      *            the margin on the bottom
347  * @return    a <CODE>boolean</CODE>
348  */

349     
350     public boolean setMargins(float marginLeft, float marginRight,
351             float marginTop, float marginBottom) {
352         this.marginLeft = marginLeft;
353         this.marginRight = marginRight;
354         this.marginTop = marginTop;
355         this.marginBottom = marginBottom;
356         DocListener listener;
357         for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
358             listener = (DocListener) iterator.next();
359             listener.setMargins(marginLeft, marginRight, marginTop,
360                     marginBottom);
361         }
362         return true;
363     }
364     
365     /**
366  * Signals that an new page has to be started.
367  *
368      * @return <CODE>true</CODE> if the page was added, <CODE>false</CODE>
369      *         if not.
370  */

371     
372     public boolean newPage() {
373         if (!open || close) {
374             return false;
375         }
376         DocListener listener;
377         for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
378             listener = (DocListener) iterator.next();
379             listener.newPage();
380         }
381         return true;
382     }
383     
384     /**
385  * Changes the header of this document.
386  *
387      * @param header
388      *            the new header
389  */

390     
391     public void setHeader(HeaderFooter header) {
392         this.header = header;
393         DocListener listener;
394         for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
395             listener = (DocListener) iterator.next();
396             listener.setHeader(header);
397         }
398     }
399     
400     /**
401  * Resets the header of this document.
402  */

403     
404     public void resetHeader() {
405         this.header = null;
406         DocListener listener;
407         for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
408             listener = (DocListener) iterator.next();
409             listener.resetHeader();
410         }
411     }
412     
413     /**
414  * Changes the footer of this document.
415  *
416      * @param footer
417      *            the new footer
418  */

419     
420     public void setFooter(HeaderFooter footer) {
421         this.footer = footer;
422         DocListener listener;
423         for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
424             listener = (DocListener) iterator.next();
425             listener.setFooter(footer);
426         }
427     }
428     
429     /**
430  * Resets the footer of this document.
431  */

432     
433     public void resetFooter() {
434         this.footer = null;
435         DocListener listener;
436         for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
437             listener = (DocListener) iterator.next();
438             listener.resetFooter();
439         }
440     }
441     
442     /**
443  * Sets the page number to 0.
444  */

445     
446     public void resetPageCount() {
447         pageN = 0;
448         DocListener listener;
449         for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
450             listener = (DocListener) iterator.next();
451             listener.resetPageCount();
452         }
453     }
454     
455     /**
456  * Sets the page number.
457  *
458      * @param pageN
459      *            the new page number
460  */

461     
462     public void setPageCount(int pageN) {
463         this.pageN = pageN;
464         DocListener listener;
465         for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
466             listener = (DocListener) iterator.next();
467             listener.setPageCount(pageN);
468         }
469     }
470     
471     /**
472  * Returns the current page number.
473  *
474  * @return the current page number
475  */

476     
477     public int getPageNumber() {
478         return this.pageN;
479     }
480     
481     /**
482  * Closes the document.
483  * <P>
484      * Once all the content has been written in the body, you have to close the
485      * body. After that nothing can be written to the body anymore.
486  */

487     
488     public void close() {
489         if (!close) {
490             open = false;
491             close = true;
492         }
493         DocListener listener;
494         for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
495             listener = (DocListener) iterator.next();
496             listener.close();
497         }
498     }
499     
500     // methods concerning the header or some meta information
501     
502     /**
503  * Adds a user defined header to the document.
504  *
505      * @param name
506      *            the name of the header
507      * @param content
508      *            the content of the header
509  * @return    <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise
510  */

511     
512     public boolean addHeader(String name, String content) {
513         try {
514             return add(new Header(name, content));
515         } catch (DocumentException de) {
516             throw new ExceptionConverter(de);
517         }
518     }
519     
520     /**
521  * Adds the title to a Document.
522  *
523      * @param title
524      *            the title
525  * @return    <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise
526  */

527     
528     public boolean addTitle(String title) {
529         try {
530             return add(new Meta(Element.TITLE, title));
531         } catch (DocumentException de) {
532             throw new ExceptionConverter(de);
533         }
534     }
535     
536     /**
537  * Adds the subject to a Document.
538  *
539      * @param subject
540      *            the subject
541  * @return    <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise
542  */

543     
544     public boolean addSubject(String subject) {
545         try {
546             return add(new Meta(Element.SUBJECT, subject));
547         } catch (DocumentException de) {
548             throw new ExceptionConverter(de);
549         }
550     }
551     
552     /**
553  * Adds the keywords to a Document.
554  *
555      * @param keywords
556      *            adds the keywords to the document
557  * @return <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise
558  */

559     
560     public boolean addKeywords(String keywords) {
561         try {
562             return add(new Meta(Element.KEYWORDS, keywords));
563         } catch (DocumentException de) {
564             throw new ExceptionConverter(de);
565         }
566     }
567     
568     /**
569  * Adds the author to a Document.
570  *
571      * @param author
572      *            the name of the author
573  * @return    <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise
574  */

575     
576     public boolean addAuthor(String author) {
577         try {
578             return add(new Meta(Element.AUTHOR, author));
579         } catch (DocumentException de) {
580             throw new ExceptionConverter(de);
581         }
582     }
583     
584     /**
585  * Adds the creator to a Document.
586  *
587      * @param creator
588      *            the name of the creator
589  * @return    <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise
590  */

591     
592     public boolean addCreator(String creator) {
593         try {
594             return add(new Meta(Element.CREATOR, creator));
595         } catch (DocumentException de) {
596             throw new ExceptionConverter(de);
597         }
598     }
599     
600     /**
601  * Adds the producer to a Document.
602  *
603  * @return    <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise
604  */

605     
606     public boolean addProducer() {
607         try {
608             return add(new Meta(Element.PRODUCER, getVersion()));
609         } catch (DocumentException de) {
610             throw new ExceptionConverter(de);
611         }
612     }
613     
614     /**
615  * Adds the current date and time to a Document.
616  *
617  * @return    <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise
618  */

619     
620     public boolean addCreationDate() {
621         try {
622             /* bugfix by 'taqua' (Thomas) */
623             final SimpleDateFormat sdf = new SimpleDateFormat(
624                     "EEE MMM dd HH:mm:ss zzz yyyy");
625             return add(new Meta(Element.CREATIONDATE, sdf.format(new Date())));
626         } catch (DocumentException de) {
627             throw new ExceptionConverter(de);
628         }
629     }
630     
631     // methods to get the layout of the document.
632     
633     /**
634  * Returns the left margin.
635  *
636  * @return    the left margin
637  */

638     
639     public float leftMargin() {
640         return marginLeft;
641     }
642     
643     /**
644  * Return the right margin.
645  *
646  * @return    the right margin
647  */

648     
649     public float rightMargin() {
650         return marginRight;
651     }
652     
653     /**
654  * Returns the top margin.
655  *
656  * @return    the top margin
657  */

658     
659     public float topMargin() {
660         return marginTop;
661     }
662     
663     /**
664  * Returns the bottom margin.
665  *
666  * @return    the bottom margin
667  */

668     
669     public float bottomMargin() {
670         return marginBottom;
671     }
672     
673     /**
674  * Returns the lower left x-coordinate.
675  *
676  * @return    the lower left x-coordinate
677  */

678     
679     public float left() {
680         return pageSize.getLeft(marginLeft);
681     }
682     
683     /**
684  * Returns the upper right x-coordinate.
685  *
686  * @return    the upper right x-coordinate
687  */

688     
689     public float right() {
690         return pageSize.getRight(marginRight);
691     }
692     
693     /**
694  * Returns the upper right y-coordinate.
695  *
696  * @return    the upper right y-coordinate
697  */

698     
699     public float top() {
700         return pageSize.getTop(marginTop);
701     }
702     
703     /**
704  * Returns the lower left y-coordinate.
705  *
706  * @return    the lower left y-coordinate
707  */

708     
709     public float bottom() {
710         return pageSize.getBottom(marginBottom);
711     }
712     
713     /**
714  * Returns the lower left x-coordinate considering a given margin.
715  *
716      * @param margin
717      *            a margin
718  * @return    the lower left x-coordinate
719  */

720     
721     public float left(float margin) {
722         return pageSize.getLeft(marginLeft + margin);
723     }
724     
725     /**
726  * Returns the upper right x-coordinate, considering a given margin.
727  *
728      * @param margin
729      *            a margin
730  * @return    the upper right x-coordinate
731  */

732     
733     public float right(float margin) {
734         return pageSize.getRight(marginRight + margin);
735     }
736     
737     /**
738  * Returns the upper right y-coordinate, considering a given margin.
739  *
740      * @param margin
741      *            a margin
742  * @return    the upper right y-coordinate
743  */

744     
745     public float top(float margin) {
746         return pageSize.getTop(marginTop + margin);
747     }
748     
749     /**
750  * Returns the lower left y-coordinate, considering a given margin.
751  *
752      * @param margin
753      *            a margin
754  * @return    the lower left y-coordinate
755  */

756     
757     public float bottom(float margin) {
758         return pageSize.getBottom(marginBottom + margin);
759     }
760     
761     /**
762  * Gets the pagesize.
763      * 
764  * @return the page size
765  */

766     
767     public Rectangle getPageSize() {
768         return this.pageSize;
769     }
770     
771     /**
772      * Checks if the document is open.
773      * 
774      * @return <CODE>true</CODE> if the document is open
775      */
    
776     public boolean isOpen() {
777         return open;
778     }
779     
780     /**
781      * Gets the product name.
782      * This method may only be changed by Paulo Soares and/or Bruno Lowagie.
783      * @return the product name
784      * @since    2.1.6
785      */
    
786     public static final String getProduct() {
787         return ITEXT;
788     }
789     
790     /**
791      * Gets the release number.
792      * This method may only be changed by Paulo Soares and/or Bruno Lowagie.
793      * @return the product name
794      * @since    2.1.6
795      */
    
796     public static final String getRelease() {
797         return RELEASE;
798     }
799     
800     /**
801      * Gets the iText version.
802      * This method may only be changed by Paulo Soares and/or Bruno Lowagie.
803      * @return iText version
804      */
    
805     public static final String getVersion() {
806         return ITEXT_VERSION;
807     }
808
809     /**
810  * Adds a JavaScript onLoad function to the HTML body tag
811  *
812      * @param code
813      *            the JavaScript code to be executed on load of the HTML page
814  */

815     
816     public void setJavaScript_onLoad(String code) {
817         this.javaScript_onLoad = code;
818     }
819
820     /**
821  * Gets the JavaScript onLoad command.
822      * 
823  * @return the JavaScript onLoad command
824  */

825
826     public String getJavaScript_onLoad() {
827         return this.javaScript_onLoad;
828     }
829
830     /**
831  * Adds a JavaScript onUnLoad function to the HTML body tag
832  *
833      * @param code
834      *            the JavaScript code to be executed on unload of the HTML page
835  */

836     
837     public void setJavaScript_onUnLoad(String code) {
838         this.javaScript_onUnLoad = code;
839     }
840
841     /**
842  * Gets the JavaScript onUnLoad command.
843      * 
844  * @return the JavaScript onUnLoad command
845  */

846
847     public String getJavaScript_onUnLoad() {
848         return this.javaScript_onUnLoad;
849     }
850
851     /**
852  * Adds a style class to the HTML body tag
853  *
854      * @param htmlStyleClass
855      *            the style class for the HTML body tag
856  */

857     
858     public void setHtmlStyleClass(String htmlStyleClass) {
859         this.htmlStyleClass = htmlStyleClass;
860     }
861
862     /**
863  * Gets the style class of the HTML body tag
864  *
865  * @return        the style class of the HTML body tag
866  */

867     
868     public String getHtmlStyleClass() {
869         return this.htmlStyleClass;
870     }
871     
872     /**
873      * Set the margin mirroring. It will mirror right/left margins for odd/even pages.
874      * <p>
875      * Note: it will not work with {@link Table}.
876      * 
877      * @param marginMirroring
878      *            <CODE>true</CODE> to mirror the margins
879      * @return always <CODE>true</CODE>
880      */
    
881     public boolean setMarginMirroring(boolean marginMirroring) {
882         this.marginMirroring = marginMirroring;
883         DocListener listener;
884         for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
885             listener = (DocListener) iterator.next();
886             listener.setMarginMirroring(marginMirroring);
887         }
888         return true;
889     }
890     
891     /**
892      * Set the margin mirroring. It will mirror top/bottom margins for odd/even pages.
893      * <p>
894      * Note: it will not work with {@link Table}.
895      * 
896      * @param marginMirroringTopBottom
897      *            <CODE>true</CODE> to mirror the margins
898      * @return always <CODE>true</CODE>
899      * @since    2.1.6
900      */
    
901     public boolean setMarginMirroringTopBottom(boolean marginMirroringTopBottom) {
902         this.marginMirroringTopBottom = marginMirroringTopBottom;
903         DocListener listener;
904         for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
905             listener = (DocListener) iterator.next();
906             listener.setMarginMirroringTopBottom(marginMirroringTopBottom);
907         }
908         return true;
909     }
910     
911     /**
912      * Gets the margin mirroring flag.
913      * 
914      * @return the margin mirroring flag
915      */
    
916     public boolean isMarginMirroring() {
917         return marginMirroring;
918     }
919 }
920