001/* 002 * $Id: PdfFormField.java 4784 2011-03-15 08:33:00Z blowagie $ 003 * 004 * This file is part of the iText (R) project. 005 * Copyright (c) 1998-2011 1T3XT BVBA 006 * Authors: Bruno Lowagie, Paulo Soares, et al. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Affero General Public License version 3 010 * as published by the Free Software Foundation with the addition of the 011 * following permission added to Section 15 as permitted in Section 7(a): 012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT, 013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. 014 * 015 * This program is distributed in the hope that it will be useful, but 016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 017 * or FITNESS FOR A PARTICULAR PURPOSE. 018 * See the GNU Affero General Public License for more details. 019 * You should have received a copy of the GNU Affero General Public License 020 * along with this program; if not, see http://www.gnu.org/licenses or write to 021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 022 * Boston, MA, 02110-1301 USA, or download the license from the following URL: 023 * http://itextpdf.com/terms-of-use/ 024 * 025 * The interactive user interfaces in modified source and object code versions 026 * of this program must display Appropriate Legal Notices, as required under 027 * Section 5 of the GNU Affero General Public License. 028 * 029 * In accordance with Section 7(b) of the GNU Affero General Public License, 030 * a covered work must retain the producer line in every PDF that is created 031 * or manipulated using iText. 032 * 033 * You can be released from the requirements of the license by purchasing 034 * a commercial license. Buying such a license is mandatory as soon as you 035 * develop commercial activities involving the iText software without 036 * disclosing the source code of your own applications. 037 * These activities include: offering paid services to customers as an ASP, 038 * serving PDFs on the fly in a web application, shipping iText with a closed 039 * source product. 040 * 041 * For more information, please contact iText Software Corp. at this 042 * address: sales@itextpdf.com 043 */ 044package com.itextpdf.text.pdf; 045import java.util.ArrayList; 046 047import com.itextpdf.text.Rectangle; 048 049/** Implements form fields. 050 * 051 * @author Paulo Soares 052 */ 053public class PdfFormField extends PdfAnnotation { 054 055 public static final int FF_READ_ONLY = 1; 056 public static final int FF_REQUIRED = 2; 057 public static final int FF_NO_EXPORT = 4; 058 public static final int FF_NO_TOGGLE_TO_OFF = 16384; 059 public static final int FF_RADIO = 32768; 060 public static final int FF_PUSHBUTTON = 65536; 061 public static final int FF_MULTILINE = 4096; 062 public static final int FF_PASSWORD = 8192; 063 public static final int FF_COMBO = 131072; 064 public static final int FF_EDIT = 262144; 065 public static final int FF_FILESELECT = 1048576; 066 public static final int FF_MULTISELECT = 2097152; 067 public static final int FF_DONOTSPELLCHECK = 4194304; 068 public static final int FF_DONOTSCROLL = 8388608; 069 public static final int FF_COMB = 16777216; 070 public static final int FF_RADIOSINUNISON = 1 << 25; 071 /** 072 * Allows text fields to support rich text. 073 * @since 5.0.6 074 */ 075 public static final int FF_RICHTEXT = 1 << 26; 076 public static final int Q_LEFT = 0; 077 public static final int Q_CENTER = 1; 078 public static final int Q_RIGHT = 2; 079 public static final int MK_NO_ICON = 0; 080 public static final int MK_NO_CAPTION = 1; 081 public static final int MK_CAPTION_BELOW = 2; 082 public static final int MK_CAPTION_ABOVE = 3; 083 public static final int MK_CAPTION_RIGHT = 4; 084 public static final int MK_CAPTION_LEFT = 5; 085 public static final int MK_CAPTION_OVERLAID = 6; 086 public static final PdfName IF_SCALE_ALWAYS = PdfName.A; 087 public static final PdfName IF_SCALE_BIGGER = PdfName.B; 088 public static final PdfName IF_SCALE_SMALLER = PdfName.S; 089 public static final PdfName IF_SCALE_NEVER = PdfName.N; 090 public static final PdfName IF_SCALE_ANAMORPHIC = PdfName.A; 091 public static final PdfName IF_SCALE_PROPORTIONAL = PdfName.P; 092 public static final boolean MULTILINE = true; 093 public static final boolean SINGLELINE = false; 094 public static final boolean PLAINTEXT = false; 095 public static final boolean PASSWORD = true; 096 static PdfName mergeTarget[] = {PdfName.FONT, PdfName.XOBJECT, PdfName.COLORSPACE, PdfName.PATTERN}; 097 098 /** Holds value of property parent. */ 099 protected PdfFormField parent; 100 101 protected ArrayList<PdfFormField> kids; 102 103/** 104 * Constructs a new <CODE>PdfAnnotation</CODE> of subtype link (Action). 105 */ 106 107 public PdfFormField(PdfWriter writer, float llx, float lly, float urx, float ury, PdfAction action) { 108 super(writer, llx, lly, urx, ury, action); 109 put(PdfName.TYPE, PdfName.ANNOT); 110 put(PdfName.SUBTYPE, PdfName.WIDGET); 111 annotation = true; 112 } 113 114 /** Creates new PdfFormField */ 115 protected PdfFormField(PdfWriter writer) { 116 super(writer, null); 117 form = true; 118 annotation = false; 119 } 120 121 public void setWidget(Rectangle rect, PdfName highlight) { 122 put(PdfName.TYPE, PdfName.ANNOT); 123 put(PdfName.SUBTYPE, PdfName.WIDGET); 124 put(PdfName.RECT, new PdfRectangle(rect)); 125 annotation = true; 126 if (highlight != null && !highlight.equals(HIGHLIGHT_INVERT)) 127 put(PdfName.H, highlight); 128 } 129 130 public static PdfFormField createEmpty(PdfWriter writer) { 131 PdfFormField field = new PdfFormField(writer); 132 return field; 133 } 134 135 public void setButton(int flags) { 136 put(PdfName.FT, PdfName.BTN); 137 if (flags != 0) 138 put(PdfName.FF, new PdfNumber(flags)); 139 } 140 141 protected static PdfFormField createButton(PdfWriter writer, int flags) { 142 PdfFormField field = new PdfFormField(writer); 143 field.setButton(flags); 144 return field; 145 } 146 147 public static PdfFormField createPushButton(PdfWriter writer) { 148 return createButton(writer, FF_PUSHBUTTON); 149 } 150 151 public static PdfFormField createCheckBox(PdfWriter writer) { 152 return createButton(writer, 0); 153 } 154 155 public static PdfFormField createRadioButton(PdfWriter writer, boolean noToggleToOff) { 156 return createButton(writer, FF_RADIO + (noToggleToOff ? FF_NO_TOGGLE_TO_OFF : 0)); 157 } 158 159 public static PdfFormField createTextField(PdfWriter writer, boolean multiline, boolean password, int maxLen) { 160 PdfFormField field = new PdfFormField(writer); 161 field.put(PdfName.FT, PdfName.TX); 162 int flags = multiline ? FF_MULTILINE : 0; 163 flags += password ? FF_PASSWORD : 0; 164 field.put(PdfName.FF, new PdfNumber(flags)); 165 if (maxLen > 0) 166 field.put(PdfName.MAXLEN, new PdfNumber(maxLen)); 167 return field; 168 } 169 170 protected static PdfFormField createChoice(PdfWriter writer, int flags, PdfArray options, int topIndex) { 171 PdfFormField field = new PdfFormField(writer); 172 field.put(PdfName.FT, PdfName.CH); 173 field.put(PdfName.FF, new PdfNumber(flags)); 174 field.put(PdfName.OPT, options); 175 if (topIndex > 0) 176 field.put(PdfName.TI, new PdfNumber(topIndex)); 177 return field; 178 } 179 180 public static PdfFormField createList(PdfWriter writer, String options[], int topIndex) { 181 return createChoice(writer, 0, processOptions(options), topIndex); 182 } 183 184 public static PdfFormField createList(PdfWriter writer, String options[][], int topIndex) { 185 return createChoice(writer, 0, processOptions(options), topIndex); 186 } 187 188 public static PdfFormField createCombo(PdfWriter writer, boolean edit, String options[], int topIndex) { 189 return createChoice(writer, FF_COMBO + (edit ? FF_EDIT : 0), processOptions(options), topIndex); 190 } 191 192 public static PdfFormField createCombo(PdfWriter writer, boolean edit, String options[][], int topIndex) { 193 return createChoice(writer, FF_COMBO + (edit ? FF_EDIT : 0), processOptions(options), topIndex); 194 } 195 196 protected static PdfArray processOptions(String options[]) { 197 PdfArray array = new PdfArray(); 198 for (int k = 0; k < options.length; ++k) { 199 array.add(new PdfString(options[k], PdfObject.TEXT_UNICODE)); 200 } 201 return array; 202 } 203 204 protected static PdfArray processOptions(String options[][]) { 205 PdfArray array = new PdfArray(); 206 for (int k = 0; k < options.length; ++k) { 207 String subOption[] = options[k]; 208 PdfArray ar2 = new PdfArray(new PdfString(subOption[0], PdfObject.TEXT_UNICODE)); 209 ar2.add(new PdfString(subOption[1], PdfObject.TEXT_UNICODE)); 210 array.add(ar2); 211 } 212 return array; 213 } 214 215 public static PdfFormField createSignature(PdfWriter writer) { 216 PdfFormField field = new PdfFormField(writer); 217 field.put(PdfName.FT, PdfName.SIG); 218 return field; 219 } 220 221 /** Getter for property parent. 222 * @return Value of property parent. 223 */ 224 public PdfFormField getParent() { 225 return parent; 226 } 227 228 public void addKid(PdfFormField field) { 229 field.parent = this; 230 if (kids == null) 231 kids = new ArrayList<PdfFormField>(); 232 kids.add(field); 233 } 234 235 public ArrayList<PdfFormField> getKids() { 236 return kids; 237 } 238 239 /** 240 * ORs together the given flags with the current /Ff value. 241 * @param flags flags to be added. 242 * @return the old flag value 243 */ 244 public int setFieldFlags(int flags) { 245 PdfNumber obj = (PdfNumber)get(PdfName.FF); 246 int old; 247 if (obj == null) 248 old = 0; 249 else 250 old = obj.intValue(); 251 int v = old | flags; 252 put(PdfName.FF, new PdfNumber(v)); 253 return old; 254 } 255 256 public void setValueAsString(String s) { 257 put(PdfName.V, new PdfString(s, PdfObject.TEXT_UNICODE)); 258 } 259 260 public void setValueAsName(String s) { 261 put(PdfName.V, new PdfName(s)); 262 } 263 264 public void setValue(PdfSignature sig) { 265 put(PdfName.V, sig); 266 } 267 268 /** 269 * Sets the rich value for this field. 270 * It is suggested that the regular value of this field be set to an 271 * equivalent value. Rich text values are only supported since PDF 1.5, 272 * and require that the FF_RV flag be set. See PDF Reference chapter 273 * 12.7.3.4 for details. 274 * @param rv HTML markup for the rich value of this field 275 * @since 5.0.6 276 */ 277 public void setRichValue(String rv) { 278 put(PdfName.RV, new PdfString( rv )); 279 } 280 281 public void setDefaultValueAsString(String s) { 282 put(PdfName.DV, new PdfString(s, PdfObject.TEXT_UNICODE)); 283 } 284 285 public void setDefaultValueAsName(String s) { 286 put(PdfName.DV, new PdfName(s)); 287 } 288 289 public void setFieldName(String s) { 290 if (s != null) 291 put(PdfName.T, new PdfString(s, PdfObject.TEXT_UNICODE)); 292 } 293 294 /** 295 * The "user name" is the text shown as a tool. 296 * @param s user name. 297 */ 298 public void setUserName(String s) { 299 put(PdfName.TU, new PdfString(s, PdfObject.TEXT_UNICODE)); 300 } 301 302 /** 303 * The mapping name is the name this field uses when submitting form data. 304 * @param s 305 */ 306 public void setMappingName(String s) { 307 put(PdfName.TM, new PdfString(s, PdfObject.TEXT_UNICODE)); 308 } 309 310 /** 311 * Sets text alginment for this field 312 * @param v one of the Q_* contstants 313 */ 314 public void setQuadding(int v) { 315 put(PdfName.Q, new PdfNumber(v)); 316 } 317 318 static void mergeResources(PdfDictionary result, PdfDictionary source, PdfStamperImp writer) { 319 PdfDictionary dic = null; 320 PdfDictionary res = null; 321 PdfName target = null; 322 for (int k = 0; k < mergeTarget.length; ++k) { 323 target = mergeTarget[k]; 324 PdfDictionary pdfDict = source.getAsDict(target); 325 if ((dic = pdfDict) != null) { 326 if ((res = (PdfDictionary)PdfReader.getPdfObject(result.get(target), result)) == null) { 327 res = new PdfDictionary(); 328 } 329 res.mergeDifferent(dic); 330 result.put(target, res); 331 if (writer != null) 332 writer.markUsed(res); 333 } 334 } 335 } 336 337 static void mergeResources(PdfDictionary result, PdfDictionary source) { 338 mergeResources(result, source, null); 339 } 340 341 @Override 342 public void setUsed() { 343 used = true; 344 if (parent != null) 345 put(PdfName.PARENT, parent.getIndirectReference()); 346 if (kids != null) { 347 PdfArray array = new PdfArray(); 348 for (int k = 0; k < kids.size(); ++k) 349 array.add((kids.get(k)).getIndirectReference()); 350 put(PdfName.KIDS, array); 351 } 352 if (templates == null) 353 return; 354 PdfDictionary dic = new PdfDictionary(); 355 for (PdfTemplate template: templates) { 356 mergeResources(dic, (PdfDictionary)template.getResources()); 357 } 358 put(PdfName.DR, dic); 359 } 360 361 public static PdfAnnotation shallowDuplicate(PdfAnnotation annot) { 362 PdfAnnotation dup; 363 if (annot.isForm()) { 364 dup = new PdfFormField(annot.writer); 365 PdfFormField dupField = (PdfFormField)dup; 366 PdfFormField srcField = (PdfFormField)annot; 367 dupField.parent = srcField.parent; 368 dupField.kids = srcField.kids; 369 } 370 else 371 dup = new PdfAnnotation(annot.writer, null); 372 dup.merge(annot); 373 dup.form = annot.form; 374 dup.annotation = annot.annotation; 375 dup.templates = annot.templates; 376 return dup; 377 } 378}