blob: 97579395f60ca8db0a417b8016e8eb706ad414ce [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tradefed.util;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.IntStream;
/** Helper class to display a matrix of String elements in a table. */
public class TableBuilder {
/*
* Sample:
*
* +======================Metric Regressions=======================+
* | Metric Name | Pre Avg | Post Avg | False Positive Probability |
* +===============================================================+
* | Run Metrics (1 compared, 0 changed) |
* +---------------------------------------------------------------+
* | Test Metrics (9 compared, 3 changed) |
* +---------------------------------------------------------------+
* | > com.android.uiautomator.samples.skeleton.DemoTestCase#testD |
* | emo3 |
* | stat1 | 100.54 | 817.40 | 0.101 |
* | |
* | > com.android.uiautomator.samples.skeleton.DemoTestCase#testD |
* | emo2 |
* | stat3 | 12.32 | 100.91 | 0.101 |
* | stat4 | 104.46 | 24.61 | 0.101 |
* | |
* +===============================================================+
*/
// Blank space on the left of the table.
private int mTableOffset = 2;
// Padding on left & right side of each column.
private int mPadding = 1;
private final int mColumns;
private int mRowLength;
private int[] mColumnWidth;
private List<Line> mTable;
private StringBuilder mBuilder;
private interface Line {
void build();
}
private class Separator implements Line {
char mEnd;
char mPipe;
String mText;
Separator(char end, char pipe, String text) {
mEnd = end;
mPipe = pipe;
mText = text;
}
@Override
public void build() {
addPadding(mTableOffset);
mBuilder.append(mEnd);
int blanks = mRowLength - mText.length() - 2;
for (int i = 0; i < blanks / 2; i++) {
mBuilder.append(mPipe);
}
mBuilder.append(mText);
for (int i = 0; i < blanks / 2; i++) {
mBuilder.append(mPipe);
}
// Correct for odd length
if (blanks % 2 != 0) {
mBuilder.append(mPipe);
}
mBuilder.append(mEnd).append('\n');
}
}
private class SingleColumn implements Line {
String mText;
SingleColumn(String text) {
mText = text;
}
@Override
public void build() {
int width = mRowLength - 2 - mPadding * 2; // Deduct boundaries
String text = mText;
while (text != null) {
addPadding(mTableOffset);
mBuilder.append('|');
addPadding(mPadding);
if (text.length() > width) {
mBuilder.append(text.substring(0, width));
text = text.substring(width);
} else {
mBuilder.append(text);
addPadding(width - text.length());
text = null;
}
addPadding(mPadding);
mBuilder.append("|\n");
}
}
}
private class MultiColumn implements Line {
String[] mColumns;
MultiColumn(String[] columns) {
mColumns = columns;
}
@Override
public void build() {
addPadding(mTableOffset);
mBuilder.append("|");
for (int i = 0; i < mColumns.length; i++) {
addPadding(mPadding);
mBuilder.append(mColumns[i]);
addPadding(mColumnWidth[i] - mColumns[i].length() + mPadding);
mBuilder.append('|');
}
mBuilder.append('\n');
}
}
/**
* Constructs a TableBuilder with specific number of columns.
*
* @param numColumns number of columns in this table.
*/
public TableBuilder(int numColumns) {
mColumns = numColumns;
mColumnWidth = new int[numColumns];
mTable = new LinkedList<>();
}
/**
* Sets the number of white space before and after each column element
*
* @param padding the number of white space
* @return this
*/
public TableBuilder setPadding(int padding) {
mPadding = padding;
return this;
}
/**
* Sets the number of white space on the left of the whole table
*
* @param offset the number of white space
* @return this
*/
public TableBuilder setOffset(int offset) {
mTableOffset = offset;
return this;
}
/**
* Adds a title to this table. Sample: +======================TITLE=======================+
*
* @param title title
* @return this
*/
public TableBuilder addTitle(String title) {
mTable.add(new Separator('+', '=', title));
return this;
}
/**
* Adds a row separator like: +---------------------------------------------+
*
* @return this
*/
public TableBuilder addSingleLineSeparator() {
return addSeparator('+', '-');
}
/**
* Adds a row separator like: +=============================================+
*
* @return this
*/
public TableBuilder addDoubleLineSeparator() {
return addSeparator('+', '=');
}
/**
* Adds a row separator like: | | (blank space between two pipes)
*
* @return this
*/
public TableBuilder addBlankLineSeparator() {
return addSeparator('|', ' ');
}
/**
* Adds a custom row separator.
*
* @param end the two end character.
* @param pipe the character connecting two ends
* @return this
*/
public TableBuilder addSeparator(char end, char pipe) {
mTable.add(new Separator(end, pipe, ""));
return this;
}
/**
* Adds a single long line. TableBuilder will wrap it if it is too long. See example above.
*
* @param line the line.
* @return this
*/
public TableBuilder addLine(String line) {
mTable.add(new SingleColumn(line));
return this;
}
/**
* Adds a line. The number of columns in line must equal numColumns provided in the constructor.
*
* @param line the line.
* @return this
* @throws IllegalArgumentException when the number of columns in line does not agree with
* numColumns provided in the constructor.
*/
public TableBuilder addLine(String[] line) {
if (line.length != mColumns) {
throw new IllegalArgumentException(
String.format("Expect %d columns, actual %d columns", mColumns, line.length));
}
mTable.add(new MultiColumn(line));
for (int i = 0; i < mColumns; i++) {
if (line[i].length() > mColumnWidth[i]) {
mColumnWidth[i] = line[i].length();
}
}
return this;
}
/**
* Builds the table and return as a string.
*
* @return the table in string format.
*/
public String build() {
mBuilder = new StringBuilder();
mRowLength = IntStream.of(mColumnWidth).map(i -> i + 2 * mPadding + 1).sum() + 1;
for (Line line : mTable) {
line.build();
}
return mBuilder.toString();
}
private void addPadding(int padding) {
for (int i = 0; i < padding; i++) {
mBuilder.append(' ');
}
}
}