1 /* 2 * Copyright 2003-2005 by Paulo Soares. 3 * 4 * The contents of this file are subject to the Mozilla Public License Version 1.1 5 * (the "License"); you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at http://www.mozilla.org/MPL/ 7 * 8 * Software distributed under the License is distributed on an "AS IS" basis, 9 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 10 * for the specific language governing rights and limitations under the License. 11 * 12 * The Original Code is 'iText, a free JAVA-PDF library'. 13 * 14 * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by 15 * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. 16 * All Rights Reserved. 17 * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer 18 * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. 19 * 20 * Contributor(s): all the names of the contributors are added in the source code 21 * where applicable. 22 * 23 * Alternatively, the contents of this file may be used under the terms of the 24 * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the 25 * provisions of LGPL are applicable instead of those above. If you wish to 26 * allow use of your version of this file only under the terms of the LGPL 27 * License and not to allow others to use your version of this file under 28 * the MPL, indicate your decision by deleting the provisions above and 29 * replace them with the notice and other provisions required by the LGPL. 30 * If you do not delete the provisions above, a recipient may use your version 31 * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. 32 * 33 * This library is free software; you can redistribute it and/or modify it 34 * under the terms of the MPL as stated above or under the terms of the GNU 35 * Library General Public License as published by the Free Software Foundation; 36 * either version 2 of the License, or any later version. 37 * 38 * This library is distributed in the hope that it will be useful, but WITHOUT 39 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 40 * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more 41 * details. 42 * 43 * If you didn't download this code from the following link, you should check if 44 * you aren't using an obsolete version: 45 * http://www.lowagie.com/iText/ 46 */ 47 48 package com.lowagie.text.pdf; 49 50 import java.awt.Color; 51 import java.io.IOException; 52 import java.util.ArrayList; 53 54 import com.lowagie.text.Chunk; 55 import com.lowagie.text.DocumentException; 56 import com.lowagie.text.Element; 57 import com.lowagie.text.Font; 58 import com.lowagie.text.Phrase; 59 import com.lowagie.text.Rectangle; 60 61 /** 62 * Supports text, combo and list fields generating the correct appearances. 63 * All the option in the Acrobat GUI are supported in an easy to use API. 64 * @author Paulo Soares (psoares@consiste.pt) 65 */ 66 public class TextField extends BaseField { 67 68 /** Holds value of property defaultText. */ 69 private String defaultText; 70 71 /** Holds value of property choices. */ 72 private String[] choices; 73 74 /** Holds value of property choiceExports. */ 75 private String[] choiceExports; 76 77 /** Holds value of property choiceSelection. */ 78 private ArrayList choiceSelections = new ArrayList(); 79 80 private int topFirst; 81 82 private float extraMarginLeft; 83 private float extraMarginTop; 84 85 /** 86 * Creates a new <CODE>TextField</CODE>. 87 * @param writer the document <CODE>PdfWriter</CODE> 88 * @param box the field location and dimensions 89 * @param fieldName the field name. If <CODE>null</CODE> only the widget keys 90 * will be included in the field allowing it to be used as a kid field. 91 */ TextField(PdfWriter writer, Rectangle box, String fieldName)92 public TextField(PdfWriter writer, Rectangle box, String fieldName) { 93 super(writer, box, fieldName); 94 } 95 checkRTL(String text)96 private static boolean checkRTL(String text) { 97 if (text == null || text.length() == 0) 98 return false; 99 char[] cc = text.toCharArray(); 100 for (int k = 0; k < cc.length; ++k) { 101 int c = cc[k]; 102 if (c >= 0x590 && c < 0x0780) 103 return true; 104 } 105 return false; 106 } 107 changeFontSize(Phrase p, float size)108 private static void changeFontSize(Phrase p, float size) { 109 for (int k = 0; k < p.size(); ++k) 110 ((Chunk)p.get(k)).getFont().setSize(size); 111 } 112 composePhrase(String text, BaseFont ufont, Color color, float fontSize)113 private Phrase composePhrase(String text, BaseFont ufont, Color color, float fontSize) { 114 Phrase phrase = null; 115 if (extensionFont == null && (substitutionFonts == null || substitutionFonts.isEmpty())) 116 phrase = new Phrase(new Chunk(text, new Font(ufont, fontSize, 0, color))); 117 else { 118 FontSelector fs = new FontSelector(); 119 fs.addFont(new Font(ufont, fontSize, 0, color)); 120 if (extensionFont != null) 121 fs.addFont(new Font(extensionFont, fontSize, 0, color)); 122 if (substitutionFonts != null) { 123 for (int k = 0; k < substitutionFonts.size(); ++k) 124 fs.addFont(new Font((BaseFont)substitutionFonts.get(k), fontSize, 0, color)); 125 } 126 phrase = fs.process(text); 127 } 128 return phrase; 129 } 130 131 /** 132 * Removes CRLF from a <code>String</code>. 133 * 134 * @param text 135 * @return String 136 * @since 2.1.5 137 */ removeCRLF(String text)138 public static String removeCRLF(String text) { 139 if (text.indexOf('\n') >= 0 || text.indexOf('\r') >= 0) { 140 char[] p = text.toCharArray(); 141 StringBuffer sb = new StringBuffer(p.length); 142 for (int k = 0; k < p.length; ++k) { 143 char c = p[k]; 144 if (c == '\n') 145 sb.append(' '); 146 else if (c == '\r') { 147 sb.append(' '); 148 if (k < p.length - 1 && p[k + 1] == '\n') 149 ++k; 150 } 151 else 152 sb.append(c); 153 } 154 return sb.toString(); 155 } 156 return text; 157 } 158 159 /** 160 * Obfuscates a password <code>String</code>. 161 * Every character is replaced by an asterisk (*). 162 * 163 * @param text 164 * @return String 165 * @since 2.1.5 166 */ obfuscatePassword(String text)167 public static String obfuscatePassword(String text) { 168 char[] pchar = new char[text.length()]; 169 for (int i = 0; i < text.length(); i++) 170 pchar[i] = '*'; 171 return new String(pchar); 172 } 173 174 /** 175 * Get the <code>PdfAppearance</code> of a text or combo field 176 * @throws IOException on error 177 * @throws DocumentException on error 178 * @return A <code>PdfAppearance</code> 179 */ getAppearance()180 public PdfAppearance getAppearance() throws IOException, DocumentException { 181 PdfAppearance app = getBorderAppearance(); 182 app.beginVariableText(); 183 if (text == null || text.length() == 0) { 184 app.endVariableText(); 185 return app; 186 } 187 188 boolean borderExtra = borderStyle == PdfBorderDictionary.STYLE_BEVELED || borderStyle == PdfBorderDictionary.STYLE_INSET; 189 float h = box.getHeight() - borderWidth * 2 - extraMarginTop; 190 float bw2 = borderWidth; 191 if (borderExtra) { 192 h -= borderWidth * 2; 193 bw2 *= 2; 194 } 195 float offsetX = Math.max(bw2, 1); 196 float offX = Math.min(bw2, offsetX); 197 app.saveState(); 198 app.rectangle(offX, offX, box.getWidth() - 2 * offX, box.getHeight() - 2 * offX); 199 app.clip(); 200 app.newPath(); 201 String ptext; 202 if ((options & PASSWORD) != 0) 203 ptext = obfuscatePassword(text); 204 else if ((options & MULTILINE) == 0) 205 ptext = removeCRLF(text); 206 else 207 ptext = text; //fixed by Kazuya Ujihara (ujihara.jp) 208 BaseFont ufont = getRealFont(); 209 Color fcolor = (textColor == null) ? GrayColor.GRAYBLACK : textColor; 210 int rtl = checkRTL(ptext) ? PdfWriter.RUN_DIRECTION_LTR : PdfWriter.RUN_DIRECTION_NO_BIDI; 211 float usize = fontSize; 212 Phrase phrase = composePhrase(ptext, ufont, fcolor, usize); 213 if ((options & MULTILINE) != 0) { 214 float width = box.getWidth() - 4 * offsetX - extraMarginLeft; 215 float factor = ufont.getFontDescriptor(BaseFont.BBOXURY, 1) - ufont.getFontDescriptor(BaseFont.BBOXLLY, 1); 216 ColumnText ct = new ColumnText(null); 217 if (usize == 0) { 218 usize = h / factor; 219 if (usize > 4) { 220 if (usize > 12) 221 usize = 12; 222 float step = Math.max((usize - 4) / 10, 0.2f); 223 ct.setSimpleColumn(0, -h, width, 0); 224 ct.setAlignment(alignment); 225 ct.setRunDirection(rtl); 226 for (; usize > 4; usize -= step) { 227 ct.setYLine(0); 228 changeFontSize(phrase, usize); 229 ct.setText(phrase); 230 ct.setLeading(factor * usize); 231 int status = ct.go(true); 232 if ((status & ColumnText.NO_MORE_COLUMN) == 0) 233 break; 234 } 235 } 236 if (usize < 4) 237 usize = 4; 238 } 239 changeFontSize(phrase, usize); 240 ct.setCanvas(app); 241 float leading = usize * factor; 242 float offsetY = offsetX + h - ufont.getFontDescriptor(BaseFont.BBOXURY, usize); 243 ct.setSimpleColumn(extraMarginLeft + 2 * offsetX, -20000, box.getWidth() - 2 * offsetX, offsetY + leading); 244 ct.setLeading(leading); 245 ct.setAlignment(alignment); 246 ct.setRunDirection(rtl); 247 ct.setText(phrase); 248 ct.go(); 249 } 250 else { 251 if (usize == 0) { 252 float maxCalculatedSize = h / (ufont.getFontDescriptor(BaseFont.BBOXURX, 1) - ufont.getFontDescriptor(BaseFont.BBOXLLY, 1)); 253 changeFontSize(phrase, 1); 254 float wd = ColumnText.getWidth(phrase, rtl, 0); 255 if (wd == 0) 256 usize = maxCalculatedSize; 257 else 258 usize = Math.min(maxCalculatedSize, (box.getWidth() - extraMarginLeft - 4 * offsetX) / wd); 259 if (usize < 4) 260 usize = 4; 261 } 262 changeFontSize(phrase, usize); 263 float offsetY = offX + ((box.getHeight() - 2*offX) - ufont.getFontDescriptor(BaseFont.ASCENT, usize)) / 2; 264 if (offsetY < offX) 265 offsetY = offX; 266 if (offsetY - offX < -ufont.getFontDescriptor(BaseFont.DESCENT, usize)) { 267 float ny = -ufont.getFontDescriptor(BaseFont.DESCENT, usize) + offX; 268 float dy = box.getHeight() - offX - ufont.getFontDescriptor(BaseFont.ASCENT, usize); 269 offsetY = Math.min(ny, Math.max(offsetY, dy)); 270 } 271 if ((options & COMB) != 0 && maxCharacterLength > 0) { 272 int textLen = Math.min(maxCharacterLength, ptext.length()); 273 int position = 0; 274 if (alignment == Element.ALIGN_RIGHT) 275 position = maxCharacterLength - textLen; 276 else if (alignment == Element.ALIGN_CENTER) 277 position = (maxCharacterLength - textLen) / 2; 278 float step = (box.getWidth() - extraMarginLeft) / maxCharacterLength; 279 float start = step / 2 + position * step; 280 if (textColor == null) 281 app.setGrayFill(0); 282 else 283 app.setColorFill(textColor); 284 app.beginText(); 285 for (int k = 0; k < phrase.size(); ++k) { 286 Chunk ck = (Chunk)phrase.get(k); 287 BaseFont bf = ck.getFont().getBaseFont(); 288 app.setFontAndSize(bf, usize); 289 StringBuffer sb = ck.append(""); 290 for (int j = 0; j < sb.length(); ++j) { 291 String c = sb.substring(j, j + 1); 292 float wd = bf.getWidthPoint(c, usize); 293 app.setTextMatrix(extraMarginLeft + start - wd / 2, offsetY - extraMarginTop); 294 app.showText(c); 295 start += step; 296 } 297 } 298 app.endText(); 299 } 300 else { 301 float x; 302 switch (alignment) { 303 case Element.ALIGN_RIGHT: 304 x = extraMarginLeft + box.getWidth() - (2 * offsetX); 305 break; 306 case Element.ALIGN_CENTER: 307 x = extraMarginLeft + (box.getWidth() / 2); 308 break; 309 default: 310 x = extraMarginLeft + (2 * offsetX); 311 } 312 ColumnText.showTextAligned(app, alignment, phrase, x, offsetY - extraMarginTop, 0, rtl, 0); 313 } 314 } 315 app.restoreState(); 316 app.endVariableText(); 317 return app; 318 } 319 320 /** 321 * Get the <code>PdfAppearance</code> of a list field 322 * @throws IOException on error 323 * @throws DocumentException on error 324 * @return A <code>PdfAppearance</code> 325 */ getListAppearance()326 PdfAppearance getListAppearance() throws IOException, DocumentException { 327 PdfAppearance app = getBorderAppearance(); 328 if (choices == null || choices.length == 0) { 329 return app; 330 } 331 app.beginVariableText(); 332 333 int topChoice = getTopChoice(); 334 335 BaseFont ufont = getRealFont(); 336 float usize = fontSize; 337 if (usize == 0) 338 usize = 12; 339 340 boolean borderExtra = borderStyle == PdfBorderDictionary.STYLE_BEVELED || borderStyle == PdfBorderDictionary.STYLE_INSET; 341 float h = box.getHeight() - borderWidth * 2; 342 float offsetX = borderWidth; 343 if (borderExtra) { 344 h -= borderWidth * 2; 345 offsetX *= 2; 346 } 347 348 float leading = ufont.getFontDescriptor(BaseFont.BBOXURY, usize) - ufont.getFontDescriptor(BaseFont.BBOXLLY, usize); 349 int maxFit = (int)(h / leading) + 1; 350 int first = 0; 351 int last = 0; 352 first = topChoice; 353 last = first + maxFit; 354 if (last > choices.length) 355 last = choices.length; 356 topFirst = first; 357 app.saveState(); 358 app.rectangle(offsetX, offsetX, box.getWidth() - 2 * offsetX, box.getHeight() - 2 * offsetX); 359 app.clip(); 360 app.newPath(); 361 Color fcolor = (textColor == null) ? GrayColor.GRAYBLACK : textColor; 362 363 364 // background boxes for selected value[s] 365 app.setColorFill(new Color(10, 36, 106)); 366 for (int curVal = 0; curVal < choiceSelections.size(); ++curVal) { 367 int curChoice = ((Integer)choiceSelections.get( curVal )).intValue(); 368 // only draw selections within our display range... not strictly necessary with 369 // that clipping rect from above, but it certainly doesn't hurt either 370 if (curChoice >= first && curChoice <= last) { 371 app.rectangle(offsetX, offsetX + h - (curChoice - first + 1) * leading, box.getWidth() - 2 * offsetX, leading); 372 app.fill(); 373 } 374 } 375 float xp = offsetX * 2; 376 float yp = offsetX + h - ufont.getFontDescriptor(BaseFont.BBOXURY, usize); 377 for (int idx = first; idx < last; ++idx, yp -= leading) { 378 String ptext = choices[idx]; 379 int rtl = checkRTL(ptext) ? PdfWriter.RUN_DIRECTION_LTR : PdfWriter.RUN_DIRECTION_NO_BIDI; 380 ptext = removeCRLF(ptext); 381 // highlight selected values against their (presumably) darker background 382 Color textCol = (choiceSelections.contains( new Integer( idx ))) ? GrayColor.GRAYWHITE : fcolor; 383 Phrase phrase = composePhrase(ptext, ufont, textCol, usize); 384 ColumnText.showTextAligned(app, Element.ALIGN_LEFT, phrase, xp, yp, 0, rtl, 0); 385 } 386 app.restoreState(); 387 app.endVariableText(); 388 return app; 389 } 390 391 /** 392 * Gets a new text field. 393 * @throws IOException on error 394 * @throws DocumentException on error 395 * @return a new text field 396 */ getTextField()397 public PdfFormField getTextField() throws IOException, DocumentException { 398 if (maxCharacterLength <= 0) 399 options &= ~COMB; 400 if ((options & COMB) != 0) 401 options &= ~MULTILINE; 402 PdfFormField field = PdfFormField.createTextField(writer, false, false, maxCharacterLength); 403 field.setWidget(box, PdfAnnotation.HIGHLIGHT_INVERT); 404 switch (alignment) { 405 case Element.ALIGN_CENTER: 406 field.setQuadding(PdfFormField.Q_CENTER); 407 break; 408 case Element.ALIGN_RIGHT: 409 field.setQuadding(PdfFormField.Q_RIGHT); 410 break; 411 } 412 if (rotation != 0) 413 field.setMKRotation(rotation); 414 if (fieldName != null) { 415 field.setFieldName(fieldName); 416 if (!"".equals(text)) 417 field.setValueAsString(text); 418 if (defaultText != null) 419 field.setDefaultValueAsString(defaultText); 420 if ((options & READ_ONLY) != 0) 421 field.setFieldFlags(PdfFormField.FF_READ_ONLY); 422 if ((options & REQUIRED) != 0) 423 field.setFieldFlags(PdfFormField.FF_REQUIRED); 424 if ((options & MULTILINE) != 0) 425 field.setFieldFlags(PdfFormField.FF_MULTILINE); 426 if ((options & DO_NOT_SCROLL) != 0) 427 field.setFieldFlags(PdfFormField.FF_DONOTSCROLL); 428 if ((options & PASSWORD) != 0) 429 field.setFieldFlags(PdfFormField.FF_PASSWORD); 430 if ((options & FILE_SELECTION) != 0) 431 field.setFieldFlags(PdfFormField.FF_FILESELECT); 432 if ((options & DO_NOT_SPELL_CHECK) != 0) 433 field.setFieldFlags(PdfFormField.FF_DONOTSPELLCHECK); 434 if ((options & COMB) != 0) 435 field.setFieldFlags(PdfFormField.FF_COMB); 436 } 437 field.setBorderStyle(new PdfBorderDictionary(borderWidth, borderStyle, new PdfDashPattern(3))); 438 PdfAppearance tp = getAppearance(); 439 field.setAppearance(PdfAnnotation.APPEARANCE_NORMAL, tp); 440 PdfAppearance da = (PdfAppearance)tp.getDuplicate(); 441 da.setFontAndSize(getRealFont(), fontSize); 442 if (textColor == null) 443 da.setGrayFill(0); 444 else 445 da.setColorFill(textColor); 446 field.setDefaultAppearanceString(da); 447 if (borderColor != null) 448 field.setMKBorderColor(borderColor); 449 if (backgroundColor != null) 450 field.setMKBackgroundColor(backgroundColor); 451 switch (visibility) { 452 case HIDDEN: 453 field.setFlags(PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_HIDDEN); 454 break; 455 case VISIBLE_BUT_DOES_NOT_PRINT: 456 break; 457 case HIDDEN_BUT_PRINTABLE: 458 field.setFlags(PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_NOVIEW); 459 break; 460 default: 461 field.setFlags(PdfAnnotation.FLAGS_PRINT); 462 break; 463 } 464 return field; 465 } 466 467 /** 468 * Gets a new combo field. 469 * @throws IOException on error 470 * @throws DocumentException on error 471 * @return a new combo field 472 */ getComboField()473 public PdfFormField getComboField() throws IOException, DocumentException { 474 return getChoiceField(false); 475 } 476 477 /** 478 * Gets a new list field. 479 * @throws IOException on error 480 * @throws DocumentException on error 481 * @return a new list field 482 */ getListField()483 public PdfFormField getListField() throws IOException, DocumentException { 484 return getChoiceField(true); 485 } 486 getTopChoice()487 private int getTopChoice() { 488 if (choiceSelections == null || choiceSelections.size() ==0) { 489 return 0; 490 } 491 492 Integer firstValue = (Integer)choiceSelections.get(0); 493 494 if (firstValue == null) { 495 return 0; 496 } 497 498 int topChoice = 0; 499 if (choices != null) { 500 topChoice = firstValue.intValue(); 501 topChoice = Math.min( topChoice, choices.length ); 502 topChoice = Math.max( 0, topChoice); 503 } // else topChoice still 0 504 return topChoice; 505 } 506 getChoiceField(boolean isList)507 protected PdfFormField getChoiceField(boolean isList) throws IOException, DocumentException { 508 options &= (~MULTILINE) & (~COMB); 509 String uchoices[] = choices; 510 if (uchoices == null) 511 uchoices = new String[0]; 512 513 int topChoice = getTopChoice(); 514 515 if (text == null) 516 text = ""; //fixed by Kazuya Ujihara (ujihara.jp) 517 518 if (topChoice >= 0) 519 text = uchoices[topChoice]; 520 521 PdfFormField field = null; 522 String mix[][] = null; 523 524 if (choiceExports == null) { 525 if (isList) 526 field = PdfFormField.createList(writer, uchoices, topChoice); 527 else 528 field = PdfFormField.createCombo(writer, (options & EDIT) != 0, uchoices, topChoice); 529 } 530 else { 531 mix = new String[uchoices.length][2]; 532 for (int k = 0; k < mix.length; ++k) 533 mix[k][0] = mix[k][1] = uchoices[k]; 534 int top = Math.min(uchoices.length, choiceExports.length); 535 for (int k = 0; k < top; ++k) { 536 if (choiceExports[k] != null) 537 mix[k][0] = choiceExports[k]; 538 } 539 if (isList) 540 field = PdfFormField.createList(writer, mix, topChoice); 541 else 542 field = PdfFormField.createCombo(writer, (options & EDIT) != 0, mix, topChoice); 543 } 544 field.setWidget(box, PdfAnnotation.HIGHLIGHT_INVERT); 545 if (rotation != 0) 546 field.setMKRotation(rotation); 547 if (fieldName != null) { 548 field.setFieldName(fieldName); 549 if (uchoices.length > 0) { 550 if (mix != null) { 551 if (choiceSelections.size() < 2) { 552 field.setValueAsString(mix[topChoice][0]); 553 field.setDefaultValueAsString(mix[topChoice][0]); 554 } else { 555 writeMultipleValues( field, mix); 556 } 557 } else { 558 if (choiceSelections.size() < 2) { 559 field.setValueAsString(text); 560 field.setDefaultValueAsString(text); 561 } else { 562 writeMultipleValues( field, null ); 563 } 564 } 565 } 566 if ((options & READ_ONLY) != 0) 567 field.setFieldFlags(PdfFormField.FF_READ_ONLY); 568 if ((options & REQUIRED) != 0) 569 field.setFieldFlags(PdfFormField.FF_REQUIRED); 570 if ((options & DO_NOT_SPELL_CHECK) != 0) 571 field.setFieldFlags(PdfFormField.FF_DONOTSPELLCHECK); 572 if ((options & MULTISELECT) != 0) { 573 field.setFieldFlags( PdfFormField.FF_MULTISELECT ); 574 } 575 } 576 field.setBorderStyle(new PdfBorderDictionary(borderWidth, borderStyle, new PdfDashPattern(3))); 577 PdfAppearance tp; 578 if (isList) { 579 tp = getListAppearance(); 580 if (topFirst > 0) 581 field.put(PdfName.TI, new PdfNumber(topFirst)); 582 } 583 else 584 tp = getAppearance(); 585 field.setAppearance(PdfAnnotation.APPEARANCE_NORMAL, tp); 586 PdfAppearance da = (PdfAppearance)tp.getDuplicate(); 587 da.setFontAndSize(getRealFont(), fontSize); 588 if (textColor == null) 589 da.setGrayFill(0); 590 else 591 da.setColorFill(textColor); 592 field.setDefaultAppearanceString(da); 593 if (borderColor != null) 594 field.setMKBorderColor(borderColor); 595 if (backgroundColor != null) 596 field.setMKBackgroundColor(backgroundColor); 597 switch (visibility) { 598 case HIDDEN: 599 field.setFlags(PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_HIDDEN); 600 break; 601 case VISIBLE_BUT_DOES_NOT_PRINT: 602 break; 603 case HIDDEN_BUT_PRINTABLE: 604 field.setFlags(PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_NOVIEW); 605 break; 606 default: 607 field.setFlags(PdfAnnotation.FLAGS_PRINT); 608 break; 609 } 610 return field; 611 } 612 writeMultipleValues( PdfFormField field, String mix[][] )613 private void writeMultipleValues( PdfFormField field, String mix[][] ) { 614 PdfArray indexes = new PdfArray(); 615 PdfArray values = new PdfArray(); 616 for (int i = 0; i < choiceSelections.size(); ++i) { 617 int idx = ((Integer)choiceSelections.get( i )).intValue(); 618 indexes.add( new PdfNumber( idx ) ); 619 620 if (mix != null) 621 values.add( new PdfString( mix[idx][0] ) ); 622 else if (choices != null) 623 values.add( new PdfString( choices[ idx ] ) ); 624 } 625 626 field.put( PdfName.V, values ); 627 field.put( PdfName.I, indexes ); 628 629 } 630 631 /** 632 * Gets the default text. 633 * @return the default text 634 */ getDefaultText()635 public String getDefaultText() { 636 return this.defaultText; 637 } 638 639 /** 640 * Sets the default text. It is only meaningful for text fields. 641 * @param defaultText the default text 642 */ setDefaultText(String defaultText)643 public void setDefaultText(String defaultText) { 644 this.defaultText = defaultText; 645 } 646 647 /** 648 * Gets the choices to be presented to the user in list/combo fields. 649 * @return the choices to be presented to the user 650 */ getChoices()651 public String[] getChoices() { 652 return this.choices; 653 } 654 655 /** 656 * Sets the choices to be presented to the user in list/combo fields. 657 * @param choices the choices to be presented to the user 658 */ setChoices(String[] choices)659 public void setChoices(String[] choices) { 660 this.choices = choices; 661 } 662 663 /** 664 * Gets the export values in list/combo fields. 665 * @return the export values in list/combo fields 666 */ getChoiceExports()667 public String[] getChoiceExports() { 668 return this.choiceExports; 669 } 670 671 /** 672 * Sets the export values in list/combo fields. If this array 673 * is <CODE>null</CODE> then the choice values will also be used 674 * as the export values. 675 * @param choiceExports the export values in list/combo fields 676 */ setChoiceExports(String[] choiceExports)677 public void setChoiceExports(String[] choiceExports) { 678 this.choiceExports = choiceExports; 679 } 680 681 /** 682 * Gets the zero based index of the selected item. 683 * @return the zero based index of the selected item 684 */ getChoiceSelection()685 public int getChoiceSelection() { 686 return getTopChoice(); 687 } 688 gteChoiceSelections()689 public ArrayList gteChoiceSelections() { 690 return choiceSelections; 691 } 692 693 /** 694 * Sets the zero based index of the selected item. 695 * @param choiceSelection the zero based index of the selected item 696 */ setChoiceSelection(int choiceSelection)697 public void setChoiceSelection(int choiceSelection) { 698 choiceSelections = new ArrayList(); 699 choiceSelections.add( new Integer( choiceSelection ) ); 700 } 701 702 /** 703 * adds another (or a first I suppose) selection to a MULTISELECT list. 704 * This doesn't do anything unless this.options & MUTLISELECT != 0 705 * @param selection new selection 706 */ addChoiceSelection( int selection)707 public void addChoiceSelection( int selection) { 708 if ((this.options & BaseField.MULTISELECT) != 0) { 709 choiceSelections.add( new Integer( selection ) ); 710 } 711 } 712 713 /** 714 * replaces the existing selections with the param. If this field isn't a MULTISELECT 715 * list, all but the first element will be removed. 716 * @param selections new selections. If null, it clear()s the underlying ArrayList. 717 */ setChoiceSelections( ArrayList selections )718 public void setChoiceSelections( ArrayList selections ) { 719 if (selections != null) { 720 choiceSelections = new ArrayList( selections ); 721 if (choiceSelections.size() > 1 && (options & BaseField.MULTISELECT) == 0 ) { 722 // can't have multiple selections in a single-select field 723 while (choiceSelections.size() > 1) { 724 choiceSelections.remove( 1 ); 725 } 726 } 727 728 } else { 729 choiceSelections.clear(); 730 } 731 } 732 getTopFirst()733 int getTopFirst() { 734 return topFirst; 735 } 736 737 /** 738 * Sets extra margins in text fields to better mimic the Acrobat layout. 739 * @param extraMarginLeft the extra margin left 740 * @param extraMarginTop the extra margin top 741 */ setExtraMargin(float extraMarginLeft, float extraMarginTop)742 public void setExtraMargin(float extraMarginLeft, float extraMarginTop) { 743 this.extraMarginLeft = extraMarginLeft; 744 this.extraMarginTop = extraMarginTop; 745 } 746 747 /** 748 * Holds value of property substitutionFonts. 749 */ 750 private ArrayList substitutionFonts; 751 752 /** 753 * Gets the list of substitution fonts. The list is composed of <CODE>BaseFont</CODE> and can be <CODE>null</CODE>. The fonts in this list will be used if the original 754 * font doesn't contain the needed glyphs. 755 * @return the list 756 */ getSubstitutionFonts()757 public ArrayList getSubstitutionFonts() { 758 return this.substitutionFonts; 759 } 760 761 /** 762 * Sets a list of substitution fonts. The list is composed of <CODE>BaseFont</CODE> and can also be <CODE>null</CODE>. The fonts in this list will be used if the original 763 * font doesn't contain the needed glyphs. 764 * @param substitutionFonts the list 765 */ setSubstitutionFonts(ArrayList substitutionFonts)766 public void setSubstitutionFonts(ArrayList substitutionFonts) { 767 this.substitutionFonts = substitutionFonts; 768 } 769 770 /** 771 * Holds value of property extensionFont. 772 */ 773 private BaseFont extensionFont; 774 775 /** 776 * Gets the extensionFont. This font will be searched before the 777 * substitution fonts. It may be <code>null</code>. 778 * @return the extensionFont 779 */ getExtensionFont()780 public BaseFont getExtensionFont() { 781 return this.extensionFont; 782 } 783 784 /** 785 * Sets the extensionFont. This font will be searched before the 786 * substitution fonts. It may be <code>null</code>. 787 * @param extensionFont New value of property extensionFont. 788 */ setExtensionFont(BaseFont extensionFont)789 public void setExtensionFont(BaseFont extensionFont) { 790 this.extensionFont = extensionFont; 791 } 792 }