70 */ 71 private boolean canWrapLines; 72 73 /** 74 * True while the current line is empty. This will remain true after 75 * indenting. 76 */ 77 private boolean isLineEmpty; 78 79 /** 80 * Used when indenting. Will contain the spaces. 81 */ 82 private char[] indentChars; 83 84 /** 85 * Used when writing out a string. 86 */ 87 private char[] tempChars; 88 89 /** 90 * This is used in <code>writeLineSeparator</code> instead of 91 * tempChars. If tempChars were used it would mean write couldn't invoke 92 * <code>writeLineSeparator</code> as it might have been passed 93 * tempChars. 94 */ 95 private char[] newlineChars; 96 97 /** 98 * Used for writing text. 99 */ 100 private Segment segment; 101 102 /** 103 * How the text packages models newlines. 104 * @see #getLineSeparator 105 */ 106 protected static final char NEWLINE = '\n'; 107 108 109 /** 110 * Creates a new AbstractWriter. 111 * Initializes the ElementIterator with the default 112 * root of the document. 252 return false; 253 } 254 255 /** 256 * This abstract method needs to be implemented 257 * by subclasses. Its responsibility is to 258 * iterate over the elements and use the write() 259 * methods to generate output in the desired format. 260 * @throws IOException if an I/O problem has occurred 261 * @throws BadLocationException for an invalid location within 262 * the document 263 */ 264 protected abstract void write() throws IOException, BadLocationException; 265 266 /** 267 * Returns the text associated with the element. 268 * The assumption here is that the element is a 269 * leaf element. Throws a BadLocationException 270 * when encountered. 271 * 272 * @param elem an <code>Element</code> 273 * @exception BadLocationException if pos represents an invalid 274 * location within the document 275 * @return the text as a <code>String</code> 276 */ 277 protected String getText(Element elem) throws BadLocationException { 278 return doc.getText(elem.getStartOffset(), 279 elem.getEndOffset() - elem.getStartOffset()); 280 } 281 282 283 /** 284 * Writes out text. If a range is specified when the constructor 285 * is invoked, then only the appropriate range of text is written 286 * out. 287 * 288 * @param elem an Element. 289 * @exception IOException on any I/O error 290 * @exception BadLocationException if pos represents an invalid 291 * location within the document. 292 */ 293 protected void text(Element elem) throws BadLocationException, 294 IOException { 295 int start = Math.max(getStartOffset(), elem.getStartOffset()); 328 * Sets the current line length. 329 * @param length the new line length 330 * @since 1.3 331 */ 332 protected void setCurrentLineLength(int length) { 333 currLength = length; 334 isLineEmpty = (currLength == 0); 335 } 336 337 /** 338 * Returns the current line length. 339 * @return the current line length 340 * @since 1.3 341 */ 342 protected int getCurrentLineLength() { 343 return currLength; 344 } 345 346 /** 347 * Returns true if the current line should be considered empty. This 348 * is true when <code>getCurrentLineLength</code> == 0 || 349 * <code>indent</code> has been invoked on an empty line. 350 * @return true if the current line should be considered empty 351 * @since 1.3 352 */ 353 protected boolean isLineEmpty() { 354 return isLineEmpty; 355 } 356 357 /** 358 * Sets whether or not lines can be wrapped. This can be toggled 359 * during the writing of lines. For example, outputting HTML might 360 * set this to false when outputting a quoted string. 361 * @param newValue new value for line wrapping 362 * @since 1.3 363 */ 364 protected void setCanWrapLines(boolean newValue) { 365 canWrapLines = newValue; 366 } 367 368 /** 369 * Returns whether or not the lines can be wrapped. If this is false 400 * in the constructor from either the Document, or the System property 401 * line.separator. 402 * @param value the new line separator 403 * @since 1.3 404 */ 405 public void setLineSeparator(String value) { 406 lineSeparator = value; 407 } 408 409 /** 410 * Returns the string used to represent newlines. 411 * @return the string used to represent newlines 412 * @since 1.3 413 */ 414 public String getLineSeparator() { 415 return lineSeparator; 416 } 417 418 /** 419 * Increments the indent level. If indenting would cause 420 * <code>getIndentSpace()</code> *<code>getIndentLevel()</code> to be > 421 * than <code>getLineLength()</code> this will not cause an indent. 422 */ 423 protected void incrIndent() { 424 // Only increment to a certain point. 425 if (offsetIndent > 0) { 426 offsetIndent++; 427 } 428 else { 429 if (++indentLevel * getIndentSpace() >= getLineLength()) { 430 offsetIndent++; 431 --indentLevel; 432 } 433 } 434 } 435 436 /** 437 * Decrements the indent level. 438 */ 439 protected void decrIndent() { 440 if (offsetIndent > 0) { 441 --offsetIndent; 442 } 443 else { 444 indentLevel--; 445 } 446 } 447 448 /** 449 * Returns the current indentation level. That is, the number of times 450 * <code>incrIndent</code> has been invoked minus the number of times 451 * <code>decrIndent</code> has been invoked. 452 * @return the current indentation level 453 * @since 1.3 454 */ 455 protected int getIndentLevel() { 456 return indentLevel; 457 } 458 459 /** 460 * Does indentation. The number of spaces written 461 * out is indent level times the space to map mapping. If the current 462 * line is empty, this will not make it so that the current line is 463 * still considered empty. 464 * 465 * @exception IOException on any I/O error 466 */ 467 protected void indent() throws IOException { 468 int max = getIndentLevel() * getIndentSpace(); 469 if (indentChars == null || max > indentChars.length) { 470 indentChars = new char[max]; 471 for (int counter = 0; counter < max; counter++) { 472 indentChars[counter] = ' '; 473 } 474 } 475 int length = getCurrentLineLength(); 476 boolean wasEmpty = isLineEmpty(); 477 output(indentChars, 0, max); 478 if (wasEmpty && length == 0) { 479 isLineEmpty = true; 480 } 481 } 482 483 /** 484 * Writes out a character. This is implemented to invoke 485 * the <code>write</code> method that takes a char[]. 486 * 487 * @param ch a char. 488 * @exception IOException on any I/O error 489 */ 490 protected void write(char ch) throws IOException { 491 if (tempChars == null) { 492 tempChars = new char[128]; 493 } 494 tempChars[0] = ch; 495 write(tempChars, 0, 1); 496 } 497 498 /** 499 * Writes out a string. This is implemented to invoke the 500 * <code>write</code> method that takes a char[]. 501 * 502 * @param content a String. 503 * @exception IOException on any I/O error 504 */ 505 protected void write(String content) throws IOException { 506 if (content == null) { 507 return; 508 } 509 int size = content.length(); 510 if (tempChars == null || tempChars.length < size) { 511 tempChars = new char[size]; 512 } 513 content.getChars(0, size, tempChars, 0); 514 write(tempChars, 0, size); 515 } 516 517 /** 518 * Writes the line separator. This invokes <code>output</code> directly 519 * as well as setting the <code>lineLength</code> to 0. 520 * @throws IOException on any I/O error 521 * @since 1.3 522 */ 523 protected void writeLineSeparator() throws IOException { 524 String newline = getLineSeparator(); 525 int length = newline.length(); 526 if (newlineChars == null || newlineChars.length < length) { 527 newlineChars = new char[length]; 528 } 529 newline.getChars(0, length, newlineChars, 0); 530 output(newlineChars, 0, length); 531 setCurrentLineLength(0); 532 } 533 534 /** 535 * All write methods call into this one. If <code>getCanWrapLines()</code> 536 * returns false, this will call <code>output</code> with each sequence 537 * of <code>chars</code> that doesn't contain a NEWLINE, followed 538 * by a call to <code>writeLineSeparator</code>. On the other hand, 539 * if <code>getCanWrapLines()</code> returns true, this will split the 540 * string, as necessary, so <code>getLineLength</code> is honored. 541 * The only exception is if the current string contains no whitespace, 542 * and won't fit in which case the line length will exceed 543 * <code>getLineLength</code>. 544 * 545 * @param chars characters to output 546 * @param startIndex starting index 547 * @param length length of output 548 * @throws IOException on any I/O error 549 * @since 1.3 550 */ 551 protected void write(char[] chars, int startIndex, int length) 552 throws IOException { 553 if (!getCanWrapLines()) { 554 // We can not break string, just track if a newline 555 // is in it. 556 int lastIndex = startIndex; 557 int endIndex = startIndex + length; 558 int newlineIndex = indexOf(chars, NEWLINE, startIndex, endIndex); 559 while (newlineIndex != -1) { 560 if (newlineIndex > lastIndex) { 561 output(chars, lastIndex, newlineIndex - lastIndex); 562 } 563 writeLineSeparator(); 667 } 668 669 /** 670 * Writes out the set of attributes as " <name>=<value>" 671 * pairs. It throws an IOException when encountered. 672 * 673 * @param attr an AttributeSet. 674 * @exception IOException on any I/O error 675 */ 676 protected void writeAttributes(AttributeSet attr) throws IOException { 677 678 Enumeration<?> names = attr.getAttributeNames(); 679 while (names.hasMoreElements()) { 680 Object name = names.nextElement(); 681 write(" " + name + "=" + attr.getAttribute(name)); 682 } 683 } 684 685 /** 686 * The last stop in writing out content. All the write methods eventually 687 * make it to this method, which invokes <code>write</code> on the 688 * Writer. 689 * <p>This method also updates the line length based on 690 * <code>length</code>. If this is invoked to output a newline, the 691 * current line length will need to be reset as will no longer be 692 * valid. If it is up to the caller to do this. Use 693 * <code>writeLineSeparator</code> to write out a newline, which will 694 * property update the current line length. 695 * 696 * @param content characters to output 697 * @param start starting index 698 * @param length length of output 699 * @throws IOException on any I/O error 700 * @since 1.3 701 */ 702 protected void output(char[] content, int start, int length) 703 throws IOException { 704 getWriter().write(content, start, length); 705 setCurrentLineLength(getCurrentLineLength() + length); 706 } 707 708 /** 709 * Support method to locate an occurrence of a particular character. 710 */ 711 private int indexOf(char[] chars, char sChar, int startIndex, 712 int endIndex) { 713 while(startIndex < endIndex) { | 70 */ 71 private boolean canWrapLines; 72 73 /** 74 * True while the current line is empty. This will remain true after 75 * indenting. 76 */ 77 private boolean isLineEmpty; 78 79 /** 80 * Used when indenting. Will contain the spaces. 81 */ 82 private char[] indentChars; 83 84 /** 85 * Used when writing out a string. 86 */ 87 private char[] tempChars; 88 89 /** 90 * This is used in {@code writeLineSeparator} instead of 91 * tempChars. If tempChars were used it would mean write couldn't invoke 92 * {@code writeLineSeparator} as it might have been passed 93 * tempChars. 94 */ 95 private char[] newlineChars; 96 97 /** 98 * Used for writing text. 99 */ 100 private Segment segment; 101 102 /** 103 * How the text packages models newlines. 104 * @see #getLineSeparator 105 */ 106 protected static final char NEWLINE = '\n'; 107 108 109 /** 110 * Creates a new AbstractWriter. 111 * Initializes the ElementIterator with the default 112 * root of the document. 252 return false; 253 } 254 255 /** 256 * This abstract method needs to be implemented 257 * by subclasses. Its responsibility is to 258 * iterate over the elements and use the write() 259 * methods to generate output in the desired format. 260 * @throws IOException if an I/O problem has occurred 261 * @throws BadLocationException for an invalid location within 262 * the document 263 */ 264 protected abstract void write() throws IOException, BadLocationException; 265 266 /** 267 * Returns the text associated with the element. 268 * The assumption here is that the element is a 269 * leaf element. Throws a BadLocationException 270 * when encountered. 271 * 272 * @param elem an {@code Element} 273 * @exception BadLocationException if pos represents an invalid 274 * location within the document 275 * @return the text as a {@code String} 276 */ 277 protected String getText(Element elem) throws BadLocationException { 278 return doc.getText(elem.getStartOffset(), 279 elem.getEndOffset() - elem.getStartOffset()); 280 } 281 282 283 /** 284 * Writes out text. If a range is specified when the constructor 285 * is invoked, then only the appropriate range of text is written 286 * out. 287 * 288 * @param elem an Element. 289 * @exception IOException on any I/O error 290 * @exception BadLocationException if pos represents an invalid 291 * location within the document. 292 */ 293 protected void text(Element elem) throws BadLocationException, 294 IOException { 295 int start = Math.max(getStartOffset(), elem.getStartOffset()); 328 * Sets the current line length. 329 * @param length the new line length 330 * @since 1.3 331 */ 332 protected void setCurrentLineLength(int length) { 333 currLength = length; 334 isLineEmpty = (currLength == 0); 335 } 336 337 /** 338 * Returns the current line length. 339 * @return the current line length 340 * @since 1.3 341 */ 342 protected int getCurrentLineLength() { 343 return currLength; 344 } 345 346 /** 347 * Returns true if the current line should be considered empty. This 348 * is true when {@code getCurrentLineLength} == 0 || 349 * {@code indent} has been invoked on an empty line. 350 * @return true if the current line should be considered empty 351 * @since 1.3 352 */ 353 protected boolean isLineEmpty() { 354 return isLineEmpty; 355 } 356 357 /** 358 * Sets whether or not lines can be wrapped. This can be toggled 359 * during the writing of lines. For example, outputting HTML might 360 * set this to false when outputting a quoted string. 361 * @param newValue new value for line wrapping 362 * @since 1.3 363 */ 364 protected void setCanWrapLines(boolean newValue) { 365 canWrapLines = newValue; 366 } 367 368 /** 369 * Returns whether or not the lines can be wrapped. If this is false 400 * in the constructor from either the Document, or the System property 401 * line.separator. 402 * @param value the new line separator 403 * @since 1.3 404 */ 405 public void setLineSeparator(String value) { 406 lineSeparator = value; 407 } 408 409 /** 410 * Returns the string used to represent newlines. 411 * @return the string used to represent newlines 412 * @since 1.3 413 */ 414 public String getLineSeparator() { 415 return lineSeparator; 416 } 417 418 /** 419 * Increments the indent level. If indenting would cause 420 * {@code getIndentSpace()} *{@code getIndentLevel()} to be > 421 * than {@code getLineLength()} this will not cause an indent. 422 */ 423 protected void incrIndent() { 424 // Only increment to a certain point. 425 if (offsetIndent > 0) { 426 offsetIndent++; 427 } 428 else { 429 if (++indentLevel * getIndentSpace() >= getLineLength()) { 430 offsetIndent++; 431 --indentLevel; 432 } 433 } 434 } 435 436 /** 437 * Decrements the indent level. 438 */ 439 protected void decrIndent() { 440 if (offsetIndent > 0) { 441 --offsetIndent; 442 } 443 else { 444 indentLevel--; 445 } 446 } 447 448 /** 449 * Returns the current indentation level. That is, the number of times 450 * {@code incrIndent} has been invoked minus the number of times 451 * {@code decrIndent} has been invoked. 452 * @return the current indentation level 453 * @since 1.3 454 */ 455 protected int getIndentLevel() { 456 return indentLevel; 457 } 458 459 /** 460 * Does indentation. The number of spaces written 461 * out is indent level times the space to map mapping. If the current 462 * line is empty, this will not make it so that the current line is 463 * still considered empty. 464 * 465 * @exception IOException on any I/O error 466 */ 467 protected void indent() throws IOException { 468 int max = getIndentLevel() * getIndentSpace(); 469 if (indentChars == null || max > indentChars.length) { 470 indentChars = new char[max]; 471 for (int counter = 0; counter < max; counter++) { 472 indentChars[counter] = ' '; 473 } 474 } 475 int length = getCurrentLineLength(); 476 boolean wasEmpty = isLineEmpty(); 477 output(indentChars, 0, max); 478 if (wasEmpty && length == 0) { 479 isLineEmpty = true; 480 } 481 } 482 483 /** 484 * Writes out a character. This is implemented to invoke 485 * the {@code write} method that takes a char[]. 486 * 487 * @param ch a char. 488 * @exception IOException on any I/O error 489 */ 490 protected void write(char ch) throws IOException { 491 if (tempChars == null) { 492 tempChars = new char[128]; 493 } 494 tempChars[0] = ch; 495 write(tempChars, 0, 1); 496 } 497 498 /** 499 * Writes out a string. This is implemented to invoke the 500 * {@code write} method that takes a char[]. 501 * 502 * @param content a String. 503 * @exception IOException on any I/O error 504 */ 505 protected void write(String content) throws IOException { 506 if (content == null) { 507 return; 508 } 509 int size = content.length(); 510 if (tempChars == null || tempChars.length < size) { 511 tempChars = new char[size]; 512 } 513 content.getChars(0, size, tempChars, 0); 514 write(tempChars, 0, size); 515 } 516 517 /** 518 * Writes the line separator. This invokes {@code output} directly 519 * as well as setting the {@code lineLength} to 0. 520 * @throws IOException on any I/O error 521 * @since 1.3 522 */ 523 protected void writeLineSeparator() throws IOException { 524 String newline = getLineSeparator(); 525 int length = newline.length(); 526 if (newlineChars == null || newlineChars.length < length) { 527 newlineChars = new char[length]; 528 } 529 newline.getChars(0, length, newlineChars, 0); 530 output(newlineChars, 0, length); 531 setCurrentLineLength(0); 532 } 533 534 /** 535 * All write methods call into this one. If {@code getCanWrapLines()} 536 * returns false, this will call {@code output} with each sequence 537 * of {@code chars} that doesn't contain a NEWLINE, followed 538 * by a call to {@code writeLineSeparator}. On the other hand, 539 * if {@code getCanWrapLines()} returns true, this will split the 540 * string, as necessary, so {@code getLineLength} is honored. 541 * The only exception is if the current string contains no whitespace, 542 * and won't fit in which case the line length will exceed 543 * {@code getLineLength}. 544 * 545 * @param chars characters to output 546 * @param startIndex starting index 547 * @param length length of output 548 * @throws IOException on any I/O error 549 * @since 1.3 550 */ 551 protected void write(char[] chars, int startIndex, int length) 552 throws IOException { 553 if (!getCanWrapLines()) { 554 // We can not break string, just track if a newline 555 // is in it. 556 int lastIndex = startIndex; 557 int endIndex = startIndex + length; 558 int newlineIndex = indexOf(chars, NEWLINE, startIndex, endIndex); 559 while (newlineIndex != -1) { 560 if (newlineIndex > lastIndex) { 561 output(chars, lastIndex, newlineIndex - lastIndex); 562 } 563 writeLineSeparator(); 667 } 668 669 /** 670 * Writes out the set of attributes as " <name>=<value>" 671 * pairs. It throws an IOException when encountered. 672 * 673 * @param attr an AttributeSet. 674 * @exception IOException on any I/O error 675 */ 676 protected void writeAttributes(AttributeSet attr) throws IOException { 677 678 Enumeration<?> names = attr.getAttributeNames(); 679 while (names.hasMoreElements()) { 680 Object name = names.nextElement(); 681 write(" " + name + "=" + attr.getAttribute(name)); 682 } 683 } 684 685 /** 686 * The last stop in writing out content. All the write methods eventually 687 * make it to this method, which invokes {@code write} on the 688 * Writer. 689 * <p>This method also updates the line length based on 690 * {@code length}. If this is invoked to output a newline, the 691 * current line length will need to be reset as will no longer be 692 * valid. If it is up to the caller to do this. Use 693 * {@code writeLineSeparator} to write out a newline, which will 694 * property update the current line length. 695 * 696 * @param content characters to output 697 * @param start starting index 698 * @param length length of output 699 * @throws IOException on any I/O error 700 * @since 1.3 701 */ 702 protected void output(char[] content, int start, int length) 703 throws IOException { 704 getWriter().write(content, start, length); 705 setCurrentLineLength(getCurrentLineLength() + length); 706 } 707 708 /** 709 * Support method to locate an occurrence of a particular character. 710 */ 711 private int indexOf(char[] chars, char sChar, int startIndex, 712 int endIndex) { 713 while(startIndex < endIndex) { |