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