org.jpedal.objects.acroforms.GUIData Maven / Gradle / Ivy
/*
* ===========================================
* Java Pdf Extraction Decoding Access Library
* ===========================================
*
* Project Info: http://www.idrsolutions.com
* Help section for developers at http://www.idrsolutions.com/support/
*
* (C) Copyright 1997-2017 IDRsolutions and Contributors.
*
* This file is part of JPedal/JPDF2HTML5
*
@LICENSE@
*
* ---------------
* GUIData.java
* ---------------
*/
package org.jpedal.objects.acroforms;
import java.awt.Rectangle;
import java.util.*;
import org.jpedal.external.CustomFormPrint;
import org.jpedal.external.ExternalHandlers;
import org.jpedal.objects.PdfPageData;
import org.jpedal.objects.acroforms.creation.FormFactory;
import org.jpedal.objects.layers.PdfLayerList;
import org.jpedal.objects.raw.FormObject;
import org.jpedal.objects.raw.PdfDictionary;
/**
* holds all data not specific to Swing/SWT/ULC
*/
public abstract class GUIData {
/**
* flag to make forms draw as images, not swing components
*/
protected boolean rasterizeForms;
/**
* for if we add a popup to the panel, could be used for adding other objects
*/
protected boolean forceRedraw;
//allow user to move relative draw position
protected int userX, userY, widestPageNR, widestPageR;
/**
* the current display view, Display.SINGLE, Display.CONTINOUS etc
*/
protected int displayView;
public float dpi = 72.0f;
protected final Map rawFormData = new HashMap();
/**
* allow user to set Forms to ignore
*/
protected Map componentsToIgnore = new HashMap();
protected int insetW, insetH;
protected PdfPageData pageData;
/**
* local copy needed in rendering
*/
protected int indent;
protected int[] cropOtherY;
/**
* track page scaling
*/
protected float displayScaling;
protected int rotation;
/**
* used to only redraw as needed
*/
protected float lastScaling = -1, oldRotation, oldIndent;
/**
* used for page tracking
*/
protected int startPage, currentPage, endPage;
/**
* used to draw pages offset if not in SINGLE_PAGE mode
*/
protected int[] xReached, yReached;
/**
* stores the forms in there original order, accessable by page
*/
protected List[] formsUnordered, formsOrdered;
/**
* array to hold page for each component so we can scan quickly on page change
*/
private int formCount;
protected PdfLayerList layers;
protected FormFactory formFactory;
public void setLayerData(final PdfLayerList layers) {
this.layers = layers;
}
public void setRasterizeForms(final boolean inlineForms) {
rasterizeForms = inlineForms;
}
public void setListForPage(final int page, final List comps, final boolean isSorted) {
if (isSorted) {
formsOrdered[page] = comps;
} else {
formsUnordered[page] = comps;
}
}
protected Object checkGUIObjectResolved(final FormObject formObject) {
Object comp = null;
if (formObject != null) {
comp = formObject.getGUIComponent();
}
if (formObject != null && comp == null) {
comp = resolveGUIComponent(formObject);
if (comp != null) {
setGUIComp(formObject, comp);
}
}
return comp;
}
protected Object resolveGUIComponent(final FormObject formObject) {
Object retComponent = null;
final int subtype = formObject.getParameterConstant(PdfDictionary.Subtype);
final int formType = formObject.getNameAsConstant(PdfDictionary.FT); //FT
final int formFactoryType = formFactory.getType();
//ExternalHandlers.isXFAPresent() will only be true in forms version of PDF2HTML
if (!ExternalHandlers.isXFAPresent() && (formFactoryType == FormFactory.HTML || formFactoryType == FormFactory.SVG)) {
if (subtype != PdfDictionary.Widget && AcroRenderer.isAnnotation(formObject)) {
retComponent = formFactory.annotationButton(formObject);
}
} else if (formType == -1) {
retComponent = formFactory.annotationButton(formObject);
} else {
retComponent = getFormComponent(formObject, formType, retComponent);
}
if (retComponent != null) {
formObject.setGUIComponent(retComponent, formFactory.getType());
setGUIComp(formObject, retComponent);
}
return retComponent;
}
private Object getFormComponent(final FormObject formObject, final int formType, Object retComponent) {
final boolean[] flags = formObject.getFieldFlags(); //Ff
switch (formType) {
case PdfDictionary.Btn:
boolean isPushButton = false, isRadio = false; // hasNoToggleToOff = false, radioinUnison = false;
if (flags != null) {
isPushButton = flags[FormObject.PUSHBUTTON_ID];
isRadio = flags[FormObject.RADIO_ID];
}
if (isPushButton) {
retComponent = formFactory.pushBut(formObject);
} else if (isRadio) {
retComponent = formFactory.radioBut(formObject);
} else {
retComponent = formFactory.checkBoxBut(formObject);
}
break;
case PdfDictionary.Tx:
boolean isMultiline = false, hasPassword = false; // doNotScroll = false, richtext = false, fileSelect = false, doNotSpellCheck = false;
if (flags != null) {
isMultiline = flags[FormObject.MULTILINE_ID] || (formObject.getTextString() != null && formObject.getTextString().indexOf('\n') != -1);
hasPassword = flags[FormObject.PASSWORD_ID];
}
if (isMultiline) {
if (hasPassword) {
retComponent = formFactory.multiLinePassword(formObject);
} else {
retComponent = formFactory.multiLineText(formObject);
}
} else { //singleLine
if (hasPassword) {
retComponent = formFactory.singleLinePassword(formObject);
} else {
retComponent = formFactory.singleLineText(formObject);
}
}
break;
case PdfDictionary.Ch:
boolean isCombo = false; // multiSelect = false, sort = false, isEditable = false, doNotSpellCheck = false, comminOnSelChange = false;
if (flags != null) {
isCombo = flags[FormObject.COMBO_ID];
}
if (isCombo) { // || (type==XFAFORM && ((XFAFormObject)formObject).choiceShown!=XFAFormObject.CHOICE_ALWAYS)){
retComponent = formFactory.comboBox(formObject);
} else { //it is a list
retComponent = formFactory.listField(formObject);
}
break;
case PdfDictionary.Sig:
retComponent = formFactory.signature(formObject);
break;
}
return retComponent;
}
public void dispose() {
//Nothing to dispose of in generic method, overrode by swing version
}
protected abstract void displayComponent(final FormObject formObject, final Object comp);
/**
* put components onto screen display
*
* @param startPage
* @param endPage
*/
protected void displayComponents(final int startPage, final int endPage) {
if (rasterizeForms || formsOrdered == null) {
return;
}
this.startPage = startPage;
this.endPage = endPage;
FormObject formObject;
Object comp;
//System.out.println("displayComponents "+startPage+" "+endPage+" "+SwingUtilities.isEventDispatchThread());
if (startPage > 1) {
removeHiddenForms(1, startPage);
}
/*
* forms currently visible
*/
for (int page = startPage; page < endPage; page++) {
//get unsorted components and iterate over forms
if (formsOrdered[page] != null) {
for (final FormObject o : formsOrdered[page]) {
if (o != null) {
formObject = o;
comp = checkGUIObjectResolved(formObject);
if (comp != null) {
displayComponent(formObject, comp);
}
}
}
}
}
removeHiddenForms(endPage, pageData.getPageCount() + 1);
}
void removeHiddenForms(final int startPage, final int endPage) {
//comment out as could be called by Canoo
//throw new UnsupportedOperationException("Not supported yet.");
}
public boolean hasformsOnPageDecoded(final int page) {
return formsOrdered != null && formsOrdered.length > page && formsOrdered[page] != null;
}
/**
* setup values needed for drawing page
*
* @param pageData
* @param page
*/
protected void initParametersForPage(final PdfPageData pageData, final int page, final FormFactory formFactory, final float dpi) {
//ensure setup
if (cropOtherY == null || cropOtherY.length <= page) {
this.resetComponents(0, pageData.getPageCount(), false);
}
final int mediaHeight = pageData.getMediaBoxHeight(page);
final int cropTop = (pageData.getCropBoxHeight(page) + pageData.getCropBoxY(page));
//take into account crop
if (mediaHeight != cropTop) {
cropOtherY[page] = (mediaHeight - cropTop);
} else {
cropOtherY[page] = 0;
}
this.currentPage = page; //track page displayed
this.formFactory = formFactory;
this.dpi = dpi;
}
/**
* used to flush/resize data structures on new document/page
*
* @param formCount
* @param pageCount
* @param keepValues return true if successful, false if formCount is less than current count.
*/
public void resetComponents(final int formCount, final int pageCount, final boolean keepValues) {
if (keepValues && this.formCount > formCount) {
return;
}
this.formCount = formCount;
if (!keepValues) {
if (formsUnordered == null && pageCount != 0) {
formsUnordered = new List[pageCount + 1];
formsOrdered = new List[pageCount + 1];
}
//reset offsets
cropOtherY = new int[pageCount + 1];
//reset the multi page shifting values so we dont get forms half way across the page on a single page view.
xReached = yReached = null;
}
}
/**
* pass in current values used for all components
*
* @param scaling
* @param rotation
* @param indent
*/
public void setPageValues(final float scaling, final int rotation, final int indent, final int userX, final int userY, final int displayView, final int widestPageNR, final int widestPageR) {
this.rotation = rotation;
this.displayScaling = scaling;
this.indent = indent;
this.userX = userX;
this.userY = userY;
this.displayView = displayView;
this.widestPageNR = widestPageNR;
this.widestPageR = widestPageR;
}
/**
* used to pass in offsets and PdfPageData object so we can access in rendering
*
* @param pageData
* @param insetW
* @param insetH
*/
protected void setPageData(final PdfPageData pageData, final int insetW, final int insetH) {
//track inset on page
this.insetW = insetW;
this.insetH = insetH;
this.pageData = pageData;
}
/**
* offsets for forms in multi-page mode
*/
public void setPageDisplacements(final int[] xReached, final int[] yReached) {
this.xReached = xReached;
this.yReached = yReached;
//force redraw
forceRedraw = true;
}
/**
* force redraw (ie for refreshing layers)
*/
public void setForceRedraw(final boolean forceRedraw) {
this.forceRedraw = forceRedraw;
}
/**
* store form data and allow lookup by PDF ref or name
* (name may not be unique)
*
* @param formObject
*/
protected void storeRawData(final FormObject formObject) {
final String ref = formObject.getObjectRefAsString();
rawFormData.put(ref, formObject);
}
protected void flushFormData() {
rawFormData.clear();
formsOrdered = null;
formsUnordered = null;
this.oldIndent = -oldIndent;
}
/**
* returns the raw formdata so that DefaultAcroRender can access
*/
protected Map getRawFormData() {
return Collections.unmodifiableMap(rawFormData);
}
protected abstract void setGUIComp(final FormObject formObject, final Object rawField);
/**
* Allow you to get a list of values from the Forms.
*
* If possible we recommend you work with the Form Objects rather than
* resolve GUI components unless you need the GUI values
*
* null key will return all values
*
* if pageNumber is -1 it will process whole document, otherwise just that page
*
* NO values will return empty list, not null
*/
public List getFormComponents(final String key, final ReturnValues value, final int pageNumber) {
final Iterator i = rawFormData.keySet().iterator();
final ArrayList