KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > text > AbstractWriter


1 /*
2  * @(#)AbstractWriter.java 1.21 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing.text;
9
10 import java.io.Writer JavaDoc;
11 import java.io.IOException JavaDoc;
12 import java.util.Enumeration JavaDoc;
13
14 /**
15  * AbstractWriter is an abstract class that actually
16  * does the work of writing out the element tree
17  * including the attributes. In terms of how much is
18  * written out per line, the writer defaults to 100.
19  * But this value can be set by subclasses.
20  *
21  * @author Sunita Mani
22  * @version 1.21, 12/19/03
23  */

24
25 public abstract class AbstractWriter {
26
27     private ElementIterator JavaDoc it;
28     private Writer JavaDoc out;
29     private int indentLevel = 0;
30     private int indentSpace = 2;
31     private Document JavaDoc doc = null;
32     private int maxLineLength = 100;
33     private int currLength = 0;
34     private int startOffset = 0;
35     private int endOffset = 0;
36     // If (indentLevel * indentSpace) becomes >= maxLineLength, this will
37
// get incremened instead of indentLevel to avoid indenting going greater
38
// than line length.
39
private int offsetIndent = 0;
40
41     /**
42      * String used for end of line. If the Document has the property
43      * EndOfLineStringProperty, it will be used for newlines. Otherwise
44      * the System property line.separator will be used. The line separator
45      * can also be set.
46      */

47     private String JavaDoc lineSeparator;
48
49     /**
50      * True indicates that when writing, the line can be split, false
51      * indicates that even if the line is > than max line length it should
52      * not be split.
53      */

54     private boolean canWrapLines;
55
56     /**
57      * True while the current line is empty. This will remain true after
58      * indenting.
59      */

60     private boolean isLineEmpty;
61
62     /**
63      * Used when indenting. Will contain the spaces.
64      */

65     private char[] indentChars;
66
67     /**
68      * Used when writing out a string.
69      */

70     private char[] tempChars;
71
72     /**
73      * This is used in <code>writeLineSeparator</code> instead of
74      * tempChars. If tempChars were used it would mean write couldn't invoke
75      * <code>writeLineSeparator</code> as it might have been passed
76      * tempChars.
77      */

78     private char[] newlineChars;
79
80     /**
81      * Used for writing text.
82      */

83     private Segment JavaDoc segment;
84
85     /**
86      * How the text packages models newlines.
87      * @see #getLineSeparator
88      */

89     protected static final char NEWLINE = '\n';
90
91
92     /**
93      * Creates a new AbstractWriter.
94      * Initializes the ElementIterator with the default
95      * root of the document.
96      *
97      * @param w a Writer.
98      * @param doc a Document
99      */

100     protected AbstractWriter(Writer JavaDoc w, Document JavaDoc doc) {
101     this(w, doc, 0, doc.getLength());
102     }
103     
104     /**
105      * Creates a new AbstractWriter.
106      * Initializes the ElementIterator with the
107      * element passed in.
108      *
109      * @param w a Writer
110      * @param doc an Element
111      * @param pos The location in the document to fetch the
112      * content.
113      * @param len The amount to write out.
114      */

115     protected AbstractWriter(Writer JavaDoc w, Document JavaDoc doc, int pos, int len) {
116     this.doc = doc;
117     it = new ElementIterator JavaDoc(doc.getDefaultRootElement());
118     out = w;
119     startOffset = pos;
120     endOffset = pos + len;
121     Object JavaDoc docNewline = doc.getProperty(DefaultEditorKit.
122                        EndOfLineStringProperty);
123     if (docNewline instanceof String JavaDoc) {
124         setLineSeparator((String JavaDoc)docNewline);
125     }
126     else {
127         String JavaDoc newline = null;
128         try {
129         newline = System.getProperty("line.separator");
130         } catch (SecurityException JavaDoc se) {}
131         if (newline == null) {
132         // Should not get here, but if we do it means we could not
133
// find a newline string, use \n in this case.
134
newline = "\n";
135         }
136         setLineSeparator(newline);
137     }
138     canWrapLines = true;
139     }
140
141     /**
142      * Creates a new AbstractWriter.
143      * Initializes the ElementIterator with the
144      * element passed in.
145      *
146      * @param w a Writer
147      * @param root an Element
148      */

149     protected AbstractWriter(Writer JavaDoc w, Element JavaDoc root) {
150     this(w, root, 0, root.getEndOffset());
151     }
152      
153     /**
154      * Creates a new AbstractWriter.
155      * Initializes the ElementIterator with the
156      * element passed in.
157      *
158      * @param w a Writer
159      * @param root an Element
160      * @param pos The location in the document to fetch the
161      * content.
162      * @param len The amount to write out.
163      */

164     protected AbstractWriter(Writer JavaDoc w, Element JavaDoc root, int pos, int len) {
165     this.doc = root.getDocument();
166     it = new ElementIterator JavaDoc(root);
167     out = w;
168     startOffset = pos;
169     endOffset = pos + len;
170     canWrapLines = true;
171     }
172
173     /**
174      * Returns the first offset to be output.
175      *
176      * @since 1.3
177      */

178     public int getStartOffset() {
179     return startOffset;
180     }
181
182     /**
183      * Returns the last offset to be output.
184      *
185      * @since 1.3
186      */

187     public int getEndOffset() {
188     return endOffset;
189     }
190
191     /**
192      * Fetches the ElementIterator.
193      *
194      * @return the ElementIterator.
195      */

196     protected ElementIterator JavaDoc getElementIterator() {
197     return it;
198     }
199
200     /**
201      * Returns the Writer that is used to output the content.
202      *
203      * @since 1.3
204      */

205     protected Writer JavaDoc getWriter() {
206     return out;
207     }
208
209     /**
210      * Fetches the document.
211      *
212      * @return the Document.
213      */

214     protected Document JavaDoc getDocument() {
215     return doc;
216     }
217
218     /**
219      * This method determines whether the current element
220      * is in the range specified. When no range is specified,
221      * the range is initialized to be the entire document.
222      * inRange() returns true if the range specified intersects
223      * with the element's range.
224      *
225      * @param next an Element.
226      * @return boolean that indicates whether the element
227      * is in the range.
228      */

229     protected boolean inRange(Element JavaDoc next) {
230     int startOffset = getStartOffset();
231     int endOffset = getEndOffset();
232     if ((next.getStartOffset() >= startOffset &&
233          next.getStartOffset() < endOffset) ||
234         (startOffset >= next.getStartOffset() &&
235          startOffset < next.getEndOffset())) {
236         return true;
237     }
238     return false;
239     }
240
241     /**
242      * This abstract method needs to be implemented
243      * by subclasses. Its responsibility is to
244      * iterate over the elements and use the write()
245      * methods to generate output in the desired format.
246      */

247     abstract protected void write() throws IOException JavaDoc, BadLocationException JavaDoc;
248
249     /**
250      * Returns the text associated with the element.
251      * The assumption here is that the element is a
252      * leaf element. Throws a BadLocationException
253      * when encountered.
254      *
255      * @param elem an <code>Element</code>
256      * @exception BadLocationException if pos represents an invalid
257      * location within the document
258      * @return the text as a <code>String</code>
259      */

260     protected String JavaDoc getText(Element JavaDoc elem) throws BadLocationException JavaDoc {
261     return doc.getText(elem.getStartOffset(),
262                elem.getEndOffset() - elem.getStartOffset());
263     }
264
265
266     /**
267      * Writes out text. If a range is specified when the constructor
268      * is invoked, then only the appropriate range of text is written
269      * out.
270      *
271      * @param elem an Element.
272      * @exception IOException on any I/O error
273      * @exception BadLocationException if pos represents an invalid
274      * location within the document.
275      */

276     protected void text(Element JavaDoc elem) throws BadLocationException JavaDoc,
277                                          IOException JavaDoc {
278     int start = Math.max(getStartOffset(), elem.getStartOffset());
279     int end = Math.min(getEndOffset(), elem.getEndOffset());
280     if (start < end) {
281         if (segment == null) {
282         segment = new Segment JavaDoc();
283         }
284         getDocument().getText(start, end - start, segment);
285         if (segment.count > 0) {
286         write(segment.array, segment.offset, segment.count);
287         }
288     }
289     }
290
291     /**
292      * Enables subclasses to set the number of characters they
293      * want written per line. The default is 100.
294      *
295      * @param l the maximum line length.
296      */

297     protected void setLineLength(int l) {
298     maxLineLength = l;
299     }
300
301     /**
302      * Returns the maximum line length.
303      *
304      * @since 1.3
305      */

306     protected int getLineLength() {
307     return maxLineLength;
308     }
309
310     /**
311      * Sets the current line length.
312      *
313      * @since 1.3.
314      */

315     protected void setCurrentLineLength(int length) {
316     currLength = length;
317     isLineEmpty = (currLength == 0);
318     }
319
320     /**
321      * Returns the current line length.
322      *
323      * @since 1.3.
324      */

325     protected int getCurrentLineLength() {
326     return currLength;
327     }
328
329     /**
330      * Returns true if the current line should be considered empty. This
331      * is true when <code>getCurrentLineLength</code> == 0 ||
332      * <code>indent</code> has been invoked on an empty line.
333      *
334      * @since 1.3
335      */

336     protected boolean isLineEmpty() {
337     return isLineEmpty;
338     }
339
340     /**
341      * Sets whether or not lines can be wrapped. This can be toggled
342      * during the writing of lines. For example, outputting HTML might
343      * set this to false when outputting a quoted string.
344      *
345      * @since 1.3
346      */

347     protected void setCanWrapLines(boolean newValue) {
348     canWrapLines = newValue;
349     }
350
351     /**
352      * Returns whether or not the lines can be wrapped. If this is false
353      * no lineSeparator's will be output.
354      *
355      * @since 1.3
356      */

357     protected boolean getCanWrapLines() {
358     return canWrapLines;
359     }
360
361     /**
362      * Enables subclasses to specify how many spaces an indent
363      * maps to. When indentation takes place, the indent level
364      * is multiplied by this mapping. The default is 2.
365      *
366      * @param space an int representing the space to indent mapping.
367      */

368     protected void setIndentSpace(int space) {
369     indentSpace = space;
370     }
371
372     /**
373      * Returns the amount of space to indent.
374      *
375      * @since 1.3
376      */

377     protected int getIndentSpace() {
378     return indentSpace;
379     }
380
381     /**
382      * Sets the String used to reprsent newlines. This is initialized
383      * in the constructor from either the Document, or the System property
384      * line.separator.
385      *
386      * @since 1.3
387      */

388     public void setLineSeparator(String JavaDoc value) {
389     lineSeparator = value;
390     }
391
392     /**
393      * Returns the string used to represent newlines.
394      *
395      * @since 1.3
396      */

397     public String JavaDoc getLineSeparator() {
398     return lineSeparator;
399     }
400
401     /**
402      * Increments the indent level. If indenting would cause
403      * <code>getIndentSpace()</code> *<code>getIndentLevel()</code> to be >
404      * than <code>getLineLength()</code> this will not cause an indent.
405      */

406     protected void incrIndent() {
407     // Only increment to a certain point.
408
if (offsetIndent > 0) {
409         offsetIndent++;
410     }
411     else {
412         if (++indentLevel * getIndentSpace() >= getLineLength()) {
413         offsetIndent++;
414         --indentLevel;
415         }
416     }
417     }
418
419     /**
420      * Decrements the indent level.
421      */

422     protected void decrIndent() {
423     if (offsetIndent > 0) {
424         --offsetIndent;
425     }
426     else {
427         indentLevel--;
428     }
429     }
430
431     /**
432      * Returns the current indentation level. That is, the number of times
433      * <code>incrIndent</code> has been invoked minus the number of times
434      * <code>decrIndent</code> has been invoked.
435      *
436      * @since 1.3
437      */

438     protected int getIndentLevel() {
439     return indentLevel;
440     }
441
442     /**
443      * Does indentation. The number of spaces written
444      * out is indent level times the space to map mapping. If the current
445      * line is empty, this will not make it so that the current line is
446      * still considered empty.
447      *
448      * @exception IOException on any I/O error
449      */

450     protected void indent() throws IOException JavaDoc {
451     int max = getIndentLevel() * getIndentSpace();
452     if (indentChars == null || max > indentChars.length) {
453         indentChars = new char[max];
454         for (int counter = 0; counter < max; counter++) {
455         indentChars[counter] = ' ';
456         }
457     }
458     int length = getCurrentLineLength();
459     boolean wasEmpty = isLineEmpty();
460     output(indentChars, 0, max);
461     if (wasEmpty && length == 0) {
462         isLineEmpty = true;
463     }
464     }
465
466     /**
467      * Writes out a character. This is implemented to invoke
468      * the <code>write</code> method that takes a char[].
469      *
470      * @param ch a char.
471      * @exception IOException on any I/O error
472      */

473     protected void write(char ch) throws IOException JavaDoc {
474     if (tempChars == null) {
475         tempChars = new char[128];
476     }
477     tempChars[0] = ch;
478     write(tempChars, 0, 1);
479     }
480
481     /**
482      * Writes out a string. This is implemented to invoke the
483      * <code>write</code> method that takes a char[].
484      *
485      * @param content a String.
486      * @exception IOException on any I/O error
487      */

488     protected void write(String JavaDoc content) throws IOException JavaDoc {
489     if (content == null) {
490         return;
491     }
492     int size = content.length();
493     if (tempChars == null || tempChars.length < size) {
494         tempChars = new char[size];
495     }
496     content.getChars(0, size, tempChars, 0);
497     write(tempChars, 0, size);
498     }
499
500     /**
501      * Writes the line separator. This invokes <code>output</code> directly
502      * as well as setting the <code>lineLength</code> to 0.
503      *
504      * @since 1.3
505      */

506     protected void writeLineSeparator() throws IOException JavaDoc {
507     String JavaDoc newline = getLineSeparator();
508     int length = newline.length();
509     if (newlineChars == null || newlineChars.length < length) {
510         newlineChars = new char[length];
511     }
512     newline.getChars(0, length, newlineChars, 0);
513     output(newlineChars, 0, length);
514     setCurrentLineLength(0);
515     }
516
517     /**
518      * All write methods call into this one. If <code>getCanWrapLines()</code>
519      * returns false, this will call <code>output</code> with each sequence
520      * of <code>chars</code> that doesn't contain a NEWLINE, followed
521      * by a call to <code>writeLineSeparator</code>. On the other hand,
522      * if <code>getCanWrapLines()</code> returns true, this will split the
523      * string, as necessary, so <code>getLineLength</code> is honored.
524      * The only exception is if the current string contains no whitespace,
525      * and won't fit in which case the line length will exceed
526      * <code>getLineLength</code>.
527      *
528      * @since 1.3
529      */

530     protected void write(char[] chars, int startIndex, int length)
531                throws IOException JavaDoc {
532     if (!getCanWrapLines()) {
533         // We can not break string, just track if a newline
534
// is in it.
535
int lastIndex = startIndex;
536         int endIndex = startIndex + length;
537         int newlineIndex = indexOf(chars, NEWLINE, startIndex, endIndex);
538         while (newlineIndex != -1) {
539         if (newlineIndex > lastIndex) {
540             output(chars, lastIndex, newlineIndex - lastIndex);
541         }
542         writeLineSeparator();
543         lastIndex = newlineIndex + 1;
544         newlineIndex = indexOf(chars, '\n', lastIndex, endIndex);
545         }
546         if (lastIndex < endIndex) {
547         output(chars, lastIndex, endIndex - lastIndex);
548         }
549     }
550     else {
551         // We can break chars if the length exceeds maxLength.
552
int lastIndex = startIndex;
553         int endIndex = startIndex + length;
554         int lineLength = getCurrentLineLength();
555         int maxLength = getLineLength();
556
557         while (lastIndex < endIndex) {
558         int newlineIndex = indexOf(chars, NEWLINE, lastIndex,
559                        endIndex);
560         boolean needsNewline = false;
561                 boolean forceNewLine = false;
562
563         lineLength = getCurrentLineLength();
564         if (newlineIndex != -1 && (lineLength +
565                   (newlineIndex - lastIndex)) < maxLength) {
566             if (newlineIndex > lastIndex) {
567             output(chars, lastIndex, newlineIndex - lastIndex);
568             }
569             lastIndex = newlineIndex + 1;
570                     forceNewLine = true;
571         }
572         else if (newlineIndex == -1 && (lineLength +
573                 (endIndex - lastIndex)) < maxLength) {
574             if (endIndex > lastIndex) {
575             output(chars, lastIndex, endIndex - lastIndex);
576             }
577             lastIndex = endIndex;
578         }
579         else {
580             // Need to break chars, find a place to split chars at,
581
// from lastIndex to endIndex,
582
// or maxLength - lineLength whichever is smaller
583
int breakPoint = -1;
584             int maxBreak = Math.min(endIndex - lastIndex,
585                         maxLength - lineLength - 1);
586             int counter = 0;
587             while (counter < maxBreak) {
588             if (Character.isWhitespace(chars[counter +
589                             lastIndex])) {
590                 breakPoint = counter;
591             }
592             counter++;
593             }
594             if (breakPoint != -1) {
595             // Found a place to break at.
596
breakPoint += lastIndex + 1;
597             output(chars, lastIndex, breakPoint - lastIndex);
598             lastIndex = breakPoint;
599                         needsNewline = true;
600             }
601             else {
602             // No where good to break.
603

604                         // find the next whitespace, or write out the
605
// whole string.
606
// maxBreak will be negative if current line too
607
// long.
608
counter = Math.max(0, maxBreak);
609                 maxBreak = endIndex - lastIndex;
610                 while (counter < maxBreak) {
611                 if (Character.isWhitespace(chars[counter +
612                                 lastIndex])) {
613                     breakPoint = counter;
614                     break;
615                 }
616                 counter++;
617                 }
618                 if (breakPoint == -1) {
619                 output(chars, lastIndex, endIndex - lastIndex);
620                 breakPoint = endIndex;
621                 }
622                 else {
623                 breakPoint += lastIndex;
624                 if (chars[breakPoint] == NEWLINE) {
625                     output(chars, lastIndex, breakPoint++ -
626                        lastIndex);
627                                 forceNewLine = true;
628                 }
629                 else {
630                     output(chars, lastIndex, ++breakPoint -
631                           lastIndex);
632                                 needsNewline = true;
633                 }
634                 }
635                 lastIndex = breakPoint;
636             }
637             }
638         if (forceNewLine || needsNewline || lastIndex < endIndex) {
639             writeLineSeparator();
640                     if (lastIndex < endIndex || !forceNewLine) {
641             indent();
642             }
643         }
644         }
645     }
646     }
647
648     /**
649      * Writes out the set of attributes as " <name>=<value>"
650      * pairs. It throws an IOException when encountered.
651      *
652      * @param attr an AttributeSet.
653      * @exception IOException on any I/O error
654      */

655     protected void writeAttributes(AttributeSet JavaDoc attr) throws IOException JavaDoc {
656
657     Enumeration JavaDoc names = attr.getAttributeNames();
658     while (names.hasMoreElements()) {
659         Object JavaDoc name = names.nextElement();
660         write(" " + name + "=" + attr.getAttribute(name));
661     }
662     }
663
664     /**
665      * The last stop in writing out content. All the write methods eventually
666      * make it to this method, which invokes <code>write</code> on the
667      * Writer.
668      * <p>This method also updates the line length based on
669      * <code>length</code>. If this is invoked to output a newline, the
670      * current line length will need to be reset as will no longer be
671      * valid. If it is up to the caller to do this. Use
672      * <code>writeLineSeparator</code> to write out a newline, which will
673      * property update the current line length.
674      *
675      * @since 1.3
676      */

677     protected void output(char[] content, int start, int length)
678                throws IOException JavaDoc {
679     getWriter().write(content, start, length);
680     setCurrentLineLength(getCurrentLineLength() + length);
681     }
682
683     /**
684      * Support method to locate an occurence of a particular character.
685      */

686     private int indexOf(char[] chars, char sChar, int startIndex,
687             int endIndex) {
688     while(startIndex < endIndex) {
689         if (chars[startIndex] == sChar) {
690         return startIndex;
691         }
692         startIndex++;
693     }
694     return -1;
695     }
696 }
697
Popular Tags