You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ti...@apache.org on 2015/05/25 15:30:54 UTC

svn commit: r1681588 - in /pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools: PDFDebugger.java pdfdebugger/ pdfdebugger/treestatus/ pdfdebugger/treestatus/TreeStatus.java pdfdebugger/treestatus/TreeStatusPane.java

Author: tilman
Date: Mon May 25 13:30:54 2015
New Revision: 1681588

URL: http://svn.apache.org/r1681588
Log:
PDFBOX-2530: Tree status line show & input feature, as done by Khyrul Bashar in GSoC2015

Added:
    pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/pdfdebugger/
    pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/pdfdebugger/treestatus/
    pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/pdfdebugger/treestatus/TreeStatus.java   (with props)
    pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/pdfdebugger/treestatus/TreeStatusPane.java   (with props)
Modified:
    pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/PDFDebugger.java

Modified: pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/PDFDebugger.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/PDFDebugger.java?rev=1681588&r1=1681587&r2=1681588&view=diff
==============================================================================
--- pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/PDFDebugger.java (original)
+++ pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/PDFDebugger.java Mon May 25 13:30:54 2015
@@ -16,6 +16,8 @@
  */
 package org.apache.pdfbox.tools;
 
+import java.awt.BorderLayout;
+import java.awt.Dimension;
 import java.awt.event.ActionEvent;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -31,6 +33,7 @@ import javax.swing.JMenuItem;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.UIManager;
+import javax.swing.border.BevelBorder;
 import javax.swing.tree.TreeModel;
 import javax.swing.tree.TreePath;
 import org.apache.pdfbox.cos.COSBoolean;
@@ -45,6 +48,8 @@ import org.apache.pdfbox.tools.gui.Array
 import org.apache.pdfbox.tools.gui.MapEntry;
 import org.apache.pdfbox.tools.gui.PDFTreeCellRenderer;
 import org.apache.pdfbox.tools.gui.PDFTreeModel;
