001/* 002 * $Id: List.java 4885 2011-05-29 13:49:53Z 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; 045 046import java.util.ArrayList; 047 048import com.itextpdf.text.api.Indentable; 049import com.itextpdf.text.factories.RomanAlphabetFactory; 050 051/** 052 * A <CODE>List</CODE> contains several <CODE>ListItem</CODE>s. 053 * <P> 054 * <B>Example 1:</B> 055 * <BLOCKQUOTE><PRE> 056 * <STRONG>List list = new List(true, 20);</STRONG> 057 * <STRONG>list.add(new ListItem("First line"));</STRONG> 058 * <STRONG>list.add(new ListItem("The second line is longer to see what happens once the end of the line is reached. Will it start on a new line?"));</STRONG> 059 * <STRONG>list.add(new ListItem("Third line"));</STRONG> 060 * </PRE></BLOCKQUOTE> 061 * 062 * The result of this code looks like this: 063 * <OL> 064 * <LI> 065 * First line 066 * </LI> 067 * <LI> 068 * The second line is longer to see what happens once the end of the line is reached. Will it start on a new line? 069 * </LI> 070 * <LI> 071 * Third line 072 * </LI> 073 * </OL> 074 * 075 * <B>Example 2:</B> 076 * <BLOCKQUOTE><PRE> 077 * <STRONG>List overview = new List(false, 10);</STRONG> 078 * <STRONG>overview.add(new ListItem("This is an item"));</STRONG> 079 * <STRONG>overview.add("This is another item");</STRONG> 080 * </PRE></BLOCKQUOTE> 081 * 082 * The result of this code looks like this: 083 * <UL> 084 * <LI> 085 * This is an item 086 * </LI> 087 * <LI> 088 * This is another item 089 * </LI> 090 * </UL> 091 * 092 * @see Element 093 * @see ListItem 094 */ 095 096public class List implements TextElementArray, Indentable { 097 098 // constants 099 100 /** a possible value for the numbered parameter */ 101 public static final boolean ORDERED = true; 102 /** a possible value for the numbered parameter */ 103 public static final boolean UNORDERED = false; 104 /** a possible value for the lettered parameter */ 105 public static final boolean NUMERICAL = false; 106 /** a possible value for the lettered parameter */ 107 public static final boolean ALPHABETICAL = true; 108 /** a possible value for the lettered parameter */ 109 public static final boolean UPPERCASE = false; 110 /** a possible value for the lettered parameter */ 111 public static final boolean LOWERCASE = true; 112 113 // member variables 114 115 /** This is the <CODE>ArrayList</CODE> containing the different <CODE>ListItem</CODE>s. */ 116 protected ArrayList<Element> list = new ArrayList<Element>(); 117 118 /** Indicates if the list has to be numbered. */ 119 protected boolean numbered = false; 120 /** Indicates if the listsymbols are numerical or alphabetical. */ 121 protected boolean lettered = false; 122 /** Indicates if the listsymbols are lowercase or uppercase. */ 123 protected boolean lowercase = false; 124 /** Indicates if the indentation has to be set automatically. */ 125 protected boolean autoindent = false; 126 /** Indicates if the indentation of all the items has to be aligned. */ 127 protected boolean alignindent = false; 128 129 /** This variable indicates the first number of a numbered list. */ 130 protected int first = 1; 131 /** This is the listsymbol of a list that is not numbered. */ 132 protected Chunk symbol = new Chunk("- "); 133 /** 134 * In case you are using numbered/lettered lists, this String is added before the number/letter. 135 * @since iText 2.1.1 136 */ 137 protected String preSymbol = ""; 138 /** 139 * In case you are using numbered/lettered lists, this String is added after the number/letter. 140 * @since iText 2.1.1 141 */ 142 protected String postSymbol = ". "; 143 144 /** The indentation of this list on the left side. */ 145 protected float indentationLeft = 0; 146 /** The indentation of this list on the right side. */ 147 protected float indentationRight = 0; 148 /** The indentation of the listitems. */ 149 protected float symbolIndent = 0; 150 151 // constructors 152 153 /** Constructs a <CODE>List</CODE>. */ 154 public List() { 155 this(false, false); 156 } 157 158 /** 159 * Constructs a <CODE>List</CODE> with a specific symbol indentation. 160 * @param symbolIndent the symbol indentation 161 * @since iText 2.0.8 162 */ 163 public List(final float symbolIndent) { 164 this.symbolIndent = symbolIndent; 165 } 166 167 /** 168 * Constructs a <CODE>List</CODE>. 169 * @param numbered a boolean 170 */ 171 public List(final boolean numbered) { 172 this(numbered, false); 173 } 174 175 /** 176 * Constructs a <CODE>List</CODE>. 177 * @param numbered a boolean 178 * @param lettered has the list to be 'numbered' with letters 179 */ 180 public List(final boolean numbered, final boolean lettered) { 181 this.numbered = numbered; 182 this.lettered = lettered; 183 this.autoindent = true; 184 this.alignindent = true; 185 } 186 187 /** 188 * Constructs a <CODE>List</CODE>. 189 * <P> 190 * Remark: the parameter <VAR>symbolIndent</VAR> is important for instance when 191 * generating PDF-documents; it indicates the indentation of the listsymbol. 192 * It is not important for HTML-documents. 193 * 194 * @param numbered a boolean 195 * @param symbolIndent the indentation that has to be used for the listsymbol 196 */ 197 public List(final boolean numbered, final float symbolIndent) { 198 this(numbered, false, symbolIndent); 199 } 200 201 /** 202 * Creates a list 203 * @param numbered has the list to be numbered? 204 * @param lettered has the list to be 'numbered' with letters 205 * @param symbolIndent the indentation of the symbol 206 */ 207 public List(final boolean numbered, final boolean lettered, final float symbolIndent) { 208 this.numbered = numbered; 209 this.lettered = lettered; 210 this.symbolIndent = symbolIndent; 211 } 212 213 // implementation of the Element-methods 214 215 /** 216 * Processes the element by adding it (or the different parts) to an 217 * <CODE>ElementListener</CODE>. 218 * 219 * @param listener an <CODE>ElementListener</CODE> 220 * @return <CODE>true</CODE> if the element was processed successfully 221 */ 222 public boolean process(final ElementListener listener) { 223 try { 224 for (Element element : list) { 225 listener.add(element); 226 } 227 return true; 228 } 229 catch(DocumentException de) { 230 return false; 231 } 232 } 233 234 /** 235 * Gets the type of the text element. 236 * 237 * @return a type 238 */ 239 public int type() { 240 return Element.LIST; 241 } 242 243 /** 244 * Gets all the chunks in this element. 245 * 246 * @return an <CODE>ArrayList</CODE> 247 */ 248 public java.util.List<Chunk> getChunks() { 249 java.util.List<Chunk> tmp = new ArrayList<Chunk>(); 250 for (Element element : list) { 251 tmp.addAll(element.getChunks()); 252 } 253 return tmp; 254 } 255 256 // methods to set the membervariables 257 258 /** 259 * Adds a <CODE>String</CODE> to the <CODE>List</CODE>. 260 * 261 * @param s the element to add. 262 * @return true if adding the object succeeded 263 * @since 5.0.1 264 */ 265 public boolean add(final String s) { 266 if (s != null) { 267 return this.add(new ListItem(s)); 268 } 269 return false; 270 } 271 272 /** 273 * Adds an <CODE>Element</CODE> to the <CODE>List</CODE>. 274 * 275 * @param o the element to add. 276 * @return true if adding the object succeeded 277 * @since 5.0.1 (signature changed to use Element) 278 */ 279 public boolean add(final Element o) { 280 if (o instanceof ListItem) { 281 ListItem item = (ListItem) o; 282 if (numbered || lettered) { 283 Chunk chunk = new Chunk(preSymbol, symbol.getFont()); 284 chunk.setAttributes(symbol.getAttributes()); 285 int index = first + list.size(); 286 if ( lettered ) 287 chunk.append(RomanAlphabetFactory.getString(index, lowercase)); 288 else 289 chunk.append(String.valueOf(index)); 290 chunk.append(postSymbol); 291 item.setListSymbol(chunk); 292 } 293 else { 294 item.setListSymbol(symbol); 295 } 296 item.setIndentationLeft(symbolIndent, autoindent); 297 item.setIndentationRight(0); 298 return list.add(item); 299 } 300 else if (o instanceof List) { 301 List nested = (List) o; 302 nested.setIndentationLeft(nested.getIndentationLeft() + symbolIndent); 303 first--; 304 return list.add(nested); 305 } 306 return false; 307 } 308 309 // extra methods 310 311 /** Makes sure all the items in the list have the same indentation. */ 312 public void normalizeIndentation() { 313 float max = 0; 314 for (Element o : list) { 315 if (o instanceof ListItem) { 316 max = Math.max(max, ((ListItem)o).getIndentationLeft()); 317 } 318 } 319 for (Element o : list) { 320 if (o instanceof ListItem) { 321 ((ListItem)o).setIndentationLeft(max); 322 } 323 } 324 } 325 326 // setters 327 328 /** 329 * @param numbered the numbered to set 330 */ 331 public void setNumbered(final boolean numbered) { 332 this.numbered = numbered; 333 } 334 335 /** 336 * @param lettered the lettered to set 337 */ 338 public void setLettered(final boolean lettered) { 339 this.lettered = lettered; 340 } 341 342 /** 343 * @param uppercase the uppercase to set 344 */ 345 public void setLowercase(final boolean uppercase) { 346 this.lowercase = uppercase; 347 } 348 349 /** 350 * @param autoindent the autoindent to set 351 */ 352 public void setAutoindent(final boolean autoindent) { 353 this.autoindent = autoindent; 354 } 355 /** 356 * @param alignindent the alignindent to set 357 */ 358 public void setAlignindent(final boolean alignindent) { 359 this.alignindent = alignindent; 360 } 361 362 /** 363 * Sets the number that has to come first in the list. 364 * 365 * @param first a number 366 */ 367 public void setFirst(final int first) { 368 this.first = first; 369 } 370 371 /** 372 * Sets the listsymbol. 373 * 374 * @param symbol a <CODE>Chunk</CODE> 375 */ 376 public void setListSymbol(final Chunk symbol) { 377 this.symbol = symbol; 378 } 379 380 /** 381 * Sets the listsymbol. 382 * <P> 383 * This is a shortcut for <CODE>setListSymbol(Chunk symbol)</CODE>. 384 * 385 * @param symbol a <CODE>String</CODE> 386 */ 387 public void setListSymbol(final String symbol) { 388 this.symbol = new Chunk(symbol); 389 } 390 391 /** 392 * Sets the indentation of this paragraph on the left side. 393 * 394 * @param indentation the new indentation 395 */ 396 public void setIndentationLeft(final float indentation) { 397 this.indentationLeft = indentation; 398 } 399 400 /** 401 * Sets the indentation of this paragraph on the right side. 402 * 403 * @param indentation the new indentation 404 */ 405 public void setIndentationRight(final float indentation) { 406 this.indentationRight = indentation; 407 } 408 409 /** 410 * @param symbolIndent the symbolIndent to set 411 */ 412 public void setSymbolIndent(final float symbolIndent) { 413 this.symbolIndent = symbolIndent; 414 } 415 416 // methods to retrieve information 417 418 /** 419 * Gets all the items in the list. 420 * 421 * @return an <CODE>ArrayList</CODE> containing <CODE>ListItem</CODE>s. 422 */ 423 public ArrayList<Element> getItems() { 424 return list; 425 } 426 427 /** 428 * Gets the size of the list. 429 * 430 * @return a <CODE>size</CODE> 431 */ 432 public int size() { 433 return list.size(); 434 } 435 436 /** 437 * Returns <CODE>true</CODE> if the list is empty. 438 * 439 * @return <CODE>true</CODE> if the list is empty 440 */ 441 public boolean isEmpty() { 442 return list.isEmpty(); 443 } 444 445 /** 446 * Gets the leading of the first listitem. 447 * 448 * @return a <CODE>leading</CODE> 449 */ 450 public float getTotalLeading() { 451 if (list.size() < 1) { 452 return -1; 453 } 454 ListItem item = (ListItem) list.get(0); 455 return item.getTotalLeading(); 456 } 457 458 // getters 459 460 /** 461 * Checks if the list is numbered. 462 * @return <CODE>true</CODE> if the list is numbered, <CODE>false</CODE> otherwise. 463 */ 464 465 public boolean isNumbered() { 466 return numbered; 467 } 468 469 /** 470 * Checks if the list is lettered. 471 * @return <CODE>true</CODE> if the list is lettered, <CODE>false</CODE> otherwise. 472 */ 473 public boolean isLettered() { 474 return lettered; 475 } 476 477 /** 478 * Checks if the list lettering is lowercase. 479 * @return <CODE>true</CODE> if it is lowercase, <CODE>false</CODE> otherwise. 480 */ 481 public boolean isLowercase() { 482 return lowercase; 483 } 484 485 /** 486 * Checks if the indentation of list items is done automatically. 487 * @return the autoindent 488 */ 489 public boolean isAutoindent() { 490 return autoindent; 491 } 492 493 /** 494 * Checks if all the listitems should be aligned. 495 * @return the alignindent 496 */ 497 public boolean isAlignindent() { 498 return alignindent; 499 } 500 501 /** 502 * Gets the first number . 503 * @return a number 504 */ 505 public int getFirst() { 506 return first; 507 } 508 509 /** 510 * Gets the Chunk containing the symbol. 511 * @return a Chunk with a symbol 512 */ 513 public Chunk getSymbol() { 514 return symbol; 515 } 516 517 /** 518 * Gets the indentation of this paragraph on the left side. 519 * @return the indentation 520 */ 521 public float getIndentationLeft() { 522 return indentationLeft; 523 } 524 525 /** 526 * Gets the indentation of this paragraph on the right side. 527 * @return the indentation 528 */ 529 public float getIndentationRight() { 530 return indentationRight; 531 } 532 533 /** 534 * Gets the symbol indentation. 535 * @return the symbol indentation 536 */ 537 public float getSymbolIndent() { 538 return symbolIndent; 539 } 540 /** 541 * @see com.itextpdf.text.Element#isContent() 542 * @since iText 2.0.8 543 */ 544 public boolean isContent() { 545 return true; 546 } 547 548 /** 549 * @see com.itextpdf.text.Element#isNestable() 550 * @since iText 2.0.8 551 */ 552 public boolean isNestable() { 553 return true; 554 } 555 556 /** 557 * Returns the String that is after a number or letter in the list symbol. 558 * @return the String that is after a number or letter in the list symbol 559 * @since iText 2.1.1 560 */ 561 public String getPostSymbol() { 562 return postSymbol; 563 } 564 565 /** 566 * Sets the String that has to be added after a number or letter in the list symbol. 567 * @since iText 2.1.1 568 * @param postSymbol the String that has to be added after a number or letter in the list symbol. 569 */ 570 public void setPostSymbol(final String postSymbol) { 571 this.postSymbol = postSymbol; 572 } 573 574 /** 575 * Returns the String that is before a number or letter in the list symbol. 576 * @return the String that is before a number or letter in the list symbol 577 * @since iText 2.1.1 578 */ 579 public String getPreSymbol() { 580 return preSymbol; 581 } 582 583 /** 584 * Sets the String that has to be added before a number or letter in the list symbol. 585 * @since iText 2.1.1 586 * @param preSymbol the String that has to be added before a number or letter in the list symbol. 587 */ 588 public void setPreSymbol(final String preSymbol) { 589 this.preSymbol = preSymbol; 590 } 591 592}