/*
* $Id$
*
* Copyright 2007 Bruno Lowagie.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.lowagie.rups.view.itext;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Observable;
import java.util.Observer;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultTreeModel;
import org.dom4j.DocumentException;
import com.lowagie.rups.controller.PdfReaderController;
import com.lowagie.rups.model.ObjectLoader;
import com.lowagie.rups.model.TreeNodeFactory;
import com.lowagie.rups.model.XfaFile;
import com.lowagie.rups.view.icons.IconTreeCellRenderer;
import com.lowagie.rups.view.itext.treenodes.FormTreeNode;
import com.lowagie.rups.view.itext.treenodes.PdfObjectTreeNode;
import com.lowagie.rups.view.itext.treenodes.PdfTrailerTreeNode;
import com.lowagie.rups.view.itext.treenodes.XfaTreeNode;
import com.lowagie.text.pdf.PdfName;
/**
* A JTree visualizing information about the Interactive Form of the
* PDF file (if any). Normally shows a tree view of the field hierarchy
* and individual XDP packets.
*/
public class FormTree extends JTree implements TreeSelectionListener, Observer {
/** Nodes in the FormTree correspond with nodes in the main PdfTree. */
protected PdfReaderController controller;
/** If the form is an XFA form, the XML file is stored in this object. */
protected XfaFile xfaFile;
/** Treeview of the XFA file. */
protected XfaTree xfaTree;
/** Textview of the XFA file. */
protected XfaTextArea xfaTextArea;
/**
* Creates a new FormTree.
*/
public FormTree(PdfReaderController controller) {
super();
this.controller = controller;
setCellRenderer(new IconTreeCellRenderer());
setModel(new DefaultTreeModel(new FormTreeNode()));
addTreeSelectionListener(this);
xfaTree = new XfaTree();
xfaTextArea = new XfaTextArea();
}
/**
* Loads the fields of a PDF document into the FormTree.
* @param observable the observable object
* @param obj the object
*/
public void update(Observable observable, Object obj) {
if (obj == null) {
setModel(new DefaultTreeModel(new FormTreeNode()));
xfaFile = null;
xfaTree.clear();
xfaTextArea.clear();
repaint();
return;
}
if (obj instanceof ObjectLoader) {
ObjectLoader loader = (ObjectLoader)obj;
TreeNodeFactory factory = loader.getNodes();
PdfTrailerTreeNode trailer = controller.getPdfTree().getRoot();
PdfObjectTreeNode catalog = factory.getChildNode(trailer, PdfName.ROOT);
PdfObjectTreeNode form = factory.getChildNode(catalog, PdfName.ACROFORM);
if (form == null) {
return;
}
PdfObjectTreeNode fields = factory.getChildNode(form, PdfName.FIELDS);
FormTreeNode root = new FormTreeNode();
if (fields != null) {
FormTreeNode node = new FormTreeNode(fields);
node.setUserObject("Fields");
loadFields(factory, node, fields);
root.add(node);
}
PdfObjectTreeNode xfa = factory.getChildNode(form, PdfName.XFA);
if (xfa != null) {
XfaTreeNode node = new XfaTreeNode(xfa);
node.setUserObject("XFA");
loadXfa(factory, node, xfa);
root.add(node);
try {
xfaFile = new XfaFile(node);
xfaTree.load(xfaFile);
xfaTextArea.load(xfaFile);
} catch (IOException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
}
setModel(new DefaultTreeModel(root));
}
}
/**
* Method that can be used recursively to load the fields hierarchy into the tree.
* @param factory a factory that can produce new PDF object nodes
* @param form_node the parent node in the form tree
* @param object_node the object node that will be used to create a child node
*/
private void loadFields(TreeNodeFactory factory, FormTreeNode form_node, PdfObjectTreeNode object_node) {
if (object_node == null)
return;
factory.expandNode(object_node);
if (object_node.isIndirectReference()) {
loadFields(factory, form_node, (PdfObjectTreeNode)object_node.getFirstChild());
}
else if (object_node.isArray()) {
Enumeration children = object_node.children();
while (children.hasMoreElements()) {
loadFields(factory, form_node, (PdfObjectTreeNode)children.nextElement());
}
}
else if (object_node.isDictionary()) {
FormTreeNode leaf = new FormTreeNode(object_node);
form_node.add(leaf);
PdfObjectTreeNode kids = factory.getChildNode(object_node, PdfName.KIDS);
loadFields(factory, leaf, kids);
}
}
/**
* Method that will load the nodes that refer to XFA streams.
* @param form_node the parent node in the form tree
* @param object_node the object node that will be used to create a child node
*/
private void loadXfa(TreeNodeFactory factory, XfaTreeNode form_node, PdfObjectTreeNode object_node) {
if (object_node == null)
return;
factory.expandNode(object_node);
if (object_node.isIndirectReference()) {
loadXfa(factory, form_node, (PdfObjectTreeNode)object_node.getFirstChild());
}
else if (object_node.isArray()) {
Enumeration children = object_node.children();
PdfObjectTreeNode key;
PdfObjectTreeNode value;
while (children.hasMoreElements()) {
key = (PdfObjectTreeNode)children.nextElement();
value = (PdfObjectTreeNode)children.nextElement();
if (value.isIndirectReference()) {
factory.expandNode(value);
value = (PdfObjectTreeNode)value.getFirstChild();
}
form_node.addPacket(key.getPdfObject().toString(), value);
}
}
else if (object_node.isStream()) {
form_node.addPacket("xdp", object_node);
}
}
/**
* @see javax.swing.event.TreeSelectionListener#valueChanged(javax.swing.event.TreeSelectionEvent)
*/
public void valueChanged(TreeSelectionEvent evt) {
if (controller == null)
return;
FormTreeNode selectednode = (FormTreeNode)this.getLastSelectedPathComponent();
if (selectednode == null)
return;
PdfObjectTreeNode node = selectednode.getCorrespondingPdfObjectNode();
if (node != null)
controller.selectNode(node);
}
public XfaTree getXfaTree() {
return xfaTree;
}
public XfaTextArea getXfaTextArea() {
return xfaTextArea;
}
/** A serial version UID. */
private static final long serialVersionUID = -3584003547303700407L;
}