001/* 002 * Copyright (C) 2016 Hobrasoft s.r.o. 003 * 004 * This program is free software: you can redistribute it and/or modify 005 * it under the terms of the GNU Affero General Public License as published by 006 * the Free Software Foundation, either version 3 of the License, or 007 * (at your option) any later version. 008 * 009 * This program is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 * GNU Affero General Public License for more details. 013 * 014 * You should have received a copy of the GNU Affero General Public License 015 * along with this program. If not, see <http://www.gnu.org/licenses/>. 016 */ 017package cz.hobrasoft.pdfmu; 018 019import java.io.Flushable; 020import java.io.IOException; 021import java.io.PrintStream; 022import org.apache.commons.lang3.StringUtils; 023 024/** 025 * Prints indented messages to a {@link PrintStream} 026 * 027 * <p> 028 * The indentation level starts at 0 and can be changed using 029 * {@link #indentMore} and {@link #indentLess}. 030 * 031 * <p> 032 * Example of usage: 033 * <pre> 034 * {@code 035 * TextOutput to = new TextOutput(System.out); 036 * to.println("Hello!"); 037 * to.indentMore("My favorite fruits:"); 038 * to.println("Banana"); 039 * to.println("Apple"); 040 * to.indentLess(); 041 * to.flush(); 042 * } 043 * </pre> 044 * 045 * @author <a href="mailto:filip.bartek@hobrasoft.cz">Filip Bartek</a> 046 */ 047public class TextOutput implements Flushable { 048 049 private final PrintStream ps; 050 private int indentLevel = 0; 051 private static final String indentString = " "; 052 053 /** 054 * Creates a {@link TextOutput} bound to a {@link PrintStream} 055 * 056 * @param ps the {@link PrintStream} to print messages to 057 */ 058 public TextOutput(PrintStream ps) { 059 // ps may be null 060 this.ps = ps; 061 } 062 063 /** 064 * Creates a {@link TextOutput} that discards all the messages 065 */ 066 public TextOutput() { 067 this(null); 068 } 069 070 /** 071 * Prints a message on a separate line 072 * 073 * <p> 074 * The message is indented by the current indentation level (starting at 0) 075 * and printed using the specified {@link PrintStream}. 076 * 077 * <p> 078 * Mimics {@link PrintStream#println(String x)}. 079 * 080 * @param x message to print 081 */ 082 public void println(String x) { 083 if (ps != null) { 084 assert indentLevel >= 0; 085 String prefix = StringUtils.repeat(indentString, indentLevel); 086 ps.println(String.format("%s%s", prefix, x)); 087 } 088 } 089 090 /** 091 * Increments the indentation level 092 * 093 * <p> 094 * If the code between {@link #indentMore} and {@link #indentLess} may throw 095 * a (checked) exception, surround the code with a 096 * {@code try}-{@code finally} block like this to maintain consistency: 097 * <pre> 098 * {@code 099 * 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}