1 /*
   2  * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.rmi.rmic.newrmic;
  27 
  28 import java.io.Writer;
  29 import java.io.BufferedWriter;
  30 import java.io.IOException;
  31 
  32 /**
  33  * A BufferedWriter that supports automatic indentation of lines of
  34  * text written to the underlying Writer.
  35  *
  36  * Methods are provided for compact/convenient indenting in and out,
  37  * writing text, and writing lines of text in various combinations.
  38  *
  39  * WARNING: The contents of this source file are not part of any
  40  * supported API.  Code that depends on them does so at its own risk:
  41  * they are subject to change or removal without notice.
  42  *
  43  * @author Peter Jones
  44  **/
  45 public class IndentingWriter extends BufferedWriter {
  46 
  47     /** number of spaces to change indent when indenting in or out */
  48     private final int indentStep;
  49 
  50     /** number of spaces to convert into tabs (use MAX_VALUE to disable) */
  51     private final int tabSize;
  52 
  53     /** true if the next character written is the first on a line */
  54     private boolean beginningOfLine = true;
  55 
  56     /** current number of spaces to prepend to lines */
  57     private int currentIndent = 0;
  58 
  59     /**
  60      * Creates a new IndentingWriter that writes indented text to the
  61      * given Writer.  Use the default indent step of four spaces.
  62      **/
  63     public IndentingWriter(Writer out) {
  64         this(out, 4);
  65     }
  66 
  67     /**
  68      * Creates a new IndentingWriter that writes indented text to the
  69      * given Writer and uses the supplied indent step.
  70      **/
  71     public IndentingWriter(Writer out, int indentStep) {
  72         this(out, indentStep, 8);
  73     }
  74 
  75     /**
  76      * Creates a new IndentingWriter that writes indented text to the
  77      * given Writer and uses the supplied indent step and tab size.
  78      **/
  79     public IndentingWriter(Writer out, int indentStep, int tabSize) {
  80         super(out);
  81         if (indentStep < 0) {
  82             throw new IllegalArgumentException("negative indent step");
  83         }
  84         if (tabSize < 0) {
  85             throw new IllegalArgumentException("negative tab size");
  86         }
  87         this.indentStep = indentStep;
  88         this.tabSize = tabSize;
  89     }
  90 
  91     /**
  92      * Writes a single character.
  93      **/
  94     public void write(int c) throws IOException {
  95         checkWrite();
  96         super.write(c);
  97     }
  98 
  99     /**
 100      * Writes a portion of an array of characters.
 101      **/
 102     public void write(char[] cbuf, int off, int len) throws IOException {
 103         if (len > 0) {
 104             checkWrite();
 105         }
 106         super.write(cbuf, off, len);
 107     }
 108 
 109     /**
 110      * Writes a portion of a String.
 111      **/
 112     public void write(String s, int off, int len) throws IOException {
 113         if (len > 0) {
 114             checkWrite();
 115         }
 116         super.write(s, off, len);
 117     }
 118 
 119     /**
 120      * Writes a line separator.  The next character written will be
 121      * preceded by an indent.
 122      **/
 123     public void newLine() throws IOException {
 124         super.newLine();
 125         beginningOfLine = true;
 126     }
 127 
 128     /**
 129      * Checks if an indent needs to be written before writing the next
 130      * character.
 131      *
 132      * The indent generation is optimized (and made consistent with
 133      * certain coding conventions) by condensing groups of eight
 134      * spaces into tab characters.
 135      **/
 136     protected void checkWrite() throws IOException {
 137         if (beginningOfLine) {
 138             beginningOfLine = false;
 139             int i = currentIndent;
 140             while (i >= tabSize) {
 141                 super.write('\t');
 142                 i -= tabSize;
 143             }
 144             while (i > 0) {
 145                 super.write(' ');
 146                 i--;
 147             }
 148         }
 149     }
 150 
 151     /**
 152      * Increases the current indent by the indent step.
 153      **/
 154     protected void indentIn() {
 155         currentIndent += indentStep;
 156     }
 157 
 158     /**
 159      * Decreases the current indent by the indent step.
 160      **/
 161     protected void indentOut() {
 162         currentIndent -= indentStep;
 163         if (currentIndent < 0)
 164             currentIndent = 0;
 165     }
 166 
 167     /**
 168      * Indents in.
 169      **/
 170     public void pI() {
 171         indentIn();
 172     }
 173 
 174     /**
 175      * Indents out.
 176      **/
 177     public void pO() {
 178         indentOut();
 179     }
 180 
 181     /**
 182      * Writes string.
 183      **/
 184     public void p(String s) throws IOException {
 185         write(s);
 186     }
 187 
 188     /**
 189      * Ends current line.
 190      **/
 191     public void pln() throws IOException {
 192         newLine();
 193     }
 194 
 195     /**
 196      * Writes string; ends current line.
 197      **/
 198     public void pln(String s) throws IOException {
 199         p(s);
 200         pln();
 201     }
 202 
 203     /**
 204      * Writes string; ends current line; indents in.
 205      **/
 206     public void plnI(String s) throws IOException {
 207         p(s);
 208         pln();
 209         pI();
 210     }
 211 
 212     /**
 213      * Indents out; writes string.
 214      **/
 215     public void pO(String s) throws IOException {
 216         pO();
 217         p(s);
 218     }
 219 
 220     /**
 221      * Indents out; writes string; ends current line.
 222      **/
 223     public void pOln(String s) throws IOException {
 224         pO(s);
 225         pln();
 226     }
 227 
 228     /**
 229      * Indents out; writes string; ends current line; indents in.
 230      *
 231      * This method is useful for generating lines of code that both
 232      * end and begin nested blocks, like "} else {".
 233      **/
 234     public void pOlnI(String s) throws IOException {
 235         pO(s);
 236         pln();
 237         pI();
 238     }
 239 
 240     /**
 241      * Writes object.
 242      **/
 243     public void p(Object o) throws IOException {
 244         write(o.toString());
 245     }
 246 
 247     /**
 248      * Writes object; ends current line.
 249      **/
 250     public void pln(Object o) throws IOException {
 251         p(o.toString());
 252         pln();
 253     }
 254 
 255     /**
 256      * Writes object; ends current line; indents in.
 257      **/
 258     public void plnI(Object o) throws IOException {
 259         p(o.toString());
 260         pln();
 261         pI();
 262     }
 263 
 264     /**
 265      * Indents out; writes object.
 266      **/
 267     public void pO(Object o) throws IOException {
 268         pO();
 269         p(o.toString());
 270     }
 271 
 272     /**
 273      * Indents out; writes object; ends current line.
 274      **/
 275     public void pOln(Object o) throws IOException {
 276         pO(o.toString());
 277         pln();
 278     }
 279 
 280     /**
 281      * Indents out; writes object; ends current line; indents in.
 282      *
 283      * This method is useful for generating lines of code that both
 284      * end and begin nested blocks, like "} else {".
 285      **/
 286     public void pOlnI(Object o) throws IOException {
 287         pO(o.toString());
 288         pln();
 289         pI();
 290     }
 291 }