History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/text/AbstractWriter.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/text/AbstractWriter.java+713−0
@@ -0,0 +1,713 @@
1+/*
2+ * Copyright (c) 1998, 2006, 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
23+ * questions.
24+ */
25+
26+package javax.swing.text;
27+
28+import java.io.Writer;
29+import java.io.IOException;
30+import java.util.Enumeration;
31+
32+/**
33+ * AbstractWriter is an abstract class that actually
34+ * does the work of writing out the element tree
35+ * including the attributes. In terms of how much is
36+ * written out per line, the writer defaults to 100.
37+ * But this value can be set by subclasses.
38+ *
39+ * @author Sunita Mani
40+ */
41+
42+public abstract class AbstractWriter {
43+
44+ private ElementIterator it;
45+ private Writer out;
46+ private int indentLevel = 0;
47+ private int indentSpace = 2;
48+ private Document doc = null;
49+ private int maxLineLength = 100;
50+ private int currLength = 0;
51+ private int startOffset = 0;
52+ private int endOffset = 0;
53+ // If (indentLevel * indentSpace) becomes >= maxLineLength, this will
54+ // get incremened instead of indentLevel to avoid indenting going greater
55+ // than line length.
56+ private int offsetIndent = 0;
57+
58+ /**
59+ * String used for end of line. If the Document has the property
60+ * EndOfLineStringProperty, it will be used for newlines. Otherwise
61+ * the System property line.separator will be used. The line separator
62+ * can also be set.
63+ */
64+ private String lineSeparator;
65+
66+ /**
67+ * True indicates that when writing, the line can be split, false
68+ * indicates that even if the line is > than max line length it should
69+ * not be split.
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.
113+ *
114+ * @param w a Writer.
115+ * @param doc a Document
116+ */
117+ protected AbstractWriter(Writer w, Document doc) {
118+ this(w, doc, 0, doc.getLength());
119+ }
120+
121+ /**
122+ * Creates a new AbstractWriter.
123+ * Initializes the ElementIterator with the
124+ * element passed in.
125+ *
126+ * @param w a Writer
127+ * @param doc an Element
128+ * @param pos The location in the document to fetch the
129+ * content.
130+ * @param len The amount to write out.
131+ */
132+ protected AbstractWriter(Writer w, Document doc, int pos, int len) {
133+ this.doc = doc;
134+ it = new ElementIterator(doc.getDefaultRootElement());
135+ out = w;
136+ startOffset = pos;
137+ endOffset = pos + len;
138+ Object docNewline = doc.getProperty(DefaultEditorKit.
139+ EndOfLineStringProperty);
140+ if (docNewline instanceof String) {
141+ setLineSeparator((String)docNewline);
142+ }
143+ else {
144+ String newline = null;
145+ try {
146+ newline = System.getProperty("line.separator");
147+ } catch (SecurityException se) {}
148+ if (newline == null) {
149+ // Should not get here, but if we do it means we could not
150+ // find a newline string, use \n in this case.
151+ newline = "\n";
152+ }
153+ setLineSeparator(newline);
154+ }
155+ canWrapLines = true;
156+ }
157+
158+ /**
159+ * Creates a new AbstractWriter.
160+ * Initializes the ElementIterator with the
161+ * element passed in.
162+ *
163+ * @param w a Writer
164+ * @param root an Element
165+ */
166+ protected AbstractWriter(Writer w, Element root) {
167+ this(w, root, 0, root.getEndOffset());
168+ }
169+
170+ /**
171+ * Creates a new AbstractWriter.
172+ * Initializes the ElementIterator with the
173+ * element passed in.
174+ *
175+ * @param w a Writer
176+ * @param root an Element
177+ * @param pos The location in the document to fetch the
178+ * content.
179+ * @param len The amount to write out.
180+ */
181+ protected AbstractWriter(Writer w, Element root, int pos, int len) {
182+ this.doc = root.getDocument();
183+ it = new ElementIterator(root);
184+ out = w;
185+ startOffset = pos;
186+ endOffset = pos + len;
187+ canWrapLines = true;
188+ }
189+
190+ /**
191+ * Returns the first offset to be output.
192+ *
193+ * @since 1.3
194+ */
195+ public int getStartOffset() {
196+ return startOffset;
197+ }
198+
199+ /**
200+ * Returns the last offset to be output.
201+ *
202+ * @since 1.3
203+ */
204+ public int getEndOffset() {
205+ return endOffset;
206+ }
207+
208+ /**
209+ * Fetches the ElementIterator.
210+ *
211+ * @return the ElementIterator.
212+ */
213+ protected ElementIterator getElementIterator() {
214+ return it;
215+ }
216+
217+ /**
218+ * Returns the Writer that is used to output the content.
219+ *
220+ * @since 1.3
221+ */
222+ protected Writer getWriter() {
223+ return out;
224+ }
225+
226+ /**
227+ * Fetches the document.
228+ *
229+ * @return the Document.
230+ */
231+ protected Document getDocument() {
232+ return doc;
233+ }
234+
235+ /**
236+ * This method determines whether the current element
237+ * is in the range specified. When no range is specified,
238+ * the range is initialized to be the entire document.
239+ * inRange() returns true if the range specified intersects
240+ * with the element's range.
241+ *
242+ * @param next an Element.
243+ * @return boolean that indicates whether the element
244+ * is in the range.
245+ */
246+ protected boolean inRange(Element next) {
247+ int startOffset = getStartOffset();
248+ int endOffset = getEndOffset();
249+ if ((next.getStartOffset() >= startOffset &&
250+ next.getStartOffset() < endOffset) ||
251+ (startOffset >= next.getStartOffset() &&
252+ startOffset < next.getEndOffset())) {
253+ return true;
254+ }
255+ return false;
256+ }
257+
258+ /**
259+ * This abstract method needs to be implemented
260+ * by subclasses. Its responsibility is to
261+ * iterate over the elements and use the write()
262+ * methods to generate output in the desired format.
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+
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());
296+ int end = Math.min(getEndOffset(), elem.getEndOffset());
297+ if (start < end) {
298+ if (segment == null) {
299+ segment = new Segment();
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+ *
321+ * @since 1.3
322+ */
323+ protected int getLineLength() {
324+ return maxLineLength;
325+ }
326+
327+ /**
328+ * Sets the current line length.
329+ *
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+ *
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+ *
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+ *
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+ *
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+ *
392+ * @since 1.3
393+ */
394+ protected int getIndentSpace() {
395+ return indentSpace;
396+ }
397+
398+ /**
399+ * Sets the String used to reprsent newlines. This is initialized
400+ * in the constructor from either the Document, or the System property
401+ * line.separator.
402+ *
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+ *
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+ *
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+ *
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+ * @since 1.3
546+ */
547+ protected void write(char[] chars, int startIndex, int length)
548+ throws IOException {
549+ if (!getCanWrapLines()) {
550+ // We can not break string, just track if a newline
551+ // is in it.
552+ int lastIndex = startIndex;
553+ int endIndex = startIndex + length;
554+ int newlineIndex = indexOf(chars, NEWLINE, startIndex, endIndex);
555+ while (newlineIndex != -1) {
556+ if (newlineIndex > lastIndex) {
557+ output(chars, lastIndex, newlineIndex - lastIndex);
558+ }
559+ writeLineSeparator();
560+ lastIndex = newlineIndex + 1;
561+ newlineIndex = indexOf(chars, '\n', lastIndex, endIndex);
562+ }
563+ if (lastIndex < endIndex) {
564+ output(chars, lastIndex, endIndex - lastIndex);
565+ }
566+ }
567+ else {
568+ // We can break chars if the length exceeds maxLength.
569+ int lastIndex = startIndex;
570+ int endIndex = startIndex + length;
571+ int lineLength = getCurrentLineLength();
572+ int maxLength = getLineLength();
573+
574+ while (lastIndex < endIndex) {
575+ int newlineIndex = indexOf(chars, NEWLINE, lastIndex,
576+ endIndex);
577+ boolean needsNewline = false;
578+ boolean forceNewLine = false;
579+
580+ lineLength = getCurrentLineLength();
581+ if (newlineIndex != -1 && (lineLength +
582+ (newlineIndex - lastIndex)) < maxLength) {
583+ if (newlineIndex > lastIndex) {
584+ output(chars, lastIndex, newlineIndex - lastIndex);
585+ }
586+ lastIndex = newlineIndex + 1;
587+ forceNewLine = true;
588+ }
589+ else if (newlineIndex == -1 && (lineLength +
590+ (endIndex - lastIndex)) < maxLength) {
591+ if (endIndex > lastIndex) {
592+ output(chars, lastIndex, endIndex - lastIndex);
593+ }
594+ lastIndex = endIndex;
595+ }
596+ else {
597+ // Need to break chars, find a place to split chars at,
598+ // from lastIndex to endIndex,
599+ // or maxLength - lineLength whichever is smaller
600+ int breakPoint = -1;
601+ int maxBreak = Math.min(endIndex - lastIndex,
602+ maxLength - lineLength - 1);
603+ int counter = 0;
604+ while (counter < maxBreak) {
605+ if (Character.isWhitespace(chars[counter +
606+ lastIndex])) {
607+ breakPoint = counter;
608+ }
609+ counter++;
610+ }
611+ if (breakPoint != -1) {
612+ // Found a place to break at.
613+ breakPoint += lastIndex + 1;
614+ output(chars, lastIndex, breakPoint - lastIndex);
615+ lastIndex = breakPoint;
616+ needsNewline = true;
617+ }
618+ else {
619+ // No where good to break.
620+
621+ // find the next whitespace, or write out the
622+ // whole string.
623+ // maxBreak will be negative if current line too
624+ // long.
625+ counter = Math.max(0, maxBreak);
626+ maxBreak = endIndex - lastIndex;
627+ while (counter < maxBreak) {
628+ if (Character.isWhitespace(chars[counter +
629+ lastIndex])) {
630+ breakPoint = counter;
631+ break;
632+ }
633+ counter++;
634+ }
635+ if (breakPoint == -1) {
636+ output(chars, lastIndex, endIndex - lastIndex);
637+ breakPoint = endIndex;
638+ }
639+ else {
640+ breakPoint += lastIndex;
641+ if (chars[breakPoint] == NEWLINE) {
642+ output(chars, lastIndex, breakPoint++ -
643+ lastIndex);
644+ forceNewLine = true;
645+ }
646+ else {
647+ output(chars, lastIndex, ++breakPoint -
648+ lastIndex);
649+ needsNewline = true;
650+ }
651+ }
652+ lastIndex = breakPoint;
653+ }
654+ }
655+ if (forceNewLine || needsNewline || lastIndex < endIndex) {
656+ writeLineSeparator();
657+ if (lastIndex < endIndex || !forceNewLine) {
658+ indent();
659+ }
660+ }
661+ }
662+ }
663+ }
664+
665+ /**
666+ * Writes out the set of attributes as " <name>=<value>"
667+ * pairs. It throws an IOException when encountered.
668+ *
669+ * @param attr an AttributeSet.
670+ * @exception IOException on any I/O error
671+ */
672+ protected void writeAttributes(AttributeSet attr) throws IOException {
673+
674+ Enumeration names = attr.getAttributeNames();
675+ while (names.hasMoreElements()) {
676+ Object name = names.nextElement();
677+ write(" " + name + "=" + attr.getAttribute(name));
678+ }
679+ }
680+
681+ /**
682+ * The last stop in writing out content. All the write methods eventually
683+ * make it to this method, which invokes <code>write</code> on the
684+ * Writer.
685+ * <p>This method also updates the line length based on
686+ * <code>length</code>. If this is invoked to output a newline, the
687+ * current line length will need to be reset as will no longer be
688+ * valid. If it is up to the caller to do this. Use
689+ * <code>writeLineSeparator</code> to write out a newline, which will
690+ * property update the current line length.
691+ *
692+ * @since 1.3
693+ */
694+ protected void output(char[] content, int start, int length)
695+ throws IOException {
696+ getWriter().write(content, start, length);
697+ setCurrentLineLength(getCurrentLineLength() + length);
698+ }
699+
700+ /**
701+ * Support method to locate an occurence of a particular character.
702+ */
703+ private int indexOf(char[] chars, char sChar, int startIndex,
704+ int endIndex) {
705+ while(startIndex < endIndex) {
706+ if (chars[startIndex] == sChar) {
707+ return startIndex;
708+ }
709+ startIndex++;
710+ }
711+ return -1;
712+ }
713+}