/*
* Copyright 2014 Jocki Hendry
*
* 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 simple.escp.dom.line;
import simple.escp.dom.Line;
import simple.escp.dom.TableColumn;
import simple.escp.placeholder.BasicPlaceholder;
import simple.escp.util.EscpUtil;
import simple.escp.util.StringUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
* DOM class to represent table. A table consists of one or more {@link simple.escp.dom.TableColumn}.
*/
public class TableLine extends Line implements Iterable<TableColumn> {
private List<TableColumn> columns = new ArrayList<>();
private String source;
private boolean drawBorder;
private boolean drawLineSeparator;
private boolean drawUnderlineSeparator;
private TextLine[] header;
private TextLine[] footer;
/**
* Create a new <code>TableLine</code>.
*
* @param source a placeholder text to retrieve data source for this table. It should be evaluated to a
* <code>Collection</code> during filling.
*/
public TableLine(String source) {
this.source = source;
}
/**
* Get the placeholder text that represents data source for this table.
*
* @return data source for this table.
*/
public String getSource() {
return source;
}
/**
* Add a new <code>TableColumn</code> to this table.
*
* @param column a new <code>TableColumn</code> that will be appended at the right-most position.
* @return the new <code>TableColumn</code>.
*/
public TableColumn addColumn(TableColumn column) {
columns.add(column);
return column;
}
/**
* Add a new <code>TableColumn</code> to this table.
*
* @param text the text, may contains placeholder, for this column.
* @param width width of this column in number of characters.
* @return the new <code>TableColumn</code>.
*/
public TableColumn addColumn(String text, int width) {
TableColumn column = new TableColumn(text, width);
return addColumn(column);
}
/**
* Get number of columns in this table.
*
* @return number of columns in this table.
*/
public int getNumberOfColumns() {
return columns.size();
}
/**
* Get a column based on index.
*
* @param index the position of column starting. The left-most column has index <code>1</code>, the next column
* is <code>2</code>, and so on.
* @return the <code>TableColumn</code> at <code>index</code> position.
*/
public TableColumn getColumnAt(int index) {
if ((index < 1) || (index > getNumberOfColumns())) {
throw new IllegalArgumentException("Index [" + index + "] is not valid.");
}
return columns.get(index - 1);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isDynamic() {
return true;
}
/**
* Determine if this table line should have border drawn around it. Drawing border will reduce the
* width of every columns by one character. It also will increase number of lines required by the table.
*
* @return <code>true</code> if this <code>TableLine</code> has border.
*/
public boolean isDrawBorder() {
return drawBorder;
}
/**
* Set wether to enable drawing solid border for this table line or not.
*
* @param drawBorder <code>true</code> to enable border for this table.
*/
public void setDrawBorder(boolean drawBorder) {
this.drawBorder = drawBorder;
}
/**
* Determine if an extra line that contains solid line as line separator should be drawn for this table.
*
* @return <code>true</code> if line separator should be drawn.
*/
public boolean isDrawLineSeparator() {
return drawLineSeparator;
}
/**
* Set wether to enable line separator for this table line or not.
*
* @param drawLineSeparator <code>true</code> to enable line separator for this table.
*/
public void setDrawLineSeparator(boolean drawLineSeparator) {
this.drawLineSeparator = drawLineSeparator;
}
/**
* Determine if the last line of a row in table should be underlined. This is more compact than creating
* a new line consists of box characters.
*
* @return <code>true</code> if underline should be applied to last line of a row.
*/
public boolean isDrawUnderlineSeparator() {
return drawUnderlineSeparator;
}
/**
* Set wether to underline the last line of a row in this table.
*
* @param drawUnderlineSeparator <code>true</code> to underline last line of each row.
*/
public void setDrawUnderlineSeparator(boolean drawUnderlineSeparator) {
this.drawUnderlineSeparator = drawUnderlineSeparator;
}
/**
* Get width of lines in this table in number of characters.
*
* @return width in number of characters.
*/
public int getWidth() {
int result = 0;
for (TableColumn column : columns) {
result += column.getWidth();
}
return result;
}
/**
* Retrieve the header for this table. If border for this table is disabled, header will only be a row that
* contains column's caption. If border is enabled, the header is three lines with CP347 pseudo-graphic
* characters to simulate a border.
*
* @return the definition of header.
*/
public TextLine[] getHeader() {
if (header == null) {
List<TextLine> tmp = new ArrayList<>();
StringBuilder line = new StringBuilder();
// draw header upper border if necessary
if (isDrawBorder()) {
line.append(EscpUtil.CP347_LIGHT_DOWN_RIGHT);
for (int columnIndex = 0; columnIndex < columns.size(); columnIndex++) {
TableColumn column = columns.get(columnIndex);
for (int i = 0; i < column.getWidth() - 1; i++) {
line.append(EscpUtil.CP347_LIGHT_HORIZONTAL);
}
if (columnIndex == (columns.size() - 1)) {
line.append(EscpUtil.CP347_LIGHT_DOWN_LEFT);
} else {
line.append(EscpUtil.CP347_LIGHT_DOWN_HORIZONTAL);
}
}
tmp.add(new TextLine(line.toString()));
}
// draw column name
line = new StringBuilder();
if (isDrawBorder()) {
line.append(EscpUtil.CP347_LIGHT_VERTICAL);
}
for (int columnIndex = 0; columnIndex < columns.size(); columnIndex++) {
TableColumn column = columns.get(columnIndex);
int width = column.getWidth() - (isDrawBorder() ? 1 : 0);
StringUtil.ALIGNMENT alignment = (new BasicPlaceholder(column.getText())).getAlignment();
if (alignment == null) {
alignment = StringUtil.ALIGNMENT.LEFT;
}
line.append(StringUtil.align(column.getCaption(), width, alignment));
if (isDrawBorder()) {
line.append(EscpUtil.CP347_LIGHT_VERTICAL);
}
}
tmp.add(new TextLine(line.toString()));
// draw lower border if necessary
line = new StringBuilder();
if (isDrawBorder()) {
line.append(EscpUtil.CP347_LIGHT_VERTICAL_RIGHT);
for (int columnIndex = 0; columnIndex < columns.size(); columnIndex++) {
TableColumn column = columns.get(columnIndex);
for (int i = 0; i < column.getWidth() - 1; i++) {
line.append(EscpUtil.CP347_LIGHT_HORIZONTAL);
}
if (columnIndex == (columns.size() - 1)) {
line.append(EscpUtil.CP347_LIGHT_VERTICAL_LEFT);
} else {
line.append(EscpUtil.CP347_LIGHT_VERTICAL_HORIZONTAL);
}
}
tmp.add(new TextLine(line.toString()));
}
header = tmp.toArray(new TextLine[0]);
}
return Arrays.copyOf(header, header.length);
}
/**
* Retrieve the footer for this table.
*
* @return the definition of footer.
*/
public TextLine[] getFooter() {
if (footer == null) {
List<TextLine> tmp = new ArrayList<>();
StringBuilder line = new StringBuilder();
// draw lower border if necessary
if (isDrawBorder()) {
line.append(EscpUtil.CP347_LIGHT_UP_RIGHT);
for (int columnIndex = 0; columnIndex < columns.size(); columnIndex++) {
TableColumn column = columns.get(columnIndex);
for (int i = 0; i < column.getWidth() - 1; i++) {
line.append(EscpUtil.CP347_LIGHT_HORIZONTAL);
}
if (columnIndex == (columns.size() - 1)) {
line.append(EscpUtil.CP347_LIGHT_UP_LEFT);
} else {
line.append(EscpUtil.CP347_LIGHT_UP_HORIZONTAL);
}
}
tmp.add(new TextLine(line.toString()));
}
footer = tmp.toArray(new TextLine[0]);
}
return Arrays.copyOf(footer, footer.length);
}
@Override
public Iterator<TableColumn> iterator() {
return columns.iterator();
}
}