TwoColumnOutput.java revision 31d87776c459972f311a3527694e0d630d92a84b
1/*
2 * Copyright 2013, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 *     * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *     * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32package org.jf.util;
33
34import javax.annotation.Nonnull;
35import java.io.IOException;
36import java.io.OutputStream;
37import java.io.OutputStreamWriter;
38import java.io.Writer;
39
40/**
41 * Class that takes a combined output destination and provides two
42 * output writers, one of which ends up writing to the left column and
43 * one which goes on the right.
44 */
45public final class TwoColumnOutput {
46    /** non-null; underlying writer for final output */
47    private final Writer out;
48
49    /** > 0; the left column width */
50    private final int leftWidth;
51
52    private final int rightWidth;
53
54    private final String spacer;
55
56    /**
57     * Constructs an instance.
58     *
59     * @param out non-null; writer to send final output to
60     * @param leftWidth > 0; width of the left column, in characters
61     * @param rightWidth > 0; width of the right column, in characters
62     * @param spacer non-null; spacer string to sit between the two columns
63     */
64    public TwoColumnOutput(@Nonnull Writer out, int leftWidth, int rightWidth,
65                           @Nonnull String spacer) {
66
67        if (leftWidth < 1) {
68            throw new IllegalArgumentException("leftWidth < 1");
69        }
70
71        if (rightWidth < 1) {
72            throw new IllegalArgumentException("rightWidth < 1");
73        }
74
75        this.out = out;
76        this.leftWidth = leftWidth;
77        this.rightWidth = rightWidth;
78        this.spacer = spacer;
79    }
80
81    /**
82     * Constructs an instance.
83     *
84     * @param out non-null; stream to send final output to
85     * @param leftWidth &gt;= 1; width of the left column, in characters
86     * @param rightWidth &gt;= 1; width of the right column, in characters
87     * @param spacer non-null; spacer string to sit between the two columns
88     */
89    public TwoColumnOutput(OutputStream out, int leftWidth, int rightWidth,
90                           String spacer) {
91        this(new OutputStreamWriter(out), leftWidth, rightWidth, spacer);
92    }
93
94    private String[] leftLines = null;
95    private String[] rightLines = null;
96    public void write(String left, String right) throws IOException {
97        leftLines = StringWrapper.wrapString(left, leftWidth, leftLines);
98        rightLines = StringWrapper.wrapString(right, rightWidth, rightLines);
99        int leftCount = leftLines.length;
100        int rightCount = rightLines.length;
101
102        for (int i=0; i<leftCount || i <rightCount; i++) {
103            String leftLine = null;
104            String rightLine = null;
105
106            if (i < leftCount) {
107                leftLine = leftLines[i];
108                if (leftLine == null) {
109                    leftCount = i;
110                }
111            }
112
113            if (i < rightCount) {
114                rightLine = rightLines[i];
115                if (rightLine == null) {
116                    rightCount = i;
117                }
118            }
119
120            if (leftLine != null || rightLine != null) {
121                int written = 0;
122                if (leftLine != null) {
123                    out.write(leftLine);
124                    written = leftLine.length();
125                }
126
127                int remaining = leftWidth - written;
128                if (remaining > 0) {
129                    writeSpaces(out, remaining);
130                }
131
132                out.write(spacer);
133
134                if (rightLine != null) {
135                    out.write(rightLine);
136                }
137
138                out.write('\n');
139            }
140        }
141    }
142
143    /**
144     * Writes the given number of spaces to the given writer.
145     *
146     * @param out non-null; where to write
147     * @param amt &gt;= 0; the number of spaces to write
148     */
149    private static void writeSpaces(Writer out, int amt) throws IOException {
150        while (amt > 0) {
151            out.write(' ');
152            amt--;
153        }
154    }
155}
156