~ubuntu-branches/ubuntu/karmic/libxerces2-java/karmic

« back to all changes in this revision

Viewing changes to src/org/apache/xml/serialize/IndentPrinter.java

  • Committer: Bazaar Package Importer
  • Author(s): Stefan Gybas
  • Date: 2004-06-06 18:00:26 UTC
  • Revision ID: james.westby@ubuntu.com-20040606180026-a3vh56uc95hjbyfh
Tags: upstream-2.6.2
ImportĀ upstreamĀ versionĀ 2.6.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * The Apache Software License, Version 1.1
 
3
 *
 
4
 *
 
5
 * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights 
 
6
 * reserved.
 
7
 *
 
8
 * Redistribution and use in source and binary forms, with or without
 
9
 * modification, are permitted provided that the following conditions
 
10
 * are met:
 
11
 *
 
12
 * 1. Redistributions of source code must retain the above copyright
 
13
 *    notice, this list of conditions and the following disclaimer. 
 
14
 *
 
15
 * 2. Redistributions in binary form must reproduce the above copyright
 
16
 *    notice, this list of conditions and the following disclaimer in
 
17
 *    the documentation and/or other materials provided with the
 
18
 *    distribution.
 
19
 *
 
20
 * 3. The end-user documentation included with the redistribution,
 
21
 *    if any, must include the following acknowledgment:  
 
22
 *       "This product includes software developed by the
 
