2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 package org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline;
19 import java.awt.Color;
20 import java.io.IOException;
21 import java.util.List;
23 import org.apache.pdfbox.cos.COSArray;
24 import org.apache.pdfbox.cos.COSDictionary;
25 import org.apache.pdfbox.cos.COSFloat;
26 import org.apache.pdfbox.cos.COSName;
27 import org.apache.pdfbox.exceptions.OutlineNotLocalException;
28 import org.apache.pdfbox.pdmodel.PDDestinationNameTreeNode;
29 import org.apache.pdfbox.pdmodel.PDDocument;
30 import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
31 import org.apache.pdfbox.pdmodel.PDPage;
32 import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureElement;
33 import org.apache.pdfbox.pdmodel.graphics.color.PDColorState;
34 import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
35 import org.apache.pdfbox.pdmodel.interactive.action.PDActionFactory;
36 import org.apache.pdfbox.pdmodel.interactive.action.type.PDAction;
37 import org.apache.pdfbox.pdmodel.interactive.action.type.PDActionGoTo;
38 import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination;
39 import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDNamedDestination;
40 import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination;
41 import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageXYZDestination;
42 import org.apache.pdfbox.util.BitFlagHelper;
45 * This represents an outline in a pdf document.
47 * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
48 * @version $Revision: 1.7 $
50 public class PDOutlineItem extends PDOutlineNode
53 private static final int ITALIC_FLAG = 1;
54 private static final int BOLD_FLAG = 2;
57 * Default Constructor.
59 public PDOutlineItem()
65 * Constructor for an existing outline item.
67 * @param dic The storage dictionary.
69 public PDOutlineItem( COSDictionary dic )
75 * Insert a sibling after this node.
77 * @param item The item to insert.
79 public void insertSiblingAfter( PDOutlineItem item )
81 item.setParent( getParent() );
82 PDOutlineItem next = getNextSibling();
83 setNextSibling( item );
84 item.setPreviousSibling( this );
87 item.setNextSibling( next );
88 next.setPreviousSibling( item );
90 updateParentOpenCount( 1 );
96 public PDOutlineNode getParent()
98 return super.getParent();
102 * Return the previous sibling or null if there is no sibling.
104 * @return The previous sibling.
106 public PDOutlineItem getPreviousSibling()
108 PDOutlineItem last = null;
109 COSDictionary lastDic = (COSDictionary)node.getDictionaryObject( COSName.PREV );
110 if( lastDic != null )
112 last = new PDOutlineItem( lastDic );
118 * Set the previous sibling, this will be maintained by this class.
120 * @param outlineNode The new previous sibling.
122 protected void setPreviousSibling( PDOutlineNode outlineNode )
124 node.setItem( COSName.PREV, outlineNode );
128 * Return the next sibling or null if there is no next sibling.
130 * @return The next sibling.
132 public PDOutlineItem getNextSibling()
134 PDOutlineItem last = null;
135 COSDictionary lastDic = (COSDictionary)node.getDictionaryObject( COSName.NEXT );
136 if( lastDic != null )
138 last = new PDOutlineItem( lastDic );
144 * Set the next sibling, this will be maintained by this class.
146 * @param outlineNode The new next sibling.
148 protected void setNextSibling( PDOutlineNode outlineNode )
150 node.setItem( COSName.NEXT, outlineNode );
154 * Get the title of this node.
156 * @return The title of this node.
158 public String getTitle()
160 return node.getString( COSName.TITLE );
164 * Set the title for this node.
166 * @param title The new title for this node.
168 public void setTitle( String title )
170 node.setString( COSName.TITLE, title );
174 * Get the page destination of this node.
176 * @return The page destination of this node.
177 * @throws IOException If there is an error creating the destination.
179 public PDDestination getDestination() throws IOException
181 return PDDestination.create( node.getDictionaryObject( COSName.DEST ) );
185 * Set the page destination for this node.
187 * @param dest The new page destination for this node.
189 public void setDestination( PDDestination dest )
191 node.setItem( COSName.DEST, dest );
195 * A convenience method that will create an XYZ destination using only the defaults.
197 * @param page The page to refer to.
199 public void setDestination( PDPage page )
201 PDPageXYZDestination dest = null;
204 dest = new PDPageXYZDestination();
205 dest.setPage( page );
207 setDestination( dest );
211 * This method will attempt to find the page in this PDF document that this outline points to.
212 * If the outline does not point to anything then this method will return null. If the outline
213 * is an action that is not a GoTo action then this methods will throw the OutlineNotLocationException
215 * @param doc The document to get the page from.
217 * @return The page that this outline will go to when activated or null if it does not point to anything.
218 * @throws IOException If there is an error when trying to find the page.
220 public PDPage findDestinationPage( PDDocument doc ) throws IOException
223 PDDestination rawDest = getDestination();
224 if( rawDest == null )
226 PDAction outlineAction = getAction();
227 if( outlineAction instanceof PDActionGoTo )
229 rawDest = ((PDActionGoTo)outlineAction).getDestination();
231 else if( outlineAction == null )
233 //if the outline action is null then this outline does not refer
234 //to anything and we will just return null.
238 throw new OutlineNotLocalException( "Error: Outline does not reference a local page." );
242 PDPageDestination pageDest = null;
243 if( rawDest instanceof PDNamedDestination )
245 //if we have a named destination we need to lookup the PDPageDestination
246 PDNamedDestination namedDest = (PDNamedDestination)rawDest;
247 PDDocumentNameDictionary namesDict = doc.getDocumentCatalog().getNames();
248 if( namesDict != null )
250 PDDestinationNameTreeNode destsTree = namesDict.getDests();
251 if( destsTree != null )
253 pageDest = (PDPageDestination)destsTree.getValue( namedDest.getNamedDestination() );
257 else if( rawDest instanceof PDPageDestination)
259 pageDest = (PDPageDestination) rawDest;
261 else if( rawDest == null )
263 //if the destination is null then we will simply return a null page.
267 throw new IOException( "Error: Unknown destination type " + rawDest );
270 if( pageDest != null )
272 page = pageDest.getPage();
275 int pageNumber = pageDest.getPageNumber();
276 if( pageNumber != -1 )
278 List allPages = doc.getDocumentCatalog().getAllPages();
279 page = (PDPage)allPages.get( pageNumber );
288 * Get the action of this node.
290 * @return The action of this node.
292 public PDAction getAction()
294 return PDActionFactory.createAction( (COSDictionary)node.getDictionaryObject( COSName.A ) );
298 * Set the action for this node.
300 * @param action The new action for this node.
302 public void setAction( PDAction action )
304 node.setItem( COSName.A, action );
308 * Get the structure element of this node.
310 * @return The structure element of this node.
312 public PDStructureElement getStructureElement()
314 PDStructureElement se = null;
315 COSDictionary dic = (COSDictionary)node.getDictionaryObject( COSName.SE );
318 se = new PDStructureElement( dic );
324 * Set the structure element for this node.
326 * @param structureElement The new structure element for this node.
328 public void setStructuredElement( PDStructureElement structureElement )
330 node.setItem( COSName.SE, structureElement );
334 * Get the text color of this node. Default is black and this method
335 * will never return null.
337 * @return The structure element of this node.
339 public PDColorState getTextColor()
341 PDColorState retval = null;
342 COSArray csValues = (COSArray)node.getDictionaryObject( COSName.C );
343 if( csValues == null )
345 csValues = new COSArray();
346 csValues.growToSize( 3, new COSFloat( 0 ) );
347 node.setItem( COSName.C, csValues );
349 retval = new PDColorState(csValues);
350 retval.setColorSpace( PDDeviceRGB.INSTANCE );
355 * Set the text color for this node. The colorspace must be a PDDeviceRGB.
357 * @param textColor The text color for this node.
359 public void setTextColor( PDColorState textColor )
361 node.setItem( COSName.C, textColor.getCOSColorSpaceValue() );
365 * Set the text color for this node. The colorspace must be a PDDeviceRGB.
367 * @param textColor The text color for this node.
369 public void setTextColor( Color textColor )
371 COSArray array = new COSArray();
372 array.add( new COSFloat( textColor.getRed()/255f));
373 array.add( new COSFloat( textColor.getGreen()/255f));
374 array.add( new COSFloat( textColor.getBlue()/255f));
375 node.setItem( COSName.C, array );
379 * A flag telling if the text should be italic.
381 * @return The italic flag.
383 public boolean isItalic()
385 return BitFlagHelper.getFlag( node, COSName.F, ITALIC_FLAG );
389 * Set the italic property of the text.
391 * @param italic The new italic flag.
393 public void setItalic( boolean italic )
395 BitFlagHelper.setFlag( node, COSName.F, ITALIC_FLAG, italic );
399 * A flag telling if the text should be bold.
401 * @return The bold flag.
403 public boolean isBold()
405 return BitFlagHelper.getFlag( node, COSName.F, BOLD_FLAG );
409 * Set the bold property of the text.
411 * @param bold The new bold flag.
413 public void setBold( boolean bold )
415 BitFlagHelper.setFlag( node, COSName.F, BOLD_FLAG, bold );