From 436bd3f0ecdee282c503a9eb0f7a240b7a68ff49 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Fri, 11 Apr 2014 14:51:50 -0400
Subject: [PATCH] Merged #6 "Support serving repositories over the SSH transport"

---
 src/main/java/com/gitblit/utils/FlipTable.java |  231 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 231 insertions(+), 0 deletions(-)

diff --git a/src/main/java/com/gitblit/utils/FlipTable.java b/src/main/java/com/gitblit/utils/FlipTable.java
new file mode 100644
index 0000000..0197517
--- /dev/null
+++ b/src/main/java/com/gitblit/utils/FlipTable.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2014 Jake Wharton
+ * Copyright 2014 gitblit.com.
+ *
+ * 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.gitblit.utils;
+
+
+/**
+ * This is a forked version of FlipTables which supports controlling the
+ * displayed borders and gracefully handles null cell values.
+ *
+ * FULL = all borders
+ * BODY_COLS = header + perimeter + column separators
+ * COLS = header + column separators
+ * BODY = header + perimeter
+ * HEADER = header only
+ *
+ * <pre>
+ * ╔═════════════╤════════════════════════════╤══════════════╗
+ * ║ Name        │ Function                   │ Author       ║
+ * ╠═════════════╪════════════════════════════╪══════════════╣
+ * ║ Flip Tables │ Pretty-print a text table. │ Jake Wharton ║
+ * ╚═════════════╧════════════════════════════╧══════════════╝
+ * </pre>
+ */
+public final class FlipTable {
+	public static final String EMPTY = "(empty)";
+
+	public static enum Borders {
+		FULL(15), BODY_HCOLS(13), HCOLS(12), BODY(9), HEADER(8), COLS(4);
+
+		final int bitmask;
+
+		private Borders(int bitmask) {
+			this.bitmask = bitmask;
+		}
+
+		boolean header() {
+			return isset(0x8);
+		}
+
+		boolean body() {
+			return isset(0x1);
+		}
+
+		boolean rows() {
+			return isset(0x2);
+		}
+
+		boolean columns() {
+			return isset(0x4);
+		}
+
+		boolean isset(int v) {
+			return (bitmask & v) == v;
+		}
+	}
+
+	/** Create a new table with the specified headers and row data. */
+	public static String of(String[] headers, Object[][] data) {
+		return of(headers, data, Borders.FULL);
+	}
+
+	/** Create a new table with the specified headers and row data. */
+	public static String of(String[] headers, Object[][] data, Borders borders) {
+		if (headers == null)
+			throw new NullPointerException("headers == null");
+		if (headers.length == 0)
+			throw new IllegalArgumentException("Headers must not be empty.");
+		if (data == null)
+			throw new NullPointerException("data == null");
+		return new FlipTable(headers, data, borders).toString();
+	}
+
+	private final String[] headers;
+	private final Object[][] data;
+	private final Borders borders;
+	private final int columns;
+	private final int[] columnWidths;
+	private final int emptyWidth;
+
+	private FlipTable(String[] headers, Object[][] data, Borders borders) {
+		this.headers = headers;
+		this.data = data;
+		this.borders = borders;
+
+		columns = headers.length;
+		columnWidths = new int[columns];
+		for (int row = -1; row < data.length; row++) {
+			Object[] rowData = (row == -1) ? headers : data[row];
+			if (rowData.length != columns) {
+				throw new IllegalArgumentException(String.format("Row %s's %s columns != %s columns", row + 1,
+						rowData.length, columns));
+			}
+			for (int column = 0; column < columns; column++) {
+				Object cell = rowData[column];
+				if (cell == null) {
+					continue;
+				}
+				for (String rowDataLine : cell.toString().split("\\n")) {
+					columnWidths[column] = Math.max(columnWidths[column], rowDataLine.length());
+				}
+			}
+		}
+
+		 // Account for column dividers and their spacing.
+		int emptyWidth = 3 * (columns - 1);
+		for (int columnWidth : columnWidths) {
+			emptyWidth += columnWidth;
+		}
+		this.emptyWidth = emptyWidth;
+
+		if (emptyWidth < EMPTY.length()) {
+			// Make sure we're wide enough for the empty text.
+			columnWidths[columns - 1] += EMPTY.length() - emptyWidth;
+		}
+	}
+
+	@Override
+	public String toString() {
+		StringBuilder builder = new StringBuilder();
+		if (borders.header()) {
+			printDivider(builder, "╔═╤═╗");
+		}
+		printData(builder, headers, true);
+		if (data.length == 0) {
+			if (borders.body()) {
+				printDivider(builder, "╠═╧═╣");
+				builder.append('║').append(pad(emptyWidth, EMPTY)).append("║\n");
+				printDivider(builder, "╚═══╝");
+			} else if (borders.header()) {
+				printDivider(builder, "╚═╧═╝");
+				builder.append(' ').append(pad(emptyWidth, EMPTY)).append(" \n");
+			}
+		} else {
+			for (int row = 0; row < data.length; row++) {
+				if (row == 0 && borders.header()) {
+					if (borders.body()) {
+						if (borders.columns()) {
+							printDivider(builder, "╠═╪═╣");
+						} else {
+							printDivider(builder, "╠═╧═╣");
+						}
+					} else {
+						if (borders.columns()) {
+							printDivider(builder, "╚═╪═╝");
+						} else {
+							printDivider(builder, "╚═╧═╝");
+						}
+					}
+				} else if (row == 0 && !borders.header()) {
+					if (borders.columns()) {
+						printDivider(builder, " ─┼─ ");
+					} else {
+						printDivider(builder, " ─┼─ ");
+					}
+				} else if (borders.rows()) {
+					if (borders.columns()) {
+						printDivider(builder, "╟─┼─╢");
+					} else {
+						printDivider(builder, "╟─┼─╢");
+					}
+				}
+				printData(builder, data[row], false);
+			}
+			if (borders.body()) {
+				if (borders.columns()) {
+					printDivider(builder, "╚═╧═╝");
+				} else {
+					printDivider(builder, "╚═══╝");
+				}
+			}
+		}
+		return builder.toString();
+	}
+
+	private void printDivider(StringBuilder out, String format) {
+		for (int column = 0; column < columns; column++) {
+			out.append(column == 0 ? format.charAt(0) : format.charAt(2));
+			out.append(pad(columnWidths[column], "").replace(' ', format.charAt(1)));
+		}
+		out.append(format.charAt(4)).append('\n');
+	}
+
+	private void printData(StringBuilder out, Object[] data, boolean isHeader) {
+		for (int line = 0, lines = 1; line < lines; line++) {
+			for (int column = 0; column < columns; column++) {
+				if (column == 0) {
+					if ((isHeader && borders.header()) || borders.body()) {
+						out.append('║');
+					} else {
+						out.append(' ');
+					}
+				} else if (isHeader || borders.columns()) {
+					out.append('│');
+				} else {
+					out.append(' ');
+				}
+				Object cell = data[column];
+				if (cell == null) {
+					cell = "";
+				}
+				String[] cellLines = cell.toString().split("\\n");
+				lines = Math.max(lines, cellLines.length);
+				String cellLine = line < cellLines.length ? cellLines[line] : "";
+				out.append(pad(columnWidths[column], cellLine));
+			}
+			if ((isHeader && borders.header()) || borders.body()) {
+				out.append("║\n");
+			} else {
+				out.append('\n');
+			}
+		}
+	}
+
+	private static String pad(int width, String data) {
+		return String.format(" %1$-" + width + "s ", data);
+	}
+}

--
Gitblit v1.9.1