org.apache.pdfbox.debugger.ui.PDFTreeCellRenderer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pdfbox-debugger Show documentation
Show all versions of pdfbox-debugger Show documentation
The Apache PDFBox library is an open source Java tool for working with PDF documents.
This artefact contains the PDFDebugger.
The newest version!
/*
* 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.debugger.ui;
import java.awt.Component;
import java.awt.Graphics;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeCellRenderer;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSBoolean;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSFloat;
import org.apache.pdfbox.cos.COSInteger;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSNull;
import org.apache.pdfbox.cos.COSObject;
import org.apache.pdfbox.cos.COSStream;
import org.apache.pdfbox.cos.COSString;
/**
* A class to render tree cells for the pdfviewer.
*
* @author Ben Litchfield
*/
public class PDFTreeCellRenderer extends DefaultTreeCellRenderer
{
private static final long serialVersionUID = 6547078597109564198L;
private static final ImageIcon ICON_ARRAY = new ImageIcon(getImageUrl("array"));
private static final ImageIcon ICON_BOOLEAN = new ImageIcon(getImageUrl("boolean"));
private static final ImageIcon ICON_DICT = new ImageIcon(getImageUrl("dict"));
private static final ImageIcon ICON_HEX = new ImageIcon(getImageUrl("hex"));
private static final ImageIcon ICON_INDIRECT = new ImageIcon(getImageUrl("indirect"));
private static final ImageIcon ICON_INTEGER = new ImageIcon(getImageUrl("integer"));
private static final ImageIcon ICON_NAME = new ImageIcon(getImageUrl("name"));
private static final ImageIcon ICON_NULL = new ImageIcon(getImageUrl("null"));
private static final ImageIcon ICON_REAL = new ImageIcon(getImageUrl("real"));
private static final ImageIcon ICON_STREAM_DICT = new ImageIcon(getImageUrl("stream-dict"));
private static final ImageIcon ICON_STRING = new ImageIcon(getImageUrl("string"));
private static final ImageIcon ICON_PDF = new ImageIcon(getImageUrl("pdf"));
private static final ImageIcon ICON_PAGE = new ImageIcon(getImageUrl("page"));
private static URL getImageUrl(String name)
{
String fullName = "/org/apache/pdfbox/debugger/" + name + ".png";
return PDFTreeCellRenderer.class.getResource(fullName);
}
@Override
public Component getTreeCellRendererComponent(
JTree tree,
Object nodeValue,
boolean isSelected,
boolean expanded,
boolean leaf,
int row,
boolean componentHasFocus)
{
Component component = super.getTreeCellRendererComponent(tree,
toTreeObject(nodeValue),
isSelected, expanded, leaf, row, componentHasFocus);
setIcon(lookupIconWithOverlay(nodeValue));
return component;
}
private Object toTreeObject(Object nodeValue)
{
Object result = nodeValue;
if (nodeValue instanceof MapEntry || nodeValue instanceof ArrayEntry)
{
String key;
Object object;
Object value;
COSBase item;
if (nodeValue instanceof MapEntry)
{
MapEntry entry = (MapEntry) nodeValue;
key = entry.getKey().getName();
object = toTreeObject(entry.getValue());
value = entry.getValue();
item = entry.getItem();
}
else
{
ArrayEntry entry = (ArrayEntry) nodeValue;
key = Integer.toString(entry.getIndex());
object = toTreeObject(entry.getValue());
value = entry.getValue();
item = entry.getItem();
}
String stringResult = key;
if (object instanceof String && ((String)object).length() > 0)
{
stringResult += ": " + object;
if (item instanceof COSObject)
{
COSObject indirect = (COSObject)item;
stringResult += " [" + indirect.getKey() + "]";
}
stringResult += toTreePostfix(value);
}
result = stringResult;
}
else if (nodeValue instanceof COSBoolean)
{
result = Boolean.toString(((COSBoolean) nodeValue).getValue());
}
else if (nodeValue instanceof COSFloat)
{
result = Float.toString(((COSFloat) nodeValue).floatValue());
}
else if (nodeValue instanceof COSInteger)
{
result = Integer.toString(((COSInteger) nodeValue).intValue());
}
else if (nodeValue instanceof COSString)
{
String text = ((COSString) nodeValue).getString();
// display unprintable strings as hex
for (char c : text.toCharArray())
{
if (Character.isISOControl(c))
{
text = "<" + ((COSString) nodeValue).toHexString() + ">";
break;
}
}
result = text;
}
else if (nodeValue instanceof COSName)
{
result = ((COSName) nodeValue).getName();
}
else if (nodeValue instanceof COSNull || nodeValue == null)
{
result = "";
}
else if (nodeValue instanceof COSDictionary)
{
COSDictionary dict = (COSDictionary) nodeValue;
if (COSName.XREF.equals(dict.getCOSName(COSName.TYPE)))
{
result = "";
}
else
{
result = "(" + dict.size() + ")";
}
}
else if (nodeValue instanceof COSArray)
{
COSArray array = (COSArray) nodeValue;
result = "(" + array.size() + ")";
}
else if (nodeValue instanceof DocumentEntry)
{
result = nodeValue.toString();
}
else if (nodeValue instanceof XrefEntries)
{
result = nodeValue.toString();
}
else if (nodeValue instanceof XrefEntry)
{
result = nodeValue.toString();
}
return result;
}
private String toTreePostfix(Object nodeValue)
{
if (nodeValue instanceof COSDictionary)
{
StringBuilder sb = new StringBuilder();
COSDictionary dict = (COSDictionary)nodeValue;
if (COSName.ANNOT.equals(dict.getCOSName(COSName.TYPE))
&& COSName.WIDGET.equals(dict.getCOSName(COSName.SUBTYPE)) ||
dict.containsKey(COSName.T) && dict.containsKey(COSName.KIDS))
{
String name = dict.getString(COSName.T);
if (name != null)
{
sb.append(" Name: ");
sb.append(name);
sb.append(' ');
}
}
if (dict.containsKey(COSName.TYPE))
{
COSName type = dict.getCOSName(COSName.TYPE);
if (type != null)
{
sb.append(" /T:").append(type.getName());
}
}
if (dict.containsKey(COSName.SUBTYPE))
{
COSName subtype = dict.getCOSName(COSName.SUBTYPE);
if (subtype != null)
{
sb.append(" /S:").append(subtype.getName());
}
}
if (dict.containsKey(COSName.S))
{
COSName subtype = dict.getCOSName(COSName.S);
if (subtype != null)
{
sb.append(" /S:").append(subtype.getName());
}
}
return sb.toString();
}
else
{
return "";
}
}
private ImageIcon lookupIconWithOverlay(Object nodeValue)
{
ImageIcon icon = lookupIcon(nodeValue);
boolean isIndirect = false;
boolean isStream = false;
if (nodeValue instanceof MapEntry)
{
MapEntry entry = (MapEntry) nodeValue;
if (entry.getItem() instanceof COSObject)
{
isIndirect = true;
isStream = entry.getValue() instanceof COSStream;
}
}
else if (nodeValue instanceof ArrayEntry)
{
ArrayEntry entry = (ArrayEntry) nodeValue;
if (entry.getItem() instanceof COSObject)
{
isIndirect = true;
isStream = entry.getValue() instanceof COSStream;
}
}
else if (nodeValue instanceof XrefEntry)
{
isIndirect = true;
}
if (isIndirect && !isStream)
{
OverlayIcon overlay = new OverlayIcon(icon);
overlay.add(ICON_INDIRECT);
return overlay;
}
return icon;
}
private ImageIcon lookupIcon(Object nodeValue)
{
if (nodeValue instanceof MapEntry)
{
MapEntry entry = (MapEntry) nodeValue;
return lookupIcon(entry.getValue());
}
if (nodeValue instanceof XrefEntry)
{
return ICON_INDIRECT;
}
else if (nodeValue instanceof ArrayEntry)
{
ArrayEntry entry = (ArrayEntry) nodeValue;
return lookupIcon(entry.getValue());
}
else if (nodeValue instanceof COSBoolean)
{
return ICON_BOOLEAN;
}
else if (nodeValue instanceof COSFloat)
{
return ICON_REAL;
}
else if (nodeValue instanceof COSInteger)
{
return ICON_INTEGER;
}
else if (nodeValue instanceof COSString)
{
String text = ((COSString) nodeValue).getString();
// display unprintable strings as hex
for (char c : text.toCharArray())
{
if (Character.isISOControl(c))
{
return ICON_HEX;
}
}
return ICON_STRING;
}
else if (nodeValue instanceof COSName)
{
return ICON_NAME;
}
else if (nodeValue instanceof COSNull || nodeValue == null)
{
return ICON_NULL;
}
else if (nodeValue instanceof COSStream)
{
return ICON_STREAM_DICT;
}
else if (nodeValue instanceof COSDictionary)
{
return ICON_DICT;
}
else if (nodeValue instanceof COSArray)
{
return ICON_ARRAY;
}
else if (nodeValue instanceof DocumentEntry)
{
return ICON_PDF;
}
else if (nodeValue instanceof PageEntry)
{
return ICON_PAGE;
}
else if (nodeValue instanceof COSObject)
{
return ICON_DICT;
}
else
{
return null;
}
}
/**
* An ImageIcon which allows other ImageIcon overlays.
*/
private static class OverlayIcon extends ImageIcon
{
private static final long serialVersionUID = 1343672579481297481L;
private final ImageIcon base;
private final List overlays;
OverlayIcon(ImageIcon base)
{
super(base.getImage());
this.base = base;
this.overlays = new ArrayList<>();
}
void add(ImageIcon overlay)
{
overlays.add(overlay);
}
@Override
public synchronized void paintIcon(Component c, Graphics g, int x, int y)
{
base.paintIcon(c, g, x, y);
overlays.forEach(icon -> icon.paintIcon(c, g, x, y));
}
}
}