+import org.apache.pdfbox.tools.pdfdebugger.treestatus.TreeStatus;
+import org.apache.pdfbox.tools.pdfdebugger.treestatus.TreeStatusPane;
 import org.apache.pdfbox.tools.util.RecentFiles;
 
 /**
@@ -54,6 +59,8 @@ import org.apache.pdfbox.tools.util.Rece
  */
 public class PDFDebugger extends javax.swing.JFrame
 {
+    private TreeStatusPane statusPane;
+
     private File currentDir=new File(".");
     private PDDocument document = null;
     private String currentFilePath = null;
@@ -102,7 +109,7 @@ public class PDFDebugger extends javax.s
         jTree1.setCellRenderer( new PDFTreeCellRenderer() );
         jTree1.setModel( null );
 
-        setTitle("PDFBox - PDF Viewer");
+        setTitle("PDFBox - PDF Debugger");
         addWindowListener(new java.awt.event.WindowAdapter()
         {
             @Override
@@ -136,6 +143,11 @@ public class PDFDebugger extends javax.s
         JScrollPane documentScroller = new JScrollPane();
         documentScroller.setViewportView( documentPanel );
 
+        statusPane = new TreeStatusPane(jTree1);
+        statusPane.getPanel().setBorder(new BevelBorder(BevelBorder.RAISED));
+        statusPane.getPanel().setPreferredSize(new Dimension(300, 25));
+        getContentPane().add(statusPane.getPanel(), BorderLayout.PAGE_START);
+
         getContentPane().add( jSplitPane1, java.awt.BorderLayout.CENTER );
 
         fileMenu.setText("File");
@@ -403,8 +415,10 @@ public class PDFDebugger extends javax.s
         currentFilePath = file.getPath();
         recentFiles.removeFile(file.getPath());
         parseDocument( file, password );
+        statusPane.updateTreeStatus(new TreeStatus(document.getDocument().getTrailer()));
         TreeModel model=new PDFTreeModel(document);
         jTree1.setModel(model);
+        jTree1.setSelectionRow(1);
         setTitle("PDFBox - " + file.getAbsolutePath());
         addRecentFileItems();
     }

Added: pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/pdfdebugger/treestatus/TreeStatus.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/pdfdebugger/treestatus/TreeStatus.java?rev=1681588&view=auto
==============================================================================
--- pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/pdfdebugger/treestatus/TreeStatus.java (added)
+++ pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/pdfdebugger/treestatus/TreeStatus.java Mon May 25 13:30:54 2015
@@ -0,0 +1,244 @@
+/*
+ * 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.tools.pdfdebugger.treestatus;
+
+import java.util.ArrayList;
+import javax.swing.tree.TreePath;
+import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSObject;
+import org.apache.pdfbox.tools.gui.ArrayEntry;
+import org.apache.pdfbox.tools.gui.MapEntry;
+
+/**
+ * @author Khyrul Bashar
+ */
+public final class TreeStatus
+{
+    private TreePath path;
+    private String pathString;
+    private Object rootNode;
+    public boolean isValid = false;
+
+    private TreeStatus()
+    {
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param rootNode the root node of the tree which will be used to construct a treepath from a
+     * tree status string.
+     */
+    public TreeStatus(Object rootNode)
+    {
+        this.rootNode = rootNode;
+    }
+
+    /**
+     * Return the treepath.
+     * @return the treepath.
+     */
+    public TreePath getPath()
+    {
+        return path;
+    }
+
+    /**
+     * Set the path and generate corresponding tree status string.
+     * @param path TreePath instance.
+     */
+    public void setPath(TreePath path)
+    {
+        this.path = path;
+        this.pathString = generatePathString(path);
+        this.isValid = true;
+    }
+
+    /**
+     * Set the tree status string and try to generate TreePath. In case of success, the path will be
+     * available for further uses. In case of failure path will be set to null.
+     *
+     * @param pathString String instance.
+     */
+    public void setPathString(String pathString)
+    {
+        this.pathString = pathString;
+        path = generatePath(pathString);
+        isValid = this.path != null;
+    }
+
+    /**
+     * Provides status string for a TreePath instance.
+     * @param path TreePath instance.
+     * @return pathString.
+     */
+    public String getStringForPath(TreePath path)
+    {
+        setPath(path);
+        return pathString;
+    }
+
+    /**
+     *Provides TreePath for a given status string. In case of invalid string returns null.
+     * @param statusString
+     * @return path.
+     */
+    public TreePath getPathForString(String statusString)
+    {
+        setPathString(statusString);
+        return path;
+    }
+
+    /**
+     * Constructs a status string from the path.
+     * @param path
+     * @return the status string.
+     */
+    private String generatePathString(TreePath path)
+    {
+        StringBuilder pathStringBuilder = new StringBuilder();
+        while (path.getParentPath() != null)
+        {
+            Object object = path.getLastPathComponent();
+            pathStringBuilder.insert(0, "/" + getObjectName(object));
+            path = path.getParentPath();
+        }
+        pathStringBuilder.delete(0, 1);
+        return pathStringBuilder.toString();
+    }
+
+    /**
+     * Constructs TreePath from Status String.
+     * @param pathString
+     * @return a TreePath, or null if there is an error.
+     */
+    private TreePath generatePath(String pathString)
+    {
+        ArrayList<String> nodes = parsePathString(pathString);
+        if (nodes == null)
+        {
+            return null;
+        }
+        Object obj = rootNode;
+        TreePath treePath = new TreePath(obj);
+        for (String node : nodes)
+        {
+            obj = searchNode(obj, node);
+            treePath = treePath.pathByAddingChild(obj);
+        }
+        return treePath;
+    }
+
+    /**
+     * Get the object name of a tree node. If the given node of the tree is a MapEntry, its key is
+     * used as node identifier; if it is an ArrayEntry, then its index is used as identifier.
+     *
+     * @param treeNode node of a tree.
+     * @return the name of the node.
+     * @throws IllegalArgumentException if there is an unknown treeNode type.
+     */
+    private String getObjectName(Object treeNode)
+    {
+        if (treeNode instanceof MapEntry)
+        {
+            MapEntry entry = (MapEntry) treeNode;
+            COSName key = (COSName) entry.getKey();
+            return key.getName();
+        }
+        if (treeNode instanceof ArrayEntry)
+        {
+            ArrayEntry entry = (ArrayEntry) treeNode;
+            return "[" + entry.getIndex() + "]";
+        }
+        throw new IllegalArgumentException("Unknown treeNode type: " + treeNode.getClass().getName());
+    }
+
+    /**
+     * Parses a string and lists all the nodes.
+     *
+     * @param path a tree path.
+     * @return a list of nodes, or null if there is an empty node.
+     */
+    private ArrayList<String> parsePathString(String path)
+    {
+        ArrayList<String> nodes = new ArrayList<String>();
+        for (String node : path.split("/"))
+        {
+            node = node.trim();
+            if (node.startsWith("["))
+            {
+                node = node.replace("]", "").replace("[", "");
+            }
+            node = node.trim();
+            if (node.isEmpty())
+            {
+                return null;
+            }
+            nodes.add(node);
+        }
+        return nodes;
+    }
+
+    /**
+     * An object is searched in the tree structure using the identifiers parsed earlier step.
+     * @param obj
+     * @param searchStr
+     * @return
+     */
+    private Object searchNode(Object obj, String searchStr)
+    {
+        if (obj instanceof MapEntry)
+        {
+            obj = ((MapEntry) obj).getValue();
+        }
+        else if (obj instanceof ArrayEntry)
+        {
+            obj = ((ArrayEntry) obj).getValue();
+        }
+        if (obj instanceof COSObject)
+        {
+            obj = ((COSObject) obj).getObject();
+        }
+        if (obj instanceof COSDictionary)
+        {
+            COSDictionary dic = (COSDictionary) obj;
+            if (dic.containsKey(searchStr))
+            {
+                MapEntry entry = new MapEntry();
+                entry.setKey(COSName.getPDFName(searchStr));
+                entry.setValue(dic.getItem(searchStr));
+                return entry;
+            }
+        }
+        else if (obj instanceof COSArray)
+        {
+            int index = Integer.parseInt(searchStr);
+            COSArray array = (COSArray) obj;
+            if (index <= array.size() - 1)
+            {
+                ArrayEntry entry = new ArrayEntry();
+                entry.setIndex(index);
+                entry.setValue(array.getObject(index));
+                return entry;
+            }
+        }
+        return null;
+    }
+}

Propchange: pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/pdfdebugger/treestatus/TreeStatus.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/pdfdebugger/treestatus/TreeStatusPane.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/pdfdebugger/treestatus/TreeStatusPane.java?rev=1681588&view=auto
==============================================================================
--- pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/pdfdebugger/treestatus/TreeStatusPane.java (added)
+++ pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/pdfdebugger/treestatus/TreeStatusPane.java Mon May 25 13:30:54 2015
@@ -0,0 +1,125 @@
+/*
+ * 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.tools.pdfdebugger.treestatus;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.event.ActionEvent;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.JTree;
+import javax.swing.border.BevelBorder;
+import javax.swing.border.Border;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.TreePath;
+
+/**
+ * @author Khyrul Bashar
+ */
+public class TreeStatusPane implements TreeSelectionListener
+{
+    private TreeStatus statusObj;
+    private JTree tree;
+
+    private JTextField statusField;
+    private JPanel panel;
+    private Border defaultBorder;
+    private Border errorBorder;
+    private final Action textInputAction = new AbstractAction()
+    {
+        @Override
+        public void actionPerformed(ActionEvent actionEvent)
+        {
+            TreePath path = statusObj.getPathForString(statusField.getText());
+            if (statusObj.isValid)
+            {
+                tree.setSelectionPath(path);
+            }
+            else
+            {
+                statusField.setBorder(errorBorder);
+            }
+        }
+    };
+
+    /**
+     * Constructor.
+     * @param targetTree The tree instance that this status pane will correspond.
+     */
+    public TreeStatusPane(JTree targetTree)
+    {
+        tree = targetTree;
+        init();
+    }
+
+    private void init()
+    {
+        panel = new JPanel(new BorderLayout());
+        statusField = new JTextField();
+        statusField.setEditable(false);
+        panel.add(statusField);
+        defaultBorder = new BevelBorder(BevelBorder.LOWERED);
+        errorBorder = new BevelBorder(BevelBorder.LOWERED, Color.RED, Color.RED);
+        statusField.setAction(textInputAction);
+        tree.addTreeSelectionListener(this);
+    }
+
+    /**
+     * Return the panel of this TreeStatusPane.
+     * @return JPanel instance.
+     */
+    public JPanel getPanel()
+    {
+        return panel;
+    }
+
+    /**
+     * In case of document changing this should be called to update TreeStatus value of the pane.
+     * @param statusObj TreeStatus instance.
+     */
+    public void updateTreeStatus(TreeStatus statusObj)
+    {
+        statusField.setEditable(true);
+        this.statusObj = statusObj;
+        updateText(null);
+    }
+
+    private void updateText(String statusString)
+    {
+        statusField.setText(statusString);
+        if (!statusField.getBorder().equals(defaultBorder))
+        {
+            statusField.setBorder(defaultBorder);
+        }
+    }
+
+    /**
+     * Tree selection change listener which updates status string.
+     * @param treeSelectionEvent
+     */
+
+    @Override
+    public void valueChanged(TreeSelectionEvent treeSelectionEvent)
+    {
+        TreePath path = treeSelectionEvent.getPath();
+        updateText(statusObj.getStringForPath(path));
+    }
+}

Propchange: pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/pdfdebugger/treestatus/TreeStatusPane.java
------------------------------------------------------------------------------
    svn:eol-style = native