AbstractOutput.java
001 /* This file is part of the project "Hilbert II" - http://www.qedeq.org
002  *
003  * Copyright 2000-2011,  Michael Meyling <mime@qedeq.org>.
004  *
005  * "Hilbert II" is free software; you can redistribute
006  * it and/or modify it under the terms of the GNU General Public
007  * License as published by the Free Software Foundation; either
008  * version 2 of the License, or (at your option) any later version.
009  *
010  * This program is distributed in the hope that it will be useful,
011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013  * GNU General Public License for more details.
014  */
015 
016 package org.qedeq.base.io;
017 
018 import org.qedeq.base.utility.Splitter;
019 import org.qedeq.base.utility.StringUtility;
020 
021 
022 /**
023  * Wraps a text output stream.
024  *
025  @author  Michael Meyling
026  */
027 public abstract class AbstractOutput {
028 
029     /** Tab level. */
030     private StringBuffer spaces = new StringBuffer();
031 
032     /** Break at this column if greater zero. */
033     private int breakAt;
034 
035     /** Tab level of current line. This is equal to spaces before any character is
036      * written. After writing to the current line this value is fixed and doesn't change even
037      * if the tab level is changed.
038      */
039     private String spacesForCurrentLine;
040 
041     /** Current column. */
042     private int col;
043 
044     /** Token buffer. */
045     private StringBuffer tokenBuffer = new StringBuffer();
046 
047     /** Whitespace buffer. */
048     private StringBuffer wsBuffer = new StringBuffer();
049 
050     /**
051      * Constructor.
052      */
053     public AbstractOutput() {
054     }
055 
056     /**
057      * Add whitespace to output.
058      *
059      @param   ws  Add this whitespace.
060      */
061     public void addWs(final String ws) {
062         if (tokenBuffer.length() 0) {
063             if (fits(wsBuffer.length() + tokenBuffer.length())) {
064                 if (col == 0) {
065                     appendSpaces();
066                 }
067                 append(wsBuffer.toString());
068                 col += wsBuffer.length();
069                 append(tokenBuffer.toString());
070                 col += tokenBuffer.length();
071             else {
072                 // forget old and new whitespace
073                 if (col != 0) {
074                     append("\n");
075                 }
076                 col = 0;
077                 appendSpaces();
078                 append(tokenBuffer.toString());
079                 col += tokenBuffer.length();
080             }
081             wsBuffer.setLength(0);
082             tokenBuffer.setLength(0);
083         }
084         wsBuffer.append(ws);
085     }
086 
087     /**
088      * Append token to output.
089      *
090      @param   part    Add this part.
091      */
092     public void addToken(final String part) {
093         // remember tabular spaces when we start writing
094         if (col == && part.length() 0) {
095             setTabLevel();
096         }
097         tokenBuffer.append(part);
098     }
099 
100     /**
101      * Flush output.
102      */
103     public void flush() {
104         addWs("");
105         wsBuffer.setLength(0);
106     }
107 
108     /**
109      * Print character to output.
110      *
111      @param   c   Append this.
112      */
113     public void print(final char c) {
114         print("" + c);
115 //        if ('\n' == c) {
116 //            println();
117 //            return;
118 //        }
119 //        if (col == 0) {
120 //            appendSpaces();
121 //        } else if (breakAt > 0 && col + 1 > breakAt) {
122 //            lastColBeforeBreak = col;
123 //            println();
124 //            appendSpaces();
125 //        }
126 //        append("" + c);
127 //        col++;
128     }
129 
130     /**
131      * Print spaces and text to output. Treads spaces and CR specially.
132      *
133      @param   text    Append this.
134      */
135     public void print(final String text) {
136         flush();
137         if (text == null) {
138             printWithoutSplit("null");
139             return;
140         }
141         final String[] lines = StringUtility.split(text, "\n");
142         for (int i = 0; i < lines.length; i++) {
143             final Splitter split = new Splitter(lines[i]);
144             while (split.hasNext()) {
145                 final String token = split.nextToken();
146 //                if (breakNecessary(token) && lastChar() == ' '
147                 if (!fits(token&& " ".equals(token)) {
148                 else {
149                     printWithoutSplit(token);
150                 }
151             }
152             if (i + < lines.length) {
153                 println();
154             }
155         }
156     }
157 
158     /**
159      * Append text directly to output device.
160      *
161      @param   text    Append this text.
162      */
163     public abstract void append(final String text);
164 
165     /**
166      * Get writing position.
167      *
168      @return  Writing position.
169      */
170     public abstract long getPosition();
171 
172     /**
173      * Print spaces and text to output.
174      *
175      @param   text    Append this.
176      */
177     public void printWithoutSplit(final String text) {
178         flush();
179         if (text == null) {
180             return;
181         }
182         if (col == 0) {
183             if (text.length() 0) {
184                 // remember tabular spaces when we start writing
185                 setTabLevel();
186                 appendSpaces();
187             }
188         else if (!fits(text)) {
189             println();
190             appendSpaces();
191         }
192         append(text);
193         col += text.length();
194     }
195 
196     /**
197      * Does the text fit to current line?
198      *
199      @param   text    Check if this text could be appended without line break.
200      @return  Does it fit?
201      */
202     private boolean fits(final String text) {
203         if (text == null) {
204             return true;
205         }
206         return fits(text.length());
207     }
208 
209     /**
210      * Does a text with given length fit to current line?
211      * TODO 20110104 m31: should't we use spacesForCurrentLine also?
212      *
213      @param   length    Check if a text of this length could be appended without line break.
214      @return  Does it fit?
215      */
216     private boolean fits(final int length) {
217         return breakAt <= || col + length <= breakAt;
218     }
219 
220     /**
221      * Print object to output.
222      *
223      @param   object  Append text representation of this.
224      */
225     public void print(final Object object) {
226         print(String.valueOf(object));
227     }
228 
229     /**
230      * Print spaces text and new line to output.
231      *
232      @param   token   Append this.
233      */
234     public final void println(final String token) {
235         print(token);
236         println();
237     }
238 
239     /**
240      * Print object and new line to output.
241      *
242      @param   object  Append text representation of this.
243      */
244     public final void println(final Object object) {
245         println(String.valueOf(object));
246     }
247 
248     /**
249      * Print new line to output.
250      */
251     public void println() {
252         flush();
253         if (col == && spaces.toString().trim().length() 0) {
254             setTabLevel();
255             appendSpaces();
256         }
257         append("\n");
258         col = 0;
259     }
260 
261     /**
262      * Skip until given column. To do this we append spaces.
263      *
264      @param   column  Skip to this column.
265      */
266     public void skipToColumn(final int column) {
267         for (int i = col; i < column; i++) {
268             printWithoutSplit(" ");
269         }
270     }
271 
272     /**
273      * Reset tab level to zero.
274      */
275     public final void clearLevel() {
276         // flush();
277         spaces.setLength(0);
278     }
279 
280     /**
281      * Decrement tab level.
282      */
283     public final void popLevel() {
284         if (spaces.length() 0) {
285             spaces.setLength(spaces.length() 2);
286         }
287     }
288 
289     /**
290      * Decrement tab level.
291      *
292      @param   characters  Number of characters to reduce from tab level.
293      */
294     public final void popLevel(final int characters) {
295         if (spaces.length() 0) {
296             spaces.setLength(Math.max(spaces.length() - characters, 0));
297         }
298     }
299 
300     /**
301      * Return current tab string.
302      *
303      @return  Current tab string.
304      */
305     public final String getLevel() {
306         return spaces.toString();
307     }
308 
309     /**
310      * Set current tab string.
311      *
312      @param   level   Tab string.
313      */
314     public final void setLevel(final String level) {
315         spaces.setLength(0);
316         spaces.append(level);
317     }
318 
319     /**
320      * Increment tab level.
321      */
322     public final void pushLevel() {
323         spaces.append("  ");
324     }
325 
326     /**
327      * Increment tab level with following symbols.
328      *
329      @param   symbols Symbols to tab width. Length should be exactly 2 characters!
330      */
331     public final void pushLevel(final String symbols) {
332         spaces.append(symbols);
333     }
334 
335     /**
336      * Set current tab level to current level. Might change unwritten lines.
337      */
338     public final void setTabLevel() {
339         spacesForCurrentLine = spaces.toString();
340     }
341 
342     /**
343      * Set number of maximum columns. If possible we break before we reach this column number.
344      * If less or equal to zero no line breaking is done automatically.
345      *
346      @param   columns Maximum column size.
347      */
348     public void setColumns(final int columns) {
349         if (columns < 0) {
350             breakAt = 0;
351         else {
352             breakAt = columns;
353         }
354     }
355 
356     /**
357      * Return number of maximum columns. If equal to zero no line breaking is done automatically.
358      *
359      @return  Maximum column size.
360      */
361     public final int getColumns() {
362         return breakAt;
363     }
364 
365     /**
366      * Append tabulation and increase current column.
367      */
368     private void appendSpaces() {
369         append(spacesForCurrentLine.toString());
370         col += spacesForCurrentLine.length();
371     }
372 
373 }