View Javadoc
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 }