1 /*
2 * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
169 * Initializes the ElementIterator with the
170 * element passed in.
171 *
172 * @param w a Writer
173 * @param root an Element
174 * @param pos The location in the document to fetch the
175 * content.
176 * @param len The amount to write out.
177 */
178 protected AbstractWriter(Writer w, Element root, int pos, int len) {
179 this.doc = root.getDocument();
180 it = new ElementIterator(root);
181 out = w;
182 startOffset = pos;
183 endOffset = pos + len;
184 canWrapLines = true;
185 }
186
187 /**
188 * Returns the first offset to be output.
189 *
190 * @since 1.3
191 */
192 public int getStartOffset() {
193 return startOffset;
194 }
195
196 /**
197 * Returns the last offset to be output.
198 *
199 * @since 1.3
200 */
201 public int getEndOffset() {
202 return endOffset;
203 }
204
205 /**
206 * Fetches the ElementIterator.
207 *
208 * @return the ElementIterator.
209 */
210 protected ElementIterator getElementIterator() {
211 return it;
212 }
213
214 /**
215 * Returns the Writer that is used to output the content.
216 *
217 * @since 1.3
218 */
219 protected Writer getWriter() {
220 return out;
221 }
222
223 /**
224 * Fetches the document.
225 *
226 * @return the Document.
227 */
228 protected Document getDocument() {
229 return doc;
230 }
231
232 /**
233 * This method determines whether the current element
234 * is in the range specified. When no range is specified,
235 * the range is initialized to be the entire document.
236 * inRange() returns true if the range specified intersects
240 * @return boolean that indicates whether the element
241 * is in the range.
242 */
243 protected boolean inRange(Element next) {
244 int startOffset = getStartOffset();
245 int endOffset = getEndOffset();
246 if ((next.getStartOffset() >= startOffset &&
247 next.getStartOffset() < endOffset) ||
248 (startOffset >= next.getStartOffset() &&
249 startOffset < next.getEndOffset())) {
250 return true;
251 }
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 */
261 abstract protected void write() throws IOException, BadLocationException;
262
263 /**
264 * Returns the text associated with the element.
265 * The assumption here is that the element is a
266 * leaf element. Throws a BadLocationException
267 * when encountered.
268 *
269 * @param elem an <code>Element</code>
270 * @exception BadLocationException if pos represents an invalid
271 * location within the document
272 * @return the text as a <code>String</code>
273 */
274 protected String getText(Element elem) throws BadLocationException {
275 return doc.getText(elem.getStartOffset(),
276 elem.getEndOffset() - elem.getStartOffset());
277 }
278
279
297 }
298 getDocument().getText(start, end - start, segment);
299 if (segment.count > 0) {
300 write(segment.array, segment.offset, segment.count);
301 }
302 }
303 }
304
305 /**
306 * Enables subclasses to set the number of characters they
307 * want written per line. The default is 100.
308 *
309 * @param l the maximum line length.
310 */
311 protected void setLineLength(int l) {
312 maxLineLength = l;
313 }
314
315 /**
316 * Returns the maximum line length.
317 *
318 * @since 1.3
319 */
320 protected int getLineLength() {
321 return maxLineLength;
322 }
323
324 /**
325 * Sets the current line length.
326 *
327 * @since 1.3
328 */
329 protected void setCurrentLineLength(int length) {
330 currLength = length;
331 isLineEmpty = (currLength == 0);
332 }
333
334 /**
335 * Returns the current line length.
336 *
337 * @since 1.3
338 */
339 protected int getCurrentLineLength() {
340 return currLength;
341 }
342
343 /**
344 * Returns true if the current line should be considered empty. This
345 * is true when <code>getCurrentLineLength</code> == 0 ||
346 * <code>indent</code> has been invoked on an empty line.
347 *
348 * @since 1.3
349 */
350 protected boolean isLineEmpty() {
351 return isLineEmpty;
352 }
353
354 /**
355 * Sets whether or not lines can be wrapped. This can be toggled
356 * during the writing of lines. For example, outputting HTML might
357 * set this to false when outputting a quoted string.
358 *
359 * @since 1.3
360 */
361 protected void setCanWrapLines(boolean newValue) {
362 canWrapLines = newValue;
363 }
364
365 /**
366 * Returns whether or not the lines can be wrapped. If this is false
367 * no lineSeparator's will be output.
368 *
369 * @since 1.3
370 */
371 protected boolean getCanWrapLines() {
372 return canWrapLines;
373 }
374
375 /**
376 * Enables subclasses to specify how many spaces an indent
377 * maps to. When indentation takes place, the indent level
378 * is multiplied by this mapping. The default is 2.
379 *
380 * @param space an int representing the space to indent mapping.
381 */
382 protected void setIndentSpace(int space) {
383 indentSpace = space;
384 }
385
386 /**
387 * Returns the amount of space to indent.
388 *
389 * @since 1.3
390 */
391 protected int getIndentSpace() {
392 return indentSpace;
393 }
394
395 /**
396 * Sets the String used to represent newlines. This is initialized
397 * in the constructor from either the Document, or the System property
398 * line.separator.
399 *
400 * @since 1.3
401 */
402 public void setLineSeparator(String value) {
403 lineSeparator = value;
404 }
405
406 /**
407 * Returns the string used to represent newlines.
408 *
409 * @since 1.3
410 */
411 public String getLineSeparator() {
412 return lineSeparator;
413 }
414
415 /**
416 * Increments the indent level. If indenting would cause
417 * <code>getIndentSpace()</code> *<code>getIndentLevel()</code> to be >
418 * than <code>getLineLength()</code> this will not cause an indent.
419 */
420 protected void incrIndent() {
421 // Only increment to a certain point.
422 if (offsetIndent > 0) {
423 offsetIndent++;
424 }
425 else {
426 if (++indentLevel * getIndentSpace() >= getLineLength()) {
427 offsetIndent++;
428 --indentLevel;
429 }
430 }
431 }
432
433 /**
434 * Decrements the indent level.
435 */
436 protected void decrIndent() {
437 if (offsetIndent > 0) {
438 --offsetIndent;
439 }
440 else {
441 indentLevel--;
442 }
443 }
444
445 /**
446 * Returns the current indentation level. That is, the number of times
447 * <code>incrIndent</code> has been invoked minus the number of times
448 * <code>decrIndent</code> has been invoked.
449 *
450 * @since 1.3
451 */
452 protected int getIndentLevel() {
453 return indentLevel;
454 }
455
456 /**
457 * Does indentation. The number of spaces written
458 * out is indent level times the space to map mapping. If the current
459 * line is empty, this will not make it so that the current line is
460 * still considered empty.
461 *
462 * @exception IOException on any I/O error
463 */
464 protected void indent() throws IOException {
465 int max = getIndentLevel() * getIndentSpace();
466 if (indentChars == null || max > indentChars.length) {
467 indentChars = new char[max];
468 for (int counter = 0; counter < max; counter++) {
469 indentChars[counter] = ' ';
497 * <code>write</code> method that takes a char[].
498 *
499 * @param content a String.
500 * @exception IOException on any I/O error
501 */
502 protected void write(String content) throws IOException {
503 if (content == null) {
504 return;
505 }
506 int size = content.length();
507 if (tempChars == null || tempChars.length < size) {
508 tempChars = new char[size];
509 }
510 content.getChars(0, size, tempChars, 0);
511 write(tempChars, 0, size);
512 }
513
514 /**
515 * Writes the line separator. This invokes <code>output</code> directly
516 * as well as setting the <code>lineLength</code> to 0.
517 *
518 * @since 1.3
519 */
520 protected void writeLineSeparator() throws IOException {
521 String newline = getLineSeparator();
522 int length = newline.length();
523 if (newlineChars == null || newlineChars.length < length) {
524 newlineChars = new char[length];
525 }
526 newline.getChars(0, length, newlineChars, 0);
527 output(newlineChars, 0, length);
528 setCurrentLineLength(0);
529 }
530
531 /**
532 * All write methods call into this one. If <code>getCanWrapLines()</code>
533 * returns false, this will call <code>output</code> with each sequence
534 * of <code>chars</code> that doesn't contain a NEWLINE, followed
535 * by a call to <code>writeLineSeparator</code>. On the other hand,
536 * if <code>getCanWrapLines()</code> returns true, this will split the
537 * string, as necessary, so <code>getLineLength</code> is honored.
538 * The only exception is if the current string contains no whitespace,
539 * and won't fit in which case the line length will exceed
540 * <code>getLineLength</code>.
541 *
542 * @since 1.3
543 */
544 protected void write(char[] chars, int startIndex, int length)
545 throws IOException {
546 if (!getCanWrapLines()) {
547 // We can not break string, just track if a newline
548 // is in it.
549 int lastIndex = startIndex;
550 int endIndex = startIndex + length;
551 int newlineIndex = indexOf(chars, NEWLINE, startIndex, endIndex);
552 while (newlineIndex != -1) {
553 if (newlineIndex > lastIndex) {
554 output(chars, lastIndex, newlineIndex - lastIndex);
555 }
556 writeLineSeparator();
557 lastIndex = newlineIndex + 1;
558 newlineIndex = indexOf(chars, '\n', lastIndex, endIndex);
559 }
560 if (lastIndex < endIndex) {
561 output(chars, lastIndex, endIndex - lastIndex);
669 protected void writeAttributes(AttributeSet attr) throws IOException {
670
671 Enumeration<?> names = attr.getAttributeNames();
672 while (names.hasMoreElements()) {
673 Object name = names.nextElement();
674 write(" " + name + "=" + attr.getAttribute(name));
675 }
676 }
677
678 /**
679 * The last stop in writing out content. All the write methods eventually
680 * make it to this method, which invokes <code>write</code> on the
681 * Writer.
682 * <p>This method also updates the line length based on
683 * <code>length</code>. If this is invoked to output a newline, the
684 * current line length will need to be reset as will no longer be
685 * valid. If it is up to the caller to do this. Use
686 * <code>writeLineSeparator</code> to write out a newline, which will
687 * property update the current line length.
688 *
689 * @since 1.3
690 */
691 protected void output(char[] content, int start, int length)
692 throws IOException {
693 getWriter().write(content, start, length);
694 setCurrentLineLength(getCurrentLineLength() + length);
695 }
696
697 /**
698 * Support method to locate an occurrence of a particular character.
699 */
700 private int indexOf(char[] chars, char sChar, int startIndex,
701 int endIndex) {
702 while(startIndex < endIndex) {
703 if (chars[startIndex] == sChar) {
704 return startIndex;
705 }
706 startIndex++;
707 }
708 return -1;
|
1 /*
2 * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
169 * Initializes the ElementIterator with the
170 * element passed in.
171 *
172 * @param w a Writer
173 * @param root an Element
174 * @param pos The location in the document to fetch the
175 * content.
176 * @param len The amount to write out.
177 */
178 protected AbstractWriter(Writer w, Element root, int pos, int len) {
179 this.doc = root.getDocument();
180 it = new ElementIterator(root);
181 out = w;
182 startOffset = pos;
183 endOffset = pos + len;
184 canWrapLines = true;
185 }
186
187 /**
188 * Returns the first offset to be output.
189 * @return the first offset to be output
190 * @since 1.3
191 */
192 public int getStartOffset() {
193 return startOffset;
194 }
195
196 /**
197 * Returns the last offset to be output.
198 * @return the last offset to be output
199 * @since 1.3
200 */
201 public int getEndOffset() {
202 return endOffset;
203 }
204
205 /**
206 * Fetches the ElementIterator.
207 *
208 * @return the ElementIterator.
209 */
210 protected ElementIterator getElementIterator() {
211 return it;
212 }
213
214 /**
215 * Returns the Writer that is used to output the content.
216 * @return the Writer that is used to output the content
217 * @since 1.3
218 */
219 protected Writer getWriter() {
220 return out;
221 }
222
223 /**
224 * Fetches the document.
225 *
226 * @return the Document.
227 */
228 protected Document getDocument() {
229 return doc;
230 }
231
232 /**
233 * This method determines whether the current element
234 * is in the range specified. When no range is specified,
235 * the range is initialized to be the entire document.
236 * inRange() returns true if the range specified intersects
240 * @return boolean that indicates whether the element
241 * is in the range.
242 */
243 protected boolean inRange(Element next) {
244 int startOffset = getStartOffset();
245 int endOffset = getEndOffset();
246 if ((next.getStartOffset() >= startOffset &&
247 next.getStartOffset() < endOffset) ||
248 (startOffset >= next.getStartOffset() &&
249 startOffset < next.getEndOffset())) {
250 return true;
251 }
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 abstract protected 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
300 }
301 getDocument().getText(start, end - start, segment);
302 if (segment.count > 0) {
303 write(segment.array, segment.offset, segment.count);
304 }
305 }
306 }
307
308 /**
309 * Enables subclasses to set the number of characters they
310 * want written per line. The default is 100.
311 *
312 * @param l the maximum line length.
313 */
314 protected void setLineLength(int l) {
315 maxLineLength = l;
316 }
317
318 /**
319 * Returns the maximum line length.
320 * @return the maximum line length
321 * @since 1.3
322 */
323 protected int getLineLength() {
324 return maxLineLength;
325 }
326
327 /**
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
370 * no lineSeparator's will be output.
371 * @return whether or not the lines can be wrapped
372 * @since 1.3
373 */
374 protected boolean getCanWrapLines() {
375 return canWrapLines;
376 }
377
378 /**
379 * Enables subclasses to specify how many spaces an indent
380 * maps to. When indentation takes place, the indent level
381 * is multiplied by this mapping. The default is 2.
382 *
383 * @param space an int representing the space to indent mapping.
384 */
385 protected void setIndentSpace(int space) {
386 indentSpace = space;
387 }
388
389 /**
390 * Returns the amount of space to indent.
391 * @return the amount of space to indent
392 * @since 1.3
393 */
394 protected int getIndentSpace() {
395 return indentSpace;
396 }
397
398 /**
399 * Sets the String used to represent newlines. This is initialized
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] = ' ';
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();
564 lastIndex = newlineIndex + 1;
565 newlineIndex = indexOf(chars, '\n', lastIndex, endIndex);
566 }
567 if (lastIndex < endIndex) {
568 output(chars, lastIndex, endIndex - lastIndex);
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) {
714 if (chars[startIndex] == sChar) {
715 return startIndex;
716 }
717 startIndex++;
718 }
719 return -1;
|