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 == 0 && 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 + 1 < 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 <= 0 || 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 == 0 && 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 }
|