23
 *        Apache Software Foundation (http://www.apache.org/)."
 
24
 *    Alternately, this acknowledgment may appear in the software itself,
 
25
 *    if and wherever such third-party acknowledgments normally appear.
 
26
 *
 
27
 * 4. The names "Xerces" and "Apache Software Foundation" must
 
28
 *    not be used to endorse or promote products derived from this
 
29
 *    software without prior written permission. For written 
 
30
 *    permission, please contact apache@apache.org.
 
31
 *
 
32
 * 5. Products derived from this software may not be called "Apache",
 
33
 *    nor may "Apache" appear in their name, without prior written
 
34
 *    permission of the Apache Software Foundation.
 
35
 *
 
36
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 
37
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
38
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 
39
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 
40
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
41
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
42
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 
43
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
44
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 
45
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 
46
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
47
 * SUCH DAMAGE.
 
48
 * ====================================================================
 
49
 *
 
50
 * This software consists of voluntary contributions made by many
 
51
 * individuals on behalf of the Apache Software Foundation and was
 
52
 * originally based on software copyright (c) 1999, International
 
53
 * Business Machines, Inc., http://www.apache.org.  For more
 
54
 * information on the Apache Software Foundation, please see
 
55
 * <http://www.apache.org/>.
 
56
 */
 
57
 
 
58
 
 
59
package org.apache.xml.serialize;
 
60
 
 
61
 
 
62
import java.io.Writer;
 
63
import java.io.StringWriter;
 
64
import java.io.IOException;
 
65
 
 
66
 
 
67
/**
 
68
 * Extends {@link Printer} and adds support for indentation and line
 
69
 * wrapping.
 
70
 *
 
71
 * @version $Revision: 1.8 $ $Date: 2003/01/13 15:59:09 $
 
72
 * @author <a href="mailto:arkin@intalio.com">Assaf Arkin</a>
 
73
 */
 
74
public class IndentPrinter
 
75
    extends Printer
 
76
{
 
77
 
 
78
 
 
79
    /**
 
80
     * Holds the currently accumulating text line. This buffer will constantly
 
81
     * be reused by deleting its contents instead of reallocating it.
 
82
     */
 
83
    private StringBuffer    _line;
 
84
 
 
85
 
 
86
    /**
 
87
     * Holds the currently accumulating text that follows {@link #_line}.
 
88
     * When the end of the part is identified by a call to {@link #printSpace}
 
89
     * or {@link #breakLine}, this part is added to the accumulated line.
 
90
     */
 
91
    private StringBuffer    _text;
 
92
 
 
93
 
 
94
    /**
 
95
     * Counts how many white spaces come between the accumulated line and the
 
96
     * current accumulated text. Multiple spaces at the end of the a line
 
97
     * will not be printed.
 
98
     */
 
99
    private int             _spaces;
 
100
 
 
101
 
 
102
    /**
 
103
     * Holds the indentation for the current line that is now accumulating in
 
104
     * memory and will be sent for printing shortly.
 
105
     */
 
106
    private int             _thisIndent;
 
107
    
 
108
    
 
109
    /**
 
110
     * Holds the indentation for the next line to be printed. After this line is
 
111
     * printed, {@link #_nextIndent} is assigned to {@link #_thisIndent}.
 
112
     */
 
113
    private int             _nextIndent;
 
114
 
 
115
 
 
116
    public IndentPrinter( Writer writer, OutputFormat format)
 
117
    {
 
118
        super( writer, format );
 
119
        // Initialize everything for a first/second run.
 
120
        _line = new StringBuffer( 80 );
 
121
        _text = new StringBuffer( 20 );
 
122
        _spaces = 0;
 
123
        _thisIndent = _nextIndent = 0;
 
124
    }
 
125
 
 
126
 
 
127
    /**
 
128
     * Called by any of the DTD handlers to enter DTD mode.
 
129
     * Once entered, all output will be accumulated in a string
 
130
     * that can be printed as part of the document's DTD.
 
131
     * This method may be called any number of time but will only
 
132
     * have affect the first time it's called. To exist DTD state
 
133
     * and get the accumulated DTD, call {@link #leaveDTD}.
 
134
     */
 
135
    public void enterDTD()
 
136
    {
 
137
        // Can only enter DTD state once. Once we're out of DTD
 
138
        // state, can no longer re-enter it.
 
139
        if ( _dtdWriter == null ) {
 
140
            _line.append( _text );
 
141
            _text = new StringBuffer( 20 );
 
142
            flushLine( false );
 
143
            _dtdWriter = new StringWriter();
 
144
            _docWriter = _writer;
 
145
            _writer = _dtdWriter;
 
146
        }
 
147
    }
 
148
    
 
149
    
 
150
    /**
 
151
     * Called by the root element to leave DTD mode and if any
 
152
     * DTD parts were printer, will return a string with their
 
153
     * textual content.
 
154
     */
 
155
    public String leaveDTD()
 
156
    {
 
157
        // Only works if we're going out of DTD mode.
 
158
        if ( _writer == _dtdWriter ) {
 
159
            _line.append( _text );
 
160
            _text = new StringBuffer( 20 );
 
161
            flushLine( false );
 
162
            _writer = _docWriter;
 
163
            return _dtdWriter.toString();
 
164
        } else
 
165
            return null;
 
166
    }
 
167
    
 
168
    
 
169
    /**
 
170
     * Called to print additional text. Each time this method is called
 
171
     * it accumulates more text. When a space is printed ({@link
 
172
     * #printSpace}) all the accumulated text becomes one part and is
 
173
     * added to the accumulate line. When a line is long enough, it can
 
174
     * be broken at its text boundary.
 
175
     *
 
176
     * @param text The text to print
 
177
     */
 
178
    public void printText( String text )
 
179
    {
 
180
        _text.append( text );
 
181
    }
 
182
    
 
183
    
 
184
    public void printText( StringBuffer text )
 
185
    {
 
186
        _text.append( text.toString() );
 
187
    }
 
188
 
 
189
 
 
190
    public void printText( char ch )
 
191
    {
 
192
        _text.append( ch );
 
193
    }
 
194
 
 
195
 
 
196
    public void printText( char[] chars, int start, int length )
 
197
    {
 
198
        _text.append( chars, start, length );
 
199
    }
 
200
    
 
201
 
 
202
    /**
 
203
     * Called to print a single space between text parts that may be
 
204
     * broken into separate lines. Must not be called to print a space
 
205
     * when preserving spaces. The text accumulated so far with {@link
 
206
     * #printText} will be added to the accumulated line, and a space
 
207
     * separator will be counted. If the line accumulated so far is
 
208
     * long enough, it will be printed.
 
209
     */
 
210
    public void printSpace()
 
211
    {
 
212
        // The line consists of the text accumulated in _line,
 
213
        // followed by one or more spaces as counted by _spaces,
 
214
        // followed by more space accumulated in _text:
 
215
        // -  Text is printed and accumulated into _text.
 
216
        // -  A space is printed, so _text is added to _line and
 
217
        //    a space is counted.
 
218
        // -  More text is printed and accumulated into _text.
 
219
        // -  A space is printed, the previous spaces are added
 
220
        //    to _line, the _text is added to _line, and a new
 
221
        //    space is counted.
 
222
        
 
223
        // If text was accumulated with printText(), then the space
 
224
        // means we have to move that text into the line and
 
225
        // start accumulating new text with printText().
 
226
        if ( _text.length() > 0 ) {
 
227
            // If the text breaks a line bounary, wrap to the next line.
 
228
            // The printed line size consists of the indentation we're going
 
229
            // to use next, the accumulated line so far, some spaces and the
 
230
            // accumulated text so far.
 
231
            if ( _format.getLineWidth() > 0 &&
 
232
                 _thisIndent + _line.length() + _spaces + _text.length() > _format.getLineWidth() ) {
 
233
                flushLine( false );
 
234
                try {
 
235
                    // Print line and new line, then zero the line contents.
 
236
                    _writer.write( _format.getLineSeparator() );
 
237
                } catch ( IOException except ) {
 
238
                    // We don't throw an exception, but hold it
 
239
                    // until the end of the document.
 
240
                    if ( _exception == null )
 
241
                        _exception = except;
 
242
                }
 
243
            }
 
244
            
 
245
            // Add as many spaces as we accumulaed before.
 
246
            // At the end of this loop, _spaces is zero.
 
247
            while ( _spaces > 0 ) {
 
248
                _line.append( ' ' );
 
249
                --_spaces;
 
250
            }
 
251
            _line.append( _text );
 
252
            _text = new StringBuffer( 20 );
 
253
        }
 
254
        // Starting a new word: accumulate the text between the line
 
255
        // and this new word; not a new word: just add another space.
 
256
        ++_spaces;
 
257
    }
 
258
 
 
259
 
 
260
    /**
 
261
     * Called to print a line consisting of the text accumulated so
 
262
     * far. This is equivalent to calling {@link #printSpace} but
 
263
     * forcing the line to print and starting a new line ({@link
 
264
     * #printSpace} will only start a new line if the current line
 
265
     * is long enough).
 
266
     */
 
267
    public void breakLine()
 
268
    {
 
269
        breakLine( false );
 
270
    }
 
271
 
 
272
 
 
273
    public void breakLine( boolean preserveSpace )
 
274
    {
 
275
        // Equivalent to calling printSpace and forcing a flushLine.
 
276
        if ( _text.length() > 0 ) {
 
277
            while ( _spaces > 0 ) {
 
278
                _line.append( ' ' );
 
279
                --_spaces;
 
280
            }
 
281
            _line.append( _text );
 
282
            _text = new StringBuffer( 20 );
 
283
        }
 
284
        flushLine( preserveSpace );
 
285
        try {
 
286
            // Print line and new line, then zero the line contents.
 
287
            _writer.write( _format.getLineSeparator() );
 
288
        } catch ( IOException except ) {
 
289
            // We don't throw an exception, but hold it
 
290
            // until the end of the document.
 
291
            if ( _exception == null )
 
292
                _exception = except;
 
293
        }
 
294
    }
 
295
    
 
296
 
 
297
    /**
 
298
     * Flushes the line accumulated so far to the writer and get ready
 
299
     * to accumulate the next line. This method is called by {@link
 
300
     * #printText} and {@link #printSpace} when the accumulated line plus
 
301
     * accumulated text are two long to fit on a given line. At the end of
 
302
     * this method _line is empty and _spaces is zero.
 
303
     */
 
304
    public void flushLine( boolean preserveSpace )
 
305
    {
 
306
        int     indent;
 
307
        
 
308
        if ( _line.length() > 0 ) {
 
309
            try {
 
310
                
 
311
                if ( _format.getIndenting() && ! preserveSpace ) {
 
312
                    // Make sure the indentation does not blow us away.
 
313
                    indent = _thisIndent;
 
314
                    if ( ( 2 * indent ) > _format.getLineWidth() && _format.getLineWidth() > 0 )
 
315
                        indent = _format.getLineWidth() / 2;
 
316
                    // Print the indentation as spaces and set the current
 
317
                    // indentation to the next expected indentation.
 
318
                    while ( indent > 0 ) {
 
319
                        _writer.write( ' ' );
 
320
                        --indent;
 
321
                    }
 
322
                }
 
323
                _thisIndent = _nextIndent;
 
324
                
 
325
                // There is no need to print the spaces at the end of the line,
 
326
                // they are simply stripped and replaced with a single line
 
327
                // separator.
 
328
                _spaces = 0;
 
329
                _writer.write( _line.toString() );
 
330
                
 
331
                _line = new StringBuffer( 40 );
 
332
            } catch ( IOException except ) {
 
333
                // We don't throw an exception, but hold it
 
334
                // until the end of the document.
 
335
                if ( _exception == null )
 
336
                    _exception = except;
 
337
            }
 
338
        }
 
339
    }
 
340
    
 
341
    
 
342
    /**
 
343
     * Flush the output stream. Must be called when done printing
 
344
     * the document, otherwise some text might be buffered.
 
345
     */
 
346
    public void flush()
 
347
    {
 
348
        if ( _line.length() > 0 || _text.length() > 0 )
 
349
            breakLine();
 
350
        try {
 
351
            _writer.flush();
 
352
        } catch ( IOException except ) {
 
353
            // We don't throw an exception, but hold it
 
354
            // until the end of the document.
 
355
            if ( _exception == null )
 
356
                _exception = except;
 
357
        }
 
358
    }
 
359
 
 
360
 
 
361
    /**
 
362
     * Increment the indentation for the next line.
 
363
     */
 
364
    public void indent()
 
365
    {
 
366
        _nextIndent += _format.getIndent();
 
367
    }
 
368
 
 
369
 
 
370
    /**
 
371
     * Decrement the indentation for the next line.
 
372
     */
 
373
    public void unindent()
 
374
    {
 
375
        _nextIndent -= _format.getIndent();
 
376
        if ( _nextIndent < 0 )
 
377
            _nextIndent = 0;
 
378
        // If there is no current line and we're de-identing then
 
379
        // this indentation level is actually the next level.
 
380
        if ( ( _line.length() + _spaces + _text.length() ) == 0 )
 
381
            _thisIndent = _nextIndent;
 
382
    }
 
383
 
 
384
 
 
385
    public int getNextIndent()
 
386
    {
 
387
        return _nextIndent;
 
388
    }
 
389
 
 
390
 
 
391
    public void setNextIndent( int indent )
 
392
    {
 
393
        _nextIndent = indent;
 
394
    }
 
395
 
 
396
 
 
397
    public void setThisIndent( int indent )
 
398
    {
 
399
        _thisIndent = indent;
 
400
    }
 
401
 
 
402
 
 
403
}