KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > pdfbox > pdmodel > interactive > documentnavigation > outline > PDOutlineNode


1 /**
2  * Copyright (c) 2005, www.pdfbox.org
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  * 3. Neither the name of pdfbox; nor the names of its
14  * contributors may be used to endorse or promote products derived from this
15  * software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * http://www.pdfbox.org
29  *
30  */

31 package org.pdfbox.pdmodel.interactive.documentnavigation.outline;
32
33 import org.pdfbox.cos.COSBase;
34 import org.pdfbox.cos.COSDictionary;
35
36 import org.pdfbox.pdmodel.common.COSObjectable;
37
38 /**
39  * This represents an node in an outline in a pdf document.
40  *
41  * @author <a HREF="mailto:ben@benlitchfield.com">Ben Litchfield</a>
42  * @version $Revision: 1.3 $
43  */

44 public class PDOutlineNode implements COSObjectable
45 {
46     /**
47      * The dictionary for this node.
48      */

49     protected COSDictionary node;
50     
51     /**
52      * Default Constructor.
53      */

54     public PDOutlineNode()
55     {
56         node = new COSDictionary();
57     }
58     
59     /**
60      * Default Constructor.
61      *
62      * @param dict The dictionary storage.
63      */

64     public PDOutlineNode( COSDictionary dict)
65     {
66         node = dict;
67     }
68     
69     /**
70      * Convert this standard java object to a COS object.
71      *
72      * @return The cos object that matches this Java object.
73      */

74     public COSBase getCOSObject()
75     {
76         return node;
77     }
78     
79     /**
80      * Convert this standard java object to a COS object.
81      *
82      * @return The cos object that matches this Java object.
83      */

84     public COSDictionary getCOSDictionary()
85     {
86         return node;
87     }
88     
89     /**
90      * Get the parent of this object. This will either be a DocumentOutline or an OutlineItem.
91      *
92      * @return The parent of this object, or null if this is the document outline and there
93      * is no parent.
94      */

95     public PDOutlineNode getParent()
96     {
97         PDOutlineNode retval = null;
98         COSDictionary parent = (COSDictionary)node.getDictionaryObject( "Parent", "P" );
99         if( parent != null )
100         {
101             if( parent.getDictionaryObject( "Parent", "P" ) == null )
102             {
103                 retval = new PDDocumentOutline( parent );
104             }
105             else
106             {
107                 retval = new PDOutlineItem( parent );
108             }
109         }
110         
111         return retval;
112     }
113     
114     /**
115      * Set the parent of this object, this is maintained by these objects and should not
116      * be called by any clients of PDFBox code.
117      *
118      * @param parent The parent of this object.
119      */

120     protected void setParent( PDOutlineNode parent )
121     {
122         node.setItem( "Parent", parent );
123     }
124     
125     /**
126      * append a child node to this node.
127      *
128      * @param outlineNode The node to add.
129      */

130     public void appendChild( PDOutlineItem outlineNode )
131     {
132         outlineNode.setParent( this );
133         if( getFirstChild() == null )
134         {
135             int currentOpenCount = getOpenCount();
136             setFirstChild( outlineNode );
137             //1 for the the item we are adding;
138
int numberOfOpenNodesWeAreAdding = 1;
139             if( outlineNode.isNodeOpen() )
140             {
141                 numberOfOpenNodesWeAreAdding += outlineNode.getOpenCount();
142             }
143             if( isNodeOpen() )
144             {
145                 setOpenCount( currentOpenCount + numberOfOpenNodesWeAreAdding );
146             }
147             else
148             {
149                 setOpenCount( currentOpenCount - numberOfOpenNodesWeAreAdding );
150             }
151             updateParentOpenCount( numberOfOpenNodesWeAreAdding );
152         }
153         else
154         {
155             PDOutlineItem previousLastChild = getLastChild();
156             previousLastChild.insertSiblingAfter( outlineNode );
157         }
158         setLastChild( outlineNode );
159     }
160     
161     /**
162      * Return the first child or null if there is no child.
163      *
164      * @return The first child.
165      */

166     public PDOutlineItem getFirstChild()
167     {
168         PDOutlineItem last = null;
169         COSDictionary lastDic = (COSDictionary)node.getDictionaryObject( "First" );
170         if( lastDic != null )
171         {
172             last = new PDOutlineItem( lastDic );
173         }
174         return last;
175     }
176     
177     /**
178      * Set the first child, this will be maintained by this class.
179      *
180      * @param outlineNode The new first child.
181      */

182     protected void setFirstChild( PDOutlineNode outlineNode )
183     {
184         node.setItem( "First", outlineNode );
185     }
186     
187     /**
188      * Return the last child or null if there is no child.
189      *
190      * @return The last child.
191      */

192     public PDOutlineItem getLastChild()
193     {
194         PDOutlineItem last = null;
195         COSDictionary lastDic = (COSDictionary)node.getDictionaryObject( "Last" );
196         if( lastDic != null )
197         {
198             last = new PDOutlineItem( lastDic );
199         }
200         return last;
201     }
202     
203     /**
204      * Set the last child, this will be maintained by this class.
205      *
206      * @param outlineNode The new last child.
207      */

208     protected void setLastChild( PDOutlineNode outlineNode )
209     {
210         node.setItem( "Last", outlineNode );
211     }
212     
213     /**
214      * Get the number of open nodes. Or a negative number if this node
215      * is closed. See PDF Reference for more details. This value
216      * is updated as you append children and siblings.
217      *
218      * @return The Count attribute of the outline dictionary.
219      */

220     public int getOpenCount()
221     {
222         return node.getInt( "Count", 0 );
223     }
224     
225     /**
226      * Set the open count. This number is automatically managed for you
227      * when you add items to the outline.
228      *
229      * @param openCount The new open cound.
230      */

231     protected void setOpenCount( int openCount )
232     {
233         node.setInt( "Count", openCount );
234     }
235     
236     /**
237      * This will set this node to be open when it is shown in the viewer. By default, when
238      * a new node is created it will be closed.
239      * This will do nothing if the node is already open.
240      */

241     public void openNode()
242     {
243         //if the node is already open then do nothing.
244
if( !isNodeOpen() )
245         {
246             int openChildrenCount = 0;
247             PDOutlineItem currentChild = getFirstChild();
248             while( currentChild != null )
249             {
250                 //first increase by one for the current child
251
openChildrenCount++;
252                 //then increase by the number of open nodes the child has
253
if( currentChild.isNodeOpen() )
254                 {
255                     openChildrenCount += currentChild.getOpenCount();
256                 }
257                 currentChild = currentChild.getNextSibling();
258             }
259             setOpenCount( openChildrenCount );
260             updateParentOpenCount( openChildrenCount );
261         }
262     }
263     
264     /**
265      * Close this node.
266      *
267      */

268     public void closeNode()
269     {
270         //if the node is already closed then do nothing.
271
if( isNodeOpen() )
272         {
273             int openCount = getOpenCount();
274             updateParentOpenCount( -openCount );
275             setOpenCount( -openCount );
276         }
277     }
278     
279     /**
280      * Node is open if the open count is greater than zero.
281      * @return true if this node is open.
282      */

283     public boolean isNodeOpen()
284     {
285         return getOpenCount() > 0;
286     }
287     
288     /**
289      * The count parameter needs to be updated when you add or remove elements to
290      * the outline. When you add an element at a lower level then you need to
291      * increase all of the parents.
292      *
293      * @param amount The amount to update by.
294      */

295     protected void updateParentOpenCount( int amount )
296     {
297         PDOutlineNode parent = getParent();
298         if( parent != null )
299         {
300             int currentCount = parent.getOpenCount();
301             //if the currentCount is negative or it is absent then
302
//we will treat it as negative. The default is to be negative.
303
boolean negative = currentCount < 0 ||
304                 parent.getCOSDictionary().getDictionaryObject( "Count" ) == null;
305             currentCount = Math.abs( currentCount );
306             currentCount += amount;
307             if( negative )
308             {
309                 currentCount = -currentCount;
310             }
311             parent.setOpenCount( currentCount );
312             //recursively call parent to update count, but the parents count is only
313
//updated if this is an open node
314
if( !negative )
315             {
316                 parent.updateParentOpenCount( amount );
317             }
318         }
319     }
320 }
321
Popular Tags