org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline;
import java.awt.Color;
import java.io.IOException;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSFloat;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureElement;
import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionFactory;
import org.apache.pdfbox.pdmodel.interactive.action.PDAction;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionGoTo;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDNamedDestination;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageXYZDestination;
/**
* This represents an outline item in a pdf document. The items at each level of the hierarchy form an iterable linked
* list, chained together through their Prev and Next entries.
*
* @author Ben Litchfield
*/
public final class PDOutlineItem extends PDOutlineNode
{
private static final int ITALIC_FLAG = 1;
private static final int BOLD_FLAG = 2;
/**
* Default Constructor.
*/
public PDOutlineItem()
{
super();
}
/**
* Constructor for an existing outline item.
*
* @param dic The storage dictionary.
*/
public PDOutlineItem( COSDictionary dic )
{
super( dic );
}
/**
* Insert a single sibling after this node.
*
* @param newSibling The item to insert.
* @throws IllegalArgumentException if the given sibling node is part of a list
* (i.e. if it has a previous or a next sibling)
*/
public void insertSiblingAfter(PDOutlineItem newSibling)
{
requireSingleNode(newSibling);
PDOutlineNode parent = getParent();
newSibling.setParent(parent);
PDOutlineItem next = getNextSibling();
setNextSibling(newSibling);
newSibling.setPreviousSibling(this);
if (next != null)
{
newSibling.setNextSibling(next);
next.setPreviousSibling(newSibling);
}
else if (parent != null)
{
getParent().setLastChild(newSibling);
}
updateParentOpenCountForAddedChild(newSibling);
}
/**
* Insert a single sibling before this node.
*
* @param newSibling The item to insert.
* @throws IllegalArgumentException if the given sibling node is part of a list
* (i.e. if it has a previous or a next sibling)
*/
public void insertSiblingBefore(PDOutlineItem newSibling)
{
requireSingleNode(newSibling);
PDOutlineNode parent = getParent();
newSibling.setParent(parent);
PDOutlineItem previous = getPreviousSibling();
setPreviousSibling(newSibling);
newSibling.setNextSibling(this);
if (previous != null)
{
previous.setNextSibling(newSibling);
newSibling.setPreviousSibling(previous);
}
else if (parent != null)
{
getParent().setFirstChild(newSibling);
}
updateParentOpenCountForAddedChild(newSibling);
}
/**
* Return the previous sibling or null if there is no sibling.
*
* @return The previous sibling.
*/
public PDOutlineItem getPreviousSibling()
{
return getOutlineItem(COSName.PREV);
}
/**
* Set the previous sibling, this will be maintained by this class.
*
* @param outlineNode The new previous sibling.
*/
void setPreviousSibling(PDOutlineNode outlineNode)
{
getCOSObject().setItem(COSName.PREV, outlineNode);
}
/**
* @return The next sibling or null if there is no next sibling.
*/
public PDOutlineItem getNextSibling()
{
return getOutlineItem(COSName.NEXT);
}
/**
* Set the next sibling, this will be maintained by this class.
*
* @param outlineNode The new next sibling.
*/
void setNextSibling(PDOutlineNode outlineNode)
{
getCOSObject().setItem(COSName.NEXT, outlineNode);
}
/**
* Get the title of this node.
*
* @return The title of this node.
*/
public String getTitle()
{
return getCOSObject().getString(COSName.TITLE);
}
/**
* Set the title for this node.
*
* @param title The new title for this node.
*/
public void setTitle(String title)
{
getCOSObject().setString(COSName.TITLE, title);
}
/**
* Get the page destination of this node.
*
* @return The page destination of this node.
* @throws IOException If there is an error creating the destination.
*/
public PDDestination getDestination() throws IOException
{
return PDDestination.create(getCOSObject().getDictionaryObject(COSName.DEST));
}
/**
* Set the page destination for this node.
*
* @param dest The new page destination for this node.
*/
public void setDestination(PDDestination dest)
{
getCOSObject().setItem(COSName.DEST, dest);
}
/**
* A convenience method that will create an XYZ destination using only the defaults.
*
* @param page The page to refer to.
*/
public void setDestination(PDPage page)
{
PDPageXYZDestination dest = null;
if( page != null )
{
dest = new PDPageXYZDestination();
dest.setPage( page );
}
setDestination( dest );
}
/**
* This method will attempt to find the page in this PDF document that this outline points to.
* If the outline does not point to anything then this method will return null. If the outline
* is an action that is not a GoTo action then this method will also return null.
*
* @param doc The document to get the page from.
*
* @return The page that this outline will go to when activated or null if it does not point to
* anything.
* @throws IOException If there is an error when trying to find the page.
*/
public PDPage findDestinationPage(PDDocument doc) throws IOException
{
PDDestination dest = getDestination();
if (dest == null)
{
PDAction outlineAction = getAction();
if (outlineAction instanceof PDActionGoTo)
{
dest = ((PDActionGoTo) outlineAction).getDestination();
}
}
if (dest == null)
{
return null;
}
PDPageDestination pageDestination = null;
if (dest instanceof PDNamedDestination)
{
pageDestination = doc.getDocumentCatalog().findNamedDestinationPage((PDNamedDestination) dest);
if (pageDestination == null)
{
return null;
}
}
else if (dest instanceof PDPageDestination)
{
pageDestination = (PDPageDestination) dest;
}
else
{
throw new IOException("Error: Unknown destination type " + dest);
}
PDPage page = pageDestination.getPage();
if (page == null)
{
// Malformed PDF: local destinations must have a page object,
// not a page number, these are meant for remote destinations.
int pageNumber = pageDestination.getPageNumber();
if (pageNumber != -1)
{
page = doc.getPage(pageNumber);
}
}
return page;
}
/**
* Get the action of this node.
*
* @return The action of this node.
*/
public PDAction getAction()
{
return PDActionFactory.createAction((COSDictionary) getCOSObject().getDictionaryObject(COSName.A));
}
/**
* Set the action for this node.
*
* @param action The new action for this node.
*/
public void setAction( PDAction action )
{
getCOSObject().setItem(COSName.A, action);
}
/**
* Get the structure element of this node.
*
* @return The structure element of this node.
*/
public PDStructureElement getStructureElement()
{
PDStructureElement se = null;
COSDictionary dic = (COSDictionary) getCOSObject().getDictionaryObject(COSName.SE);
if( dic != null )
{
se = new PDStructureElement( dic );
}
return se;
}
/**
* Set the structure element for this node.
*
* @param structureElement The new structure element for this node.
*/
public void setStructureElement( PDStructureElement structureElement )
{
getCOSObject().setItem(COSName.SE, structureElement);
}
/**
* Get the RGB text color of this node. Default is black and this method
* will never return null.
*
* @return The structure element of this node.
*/
public PDColor getTextColor()
{
COSArray csValues = (COSArray) getCOSObject().getDictionaryObject(COSName.C);
if( csValues == null )
{
csValues = new COSArray();
csValues.growToSize( 3, new COSFloat( 0 ) );
getCOSObject().setItem( COSName.C, csValues );
}
return new PDColor(csValues, PDDeviceRGB.INSTANCE);
}
/**
* Set the RGB text color for this node.
*
* @param textColor The text color for this node.
*/
public void setTextColor( PDColor textColor )
{
getCOSObject().setItem( COSName.C, textColor.toCOSArray() );
}
/**
* Set the RGB text color for this node.
*
* @param textColor The text color for this node.
*/
public void setTextColor( Color textColor )
{
COSArray array = new COSArray();
array.add( new COSFloat( textColor.getRed()/255f));
array.add( new COSFloat( textColor.getGreen()/255f));
array.add( new COSFloat( textColor.getBlue()/255f));
getCOSObject().setItem( COSName.C, array );
}
/**
* A flag telling if the text should be italic.
*
* @return The italic flag.
*/
public boolean isItalic()
{
return getCOSObject().getFlag( COSName.F, ITALIC_FLAG );
}
/**
* Set the italic property of the text.
*
* @param italic The new italic flag.
*/
public void setItalic( boolean italic )
{
getCOSObject().setFlag( COSName.F, ITALIC_FLAG, italic );
}
/**
* A flag telling if the text should be bold.
*
* @return The bold flag.
*/
public boolean isBold()
{
return getCOSObject().getFlag( COSName.F, BOLD_FLAG );
}
/**
* Set the bold property of the text.
*
* @param bold The new bold flag.
*/
public void setBold( boolean bold )
{
getCOSObject().setFlag( COSName.F, BOLD_FLAG, bold );
}
}