Tue Nov 30, 2021 10:56 am
Hi,
here an extract of the code used to manipulate table and cells :
import com.example.demo.CellTypeEnum;
import com.example.demo.CellValue;
import com.spire.doc.*;
import com.spire.doc.documents.BorderStyle;
import com.spire.doc.documents.Paragraph;
import com.spire.doc.fields.TextRange;
import com.spire.doc.formatting.CharacterFormat;
import java.awt.*;
import java.io.*;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
public class ExportPdfIndexOutOfBounds {
protected static NumberFormat currencyFormater;
protected static NumberFormat percentFormater;
protected static NumberFormat currencyCompactFormater;
protected static boolean formatCurrencyWithSymbol = true;
protected static NumberFormat numberFormater;
public static final SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
{
percentFormater = NumberFormat.getPercentInstance(Locale.FRANCE);
percentFormater.setMaximumFractionDigits(2);
currencyFormater = NumberFormat.getCurrencyInstance(Locale.FRANCE);
currencyCompactFormater = DecimalFormat.getCompactNumberInstance(Locale.FRANCE, NumberFormat.Style.SHORT);
numberFormater = NumberFormat.getNumberInstance(Locale.FRANCE);
numberFormater.setMaximumFractionDigits(2);
}
public static void main(String[] args) throws Exception {
String inputFile = "document.docx";
//create word document
FileInputStream stream1 = new FileInputStream(new File(inputFile));
Document document = new Document();
document.loadFromStream(stream1, FileFormat.Auto);
Map<String, TagValue<?>> rows = new HashMap<>();
rows.put("period", new TagValue<>(List.of("1", "2", "3", "Total"), TagValueTypeEnum.ROW));
rows.put("rentAmount", new TagValue<>(List.of("1000", "2000", "3000", "6000"), TagValueTypeEnum.ROW));
/**
* @TODO More example
*/
fillTables(rows, document);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
document.saveToStream(stream, FileFormat.PDF);
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream("topdf.pdf");
fileOutputStream.write(stream.toByteArray());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Traite les tableaux dynamiques d'un document WORD
*
* @param mapList values
* @param doc document
*/
public static void fillTables(Map<String, TagValue<?>> mapList, Document doc) {
if (doc.getSections() != null && doc.getSections().getCount() > 0) {
for (Section section : (Iterable<Section>) doc.getSections()) {
if (section.getTables() != null && section.getTables().getCount() > 0) {
for (int i = 0; i < section.getTables().getCount(); i++) {
int maxColumnCount = fillTable(mapList, section.getTables().get(i));
if (maxColumnCount > 0) {
formatTable(section.getTables().get(i), maxColumnCount);
}
}
}
}
}
}
/**
* Complète un tableau WORD par les valeurs correspondantes de la liste formatée et supprime les tags traités du référentiel de tags si non null
*
* @param map values
* @param table table
*/
private static int fillTable(Map<String, TagValue<?>> map, Table table) {
boolean isReplaced;
int maxColumnCount = 0;
// replace values from map list
for (Object o : table.getRows()) {
final TableRow row = ((TableRow) o);
for (Map.Entry<String, TagValue<?>> entry : map.entrySet()) {
final String formatedKey = "${" + entry.getKey() + "[n]}";
if (row.getCells().getCount() > 0) {
if (row.getCells().get(row.getCells().getCount() - 1).getParagraphs().get(0).getText()
.contains(formatedKey))
{
isReplaced = false;
final List<?> values = (List<?>) entry.getValue().getValue();
maxColumnCount = Math.max(values.size(), maxColumnCount);
for (Object v : values) {
final String value = formatValue(mapToTagValue(v));
if (!isReplaced) {
row.getCells().get(row.getCells().getCount() - 1).getFirstParagraph()
.replace(formatedKey, value, true, true);
isReplaced = true;
} else {
row.addCell().addParagraph().appendText(value);
}
}
}
}
}
}
return maxColumnCount;
}
/**
* return appropriate representation oif tag value depending on type
*
* @param o Object value
*/
protected static TagValue<?> mapToTagValue(Object o) {
if (o instanceof TagValue) {
return (TagValue<?>) o;
}
if (o instanceof CellValue) {
final CellValue<?> cellValue = (CellValue<?>) o;
if (cellValue.getType() == CellTypeEnum.CURRENCY) {
return new TagValue<>(cellValue.getValue(), TagValueTypeEnum.CURRENCY);
}
if (cellValue.getType() == CellTypeEnum.CURRENCY_COMPACT) {
return new TagValue<>(cellValue.getValue(), TagValueTypeEnum.CURRENCY_COMPACT);
}
if (cellValue.getType() == CellTypeEnum.NUMBER) {
return new TagValue<>(cellValue.getValue(), TagValueTypeEnum.NUMBER);
}
if (cellValue.getType() == CellTypeEnum.PERCENT) {
return new TagValue<>(cellValue.getValue(), TagValueTypeEnum.PERCENT);
}
if (cellValue.getType() == CellTypeEnum.DATE) {
return new TagValue<>(cellValue.getValue(), TagValueTypeEnum.DATE);
}
}
if (o instanceof Long || o instanceof Integer || o instanceof Float) {
return new TagValue<>(o, TagValueTypeEnum.NUMBER);
}
if (o instanceof Double) {
return new TagValue<>(o, TagValueTypeEnum.PERCENT);
}
if (o instanceof List) {
return new TagValue<>(((List<?>) o).stream().map(ExportPdfIndexOutOfBounds::mapToTagValue).collect(Collectors.toList()),
TagValueTypeEnum.LIST);
}
return new TagValue<>(o, TagValueTypeEnum.TEXT);
}
public enum TagValueTypeEnum {
TEXT, CURRENCY, CURRENCY_COMPACT, NUMBER, PERCENT, DATE, IMAGE_BYTE, IMAGE_BASE64, IMAGE_PATH, MERGE_FIELD, CHART, LIST, ROW
}
public static class TagValue<T> {
private T value;
private TagValueTypeEnum type = TagValueTypeEnum.TEXT;
public TagValue(T value) {
this.value = value;
}
public TagValue(T value, TagValueTypeEnum type) {
this.value = value;
this.type = type;
}
public boolean isPrimitive() {
return type.equals(TagValueTypeEnum.TEXT) || type.equals(TagValueTypeEnum.DATE) || type.equals(
TagValueTypeEnum.CURRENCY) || type.equals(TagValueTypeEnum.CURRENCY_COMPACT) || type.equals(
TagValueTypeEnum.NUMBER) || type.equals(TagValueTypeEnum.PERCENT);
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
public TagValueTypeEnum getType() {
return type;
}
public void setType(TagValueTypeEnum type) {
this.type = type;
}
}
/**
* Mise en forme des lignes d'un tableau WORD
*
* @param table table
* @param maxColumnCount max column count
*/
private static void formatTable(Table table, int maxColumnCount) {
TableRow row;
TableCell cell, firstCell;
Paragraph cellParagraph, firstParagraph;
TextRange cellText;
Color borderColor;
// format table rows
final int totalColumnCount = maxColumnCount;
int columnCount;
int rowCount = 1;
final PreferredWidth tableWidth = new PreferredWidth(WidthType.Percentage, (short) 100);
table.setPreferredWidth(tableWidth);
table.getTableFormat().getPaddings().setLeft(5);
table.getTableFormat().getPaddings().setRight(5);
float columnWidth =
(table.getWidth() - table.getFirstRow().getCells().get(0).getWidth()) / (totalColumnCount + 1);
table.setDefaultColumnWidth(columnWidth);
for (Object o1 : table.getRows()) {
row = ((TableRow) o1);
while (row.getCells().getCount() <= totalColumnCount) {
row.addCell().addParagraph().appendText("");
}
firstCell = row.getCells().get(1);
firstParagraph = (Paragraph) firstCell.getFirstParagraph();
final CharacterFormat characterFormatModel = firstParagraph.getChildObjects().getCount() > 0 ?
((TextRange) firstParagraph.getChildObjects().get(0)).getCharacterFormat() :
firstParagraph.getBreakCharacterFormat();
columnCount = 1;
for (Object o2 : row.getCells()) {
if (columnCount == 1) {
columnCount++;
continue;
}
borderColor = rowCount == 1 ? Color.WHITE : Color.BLACK;
cell = (TableCell) o2;
// TODO -> appliquer le format de la première ligne cell et paragraph à la dernière colonne de chaque ligne
// condition : rowCount != 2 && columnCount == row.getCells().getCount()
if (columnCount == totalColumnCount + 1) {
cell.setCellWidth((float) (columnWidth * 1.20), CellWidthType.Point);
} else {
cell.setCellWidth(columnWidth, CellWidthType.Point);
}
// cell format
cell.getCellFormat().setBackColor(firstCell.getCellFormat().getBackColor());
cell.getCellFormat().setVerticalAlignment(firstCell.getCellFormat().getVerticalAlignment());
cell.getCellFormat().setVerticalMerge(firstCell.getCellFormat().getVerticalMerge());
cell.getCellFormat().setTextWrap(false);
// right border all 5 year period ; no border for line 2
cell.getCellFormat().getBorders().getBottom()
.setBorderType(firstCell.getCellFormat().getBorders().getBottom().getBorderType());
cell.getCellFormat().getBorders().getTop()
.setBorderType(firstCell.getCellFormat().getBorders().getTop().getBorderType());
cell.getCellFormat().getBorders().getLeft().setBorderType(
rowCount != 2 && columnCount <= 2 ? BorderStyle.Basic_Thin_Lines : BorderStyle.Cleared);
cell.getCellFormat().getBorders().getRight().setBorderType(
rowCount != 2 && ((columnCount - 1) % 5 == 0 || columnCount == row.getCells().getCount()) ?
BorderStyle.Basic_Thin_Lines : BorderStyle.Cleared);
cell.getCellFormat().getBorders().getRight().setColor(borderColor);
cell.getCellFormat().getBorders().getLeft().setColor(borderColor);
// paragraph format
cellParagraph = cell.getParagraphs().getCount() > 0 ? (Paragraph) cell.getFirstParagraph() :
cell.addParagraph();
cellParagraph.applyStyle(firstParagraph.getStyleName());
cellParagraph.getFormat().setHorizontalAlignment(firstParagraph.getFormat().getHorizontalAlignment());
cellParagraph.getFormat().setTextAlignment(firstParagraph.getFormat().getTextAlignment());
cellParagraph.getFormat().setBeforeSpacing(firstParagraph.getFormat().getBeforeSpacing());
cellParagraph.getFormat().setAfterSpacing(firstParagraph.getFormat().getAfterSpacing());
cellText = cellParagraph.getChildObjects().getCount() > 0 ?
(TextRange) cellParagraph.getChildObjects().get(0) : cellParagraph.appendText("");
if (characterFormatModel != null) {
cellText.getCharacterFormat().setTextColor(characterFormatModel.getTextColor());
cellText.getCharacterFormat().setFontName(characterFormatModel.getFontName());
cellText.getCharacterFormat().setFontSize(characterFormatModel.getFontSize());
cellText.getCharacterFormat().setBold(characterFormatModel.getBold());
cellText.getCharacterFormat().setUnderlineStyle(characterFormatModel.getUnderlineStyle());
}
if (cellText.getText().isBlank()) {
cellText.getCharacterFormat().setTextColor(Color.WHITE);
// Mandatory to have a character (not space) for the style to be applied correctly
cellText.setText("-");
cellText.getCharacterFormat().setFontSize(1);
}
columnCount++;
}
//row.setHeight(initialRowHeight);
rowCount++;
}
}
/**
* Format tag value ; if null, return ""
*
* @param tag value to format
*/
protected static String formatValue(TagValue<?> tag) {
Object tagValue = tag.getValue() != null ? tag.getValue() : null;
if (tagValue != null) {
if (TagValueTypeEnum.CURRENCY == tag.getType()) {
tagValue = currencyFormat(String.valueOf(tagValue), formatCurrencyWithSymbol);
} else if (TagValueTypeEnum.CURRENCY_COMPACT == tag.getType()) {
tagValue = currencyCompactFormat(String.valueOf(tagValue), formatCurrencyWithSymbol);
} else if (TagValueTypeEnum.NUMBER == tag.getType()) {
tagValue = numberFormat(tagValue);
} else if (TagValueTypeEnum.PERCENT == tag.getType()) {
tagValue = percentFormat(tagValue);
} else if (TagValueTypeEnum.DATE == tag.getType()) {
assert tagValue instanceof Date;
tagValue = dateFormat.format((Date) tagValue);
}
}
return getFixedValue(tagValue);
}
/**
* Return string value with fixed chars
*
* @param tagValue the object
* @return the fixed string value
*/
protected static String getFixedValue(Object tagValue) {
return tagValue == null ? "" :
(tagValue instanceof String ? (String) tagValue : tagValue.toString()).replace((char) 8239, (char) 160);
}
/**
* Formattage du prix
*
* @param amount value to format
* @param currencySymbol boolean
* @return String
*/
protected static String currencyFormat(String amount, boolean currencySymbol) {
return currencyFormat(amount, currencySymbol, currencyFormater);
}
/**
* Formattage du prix
*
* @param amount value to format
* @param currencySymbol boolean
* @return String
*/
protected static String currencyCompactFormat(String amount, boolean currencySymbol) {
NumberFormat numberFormat;
if (isNullOrZeroValue(amount)) {
numberFormat = currencyFormater;
} else {
final double value = Double.parseDouble(amount);
if (value > -1000000. && value < 1000000.) {
numberFormat = currencyFormater;
} else {
numberFormat = (NumberFormat) currencyCompactFormater.clone();
double absValue = Math.abs(value);
while (absValue > 1000) {
double r = absValue % 1000;
if (r != 0) {
numberFormat.setMinimumFractionDigits(String.valueOf(r).length());
break;
}
absValue = absValue / 1000;
}
}
}
String value = currencyFormat(amount, false, numberFormat);
if(currencySymbol) {
value = value.concat(Currency.getInstance(Locale.FRANCE).getSymbol());
}
return value;
}
public static boolean isNullOrZeroValue(String value) {
return (value == null || "".equals(value) || "null".equals(value));
}
/**
* Formattage du prix
*
* @param amount value to format
* @param currencySymbol boolean
* @return String
*/
protected static String currencyFormat(String amount, boolean currencySymbol, final NumberFormat numberFormat) {
NumberFormat format = numberFormat;
if (isNullOrZeroValue(amount)) {
return format.format(0);
}
if (!currencySymbol) {
if (format instanceof DecimalFormat) {
final DecimalFormat decimalFormat = (DecimalFormat) format.clone();
final DecimalFormatSymbols decimalFormatSymbols = decimalFormat.getDecimalFormatSymbols();
decimalFormatSymbols.setCurrencySymbol("");
decimalFormat.setDecimalFormatSymbols(decimalFormatSymbols);
format = decimalFormat;
}
}
return format.format(Double.parseDouble(amount));
}
/**
* Formattage d'un nombre
*
* @param number value to format
* @return String
*/
protected static String numberFormat(Object number) {
if (number == null || "".equals(number) || "null".equals(number)) {
return numberFormater.format(0);
}
return numberFormater.format(number);
}
/**
* Formattage d'un nombre
*
* @param number value to format
* @return String
*/
protected static String percentFormat(Object number) {
if (number == null || "".equals(number) || "null".equals(number)) {
return percentFormater.format(0);
}
return percentFormater.format(number);
}
}
[/code]