1 /* 2 * $Id$ 3 * 4 * Copyright 2007 Bruno Lowagie. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21 package com.lowagie.rups.model; 22 23 import java.util.ArrayList; 24 import java.util.Enumeration; 25 import java.util.Iterator; 26 27 import com.lowagie.rups.view.itext.treenodes.PdfObjectTreeNode; 28 import com.lowagie.rups.view.itext.treenodes.PdfPagesTreeNode; 29 import com.lowagie.text.pdf.PdfArray; 30 import com.lowagie.text.pdf.PdfDictionary; 31 import com.lowagie.text.pdf.PdfIndirectReference; 32 import com.lowagie.text.pdf.PdfName; 33 import com.lowagie.text.pdf.PdfNull; 34 import com.lowagie.text.pdf.PdfObject; 35 36 /** 37 * A factory that creates TreeNode objects corresponding with PDF objects. 38 */ 39 public class TreeNodeFactory { 40 41 /** The factory that can produce all indirect objects. */ 42 protected IndirectObjectFactory objects; 43 /** An list containing the nodes of every indirect object. */ 44 protected ArrayList<PdfObjectTreeNode> nodes = new ArrayList<PdfObjectTreeNode>(); 45 46 /** 47 * Creates a factory that can produce TreeNode objects 48 * corresponding with PDF objects. 49 * @param objects a factory that can produce all the indirect objects of a PDF file. 50 */ TreeNodeFactory(IndirectObjectFactory objects)51 public TreeNodeFactory(IndirectObjectFactory objects) { 52 this.objects = objects; 53 for (int i = 0; i < objects.size(); i++) { 54 int ref = objects.getRefByIndex(i); 55 nodes.add(PdfObjectTreeNode.getInstance(PdfNull.PDFNULL, ref)); 56 } 57 } 58 59 /** 60 * Gets a TreeNode for an indirect objects. 61 * @param ref the reference number of the indirect object. 62 * @return the TreeNode representing the PDF object 63 */ getNode(int ref)64 public PdfObjectTreeNode getNode(int ref) { 65 int idx = objects.getIndexByRef(ref); 66 PdfObjectTreeNode node = nodes.get(idx); 67 if (node.getPdfObject().isNull()) { 68 node = PdfObjectTreeNode.getInstance(objects.loadObjectByReference(ref), ref); 69 nodes.set(idx, node); 70 } 71 return node; 72 } 73 74 /** 75 * Creates the Child TreeNode objects for a PDF object TreeNode. 76 * @param node the parent node 77 */ expandNode(PdfObjectTreeNode node)78 public void expandNode(PdfObjectTreeNode node) { 79 if (node.getChildCount() > 0) { 80 return; 81 } 82 PdfObject object = node.getPdfObject(); 83 PdfObjectTreeNode leaf; 84 switch (object.type()) { 85 case PdfObject.INDIRECT: 86 PdfIndirectReference ref = (PdfIndirectReference)object; 87 leaf = getNode(ref.getNumber()); 88 addNodes(node, leaf); 89 if (leaf instanceof PdfPagesTreeNode) 90 expandNode(leaf); 91 return; 92 case PdfObject.ARRAY: 93 PdfArray array = (PdfArray)object; 94 for (Iterator it = array.listIterator(); it.hasNext(); ) { 95 leaf = PdfObjectTreeNode.getInstance((PdfObject)it.next()); 96 addNodes(node, leaf); 97 expandNode(leaf); 98 } 99 return; 100 case PdfObject.DICTIONARY: 101 case PdfObject.STREAM: 102 PdfDictionary dict = (PdfDictionary)object; 103 for (Iterator it = dict.getKeys().iterator(); it.hasNext(); ) { 104 leaf = PdfObjectTreeNode.getInstance(dict, (PdfName)it.next()); 105 addNodes(node, leaf); 106 expandNode(leaf); 107 } 108 return; 109 } 110 } 111 112 /** 113 * Finds a specific child of dictionary node. 114 * @param node the node with a dictionary among its children 115 * @param key the key of the item corresponding with the node we need 116 */ getChildNode(PdfObjectTreeNode node, PdfName key)117 public PdfObjectTreeNode getChildNode(PdfObjectTreeNode node, PdfName key) { 118 Enumeration children = node.breadthFirstEnumeration(); 119 PdfObjectTreeNode child; 120 while (children.hasMoreElements()) { 121 child = (PdfObjectTreeNode)children.nextElement(); 122 if (child.isDictionaryNode(key)) { 123 if (child.isIndirectReference()) { 124 expandNode(child); 125 child = (PdfObjectTreeNode)child.getFirstChild(); 126 } 127 expandNode(child); 128 return child; 129 } 130 } 131 return null; 132 } 133 134 /** 135 * Tries adding a child node to a parent node without 136 * throwing an exception. Normally, if the child node is already 137 * added as one of the ancestors, an IllegalArgumentException is 138 * thrown (to avoid an endless loop). Loops like this are allowed 139 * in PDF, not in a JTree. 140 * @param parent the parent node 141 * @param child a child node 142 */ addNodes(PdfObjectTreeNode parent, PdfObjectTreeNode child)143 private void addNodes(PdfObjectTreeNode parent, PdfObjectTreeNode child) { 144 try { 145 parent.add(child); 146 } 147 catch(IllegalArgumentException iae) { 148 parent.setRecursive(true); 149 } 150 } 151 } 152