1 /*
2 * Copyright (C) 2016 Hobrasoft s.r.o.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17 package cz.hobrasoft.pdfmu;
18
19 import java.io.Flushable;
20 import java.io.IOException;
21 import java.io.PrintStream;
22 import org.apache.commons.lang3.StringUtils;
23
24 /**
25 * Prints indented messages to a {@link PrintStream}
26 *
27 * <p>
28 * The indentation level starts at 0 and can be changed using
29 * {@link #indentMore} and {@link #indentLess}.
30 *
31 * <p>
32 * Example of usage:
33 * <pre>
34 * {@code
35 * TextOutput to = new TextOutput(System.out);
36 * to.println("Hello!");
37 * to.indentMore("My favorite fruits:");
38 * to.println("Banana");
39 * to.println("Apple");
40 * to.indentLess();
41 * to.flush();
42 * }
43 * </pre>
44 *
45 * @author <a href="mailto:filip.bartek@hobrasoft.cz">Filip Bartek</a>
46 */
47 public class TextOutput implements Flushable {
48
49 private final PrintStream ps;
50 private int indentLevel = 0;
51 private static final String indentString = " ";
52
53 /**
54 * Creates a {@link TextOutput} bound to a {@link PrintStream}
55 *
56 * @param ps the {@link PrintStream} to print messages to
57 */
58 public TextOutput(PrintStream ps) {
59 // ps may be null
60 this.ps = ps;
61 }
62
63 /**
64 * Creates a {@link TextOutput} that discards all the messages
65 */
66 public TextOutput() {
67 this(null);
68 }
69
70 /**
71 * Prints a message on a separate line
72 *
73 * <p>
74 * The message is indented by the current indentation level (starting at 0)
75 * and printed using the specified {@link PrintStream}.
76 *
77 * <p>
78 * Mimics {@link PrintStream#println(String x)}.
79 *
80 * @param x message to print
81 */
82 public void println(String x) {
83 if (ps != null) {
84 assert indentLevel >= 0;
85 String prefix = StringUtils.repeat(indentString, indentLevel);
86 ps.println(String.format("%s%s", prefix, x));
87 }
88 }
89
90 /**
91 * Increments the indentation level
92 *
93 * <p>
94 * If the code between {@link #indentMore} and {@link #indentLess} may throw
95 * a (checked) exception, surround the code with a
96 * {@code try}-{@code finally} block like this to maintain consistency:
97 * <pre>
98 * {@code
99 * TextOutput to;
100 * to.indentMore();
101 * try {
102 * // Do stuff, possibly throwing an exception
103 * // Possibly catch the exception
104 * } finally {
105 * to.indentLess();
106 * }
107 * }
108 * </pre>
109 */
110 public void indentMore() {
111 ++indentLevel;
112 }
113
114 /**
115 * Prints a message and increments the indentation level
116 *
117 * @param message message to print
118 */
119 public void indentMore(String message) {
120 println(message);
121 indentMore();
122 }
123
124 /**
125 * Decrements the indentation level
126 */
127 public void indentLess() {
128 if (indentLevel > 0) {
129 --indentLevel;
130 }
131 assert indentLevel >= 0;
132 }
133
134 /**
135 * Flushes the underlying {@link PrintStream}
136 *
137 * @throws IOException if the underlying {@link PrintStream#flush} throws an
138 * {@link IOException}
139 */
140 @Override
141 public void flush() throws IOException {
142 if (ps != null) {
143 ps.flush();
144 }
145 }
146 }