001/*
002 * $Id: PdfOutline.java 4784 2011-03-15 08:33:00Z blowagie $
003 *
004 * This file is part of the iText (R) project.
005 * Copyright (c) 1998-2011 1T3XT BVBA
006 * Authors: Bruno Lowagie, Paulo Soares, et al.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU Affero General Public License version 3
010 * as published by the Free Software Foundation with the addition of the
011 * following permission added to Section 15 as permitted in Section 7(a):
012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT,
013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
014 *
015 * This program is distributed in the hope that it will be useful, but
016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
017 * or FITNESS FOR A PARTICULAR PURPOSE.
018 * See the GNU Affero General Public License for more details.
019 * You should have received a copy of the GNU Affero General Public License
020 * along with this program; if not, see http://www.gnu.org/licenses or write to
021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
022 * Boston, MA, 02110-1301 USA, or download the license from the following URL:
023 * http://itextpdf.com/terms-of-use/
024 *
025 * The interactive user interfaces in modified source and object code versions
026 * of this program must display Appropriate Legal Notices, as required under
027 * Section 5 of the GNU Affero General Public License.
028 *
029 * In accordance with Section 7(b) of the GNU Affero General Public License,
030 * a covered work must retain the producer line in every PDF that is created
031 * or manipulated using iText.
032 *
033 * You can be released from the requirements of the license by purchasing
034 * a commercial license. Buying such a license is mandatory as soon as you
035 * develop commercial activities involving the iText software without
036 * disclosing the source code of your own applications.
037 * These activities include: offering paid services to customers as an ASP,
038 * serving PDFs on the fly in a web application, shipping iText with a closed
039 * source product.
040 *
041 * For more information, please contact iText Software Corp. at this
042 * address: sales@itextpdf.com
043 */
044package com.itextpdf.text.pdf;
045
046import java.io.IOException;
047import java.io.OutputStream;
048import java.util.ArrayList;
049
050import com.itextpdf.text.BaseColor;
051import com.itextpdf.text.Chunk;
052import com.itextpdf.text.Font;
053import com.itextpdf.text.Paragraph;
054
055/**
056 * <CODE>PdfOutline</CODE> is an object that represents a PDF outline entry.
057 * <P>
058 * An outline allows a user to access views of a document by name.<BR>
059 * This object is described in the 'Portable Document Format Reference Manual version 1.3'
060 * section 6.7 (page 104-106)
061 *
062 * @see         PdfDictionary
063 */
064
065public class PdfOutline extends PdfDictionary {
066
067    // membervariables
068
069    /** the <CODE>PdfIndirectReference</CODE> of this object */
070    private PdfIndirectReference reference;
071
072    /** value of the <B>Count</B>-key */
073    private int count = 0;
074
075    /** value of the <B>Parent</B>-key */
076    private PdfOutline parent;
077
078    /** value of the <B>Destination</B>-key */
079    private PdfDestination destination;
080
081    /** The <CODE>PdfAction</CODE> for this outline.
082     */
083    private PdfAction action;
084
085    protected ArrayList<PdfOutline> kids = new ArrayList<PdfOutline>();
086
087    protected PdfWriter writer;
088
089    /** Holds value of property tag. */
090    private String tag;
091
092    /** Holds value of property open. */
093    private boolean open;
094
095    /** Holds value of property color. */
096    private BaseColor color;
097
098    /** Holds value of property style. */
099    private int style = 0;
100
101    // constructors
102
103    /**
104     * Constructs a <CODE>PdfOutline</CODE>.
105     * <P>
106     * This is the constructor for the <CODE>outlines object</CODE>.
107     *
108     * @param writer The PdfWriter you are adding the outline to
109     */
110
111    PdfOutline(PdfWriter writer) {
112        super(OUTLINES);
113        open = true;
114        parent = null;
115        this.writer = writer;
116    }
117
118    /**
119     * Constructs a <CODE>PdfOutline</CODE>.
120     * <P>
121     * This is the constructor for an <CODE>outline entry</CODE>. The open mode is
122     * <CODE>true</CODE>.
123     *
124     * @param parent the parent of this outline item
125     * @param action the <CODE>PdfAction</CODE> for this outline item
126     * @param title the title of this outline item
127     */
128
129    public PdfOutline(PdfOutline parent, PdfAction action, String title) {
130        this(parent, action, title, true);
131    }
132
133    /**
134     * Constructs a <CODE>PdfOutline</CODE>.
135     * <P>
136     * This is the constructor for an <CODE>outline entry</CODE>.
137     *
138     * @param parent the parent of this outline item
139     * @param action the <CODE>PdfAction</CODE> for this outline item
140     * @param title the title of this outline item
141     * @param open <CODE>true</CODE> if the children are visible
142     */
143    public PdfOutline(PdfOutline parent, PdfAction action, String title, boolean open) {
144        super();
145        this.action = action;
146        initOutline(parent, title, open);
147    }
148
149    /**
150     * Constructs a <CODE>PdfOutline</CODE>.
151     * <P>
152     * This is the constructor for an <CODE>outline entry</CODE>. The open mode is
153     * <CODE>true</CODE>.
154     *
155     * @param parent the parent of this outline item
156     * @param destination the destination for this outline item
157     * @param title the title of this outline item
158     */
159
160    public PdfOutline(PdfOutline parent, PdfDestination destination, String title) {
161        this(parent, destination, title, true);
162    }
163
164    /**
165     * Constructs a <CODE>PdfOutline</CODE>.
166     * <P>
167     * This is the constructor for an <CODE>outline entry</CODE>.
168     *
169     * @param parent the parent of this outline item
170     * @param destination the destination for this outline item
171     * @param title the title of this outline item
172     * @param open <CODE>true</CODE> if the children are visible
173     */
174    public PdfOutline(PdfOutline parent, PdfDestination destination, String title, boolean open) {
175        super();
176        this.destination = destination;
177        initOutline(parent, title, open);
178    }
179
180    /**
181     * Constructs a <CODE>PdfOutline</CODE>.
182     * <P>
183     * This is the constructor for an <CODE>outline entry</CODE>. The open mode is
184     * <CODE>true</CODE>.
185     *
186     * @param parent the parent of this outline item
187     * @param action the <CODE>PdfAction</CODE> for this outline item
188     * @param title the title of this outline item
189     */
190    public PdfOutline(PdfOutline parent, PdfAction action, PdfString title) {
191        this(parent, action, title, true);
192    }
193
194    /**
195     * Constructs a <CODE>PdfOutline</CODE>.
196     * <P>
197     * This is the constructor for an <CODE>outline entry</CODE>.
198     *
199     * @param parent the parent of this outline item
200     * @param action the <CODE>PdfAction</CODE> for this outline item
201     * @param title the title of this outline item
202     * @param open <CODE>true</CODE> if the children are visible
203     */
204    public PdfOutline(PdfOutline parent, PdfAction action, PdfString title, boolean open) {
205        this(parent, action, title.toString(), open);
206    }
207
208    /**
209     * Constructs a <CODE>PdfOutline</CODE>.
210     * <P>
211     * This is the constructor for an <CODE>outline entry</CODE>. The open mode is
212     * <CODE>true</CODE>.
213     *
214     * @param parent the parent of this outline item
215     * @param destination the destination for this outline item
216     * @param title the title of this outline item
217     */
218
219    public PdfOutline(PdfOutline parent, PdfDestination destination, PdfString title) {
220        this(parent, destination, title, true);
221    }
222
223    /**
224     * Constructs a <CODE>PdfOutline</CODE>.
225     * <P>
226     * This is the constructor for an <CODE>outline entry</CODE>.
227     *
228     * @param parent the parent of this outline item
229     * @param destination the destination for this outline item
230     * @param title the title of this outline item
231     * @param open <CODE>true</CODE> if the children are visible
232     */
233    public PdfOutline(PdfOutline parent, PdfDestination destination, PdfString title, boolean open) {
234        this(parent, destination, title.toString(), true);
235    }
236
237    /**
238     * Constructs a <CODE>PdfOutline</CODE>.
239     * <P>
240     * This is the constructor for an <CODE>outline entry</CODE>. The open mode is
241     * <CODE>true</CODE>.
242     *
243     * @param parent the parent of this outline item
244     * @param action the <CODE>PdfAction</CODE> for this outline item
245     * @param title the title of this outline item
246     */
247
248    public PdfOutline(PdfOutline parent, PdfAction action, Paragraph title) {
249        this(parent, action, title, true);
250    }
251
252    /**
253     * Constructs a <CODE>PdfOutline</CODE>.
254     * <P>
255     * This is the constructor for an <CODE>outline entry</CODE>.
256     *
257     * @param parent the parent of this outline item
258     * @param action the <CODE>PdfAction</CODE> for this outline item
259     * @param title the title of this outline item
260     * @param open <CODE>true</CODE> if the children are visible
261     */
262    public PdfOutline(PdfOutline parent, PdfAction action, Paragraph title, boolean open) {
263        super();
264        StringBuffer buf = new StringBuffer();
265        for (Chunk chunk: title.getChunks()) {
266            buf.append(chunk.getContent());
267        }
268        this.action = action;
269        initOutline(parent, buf.toString(), open);
270    }
271
272    /**
273     * Constructs a <CODE>PdfOutline</CODE>.
274     * <P>
275     * This is the constructor for an <CODE>outline entry</CODE>. The open mode is
276     * <CODE>true</CODE>.
277     *
278     * @param parent the parent of this outline item
279     * @param destination the destination for this outline item
280     * @param title the title of this outline item
281     */
282
283    public PdfOutline(PdfOutline parent, PdfDestination destination, Paragraph title) {
284        this(parent, destination, title, true);
285    }
286
287    /**
288     * Constructs a <CODE>PdfOutline</CODE>.
289     * <P>
290     * This is the constructor for an <CODE>outline entry</CODE>.
291     *
292     * @param parent the parent of this outline item
293     * @param destination the destination for this outline item
294     * @param title the title of this outline item
295     * @param open <CODE>true</CODE> if the children are visible
296     */
297    public PdfOutline(PdfOutline parent, PdfDestination destination, Paragraph title, boolean open) {
298        super();
299        StringBuffer buf = new StringBuffer();
300        for (Object element : title.getChunks()) {
301            Chunk chunk = (Chunk) element;
302            buf.append(chunk.getContent());
303        }
304        this.destination = destination;
305        initOutline(parent, buf.toString(), open);
306    }
307
308
309    // methods
310
311    /** Helper for the constructors.
312     * @param parent the parent outline
313     * @param title the title for this outline
314     * @param open <CODE>true</CODE> if the children are visible
315     */
316    void initOutline(PdfOutline parent, String title, boolean open) {
317        this.open = open;
318        this.parent = parent;
319        writer = parent.writer;
320        put(PdfName.TITLE, new PdfString(title, PdfObject.TEXT_UNICODE));
321        parent.addKid(this);
322        if (destination != null && !destination.hasPage()) // bugfix Finn Bock
323            setDestinationPage(writer.getCurrentPage());
324    }
325
326    /**
327     * Sets the indirect reference of this <CODE>PdfOutline</CODE>.
328     *
329     * @param reference the <CODE>PdfIndirectReference</CODE> to this outline.
330     */
331
332    public void setIndirectReference(PdfIndirectReference reference) {
333        this.reference = reference;
334    }
335
336    /**
337     * Gets the indirect reference of this <CODE>PdfOutline</CODE>.
338     *
339     * @return          the <CODE>PdfIndirectReference</CODE> to this outline.
340     */
341
342    public PdfIndirectReference indirectReference() {
343        return reference;
344    }
345
346    /**
347     * Gets the parent of this <CODE>PdfOutline</CODE>.
348     *
349     * @return          the <CODE>PdfOutline</CODE> that is the parent of this outline.
350     */
351
352    public PdfOutline parent() {
353        return parent;
354    }
355
356    /**
357     * Set the page of the <CODE>PdfDestination</CODE>-object.
358     *
359     * @param pageReference indirect reference to the page
360     * @return <CODE>true</CODE> if this page was set as the <CODE>PdfDestination</CODE>-page.
361     */
362
363    public boolean setDestinationPage(PdfIndirectReference pageReference) {
364        if (destination == null) {
365            return false;
366        }
367        return destination.addPage(pageReference);
368    }
369
370    /**
371     * Gets the destination for this outline.
372     * @return the destination
373     */
374    public PdfDestination getPdfDestination() {
375        return destination;
376    }
377
378    int getCount() {
379        return count;
380    }
381
382    void setCount(int count) {
383        this.count = count;
384    }
385
386    /**
387     * returns the level of this outline.
388     *
389     * @return          a level
390     */
391
392    public int level() {
393        if (parent == null) {
394            return 0;
395        }
396        return parent.level() + 1;
397    }
398
399    /**
400     * Returns the PDF representation of this <CODE>PdfOutline</CODE>.
401     *
402     * @param writer the PdfWriter
403     * @param os
404     * @throws IOException
405     */
406
407    @Override
408    public void toPdf(PdfWriter writer, OutputStream os) throws IOException {
409        if (color != null && !color.equals(BaseColor.BLACK)) {
410            put(PdfName.C, new PdfArray(new float[]{color.getRed()/255f,color.getGreen()/255f,color.getBlue()/255f}));
411        }
412        int flag = 0;
413        if ((style & Font.BOLD) != 0)
414            flag |= 2;
415        if ((style & Font.ITALIC) != 0)
416            flag |= 1;
417        if (flag != 0)
418            put(PdfName.F, new PdfNumber(flag));
419        if (parent != null) {
420            put(PdfName.PARENT, parent.indirectReference());
421        }
422        if (destination != null && destination.hasPage()) {
423            put(PdfName.DEST, destination);
424        }
425        if (action != null)
426            put(PdfName.A, action);
427        if (count != 0) {
428            put(PdfName.COUNT, new PdfNumber(count));
429        }
430        super.toPdf(writer, os);
431    }
432
433    /**
434     * Adds a kid to the outline
435     * @param outline
436     */
437    public void addKid(PdfOutline outline) {
438        kids.add(outline);
439    }
440
441    /**
442     * Returns the kids of this outline
443     * @return an ArrayList with PdfOutlines
444     */
445    public ArrayList<PdfOutline> getKids() {
446        return kids;
447    }
448
449    /**
450     * Sets the kids of this outline
451     * @param kids
452     */
453    public void setKids(ArrayList<PdfOutline> kids) {
454        this.kids = kids;
455    }
456
457    /** Getter for property tag.
458     * @return Value of property tag.
459     */
460    public String getTag() {
461        return tag;
462    }
463
464    /** Setter for property tag.
465     * @param tag New value of property tag.
466     */
467    public void setTag(String tag) {
468        this.tag = tag;
469    }
470
471    /**
472     * Gets the title of this outline
473     * @return the title as a String
474     */
475    public String getTitle() {
476        PdfString title = (PdfString)get(PdfName.TITLE);
477        return title.toString();
478    }
479
480    /**
481     * Sets the title of this outline
482     * @param title
483     */
484    public void setTitle(String title) {
485        put(PdfName.TITLE, new PdfString(title, PdfObject.TEXT_UNICODE));
486    }
487
488    /** Getter for property open.
489     * @return Value of property open.
490     */
491    public boolean isOpen() {
492        return open;
493    }
494
495    /** Setter for property open.
496     * @param open New value of property open.
497     */
498    public void setOpen(boolean open) {
499        this.open = open;
500    }
501
502    /** Getter for property color.
503     * @return Value of property color.
504     *
505     */
506    public BaseColor getColor() {
507        return this.color;
508    }
509
510    /** Setter for property color.
511     * @param color New value of property color.
512     *
513     */
514    public void setColor(BaseColor color) {
515        this.color = color;
516    }
517
518    /** Getter for property style.
519     * @return Value of property style.
520     *
521     */
522    public int getStyle() {
523        return this.style;
524    }
525
526    /** Setter for property style.
527     * @param style New value of property style.
528     *
529     */
530    public void setStyle(int style) {
531        this.style = style;
532    }
533
534}