it.discovery.jasperreports.jasper2word.J2WDocxPoiHelper Maven / Gradle / Ivy
The newest version!
package it.discovery.jasperreports.jasper2word;
import it.discovery.jasperreports.jasper2word.J2WAbstractJRExporter.PageOrder;
import it.discovery.jasperreports.jasper2word.J2WAbstractPrintElementVisitorContext.DocxDocumentPart;
import it.discovery.jasperreports.jasper2word.J2WAbstractPrintElementVisitorContext.LastDocxElement;
import it.discovery.jasperreports.jasper2word.J2WGridPageLayout.ComponentPosition;
import it.discovery.jasperreports.jasper2word.J2WGridPageLayout.ComponentPositionInTable;
import it.discovery.jasperreports.jasper2word.J2WGridPageLayout.ComponentTableInfo;
import it.discovery.jasperreports.jasper2word.J2WGridPageLayout.HeaderFooterPageInfo;
import it.discovery.jasperreports.jasper2word.J2WReportConfiguration.ESpacingPolicy;
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.base.JRBaseStyle;
import net.sf.jasperreports.engine.base.JRBoxPen;
import net.sf.jasperreports.engine.fill.JRTemplatePrintElement;
import net.sf.jasperreports.engine.type.FillEnum;
import net.sf.jasperreports.engine.type.LineSpacingEnum;
import net.sf.jasperreports.engine.type.ModeEnum;
import net.sf.jasperreports.engine.type.VerticalAlignEnum;
import net.sf.jasperreports.engine.util.JRStyledText;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.impl.xb.xmlschema.SpaceAttribute.Space;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.font.LineMetrics;
import java.awt.font.TextAttribute;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.text.AttributedCharacterIterator;
import java.text.AttributedCharacterIterator.Attribute;
import java.text.MessageFormat;
import java.util.*;
import java.util.List;
/**
* Helper class to prodoce docx document with poi-apache library.
* @author discovery
* @date 13/08/15 10.07
*/
class J2WDocxPoiHelper {
/** Macro for automatic color */
private static final String COLOR_AUTO = "auto";
/**
* Hide the constructor.
*/
private J2WDocxPoiHelper() {
}
/**
* Append, if necessary, a new table in the doc.
* @param tablePos The position of an element in a table.
* @param context The exporter visitor context.
* @return The metadata of the built table.
*/
static TableDocInfo buildTables(ComponentPositionInTable tablePos, J2WDocxPrintElementVisitorContext context) {
Map tables = context.tables;
ComponentTableInfo table = tablePos.getTableInfo();
TableDocInfo res = tables.get(table.getTableId());
XWPFDocument document = context.getDocument();
// Check for pre-built table
if (res == null) {
// if the previous element in document was a table or table must be moved more down, a new space paragraph is appended
if (context.getLastDocxElement() == LastDocxElement.TABLE || context.getLastY(tablePos.getDocumentPart()) < tablePos.getTableInfo().getY()) {
CTP paragraph;
if (tablePos.getDocumentPart() == DocxDocumentPart.HEADER)
paragraph = context.headerContent.addNewP();
else if (tablePos.getDocumentPart() == DocxDocumentPart.FOOTER)
paragraph = context.footerContent.addNewP();
else
paragraph = document.createParagraph().getCTP();
CTR run = paragraph.addNewR();
CTPPr pPr = paragraph.getPPr();
if (pPr == null)
pPr = paragraph.addNewPPr();
CTString pStyle = pPr.getPStyle();
if (pStyle == null)
pStyle = pPr.addNewPStyle();
pStyle.setVal("Normal");
CTRPr rPr = run.getRPr();
if (rPr == null)
run.addNewRPr();
CTSpacing spacing = pPr.getSpacing();
if (spacing == null)
spacing = pPr.addNewSpacing();
spacing.setBefore(BigInteger.ZERO);
spacing.setBeforeLines(BigInteger.ZERO);
spacing.setAfterLines(BigInteger.ZERO);
// if (table.getParent() != null)
// setParagraphMargins(paragraph, context.getLastParagraphX(), context.getLastParagraphWidth(), context);
// else
// setParagraphMargins(paragraph, table.getX(), table.getWidth(), context);
if (context.getLastY(tablePos.getDocumentPart()) < tablePos.getTableInfo().getY()) {
BigInteger gap = EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, tablePos.getTableInfo().getY() - context.getLastY(tablePos.getDocumentPart())).divide(BigInteger.valueOf(2));
BigInteger check = BigInteger.valueOf(240);
if (gap.min(check).equals(check)) {
spacing.setAfter(BigInteger.ZERO);
spacing.setLine(gap.add(gap));
}
else {
spacing.setAfter(gap);
spacing.setLine(gap);
}
spacing.setLineRule(STLineSpacingRule.EXACT);
}
else {
spacing.setAfter(BigInteger.ZERO);
spacing.setLineRule(STLineSpacingRule.EXACT);
spacing.setLine(BigInteger.ONE);
}
}
TableDocInfo parent = null;
if (table.getParent() instanceof ComponentPositionInTable)
parent = buildTables((ComponentPositionInTable) table.getParent(), context);
// Building the table
int[] rowsHeight = table.getRows();
int[] columnsWidth = table.getColumns();
BigInteger columnsX[] = new BigInteger[columnsWidth.length + 1];
columnsX[0] = BigInteger.ZERO;
CTTbl xwpfTable;
if (parent == null) {
if (tablePos.getDocumentPart() == DocxDocumentPart.HEADER)
xwpfTable = context.headerContent.addNewTbl();
else if (tablePos.getDocumentPart() == DocxDocumentPart.FOOTER)
xwpfTable = context.footerContent.addNewTbl();
else {
XWPFTable emptyTable = context.getDocument().createTable();
while (!emptyTable.getRows().isEmpty())
emptyTable.removeRow(0);
xwpfTable = emptyTable.getCTTbl();
}
}
else {
CTRow row = parent.table.getTrList().get(tablePos.getRow());
CTTc cell = row.getTcList().get(tablePos.getCol());
while (!cell.getPList().isEmpty())
cell.removeP(0);
xwpfTable = cell.addNewTbl();
}
for (int rowHeight : rowsHeight) {
CTRow ctRow = xwpfTable.addNewTr();
CTTrPr trPr = ctRow.getTrPr();
if (trPr == null)
trPr = ctRow.addNewTrPr();
// Rows height
CTHeight ctHeight;
if (trPr.getTrHeightList().isEmpty())
ctHeight = trPr.addNewTrHeight();
else
ctHeight = trPr.getTrHeightList().get(0);
ctHeight.setVal(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, rowHeight));
if (table.isForceRowHeight())
ctHeight.setHRule(STHeightRule.EXACT);
else
ctHeight.setHRule(STHeightRule.AUTO);
// Columns width (paragraph)
for (int aColumnsWidth : columnsWidth) {
CTTc tc = ctRow.addNewTc();
tc.addNewP();
CTTcPr tcPr = tc.getTcPr();
if (tcPr == null)
tcPr = tc.addNewTcPr();
CTTblWidth w = tcPr.getTcW();
if (w == null)
w = tcPr.addNewTcW();
w.setType(STTblWidth.DXA);
w.setW(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, aColumnsWidth));
tcPr.setTcW(w);
}
}
CTTblPr tblPr = xwpfTable.getTblPr();
if (tblPr == null)
tblPr = xwpfTable.addNewTblPr();
// Table width
CTTblWidth tblW = tblPr.getTblW();
if (tblW == null)
tblW = tblPr.addNewTblW();
tblW.setW(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, table.getWidth()));
tblW.setType(STTblWidth.DXA);
// Table right margin
CTTblWidth tblInd = tblPr.getTblInd();
if (tblInd == null)
tblInd = tblPr.addNewTblInd();
if (table.getParent() == null)
tblInd.setW(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, table.getX() - context.getLayout().getPageInfo().getLeftMargin()));
else
tblInd.setW(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, table.getX() - table.getParent().getX()));
tblInd.setType(STTblWidth.DXA);
// Table borders
if (table.isBordered()) {
CTTblBorders tblBorders = tblPr.getTblBorders();
if (tblBorders == null)
tblBorders = tblPr.addNewTblBorders();
updateBorder(tblBorders.addNewInsideH(), 1, 2, "000000", STBorder.SINGLE);
updateBorder(tblBorders.addNewInsideV(), 1, 2, "000000", STBorder.SINGLE);
updateBorder(tblBorders.addNewBottom(), 1, 2, "000000", STBorder.SINGLE);
updateBorder(tblBorders.addNewLeft(), 1, 2, "000000", STBorder.SINGLE);
updateBorder(tblBorders.addNewRight(), 1, 2, "000000", STBorder.SINGLE);
updateBorder(tblBorders.addNewTop(), 1, 2, "000000", STBorder.SINGLE);
}
else {
if (tblPr.isSetTblBorders())
tblPr.unsetTblBorders();
// updateBorder(tblBorders.addNewInsideH(), 0, 0, "000000", STBorder.SINGLE);
// updateBorder(tblBorders.addNewInsideV(), 0, 0, "000000", STBorder.SINGLE);
// updateBorder(tblBorders.addNewBottom(), 0, 0, "000000", STBorder.SINGLE);
// updateBorder(tblBorders.addNewLeft(), 0, 0, "000000", STBorder.SINGLE);
// updateBorder(tblBorders.addNewRight(), 0, 0, "000000", STBorder.SINGLE);
// updateBorder(tblBorders.addNewTop(), 0, 0, "000000", STBorder.SINGLE);
}
// Table grid column definition
CTTblGrid tblGrid = xwpfTable.getTblGrid();
if (tblGrid == null)
tblGrid = xwpfTable.addNewTblGrid();
for (int i = 0; i < columnsWidth.length; i++) {
int colWidth = columnsWidth[i];
CTTblGridCol col = tblGrid.addNewGridCol();
BigInteger width = EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, colWidth);
col.setW(width);
columnsX[i + 1] = width;
}
res = new TableDocInfo(xwpfTable);
SortedSet cellToRemove = new TreeSet<>(new CellToRemovePointComparator());
for (Rectangle mergedRegion : table.getMergedRegions()) {
CTRow row = xwpfTable.getTrList().get(mergedRegion.y);
CTTc cell = row.getTcList().get(mergedRegion.x);
CTTcPr tcPr = cell.getTcPr();
if (tcPr == null)
tcPr = cell.addNewTcPr();
if (mergedRegion.width > 1)
tcPr.addNewGridSpan().setVal(BigInteger.valueOf((long) mergedRegion.width));
if (mergedRegion.height > 1)
tcPr.addNewVMerge().setVal(STMerge.RESTART);
CTTblWidth tcW = tcPr.getTcW();
if (tcW == null)
tcW = tcPr.addNewTcW();
tcW.setW(columnsX[mergedRegion.x + 1].subtract(columnsX[mergedRegion.x]));
tcW.setType(STTblWidth.DXA);
tcPr.setTcW(tcW);
for (int rowIndex = mergedRegion.y; rowIndex < mergedRegion.height + mergedRegion.y; rowIndex++) {
CTRow rowSpan = xwpfTable.getTrList().get(rowIndex);
for (int columnIndex = mergedRegion.x; columnIndex < mergedRegion.x + mergedRegion.width ; columnIndex++) {
if (columnIndex > mergedRegion.x)
cellToRemove.add(new Point(columnIndex, rowIndex));
if (rowIndex > mergedRegion.y && columnIndex == mergedRegion.x) {
cell = rowSpan.getTcList().get(columnIndex);
tcPr = cell.getTcPr();
if (tcPr == null)
tcPr = cell.addNewTcPr();
if (mergedRegion.width > 1)
tcPr.addNewGridSpan().setVal(BigInteger.valueOf((long) mergedRegion.width));
if (mergedRegion.height > 1) {
tcPr.addNewVMerge().setVal(STMerge.CONTINUE);
}
tcPr.setTcW(tcW);
}
}
}
}
for (Point cellCoord : cellToRemove) {
CTRow rowSpan = xwpfTable.getTrList().get(cellCoord.y);
rowSpan.removeTc(cellCoord.x);
}
tables.put(table.getTableId(), res);
context.setLastY(tablePos.getDocumentPart(), table.getY() + table.getHeight());
}
context.setLastDocxElement(LastDocxElement.TABLE);
return res;
}
/**
* Update a table border style.
* @param ctBorder The border to update.
* @param size The border size in points.
* @param space The space between border and cell content in points.
* @param color The border color.
* @param type The border style.
*/
private static void updateBorder(CTBorder ctBorder, int size, int space, String color, org.openxmlformats.schemas.wordprocessingml.x2006.main.STBorder.Enum type) {
ctBorder.setColor(color);
ctBorder.setVal(type);
ctBorder.setSz(BigInteger.valueOf(size));
ctBorder.setSpace(BigInteger.valueOf(space));
}
/**
* Format a {@link Color color} in a hexadecimal string (RRGGBB).
* @param color The java awt Color.
* @return The formatted string color.
*/
static String colorToStringFormat(Color color) {
Color base = new Color(255, 255, 255, 0);
return String.format("%6s", Integer.toHexString(color.getRGB() & base.getRGB())).replaceAll(" ", "0");
}
/**
* Parse string (or byte[]) color into a java awt Color.
* @param color It can be a hexadecimal {@link String String} like RRGGBB or a {@code byte[]} like byte[] {R, G, B}.
* @return The java awt Color.
*/
static Color stringToColorParse(Object color) {
if (color == null)
return null;
if (color instanceof String) {
String s_color = (String) color;
if (s_color.equals(COLOR_AUTO))
return null;
String tokens[] = s_color.split("(?<=\\G\\d{2})", 3);
return new Color(Integer.parseInt(tokens[0], 16), Integer.parseInt(tokens[1], 16), Integer.parseInt(tokens[2], 16), 0);
}
else if (color instanceof byte[]) {
byte c[] = (byte[]) color;
return new Color(c[0], c[1], c[2]);
}
else
throw new JRRuntimeException("Unknown color type: " + color.getClass().getName());
}
/**
* Reset document status variables and build document styles.
* @param firstReport {@code true} if first report, {@code} false otherwise.
* @param context The visitor context.
* @param report Thre report to export.
*/
static void prepareNewDocument(boolean firstReport, J2WDocxPrintElementVisitorContext context, JasperPrint report) {
context.resetDocumentStatus();
context.setReport(report);
if (firstReport)
context.currentSection = null;
buildStyles(context, report.getStylesList());
}
/**
* Prepare new page (build new section if required), set page size and (optiona) header and footer.
* @param context The visitor context.
* @param jrPage The jasper page.
* @param pageNumber The relative page number.
* @param pageOrder The absolute page position.
*/
static void prepareNewPage(J2WDocxPrintElementVisitorContext context, JRPrintPage jrPage, int pageNumber, PageOrder pageOrder) {
if (!pageOrder.isFirstestPage() && context.currentSection == null) {
XWPFDocument document = context.getDocument();
XWPFParagraph xwpfParagraph = document.createParagraph();
CTP paragraph = xwpfParagraph.getCTP();
CTR run = paragraph.addNewR();
CTBr breakObj = run.addNewBr();
breakObj.setType(STBrType.PAGE);
breakObj.setClear(STBrClear.ALL);
}
context.currentSection = null;
context.policy = null;
setPageSizeAndMargins(context, pageOrder);
buildHeaderFooter(context, pageNumber, pageOrder);
}
/**
* Finalize the page (add the page section, if present).
* @param context The visitor context.
* @param jrPage The jasper page.
* @param pageNumber The relative page number.
* @param pageOrder The absolute page position.
*/
static void finalizePage(J2WDocxPrintElementVisitorContext context, JRPrintPage jrPage, int pageNumber, PageOrder pageOrder) {
XWPFDocument document = context.getDocument();
if (context.currentSection != null && !pageOrder.isLastestPage()) {
CTP paragraph = document.createParagraph().getCTP();
CTPPr pPr = paragraph.getPPr();
if (pPr == null)
pPr = paragraph.addNewPPr();
pPr.setSectPr(context.currentSection);
CTR run = paragraph.addNewR();
run.addNewLastRenderedPageBreak();
}
}
/**
* Return the current section if exits, or create a new one.
* @param context The visitor context.
* @param pageOrder The absolute page position.
* @return The current section or new one.
*/
private static CTSectPr getOrCreateCurrentSection(J2WDocxPrintElementVisitorContext context, PageOrder pageOrder) {
CTSectPr sectPr;
sectPr = context.currentSection;
if (sectPr == null) {
if (pageOrder.isLastestPage()) {
CTBody body = context.getDocument().getDocument().getBody();
sectPr = body.getSectPr();
if (sectPr == null)
sectPr = body.addNewSectPr();
}
else
sectPr = CTSectPr.Factory.newInstance();
}
context.currentSection = sectPr;
return sectPr;
}
/**
* Set the page size and margins. If the report has not margins, default margins are created with 5pt size.
* @param context The visitor context.
* @param pageOrder The absolute page position.
*/
private static void setPageSizeAndMargins(J2WDocxPrintElementVisitorContext context, PageOrder pageOrder) {
JasperPrint report = context.getReport();
HeaderFooterPageInfo pageInfo = context.getLayout().getPageInfo();
if (context.getLastPageInfo() == null || context.getLastPageInfo().containsHeaderFooter() || pageInfo.containsHeaderFooter() || pageOrder.isLastestPage()) {
CTSectPr sectPr = getOrCreateCurrentSection(context, pageOrder);
int top;
int bottom;
int right = 5;
int left = 5;
int header = 0;
int footer = 0;
if (pageInfo.getRightMargin() > 0)
right = pageInfo.getRightMargin();
if (pageInfo.getLeftMargin() > 0)
left = pageInfo.getLeftMargin();
if (pageInfo.getMinHeader() != null) {
top = pageInfo.getTopMargin() + pageInfo.getMinHeader();
header = pageInfo.getMinHeader();
}
else if (pageInfo.getTopMargin() > 0)
top = pageInfo.getTopMargin();
else
top = 5;
if (pageInfo.getMaxFooter() != null) {
bottom = pageInfo.getMaxFooter() + pageInfo.getBottomMargin();
footer = pageInfo.getMaxFooter();
}
else if (pageInfo.getBottomMargin() > 0)
bottom = pageInfo.getBottomMargin();
else
bottom = 5;
CTPageSz ctPageSz = sectPr.getPgSz();
if (ctPageSz == null)
ctPageSz = sectPr.addNewPgSz();
ctPageSz.setH(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, report.getPageHeight()));
ctPageSz.setW(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, report.getPageWidth()));
CTPageMar ctPageMar = sectPr.getPgMar();
if (ctPageMar == null)
ctPageMar = sectPr.addNewPgMar();
ctPageMar.setBottom(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, bottom));
ctPageMar.setTop(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, top));
ctPageMar.setLeft(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, left));
ctPageMar.setRight(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, right));
ctPageMar.setHeader(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, header));
ctPageMar.setFooter(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, footer));
ctPageMar.setGutter(BigInteger.ZERO);
sectPr.setPgMar(ctPageMar);
}
}
/**
* Build the header and footer, if exist.
* @param context The visitor context.
* @param pageNumber The relative page number.
* @param pageOrder The absolute page position.
*/
static void buildHeaderFooter(J2WDocxPrintElementVisitorContext context, int pageNumber, PageOrder pageOrder) {
try {
HeaderFooterPageInfo pageInfo = context.getLayout().getPageInfo();
if (context.getLastPageInfo() == null || context.getLastPageInfo().containsHeaderFooter() || context.getLayout().getPageInfo().containsHeaderFooter()) {
XWPFDocument document = context.getDocument();
// Get last section SectPr and create a new one if it doesn't exist
CTSectPr sectPr = getOrCreateCurrentSection(context, pageOrder);
CTBody body = document.getDocument().getBody();
CTSectPr oldSectPr = body.getSectPr();
body.setSectPr(sectPr);
XWPFHeaderFooterPolicy policy = context.policy;
if (policy == null) {
policy = new XWPFHeaderFooterPolicy(document, sectPr);
context.policy = policy;
}
if (pageInfo.getHeaderHeight() != null) {
XWPFHeader header = policy.createHeader(XWPFHeaderFooterPolicy.DEFAULT, new XWPFParagraph[]{});
context.headerContent = header._getHdrFtr();
CTHdrFtrRef ctHdrFtrRef;
if (sectPr.getHeaderReferenceList().isEmpty())
ctHdrFtrRef = sectPr.addNewHeaderReference();
else
ctHdrFtrRef = sectPr.getHeaderReferenceArray(0);
ctHdrFtrRef.setId(header.getPackageRelationship().getId());
ctHdrFtrRef.setType(STHdrFtr.DEFAULT);
}
else {
context.headerContent = null;
}
if (pageInfo.getFooterHeight() != null) {
XWPFFooter footer = policy.createFooter(XWPFHeaderFooterPolicy.DEFAULT, new XWPFParagraph[]{});
context.footerContent = footer._getHdrFtr();
CTHdrFtrRef ctHdrFtrRef;
if (sectPr.getFooterReferenceList().isEmpty())
ctHdrFtrRef = sectPr.addNewFooterReference();
else
ctHdrFtrRef = sectPr.getFooterReferenceArray(0);
ctHdrFtrRef.setId(footer.getPackageRelationship().getId());
ctHdrFtrRef.setType(STHdrFtr.DEFAULT);
}
else {
context.footerContent = null;
}
sectPr.addNewTitlePg().setVal(STOnOff.FALSE);
if (oldSectPr != null)
body.setSectPr(oldSectPr);
else
body.unsetSectPr();
}
} catch (Exception e) {
throw new JRRuntimeException(e);
}
}
/**
* Update doc style with jasper style attributes.
* @param ctStyle The doc style.
* @param jrStyle The jasper style.
* @param context The visito context.
* @param update {@code true} to update doc style, {@code false} to create a new one doc style with jasper style attributes.
* @return The updated doc style.
*/
private static String updateStyle(CTStyle ctStyle, JRStyle jrStyle, J2WDocxPrintElementVisitorContext context, boolean update) {
JRPen linePen = jrStyle.getLinePen();
String styleName = jrStyle.getName();
if (!update) {
int styleCount = 1;
while (context.allStyles.contains(styleName)) {
styleName = jrStyle.getName() + styleCount;
styleCount++;
}
context.allStyles.add(styleName);
CTString name = ctStyle.getName();
if (name == null)
name = ctStyle.addNewName();
name.setVal(styleName);
ctStyle.setName(name);
ctStyle.setStyleId(styleName);
if (!styleName.equals(jrStyle.getName())) {
CTString aliases = ctStyle.getAliases();
if (aliases == null)
aliases = ctStyle.addNewAliases();
aliases.setVal(jrStyle.getName());
ctStyle.setAliases(aliases);
}
ctStyle.setType(STStyleType.PARAGRAPH);
CTOnOff qFormat = ctStyle.getQFormat();
if (qFormat == null)
qFormat = ctStyle.addNewQFormat();
qFormat.setVal(STOnOff.ON);
}
// Default run settings
CTRPr ctrPr = ctStyle.getRPr();
if (ctrPr == null)
ctrPr = ctStyle.addNewRPr();
// Default paragraph settings
CTPPr ctpPr = ctStyle.getPPr();
if (ctpPr == null)
ctpPr = ctStyle.addNewPPr();
// Bold
if (jrStyle.isOwnBold() != null) {
CTOnOff b = ctrPr.getB();
if (b == null)
b = ctrPr.addNewB();
b.setVal(jrStyle.isOwnBold() ? STOnOff.ON : STOnOff.OFF);
}
// Italic
if (jrStyle.isOwnItalic() != null) {
CTOnOff i = ctrPr.getI();
if (i == null)
i = ctrPr.addNewI();
i.setVal(jrStyle.isOwnItalic() ? STOnOff.ON : STOnOff.OFF);
}
// Underline
if (jrStyle.isOwnUnderline() != null && jrStyle.isOwnUnderline()) {
CTUnderline ctUnderline = ctrPr.getU();
if (ctUnderline == null)
ctUnderline = ctrPr.addNewU();
if (linePen == null) {
ctUnderline.setVal(STUnderline.SINGLE);
if (jrStyle.getForecolor() != null)
ctUnderline.setColor(colorToStringFormat(jrStyle.getForecolor()));
else
ctUnderline.setColor(COLOR_AUTO);
}
else {
if (linePen.getOwnLineStyleValue() != null) {
switch (linePen.getOwnLineStyleValue()) {
case SOLID:
ctUnderline.setVal(STUnderline.SINGLE);
break;
case DASHED:
ctUnderline.setVal(STUnderline.DASH);
break;
case DOTTED:
ctUnderline.setVal(STUnderline.DOTTED);
break;
case DOUBLE:
ctUnderline.setVal(STUnderline.DOUBLE);
break;
default:
ctUnderline.setVal(STUnderline.SINGLE);
break;
}
}
else
ctUnderline.setVal(STUnderline.SINGLE);
if (linePen.getLineColor() != null)
ctUnderline.setColor(colorToStringFormat(linePen.getLineColor()));
else if (jrStyle.getForecolor() != null)
ctUnderline.setColor(colorToStringFormat(jrStyle.getForecolor()));
else
ctUnderline.setColor(colorToStringFormat(Color.black));
}
}
// Strike Through
if (jrStyle.isOwnStrikeThrough() != null) {
CTOnOff strike = ctrPr.getStrike();
if (strike == null)
strike = ctrPr.addNewStrike();
strike.setVal(jrStyle.isOwnStrikeThrough() ? STOnOff.ON : STOnOff.OFF);
}
// Fore color
CTColor foreColor = ctrPr.getColor();
if (foreColor == null)
foreColor = ctrPr.addNewColor();
if (jrStyle.getOwnForecolor() != null)
foreColor.setVal(colorToStringFormat(jrStyle.getOwnForecolor()));
else
foreColor.setVal(COLOR_AUTO);
ctrPr.setColor(foreColor);
// Background / Highlight
if (jrStyle.getOwnBackcolor() != null) {
CTShd shdp = ctpPr.getShd();
if (shdp == null)
shdp = ctpPr.addNewShd();
shdp.setVal(STShd.CLEAR);
shdp.setFill(colorToStringFormat(jrStyle.getOwnBackcolor()));
}
// Text alignment
CTTextAlignment alignment = ctpPr.getTextAlignment();
if (alignment == null)
alignment = ctpPr.addNewTextAlignment();
if (jrStyle.getOwnVerticalAlignmentValue() != null) {
switch (jrStyle.getOwnVerticalAlignmentValue()) {
case TOP:
alignment.setVal(STTextAlignment.TOP);
break;
case MIDDLE:
alignment.setVal(STTextAlignment.CENTER);
break;
case BOTTOM:
alignment.setVal(STTextAlignment.BOTTOM);
break;
case JUSTIFIED:
alignment.setVal(STTextAlignment.BASELINE);
break;
default:
alignment.setVal(STTextAlignment.AUTO);
break;
}
}
else
alignment.setVal(STTextAlignment.AUTO);
ctpPr.setTextAlignment(alignment);
if (jrStyle.getOwnHorizontalAlignmentValue() != null) {
CTJc ctJc = ctpPr.getJc();
if (ctJc == null)
ctJc = ctpPr.addNewJc();
switch (jrStyle.getOwnHorizontalAlignmentValue()) {
case LEFT:
ctJc.setVal(STJc.LEFT);
break;
case CENTER:
ctJc.setVal(STJc.CENTER);
break;
case RIGHT:
ctJc.setVal(STJc.RIGHT);
break;
case JUSTIFIED:
ctJc.setVal(STJc.BOTH);
break;
default:
ctJc.setVal(STJc.LEFT);
break;
}
}
// Font
if (jrStyle.getOwnFontName() != null) {
CTFonts ctFonts = ctrPr.getRFonts();
if (ctFonts == null)
ctFonts = ctrPr.addNewRFonts();
ctFonts.setAscii(jrStyle.getOwnFontName());
ctFonts.setHAnsi(jrStyle.getOwnFontName());
}
if (jrStyle.getOwnFontsize() != null) {
CTHpsMeasure ctHpsMeasure = ctrPr.getSz();
if (ctHpsMeasure == null)
ctHpsMeasure = ctrPr.addNewSz();
ctHpsMeasure.setVal(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.HALF_POINTS, jrStyle.getOwnFontsize()));
}
// Paragraph advanced settings
JRParagraph paragraph = jrStyle.getParagraph();
if (paragraph != null) {
CTInd ctInd = ctpPr.getInd();
if (ctInd == null)
ctInd = ctpPr.addNewInd();
if (paragraph.getOwnFirstLineIndent() != null)
ctInd.setFirstLine(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, paragraph.getOwnFirstLineIndent()));
if (paragraph.getOwnLeftIndent() != null)
ctInd.setLeft(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, paragraph.getOwnLeftIndent()));
if (paragraph.getOwnRightIndent() != null)
ctInd.setRight(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, paragraph.getOwnRightIndent()));
buildParagraphSpacing(paragraph, ctpPr.getSpacing(), ctpPr, update);
}
if (jrStyle.getStyle() != null && ctStyle.getBasedOn() == null) {
CTString basedOn = ctStyle.addNewBasedOn();
basedOn.setVal(jrStyle.getStyle().getName());
}
return styleName;
}
/**
* Build all the jaspser styles.
* @param context The visitor context.
* @param stylesList The jasper styles.
*/
private static void buildStyles(J2WDocxPrintElementVisitorContext context, java.util.List stylesList) {
if (!stylesList.isEmpty()) {
XWPFDocument document = context.getDocument();
XWPFStyles styles = document.getStyles();
if (styles == null)
styles = document.createStyles();
CTOnOff ctOnOff_ON = CTOnOff.Factory.newInstance();
CTOnOff ctOnOff_OFF = CTOnOff.Factory.newInstance();
ctOnOff_ON.setVal(STOnOff.ON);
ctOnOff_OFF.setVal(STOnOff.OFF);
for (JRStyle jrStyle : stylesList) {
CTStyle ctStyle = CTStyle.Factory.newInstance();
String styleName = updateStyle(ctStyle, jrStyle, context, false);
XWPFStyle style = new XWPFStyle(ctStyle, styles);
styles.addStyle(style);
context.remapStylesNameByJrStyle.put(jrStyle.getName(), styleName);
}
}
}
/**
* Find a style by name.
* @param styleName The style name to find.
* @param context The visitor context.
* @param safe {@code true} return {@code null} in case of errors; {@code false} throw a {@link JRRuntimeException JRRuntimeException} in case of error.
* @return The found style, or {@code null} if not exists.
* @throws JRRuntimeException In case of IO errors.
*/
private static CTStyle findStyle(String styleName, J2WDocxPrintElementVisitorContext context, boolean safe) throws JRRuntimeException {
CTStyle style = context.builtFoundStyle.get(styleName);
if (style == null) {
XWPFDocument document = context.getDocument();
CTStyles stylePart;
try {
stylePart = document.getStyle();
} catch (Exception e) {
if (safe)
return null;
else
throw new JRRuntimeException(e);
}
List styleList = stylePart.getStyleList();
for (CTStyle ctStyle : styleList) {
if (ctStyle.getName() != null && ctStyle.getName().getVal().equalsIgnoreCase(styleName)) {
style = ctStyle;
break;
}
}
if (style != null)
context.builtFoundStyle.put(styleName, style);
}
return style;
}
/**
* Utility method: return {@code valOverride} if {@code useOverriding} is {@code true} and {@code valOverride} is not {@code null};
* return {@code vale} otherwise.
* @param val The default value.
* @param valOverride The overriding value.
* @param useOverriding {@code} true to use {@code valOverride}, {@code false} to use {@code val}.
* @param Type of value.
* @return {@code valOverride} if {@code useOverriding} is {@code true} and {@code valOverride} is not {@code null};
* return {@code vale} otherwise.
*/
static T getOverridingValue(T val, T valOverride, boolean useOverriding) {
if (useOverriding)
return valOverride != null? valOverride : val;
else
return val;
}
/**
* Set paragraph spacing: before, after and line spacing.
* @param paragraph The jasper paragraph.
* @param from The input/output spacing object (can be {@code null}).
* @param paragraphProperties The doc paragraph properties.
* @param useOverriding {@code true} to use paragraph own spacing, {@code false} otherwise.
* @return The spacing object.
* @see #getOverridingValue(Object, Object, boolean)
*/
static boolean buildParagraphSpacing(JRParagraph paragraph, CTSpacing from, CTPPr paragraphProperties, boolean useOverriding) {
boolean setSpacing = false;
CTSpacing ctSpacing = from;
if (ctSpacing == null)
ctSpacing = paragraphProperties.addNewSpacing();
else
setSpacing = true;
Integer spacingAfter = getOverridingValue(paragraph.getSpacingAfter(), paragraph.getOwnSpacingAfter(), useOverriding);
if (spacingAfter != null) {
ctSpacing.setAfter(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, spacingAfter));
setSpacing = true;
}
Integer spacingBefore = getOverridingValue(paragraph.getSpacingBefore(), paragraph.getOwnSpacingBefore(), useOverriding);
if (spacingBefore != null) {
ctSpacing.setBefore(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, spacingBefore));
setSpacing = true;
}
LineSpacingEnum lineSpacingEnum = getOverridingValue(paragraph.getLineSpacing(), paragraph.getOwnLineSpacing(), useOverriding);
if (lineSpacingEnum != null) {
Float lineSpacingSize = getOverridingValue(paragraph.getLineSpacingSize(), paragraph.getOwnLineSpacingSize(), useOverriding);
switch (lineSpacingEnum) {
case SINGLE:
ctSpacing.setLineRule(STLineSpacingRule.AUTO);
ctSpacing.setLine(EConvertMisure.toLineSpacing(null, 1D));
break;
case ONE_AND_HALF:
ctSpacing.setLineRule(STLineSpacingRule.AUTO);
ctSpacing.setLine(EConvertMisure.toLineSpacing(null, 1.5D));
break;
case DOUBLE:
ctSpacing.setLineRule(STLineSpacingRule.AUTO);
ctSpacing.setLine(EConvertMisure.toLineSpacing(null, 2D));
break;
case AT_LEAST:
ctSpacing.setLineRule(STLineSpacingRule.AT_LEAST);
if (lineSpacingSize != null)
ctSpacing.setLine(EConvertMisure.toLineSpacing(lineSpacingSize.doubleValue(), 1D));
else
ctSpacing.setLine(EConvertMisure.toLineSpacing(null, 1D));
break;
case FIXED:
ctSpacing.setLineRule(STLineSpacingRule.EXACT);
if (lineSpacingSize != null)
ctSpacing.setLine(EConvertMisure.toLineSpacing(lineSpacingSize.doubleValue(), 1D));
else
ctSpacing.setLine(EConvertMisure.toLineSpacing(null, 1D));
break;
case PROPORTIONAL:
ctSpacing.setLineRule(STLineSpacingRule.AUTO);
if (lineSpacingSize != null)
ctSpacing.setLine(EConvertMisure.toLineSpacing(lineSpacingSize.doubleValue(), 1D));
else
ctSpacing.setLine(EConvertMisure.toLineSpacing(null, 1D));
break;
}
setSpacing = true;
}
if (!setSpacing) {
paragraphProperties.unsetSpacing();
return false;
}
else
return true;
}
/**
* Set paragraph margins (left and right).
* @param paragraph The doc paragraph.
* @param x The left margin.
* @param width The paragraph width.
* @param context The visitor context.
*/
static void setParagraphMargins(CTP paragraph, Integer x, Integer width, J2WDocxPrintElementVisitorContext context) {
if (x != null && width != null) {
CTPPr pPr = paragraph.getPPr();
if (pPr == null)
pPr = paragraph.addNewPPr();
CTInd ind = pPr.getInd();
if (ind == null)
ind = pPr.addNewInd();
HeaderFooterPageInfo pageInfo = context.getLayout().getPageInfo();
ind.setLeft(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, Math.max(x - pageInfo.getLeftMargin(), 0)));
ind.setRight(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, Math.max(pageInfo.getPageSize().width - pageInfo.getRightMargin() - x - width, 0)));
context.setLastParagraphX(x);
context.setLastParagraphWidth(width);
}
}
/**
* Set the paragraph borders.
* @param paragraph The doc baragraph.
* @param element The box element container with border infos.
*/
static void setParagraphBorders(CTP paragraph, JRBoxContainer element) {
if (element != null) {
JRLineBox lineBox = element.getLineBox();
if (lineBox != null) {
CTPPr pPr = paragraph.getPPr();
if (pPr == null)
pPr = paragraph.addNewPPr();
CTPBdr pBdr = pPr.getPBdr();
if (pBdr == null)
pBdr = pPr.addNewPBdr();
CTBorder ctBorder = buildBorder(lineBox.getBottomPen());
if (ctBorder != null)
pBdr.setBottom(ctBorder);
else if (pBdr.isSetBottom())
pBdr.unsetBottom();
ctBorder = buildBorder(lineBox.getTopPen());
if (ctBorder != null)
pBdr.setTop(ctBorder);
else if (pBdr.isSetTop())
pBdr.unsetTop();
ctBorder = buildBorder(lineBox.getRightPen());
if (ctBorder != null)
pBdr.setRight(ctBorder);
else if (pBdr.isSetRight())
pBdr.unsetRight();
ctBorder = buildBorder(lineBox.getLeftPen());
if (ctBorder != null)
pBdr.setLeft(ctBorder);
else if (pBdr.isSetLeft())
pBdr.unsetLeft();
}
}
}
/**
* Set table cell borders.
* @param cell A doc table cell.
* @param element The box element container with border infos.
*/
static void setTableCellBorders(ComponentPositionInTable position, CTTbl xwpfTable, CTTc cell, JRBoxContainer element) {
if (element != null) {
CTTc cellTop[];
CTTc cellLeft[];
CTTc cellBottom[];
CTTc cellRight[];
JRLineBox lineBox = element.getLineBox();
if (lineBox != null) {
if (position.getColSpan() > 1 || position.getRowSpan() > 1) {
List mergedRegions = position.getTableInfo().getMergedRegions();
Rectangle region = null;
Point coord = position.getTableInfo().getInverseCellCoordinate(position.getCol(), position.getRow());
for (Rectangle mergedRegion : mergedRegions) {
if (mergedRegion.x <= coord.x &&
mergedRegion.y <= coord.y &&
mergedRegion.x + mergedRegion.width - 1 >= coord.x &&
mergedRegion.y + mergedRegion.height - 1 >= coord.y) {
region = mergedRegion;
break;
}
}
if (region == null) {
String detail = "";
if (element instanceof JRIdentifiable)
detail += "ID = " + ((JRIdentifiable) element).getUUID();
if (element instanceof JRCommonElement) {
if (!detail.isEmpty())
detail += ", ";
detail += "Name = " + ((JRCommonElement) element).getKey();
}
throw new JRRuntimeException("Merged region not found for cell (element " + detail + ")");
}
coord = position.getTableInfo().getCellCoordinate(region.x, region.y);
CTRow row = xwpfTable.getTrList().get(coord.y);
cellTop = new CTTc[]{row.getTcList().get(coord.x), cell};
coord = position.getTableInfo().getCellCoordinate(region.x + region.width - 1, region.y + region.height - 1);
row = xwpfTable.getTrList().get(coord.y);
cellBottom = new CTTc[]{row.getTcList().get(coord.x), cell};
cellLeft = new CTTc[region.height + 1];
cellRight = new CTTc[region.height + 1];
cellLeft[0] = cellRight[0] = cell;
for (int r = region.y, i = 1; r < region.y + region.height; r++, i++) {
coord = position.getTableInfo().getCellCoordinate(region.x + region.width - 1, r);
row = xwpfTable.getTrList().get(coord.y);
cellRight[i] = row.getTcList().get(coord.x);
coord = position.getTableInfo().getCellCoordinate(region.x, r);
cellLeft[i] = row.getTcList().get(coord.x);
}
}
else {
cellTop = cellBottom = new CTTc[]{cell};
cellLeft = cellRight = new CTTc[]{cell};
}
for (int edge = 0; edge < 4; edge++) {
CTTc cells[];
switch (edge) {
case 0:
cells = cellTop;
break;
case 1:
cells = cellLeft;
break;
case 2:
cells = cellBottom;
break;
case 3:
cells = cellRight;
break;
default:
continue;
}
for (CTTc cellb: cells) {
CTTcPr tcPr = cellb.getTcPr();
if (tcPr == null)
tcPr = cellb.addNewTcPr();
CTTcBorders tcBorders = tcPr.getTcBorders();
if (tcBorders == null)
tcBorders = tcPr.addNewTcBorders();
CTBorder ctBorder;
switch (edge) {
case 0:
ctBorder = buildBorder(lineBox.getTopPen());
if (ctBorder != null)
tcBorders.setTop(ctBorder);
else if (tcBorders.isSetTop())
tcBorders.unsetTop();
break;
case 1:
ctBorder = buildBorder(lineBox.getLeftPen());
if (ctBorder != null)
tcBorders.setLeft(ctBorder);
else if (tcBorders.isSetLeft())
tcBorders.unsetLeft();
break;
case 2:
ctBorder = buildBorder(lineBox.getBottomPen());
if (ctBorder != null)
tcBorders.setBottom(ctBorder);
else if (tcBorders.isSetBottom())
tcBorders.unsetBottom();
break;
case 3:
ctBorder = buildBorder(lineBox.getRightPen());
if (ctBorder != null)
tcBorders.setRight(ctBorder);
else if (tcBorders.isSetRight())
tcBorders.unsetRight();
break;
}
}
}
}
}
}
/**
* Build a single edge for a cell.
* @param pen The border style.
* @return The border for cell.
*/
static CTBorder buildBorder(JRBoxPen pen) {
if (pen == null || pen.getLineWidth() == 0f)
return null;
else {
CTBorder ctBorder = CTBorder.Factory.newInstance();
ctBorder.setColor(colorToStringFormat(pen.getPen(pen.getBox()).getLineColor()));
ctBorder.setSz(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.POINTS, pen.getLineWidth()));
switch (pen.getLineStyleValue()) {
case SOLID:
ctBorder.setVal(STBorder.SINGLE);
break;
case DASHED:
ctBorder.setVal(STBorder.DASHED);
break;
case DOTTED:
ctBorder.setVal(STBorder.DOTTED);
break;
case DOUBLE:
ctBorder.setVal(STBorder.DOUBLE);
break;
default:
ctBorder.setVal(STBorder.SINGLE);
break;
}
ctBorder.setColor(colorToStringFormat(pen.getLineColor()));
return ctBorder;
}
}
/**
* Print visitor context. This class improves the base visitor context with extra information useful to build the output document,
* like jaxb object factories, table infos, styles, etc...
*/
static class J2WDocxPrintElementVisitorContext extends J2WAbstractPrintElementVisitorContext {
/** Table infos */
private Map tables;
/** Remapped style name in document */
private Map remapStylesNameByJrStyle;
/** Built style's name */
private final Set allStyles;
/** The current header */
private CTHdrFtr headerContent;
/** The current footer */
private CTHdrFtr footerContent;
/** The current section */
private CTSectPr currentSection;
/** Cache built found style by name */
private final Map builtFoundStyle;
/** New header/footer policy */
private XWPFHeaderFooterPolicy policy;
/**
* Construct the context.
*/
public J2WDocxPrintElementVisitorContext() {
this.allStyles = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
this.builtFoundStyle = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
}
/**
* Reset the document status (reset remapped style's name).
*/
private void resetDocumentStatus() {
this.remapStylesNameByJrStyle = new TreeMap<>();
this.builtFoundStyle.clear();
}
/**
* Reset the page status (tables end last docx element).
*/
public void resetPageStatus() {
this.tables = new TreeMap<>();
this.setLastDocxElement(null);
}
}
/**
* A table informations.
*/
static class TableDocInfo {
/** Docx table */
private final CTTbl table;
/**
* Construct a table info with a docx table,
* @param table The docx table.
*/
public TableDocInfo(CTTbl table) {
this.table = table;
}
}
/**
* Comparator that sorts Point from bottom to top and from right to left.
*/
private static class CellToRemovePointComparator implements Comparator {
/** Constructor */
public CellToRemovePointComparator() {
}
@Override
public int compare(Point o1, Point o2) {
if (o1.y > o2.y)
return 1;
else if (o1.y < o2.y)
return -1;
else if (o1.x > o2.x)
return -1;
else if (o1.x < o2.x)
return 1;
else
return 0;
}
}
/**
* Poi-apache print element visitor. This class can "visit" every jasper report element and draw it in the
* output document.
*/
protected static class J2WDocxPrintElementVisitor implements PrintElementVisitor {
/** Attribute styled text selector (all attributes) */
protected JRStyledTextAttributeSelector allSelector;
/** Jasper context */
protected JasperReportsContext jasperReportsContext;
/**
* Construct a visitor context.
* @param allSelector The attribute selector.
* @param jasperReportsContext The jasper context.
*/
public J2WDocxPrintElementVisitor(JRStyledTextAttributeSelector allSelector, JasperReportsContext jasperReportsContext) {
this.allSelector = allSelector;
this.jasperReportsContext = jasperReportsContext;
}
/**
* Search or create the output paragraph for the current element to visit.
* @param compPosition The element position.
* @param container The element container.
* @param arg The visitor context.
* @param createParagraph {@code true} to create the missing paragraph.
* @return The paragraph for the element (both free paragraphs and table cell paragraphs).
*/
protected FoundDocParagraph findParagraph(ComponentPosition compPosition, JRBoxContainer container, J2WDocxPrintElementVisitorContext arg, boolean createParagraph) {
CTP paragraph = null;
XWPFDocument document = arg.getDocument();
FoundDocParagraph parent = null;
if (compPosition.getParent() != null)
parent = this.findParagraph(compPosition.getParent(), container, arg, false);
CTTc cell = null;
// For element in table cell
if (compPosition instanceof ComponentPositionInTable) {
ComponentPositionInTable position = (ComponentPositionInTable) compPosition;
TableDocInfo tableDocInfo = buildTables(position, arg);
CTTbl xwpfTable = tableDocInfo.table;
CTRow row = xwpfTable.getTrList().get(position.getRow());
cell = row.getTcList().get(position.getCol());
if (cell.getPList().isEmpty())
paragraph = cell.addNewP();
else
paragraph = cell.getPArray(0);
CTTcPr tcPr = cell.getTcPr();
if (tcPr == null)
tcPr = cell.addNewTcPr();
// Background
CTShd ctShd = tcPr.getShd();
if (ctShd == null)
ctShd = tcPr.addNewShd();
ctShd.setFill(COLOR_AUTO);
ctShd.setVal(STShd.CLEAR);
CTVerticalJc ctVerticalJc = tcPr.getVAlign();
if (ctVerticalJc == null)
ctVerticalJc = tcPr.addNewVAlign();
ctVerticalJc.setVal(STVerticalJc.CENTER);
if (container != null) {
setTableCellBorders(position, xwpfTable, cell, container);
JRLineBox lineBox = container.getLineBox();
if (lineBox != null) {
CTTcMar ctTcMar = tcPr.getTcMar();
if (ctTcMar == null)
ctTcMar = tcPr.addNewTcMar();
CTTblWidth b = CTTblWidth.Factory.newInstance();
CTTblWidth t = CTTblWidth.Factory.newInstance();
CTTblWidth l = CTTblWidth.Factory.newInstance();
CTTblWidth r = CTTblWidth.Factory.newInstance();
b.setType(STTblWidth.DXA);
t.setType(STTblWidth.DXA);
l.setType(STTblWidth.DXA);
r.setType(STTblWidth.DXA);
if (lineBox.getBottomPadding() != null)
b.setW(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, lineBox.getBottomPadding()));
else
b = null;
if (lineBox.getTopPadding() != null)
t.setW(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, lineBox.getTopPadding()));
else
t = null;
if (lineBox.getLeftPadding() != null)
l.setW(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, lineBox.getLeftPadding()));
else
l = null;
if (lineBox.getRightPadding() != null)
r.setW(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, lineBox.getRightPadding()));
else
r = null;
ctTcMar.setBottom(b);
ctTcMar.setTop(t);
ctTcMar.setLeft(l);
ctTcMar.setRight(r);
}
}
}
if (paragraph == null && parent != null)
paragraph = parent.getParagraph();
if (cell == null && parent != null)
cell = parent.getCell();
if (paragraph == null && createParagraph) {
// Add the new paragraph in the document
if (compPosition.getDocumentPart() == DocxDocumentPart.HEADER)
paragraph = arg.headerContent.addNewP();
else if (compPosition.getDocumentPart() == DocxDocumentPart.FOOTER)
paragraph = arg.footerContent.addNewP();
else
paragraph = arg.getDocument().createParagraph().getCTP();
}
if (paragraph != null) {
if (container != null && cell == null)
setParagraphBorders(paragraph, container);
CTPPr pPr = paragraph.getPPr();
if (pPr == null)
pPr = paragraph.addNewPPr();
CTParaRPr rPr = pPr.getRPr();
if (rPr == null)
pPr.addNewRPr();
if (container != null && container.getStyle() != null) {
CTString pStyle = pPr.getPStyle();
if (pStyle == null)
pStyle = pPr.addNewPStyle();
pStyle.setVal(arg.remapStylesNameByJrStyle.get(container.getStyle().getName()));
}
if (cell == null) {
int leftPadding = 0;
int rightPadding = 0;
if (container != null && container.getLineBox() != null) {
JRLineBox lineBox = container.getLineBox();
if (lineBox.getLeftPadding() != null)
leftPadding = lineBox.getLeftPadding();
if (lineBox.getRightPadding() != null)
rightPadding = lineBox.getRightPadding();
}
setParagraphMargins(paragraph, compPosition.getX(), compPosition.getWidth() - rightPadding - leftPadding, arg);
}
}
int pIndex = -1;
if (paragraph != null && cell == null) {
if (compPosition.getDocumentPart() == DocxDocumentPart.HEADER)
pIndex = arg.headerContent.sizeOfPArray() - 1;
else if (compPosition.getDocumentPart() == DocxDocumentPart.FOOTER)
pIndex = arg.footerContent.sizeOfPArray() - 1;
else
pIndex = arg.getDocument().getParagraphs().size() - 1;
}
return new FoundDocParagraph(cell, paragraph, pIndex);
}
public void visit(JRPrintText textElement, J2WDocxPrintElementVisitorContext arg) {
ComponentPosition compPosition = arg.getLayout().getElementPosition(textElement);
FoundDocParagraph foundDocParagraph = this.findParagraph(compPosition, textElement, arg, true);
CTP paragraph = foundDocParagraph.getParagraph();
boolean setInd = false;
boolean setPPr = false;
int pCount = 0;
CTPPr pPr = paragraph.getPPr();
if (pPr == null)
pPr = paragraph.addNewPPr();
else
setPPr = true;
CTInd ind = pPr.getInd();
if (ind == null)
ind = pPr.addNewInd();
else
setInd = true;
boolean spacing = buildParagraphSpacing(textElement.getParagraph(), pPr.getSpacing(), pPr, true);
if (textElement.getOwnHorizontalAlignmentValue() != null) {
CTJc jc = pPr.getJc();
if (jc == null)
jc = pPr.addNewJc();
switch (textElement.getOwnHorizontalAlignmentValue()) {
case LEFT:
jc.setVal(STJc.LEFT);
break;
case CENTER:
jc.setVal(STJc.CENTER);
break;
case RIGHT:
jc.setVal(STJc.RIGHT);
break;
case JUSTIFIED:
jc.setVal(STJc.BOTH);
break;
}
setPPr = true;
}
if (textElement.getOwnVerticalAlignmentValue() != null) {
CTTextAlignment alignment = pPr.getTextAlignment();
if (alignment == null)
alignment = pPr.addNewTextAlignment();
switch (textElement.getOwnVerticalAlignmentValue()) {
case TOP:
alignment.setVal(STTextAlignment.TOP);
break;
case MIDDLE:
alignment.setVal(STTextAlignment.CENTER);
break;
case BOTTOM:
alignment.setVal(STTextAlignment.BOTTOM);
break;
case JUSTIFIED:
alignment.setVal(STTextAlignment.AUTO);
break;
}
setPPr = true;
}
JRParagraph jrParagraph = textElement.getParagraph();
if (jrParagraph.getOwnFirstLineIndent() != null) {
ind.setFirstLine(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, jrParagraph.getOwnFirstLineIndent()));
setInd = true;
}
if (jrParagraph.getOwnLeftIndent() != null) {
ind.setLeft(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, jrParagraph.getOwnLeftIndent()));
setInd = true;
}
if (jrParagraph.getOwnRightIndent() != null) {
ind.setRight(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, jrParagraph.getOwnRightIndent()));
setInd = true;
}
if (textElement.getOwnBackcolor() != null) {
CTShd shd = pPr.getShd();
if (shd == null) {
shd = pPr.addNewShd();
pPr.setShd(shd);
}
shd.setFill(colorToStringFormat(textElement.getOwnBackcolor()));
shd.setVal(STShd.CLEAR);
setPPr = true;
}
if (!setPPr && !setInd & !spacing)
paragraph.unsetPPr();
if (!setInd)
pPr.unsetInd();
if (!spacing)
pPr.unsetSpacing();
JRStyledText styledText = textElement.getFullStyledText(allSelector);
String fullText = styledText.getText();
AttributedCharacterIterator iterator = styledText.getAttributedString().getIterator();
int runLimit = 0;
boolean lastNewLine = false;
XWPFDocument document = arg.getDocument();
while(runLimit < styledText.length() && (runLimit = iterator.getRunLimit()) <= styledText.length()) {
CTR docRun = paragraph.addNewR();
this.setRunFontStyle(docRun, textElement, iterator.getAttributes(), arg);
String value = fullText.substring(iterator.getIndex(), runLimit);
StringTokenizer tkzer = new StringTokenizer(value, "\n", true);
while(tkzer.hasMoreTokens()) {
String token = tkzer.nextToken();
boolean isNewLine = "\n".equals(token);
if (lastNewLine || isNewLine) {
if (tkzer.hasMoreTokens() || lastNewLine) {
CTP newParagraph;
pCount++;
if (foundDocParagraph.isTableCell())
newParagraph = foundDocParagraph.getCell().addNewP();
else {
if (compPosition.getDocumentPart() == DocxDocumentPart.HEADER)
newParagraph = arg.headerContent.addNewP();
else if (compPosition.getDocumentPart() == DocxDocumentPart.FOOTER)
newParagraph = arg.footerContent.addNewP();
else
newParagraph = document.createParagraph().getCTP();
}
CTPPr newPPr = this.cloneParagraphProperties(pPr, newParagraph);
if (pPr.getSpacing() != null)
pPr.getSpacing().setAfter(BigInteger.ZERO);
if (newPPr.getSpacing() != null)
newPPr.getSpacing().setBefore(BigInteger.ZERO);
paragraph = newParagraph;
docRun = paragraph.addNewR();
this.setRunFontStyle(docRun, textElement, iterator.getAttributes(), arg);
lastNewLine = false;
}
else
lastNewLine = true;
}
if (!isNewLine) {
CTText text = docRun.addNewT();
text.setStringValue(token);
text.setSpace(Space.PRESERVE);
}
}
iterator.setIndex(runLimit);
}
if (!foundDocParagraph.isTableCell()) {
float textHeight = textElement.getTextHeight();
int realHeight = 0;
int topMargin = 0;
if (jrParagraph.getSpacingAfter() != null)
realHeight += jrParagraph.getSpacingAfter();
if (jrParagraph.getSpacingBefore() != null) {
realHeight += jrParagraph.getSpacingBefore();
topMargin = jrParagraph.getSpacingBefore();
}
JRLineBox lineBox = textElement.getLineBox();
if (lineBox != null) {
if (lineBox.getBottomPadding() != null)
realHeight += lineBox.getBottomPadding();
if (lineBox.getTopPadding() != null)
realHeight += lineBox.getTopPadding();
}
realHeight += textHeight; // EConvertMisure.HALF_POINTS.convertInto(EConvertMisure.POINTS, textHeight);
CTStyle style = findStyle("Normal", arg, true);
int defaultFontSize = 12;
String defaultFontName = "Times New Roman";
if (style != null && style.getPPr() != null && style.getPPr().getRPr() != null) {
CTParaRPr defaultRPr = style.getPPr().getRPr();
if (defaultRPr.getRFonts() != null && defaultRPr.getRFonts().getAscii() != null)
defaultFontName = defaultRPr.getRFonts().getAscii();
if (defaultRPr.getSz() != null && defaultRPr.getSz().getVal() != null)
defaultFontSize = (int) EConvertMisure.HALF_POINTS.convertInto(EConvertMisure.POINTS, defaultRPr.getSz().getVal().doubleValue());
}
Font newLineFont = new Font(defaultFontName, Font.PLAIN, defaultFontSize);
LineMetrics lineMetrics = newLineFont.getLineMetrics("\n", new FontRenderContext(null, false, true));
if (realHeight < compPosition.getHeight()) {
int gap = compPosition.getHeight() - realHeight;
int newLines;
if (arg.getConfiguration().getSpacingPolicy() == ESpacingPolicy.EDITABLE)
newLines = (int) (gap / lineMetrics.getHeight());
else
newLines = 0;
gap -= (newLines * defaultFontSize);
if (gap > defaultFontSize) {
CTSpacing spacingLast = paragraph.getPPr().getSpacing();
if (spacingLast == null)
spacingLast = paragraph.getPPr().addNewSpacing();
CTSpacing spacingFirst = foundDocParagraph.getParagraph().getPPr().getSpacing();
if (spacingFirst == null)
spacingFirst = foundDocParagraph.getParagraph().getPPr().addNewSpacing();
BigInteger bigGap = EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, gap);
VerticalAlignEnum alignmentValue = textElement.getVerticalAlignmentValue();
if (alignmentValue == null)
alignmentValue = VerticalAlignEnum.JUSTIFIED;
switch (alignmentValue) {
case TOP:
spacingLast.setAfter(spacingLast.getAfter() != null ? spacingLast.getAfter().add(bigGap) : bigGap);
break;
case MIDDLE:
case JUSTIFIED: {
bigGap = bigGap.divide(BigInteger.valueOf(2));
spacingLast.setAfter(spacingLast.getAfter() != null ? spacingLast.getAfter().add(bigGap) : bigGap);
spacingFirst.setBefore(spacingFirst.getBefore() != null ? spacingFirst.getBefore().add(bigGap) : bigGap);
}
break;
case BOTTOM:
spacingFirst.setBefore(spacingFirst.getBefore() != null ? spacingFirst.getBefore().add(bigGap) : bigGap);
break;
}
}
this.createBeforeNewLinesParagraphs(arg, newLines, defaultFontSize, defaultFontName, foundDocParagraph.getParagraphIndexInDoc() + pCount + 1, compPosition.getDocumentPart());
}
if (arg.getLastY(compPosition.getDocumentPart()) < compPosition.getY()) {
int gap = compPosition.getY() - arg.getLastY(compPosition.getDocumentPart());
int newLines;
if (arg.getConfiguration().getSpacingPolicy() == ESpacingPolicy.EDITABLE)
newLines = (int) (gap / lineMetrics.getHeight());
else
newLines = 0;
gap -= (newLines * defaultFontSize);
if (gap > 0) {
CTSpacing spacingFirst = foundDocParagraph.getParagraph().getPPr().getSpacing();
if (spacingFirst == null)
spacingFirst = foundDocParagraph.getParagraph().getPPr().addNewSpacing();
BigInteger bigGap = EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, gap + topMargin);
spacingFirst.setBefore(spacingFirst.getBefore() != null ? spacingFirst.getBefore().add(bigGap) : bigGap);
}
this.createBeforeNewLinesParagraphs(arg, newLines, defaultFontSize, defaultFontName, foundDocParagraph.getParagraphIndexInDoc(), compPosition.getDocumentPart());
}
arg.setLastY(compPosition.getDocumentPart(), compPosition.getY() + compPosition.getHeight());
arg.setLastDocxElement(LastDocxElement.TEXT_PARAGRAPH);
}
}
/**
* Add many paragraphs those indicated in {@code newLines}.
* @param arg The visitor context.
* @param newLines How many lines to add.
* @param defaultFontSize The font size.
* @param defaultFontName The font name.
* @param startIndex The index in the document objects list.
* @param part The document part.
*/
protected void createBeforeNewLinesParagraphs(J2WDocxPrintElementVisitorContext arg, int newLines, int defaultFontSize,
String defaultFontName, int startIndex, DocxDocumentPart part) {
for (int i = 0; i < newLines; i++) {
CTP newLineP;
switch (part) {
case HEADER:
newLineP = arg.headerContent.insertNewP(startIndex);
break;
case FOOTER:
newLineP = arg.footerContent.insertNewP(startIndex);
break;
default:
case BODY: {
XWPFDocument document = arg.getDocument();
XWPFParagraph paragraphAt;
if (startIndex < document.getParagraphs().size()) {
paragraphAt = document.getParagraphs().get(startIndex);
newLineP = document.insertNewParagraph(paragraphAt.getCTP().newCursor()).getCTP();
}
else
newLineP = document.createParagraph().getCTP();
}
break;
}
CTPPr pPr = newLineP.addNewPPr();
pPr.addNewRPr();
CTHpsMeasure hpsMeasure = pPr.getRPr().addNewSz();
hpsMeasure.setVal(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.HALF_POINTS, defaultFontSize));
pPr.getRPr().addNewRFonts();
pPr.getRPr().getRFonts().setAscii(defaultFontName);
CTSpacing spacing = pPr.addNewSpacing();
spacing.setAfter(BigInteger.ZERO);
spacing.setBefore(BigInteger.ZERO);
spacing.setBeforeLines(BigInteger.ZERO);
spacing.setLine(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.th20_POINTS, defaultFontSize));
spacing.setLineRule(STLineSpacingRule.EXACT);
setParagraphMargins(newLineP, arg.getLastParagraphX(), arg.getLastParagraphWidth(), arg);
CTR newLineR = newLineP.addNewR();
newLineR.addNewRPr();
CTText text = newLineR.addNewT();
text.setSpace(Space.PRESERVE);
text.setStringValue("");
}
}
/**
* Clone paragraphs properties.
* @param pPr The source paragraph properties.
* @param paragraphDest The paragraph where to clone the properties.
* @return Return a clone of the {@code pPr} properties.
*/
protected CTPPr cloneParagraphProperties(CTPPr pPr, CTP paragraphDest) {
CTSpacing spacing = pPr.getSpacing();
CTPPr newPPr = paragraphDest.getPPr();
if (newPPr == null)
newPPr = paragraphDest.addNewPPr();
if (pPr.getInd() != null)
newPPr.setInd(pPr.getInd());
if (pPr.getJc() != null)
newPPr.setJc(pPr.getJc());
if (pPr.getPBdr() != null)
newPPr.setPBdr(pPr.getPBdr());
if (pPr.getPStyle() != null)
newPPr.setPStyle(pPr.getPStyle());
if (pPr.getRPr() != null)
newPPr.setRPr(pPr.getRPr());
if (pPr.getShd() != null)
newPPr.setShd(pPr.getShd());
if (spacing != null) {
CTSpacing newSpacing = newPPr.getSpacing();
if (newSpacing == null)
newSpacing = newPPr.addNewSpacing();
newSpacing.setAfter(spacing.getAfter());
newSpacing.setAfterAutospacing(spacing.getAfterAutospacing());
newSpacing.setAfterLines(spacing.getAfterLines());
newSpacing.setBefore(spacing.getBefore());
newSpacing.setBeforeAutospacing(spacing.getBeforeAutospacing());
newSpacing.setBeforeLines(spacing.getBeforeLines());
newSpacing.setLine(spacing.getLine());
newSpacing.setLineRule(spacing.getLineRule());
}
newPPr.setTextAlignment(pPr.getTextAlignment());
newPPr.setTextDirection(pPr.getTextDirection());
return newPPr;
}
/**
* Set the run (a text block in a paragraph) properties (font, size, colors, etc.)
* @param docRun The document run.
* @param textElement The jasper text element.
* @param attributes The global jasper text element attributes.
* @param arg The visitor context.
*/
protected void setRunFontStyle(CTR docRun, JRPrintText textElement, Map attributes, J2WDocxPrintElementVisitorContext arg) {
String styleName = textElement.getStyle() != null? textElement.getStyle().getName() : null;
boolean setRPr = false;
CTRPr ctrPr = docRun.getRPr();
if (ctrPr == null)
ctrPr = docRun.addNewRPr();
if (textElement.isOwnBold() != null) {
CTOnOff value = ctrPr.getB();
if (value == null)
value = ctrPr.addNewB();
value.setVal(textElement.isOwnBold()? STOnOff.TRUE : STOnOff.FALSE);
setRPr = true;
}
if (textElement.getOwnForecolor() != null) {
CTColor color = ctrPr.getColor();
if (color == null)
color = ctrPr.addNewColor();
color.setVal(colorToStringFormat(textElement.getOwnForecolor()));
setRPr = true;
}
if (textElement.getOwnFontName() != null) {
CTFonts rFonts = ctrPr.getRFonts();
if (rFonts == null)
rFonts = ctrPr.addNewRFonts();
rFonts.setAscii(textElement.getOwnFontName());
rFonts.setHAnsi(textElement.getOwnFontName());
setRPr = true;
}
if (textElement.getOwnFontsize() != null) {
CTHpsMeasure sz = ctrPr.getSz();
if (sz == null)
sz = ctrPr.addNewSz();
sz.setVal(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.HALF_POINTS, textElement.getOwnFontsize()));
setRPr = true;
}
if (textElement.isOwnItalic() != null) {
CTOnOff i = ctrPr.getI();
if (i == null)
i = ctrPr.addNewI();
i.setVal(textElement.isOwnItalic()? STOnOff.TRUE : STOnOff.FALSE);
setRPr = true;
}
if (textElement.isOwnStrikeThrough() != null) {
CTOnOff strike = ctrPr.getStrike();
if (strike == null)
strike = ctrPr.addNewStrike();
strike.setVal(textElement.isOwnStrikeThrough()? STOnOff.TRUE : STOnOff.FALSE);
setRPr = true;
}
if (textElement.isOwnUnderline() != null && textElement.isOwnUnderline()) {
CTUnderline value = ctrPr.getU();
if (value == null)
value = ctrPr.addNewU();
if (textElement.getStyle() != null && textElement.getStyle().getLinePen() != null && textElement.getStyle().getLinePen().getLineStyleValue() != null) {
switch (textElement.getStyle().getLinePen().getLineStyleValue()) {
case SOLID:
value.setVal(STUnderline.SINGLE);
break;
case DASHED:
value.setVal(STUnderline.DASH);
break;
case DOTTED:
value.setVal(STUnderline.DOTTED);
break;
case DOUBLE:
value.setVal(STUnderline.DOUBLE);
break;
default:
value.setVal(STUnderline.SINGLE);
break;
}
if (textElement.getStyle().getLinePen().getOwnLineColor() != null)
value.setColor(colorToStringFormat(textElement.getStyle().getLinePen().getOwnLineColor()));
}
else {
value.setVal(STUnderline.SINGLE);
}
setRPr = true;
}
Map docRunAttributes = buildDocRunAttributes(docRun, styleName, arg);
if (attributes != null) {
String fontFamily = this.readAttribute(attributes, docRunAttributes, TextAttribute.FAMILY);
if (fontFamily != null) {
CTFonts rFonts = ctrPr.getRFonts();
if (rFonts == null)
rFonts = ctrPr.addNewRFonts();
rFonts.setAscii(fontFamily);
rFonts.setHAnsi(fontFamily);
setRPr = true;
}
Number weight = this.readAttribute(attributes, docRunAttributes, TextAttribute.WEIGHT);
if (weight != null) {
CTOnOff value = ctrPr.getB();
if (value == null)
value = ctrPr.addNewB();
value.setVal(weight.floatValue() >= TextAttribute.WEIGHT_REGULAR? STOnOff.TRUE : STOnOff.FALSE);
setRPr = true;
}
Paint color = this.readAttribute(attributes, docRunAttributes, TextAttribute.FOREGROUND);
if (color instanceof Color) {
CTColor color2 = ctrPr.getColor();
if (color2 == null)
color2 = ctrPr.addNewColor();
color2.setVal(colorToStringFormat((Color) color));
setRPr = true;
}
Number size = this.readAttribute(attributes, docRunAttributes, TextAttribute.SIZE);
if (size != null) {
CTHpsMeasure sz = ctrPr.getSz();
if (sz == null)
sz = ctrPr.addNewSz();
sz.setVal(EConvertMisure.POINTS.convertIntoBigInteger(EConvertMisure.HALF_POINTS, size.doubleValue()));
setRPr = true;
}
Number posture = this.readAttribute(attributes, docRunAttributes, TextAttribute.POSTURE);
if (posture != null) {
CTOnOff i = ctrPr.getI();
if (i == null)
i = ctrPr.addNewI();
i.setVal(posture.floatValue() >= TextAttribute.POSTURE_OBLIQUE? STOnOff.TRUE : STOnOff.FALSE);
setRPr = true;
}
Boolean strikeThrough = this.readAttribute(attributes, docRunAttributes, TextAttribute.STRIKETHROUGH);
if (strikeThrough != null) {
CTOnOff strike = ctrPr.getStrike();
if (strike == null)
strike = ctrPr.addNewStrike();
strike.setVal(strikeThrough? STOnOff.TRUE : STOnOff.FALSE);
setRPr = true;
}
Integer underline = this.readAttribute(attributes, docRunAttributes, TextAttribute.UNDERLINE);
if (underline != null) {
CTUnderline value = ctrPr.getU();
if (value == null)
value = ctrPr.addNewU();
if (underline.equals(TextAttribute.UNDERLINE_ON))
value.setVal(STUnderline.SINGLE);
else if (underline.equals(TextAttribute.UNDERLINE_LOW_ONE_PIXEL))
value.setVal(STUnderline.THICK);
else if (underline.equals(TextAttribute.UNDERLINE_LOW_TWO_PIXEL))
value.setVal(STUnderline.DOUBLE);
else if (underline.equals(TextAttribute.UNDERLINE_LOW_DOTTED))
value.setVal(STUnderline.DOTTED_HEAVY);
else if (underline.equals(TextAttribute.UNDERLINE_LOW_GRAY))
value.setVal(STUnderline.DOTTED);
else if (underline.equals(TextAttribute.UNDERLINE_LOW_DASHED))
value.setVal(STUnderline.DASH);
else
value.setVal(STUnderline.SINGLE);
setRPr = true;
}
Paint background = this.readAttribute(attributes, docRunAttributes, TextAttribute.BACKGROUND);
if (background instanceof Color) {
CTShd shd = ctrPr.getShd();
if (shd == null)
shd = ctrPr.addNewShd();
shd.setFill(colorToStringFormat((Color) background));
shd.setVal(STShd.CLEAR);
setRPr = true;
}
}
Locale locale = JRStyledTextAttributeSelector.getTextLocale(textElement);
if (locale != null) {
CTLanguage language = ctrPr.getLang();
if (language == null)
language = ctrPr.addNewLang();
language.setVal(locale.toLanguageTag());
ctrPr.setLang(language);
setRPr = true;
}
if (!setRPr)
docRun.unsetRPr();
}
/**
* Check for {@code flag} if {@code true} or {@code false}.
* @param flag The flag to check.
* @return {@code true} if {@code flag} is one of this: {@code STOnOff.TRUE}, {@code STOnOff.ON} or {@code STOnOff.X_1};
* {@code false} otherwise or {@code flag} is {@code null}.
*/
private boolean checkForDocFlag(STOnOff flag) {
return flag != null && (flag.enumValue() == STOnOff.TRUE || flag.enumValue() == STOnOff.ON || flag.enumValue() == STOnOff.X_1);
}
/**
* Extract text attributes from document run.
* @param docRun The document run.
* @param styleName The style name of the run paragraph.
* @return The text attributes of the run.
*/
protected Map buildDocRunAttributes(CTR docRun, String styleName, J2WDocxPrintElementVisitorContext arg) {
Map res = new HashMap<>();
CTStyle ctStyle = findStyle(styleName, arg, true);
CTPPr stylePPr = null;
CTRPr styleRPr = null;
CTRPr rPr = docRun.getRPr();
if (ctStyle != null) {
stylePPr = ctStyle.getPPr();
styleRPr = ctStyle.getRPr();
}
// Font family
if (rPr != null && rPr.getRFonts() != null)
res.put(TextAttribute.FAMILY, rPr.getRFonts().getAscii());
else if (styleRPr != null && styleRPr.getRFonts() != null && styleRPr.getRFonts().getAscii() != null)
res.put(TextAttribute.FAMILY, styleRPr.getRFonts().getAscii());
// Bold
if (rPr != null && rPr.getB() != null)
res.put(TextAttribute.WEIGHT, this.checkForDocFlag(rPr.getB().xgetVal())? TextAttribute.WEIGHT_BOLD : TextAttribute.WEIGHT_REGULAR);
else if (styleRPr != null && styleRPr.getB() != null)
res.put(TextAttribute.WEIGHT, this.checkForDocFlag(styleRPr.getB().xgetVal())? TextAttribute.WEIGHT_BOLD : TextAttribute.WEIGHT_REGULAR);
// Fore color
if (rPr != null && rPr.getColor() != null)
res.put(TextAttribute.FOREGROUND, stringToColorParse(rPr.getColor().getVal()));
else if (styleRPr != null && styleRPr.getColor() != null)
res.put(TextAttribute.FOREGROUND, stringToColorParse(styleRPr.getColor().getVal()));
// Font size
if (rPr != null && rPr.getSz() != null)
res.put(TextAttribute.SIZE, EConvertMisure.HALF_POINTS.convertInto(EConvertMisure.POINTS, rPr.getSz().getVal().doubleValue()));
else if (styleRPr != null && styleRPr.getSz() != null)
res.put(TextAttribute.SIZE, EConvertMisure.HALF_POINTS.convertInto(EConvertMisure.POINTS, styleRPr.getSz().getVal().doubleValue()));
// Italic
if (rPr != null && rPr.getI() != null)
res.put(TextAttribute.POSTURE, this.checkForDocFlag(rPr.getI().xgetVal())? TextAttribute.POSTURE_OBLIQUE : TextAttribute.POSTURE_REGULAR);
else if (styleRPr != null && styleRPr.getI() != null)
res.put(TextAttribute.POSTURE, this.checkForDocFlag(styleRPr.getI().xgetVal())? TextAttribute.POSTURE_OBLIQUE : TextAttribute.POSTURE_REGULAR);
// Strike
if (rPr != null && rPr.getStrike() != null)
res.put(TextAttribute.STRIKETHROUGH, this.checkForDocFlag(rPr.getStrike().xgetVal()));
else if (styleRPr != null && styleRPr.getStrike() != null)
res.put(TextAttribute.STRIKETHROUGH, this.checkForDocFlag(styleRPr.getStrike().xgetVal()));
// Underline
CTUnderline ctUnderline = null;
if (rPr != null && rPr.getU() != null)
ctUnderline = rPr.getU();
else if (styleRPr != null && styleRPr.getU() != null)
ctUnderline = styleRPr.getU();
if (ctUnderline != null) {
STUnderline val = ctUnderline.xgetVal();
if (val.enumValue() == STUnderline.SINGLE)
res.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
else if (val.enumValue() == STUnderline.DOUBLE)
res.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_LOW_TWO_PIXEL);
else if (val.enumValue() == STUnderline.THICK)
res.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_LOW_ONE_PIXEL);
else if (val.enumValue() == STUnderline.DOTTED_HEAVY)
res.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_LOW_DOTTED);
else if (val.enumValue() == STUnderline.DOTTED)
res.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_LOW_GRAY);
else if (val.enumValue() == STUnderline.DASH)
res.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_LOW_DASHED);
else if (val.enumValue() != STUnderline.NONE)
res.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
}
// Background
if (rPr != null && rPr.getShd() != null)
res.put(TextAttribute.BACKGROUND, stringToColorParse(rPr.getShd().getColor()));
else if (styleRPr != null && styleRPr.getShd() != null)
res.put(TextAttribute.BACKGROUND, stringToColorParse(styleRPr.getShd().getColor()));
else if (stylePPr != null && stylePPr.getShd() != null)
res.put(TextAttribute.BACKGROUND, stringToColorParse(stylePPr.getShd().getColor()));
return res;
}
/**
* Read the text attribute difference between the two parameters map:
*
* - if run has not the attribute, return the jasper attribute
* - if both run and jasper have not the attribute, return {@code null}
* - if both attributes are present but they are not equal, return the jasper value
* - otherwise return {@code null}
*
* @param jasperAttributes The jasper attributes.
* @param runAttributes The run attributes.
* @param attributeName The attribute name.
* @param The type of attribute.
* @return The different attribute value.
*/
private V readAttribute(Map jasperAttributes, Map runAttributes, Attribute attributeName) {
@SuppressWarnings("unchecked") V jasperValue = (V) jasperAttributes.get(attributeName);
@SuppressWarnings("unchecked") V runValue = (V) runAttributes.get(attributeName);
if (runValue == null)
return jasperValue;
else if (jasperValue == null)
return null;
else if (!jasperValue.equals(runValue))
return jasperValue;
else
return null;
}
public void visit(JRPrintImage image, J2WDocxPrintElementVisitorContext arg) {
Renderable renderable = image.getRenderable();
int imageType;
if (renderable != null) {
switch (renderable.getImageTypeValue()) {
case UNKNOWN:
throw new JRRuntimeException("Unknown image type: " + image.getOrigin());
case GIF:
imageType = Document.PICTURE_TYPE_GIF;
break;
case JPEG:
imageType = Document.PICTURE_TYPE_JPEG;
break;
case PNG:
imageType = Document.PICTURE_TYPE_PNG;
break;
case TIFF:
imageType = Document.PICTURE_TYPE_TIFF;
break;
default:
throw new JRRuntimeException("Unknown image type: (" + renderable.getImageTypeValue() + ") " + image.getOrigin());
}
try {
XWPFDocument document = arg.getDocument();
ByteArrayInputStream inputImage = new ByteArrayInputStream(renderable.getImageData(jasperReportsContext));
ComponentPosition position = arg.getLayout().getElementPosition(image);
CTP paragraph = this.findParagraph(position, image, arg, true).getParagraph();
CTR run = paragraph.addNewR();
XWPFParagraph xwpfParagraph = new XWPFParagraph(paragraph, document);
// switch (position.getDocumentPart()) {
// case HEADER:
// xwpfParagraph = new XWPFParagraph(paragraph, arg.headerContent);
// break;
// case FOOTER:
// break;
// case BODY:
// break;
// }
XWPFRun xrun = new XWPFRun(run, xwpfParagraph);
xrun.addPicture(inputImage, imageType, "", Units.toEMU(position.getWidth()), Units.toEMU(position.getHeight()));
} catch (InvalidFormatException e) {
throw new JRRuntimeException("Unknown image type", e);
} catch (JRException e) {
throw new JRRuntimeException("Unreadable image", e);
} catch (IOException e) {
throw new JRRuntimeException("Write image error", e);
}
}
}
public void visit(JRPrintRectangle rectangle, J2WDocxPrintElementVisitorContext arg) {
if (rectangle.getLinePen() != null && (rectangle.getLinePen().getLineWidth() > 0f ||
(rectangle.getModeValue() == ModeEnum.OPAQUE && rectangle.getFillValue() == FillEnum.SOLID && rectangle.getBackcolor() != null))) {
ComponentPosition position = arg.getLayout().getElementPosition(rectangle);
FoundDocParagraph foundDocParagraph = this.findParagraph(position, rectangle.getStyle(), arg, true);
CTP paragraph = foundDocParagraph.getParagraph();
CTR run = paragraph.addNewR();
CTPicture ctPicture = run.addNewPict();
XmlObject docLine;
try {
String zIndex = "z-index:251661312";
String color = J2WDocxPoiHelper.colorToStringFormat(rectangle.getForecolor());
String fillcolor;
String filltemplate;
if (rectangle.getModeValue() == ModeEnum.OPAQUE && rectangle.getFillValue() == FillEnum.SOLID) {
fillcolor = "filled=\"t\" fillcolor=\"#" + J2WDocxPoiHelper.colorToStringFormat(rectangle.getBackcolor()) + "\"";
filltemplate = "\n\t";
}
else {
fillcolor = "";
filltemplate = "";
}
String xmlAsString = MessageFormat.format(
"" +
// "\n\t" +
filltemplate +
"\n\t" +
" "
,
position.getX(), position.getY(), position.getWidth(), position.getHeight(), zIndex, String.valueOf(rectangle.hashCode()), color, rectangle.getLinePen().getLineWidth(), fillcolor);
docLine = XmlObject.Factory.parse(xmlAsString);
} catch (XmlException e) {
throw new JRRuntimeException("Rectangle error:", e);
}
ctPicture.set(docLine);
}
}
public void visit(JRPrintLine line, J2WDocxPrintElementVisitorContext arg) {
if (line.getLinePen() != null && line.getLinePen().getLineWidth() > 0f) {
ComponentPosition position = arg.getLayout().getElementPosition(line);
CTP paragraph = this.findParagraph(position, line.getStyle(), arg, true).getParagraph();
CTR run = paragraph.addNewR();
CTPicture ctPicture = run.addNewPict();
XmlObject docLine;
try {
String zIndex = "z-index:251661312;";
String color = J2WDocxPoiHelper.colorToStringFormat(line.getLinePen().getLineColor());
docLine = XmlObject.Factory.parse(
MessageFormat.format(
"" +
" "
,
position.getX(), position.getY(), position.getX() + position.getWidth(), position.getY() + position.getHeight(), zIndex, String.valueOf(line.hashCode()), color, line.getLinePen().getLineWidth())
);
} catch (XmlException e) {
throw new JRRuntimeException("Line error:", e);
}
ctPicture.set(docLine);
}
}
public void visit(JRPrintEllipse ellipse, J2WDocxPrintElementVisitorContext arg) {
if (ellipse.getLinePen() != null && ellipse.getLinePen().getLineWidth() > 0f) {
ComponentPosition position = arg.getLayout().getElementPosition(ellipse);
CTP paragraph = this.findParagraph(position, ellipse.getStyle(), arg, true).getParagraph();
CTR run = paragraph.addNewR();
CTPicture ctPicture = run.addNewPict();
XmlObject docLine;
try {
String zIndex = "z-index:251661312";
String color = J2WDocxPoiHelper.colorToStringFormat(ellipse.getLinePen().getLineColor());
String fillcolor;
if (ellipse.getModeValue() == ModeEnum.OPAQUE && ellipse.getFillValue() == FillEnum.SOLID)
fillcolor = "fillcolor=\"" + J2WDocxPoiHelper.colorToStringFormat(ellipse.getLinePen().getLineColor()) + "\"";
else
fillcolor = "";
docLine = XmlObject.Factory.parse(
MessageFormat.format(
"" +
"id=\"{5}\" o:spid=\"_x0000_s1026\" strokecolor=\"{6}\" strokeweight=\"{7,number,0.00}\" {8}>" +
" "
,
position.getX(), position.getY(), position.getWidth(), position.getHeight(), zIndex, String.valueOf(ellipse.hashCode()), color, ellipse.getLinePen().getLineWidth(), fillcolor)
);
} catch (XmlException e) {
throw new JRRuntimeException("Ellipse error:", e);
}
ctPicture.set(docLine);
}
}
public void visit(JRPrintFrame frame, J2WDocxPrintElementVisitorContext arg) {
ComponentPosition framePosition = arg.getLayout().getElementPosition(frame);
// if (framePosition.getParent() == null || !(framePosition.getParent() instanceof ComponentPositionInTable))
// this.findParagraph(framePosition, frame, arg, true);
Collection elements = arg.getLayout().listJRPrintElements(frame);
JRStyle frameStyle = frame.getStyle();
for (JRPrintElement element : elements) {
JRStyle elementStyle = element.getStyle();
if (elementStyle == null)
element.setStyle(frameStyle);
else if (frameStyle != null) {
if (arg.getReport().getStylesMap().containsKey(elementStyle.getName())) {
JRStyle newElementStyle = (JRStyle) elementStyle.clone();
String newStyleName = arg.remapStylesNameByJrStyle.get(newElementStyle.getName()) + "BasedOn" + arg.remapStylesNameByJrStyle.get(frameStyle.getName());
if (newElementStyle instanceof JRBaseStyle) {
((JRBaseStyle) newElementStyle).rename(newStyleName);
} else
throw new JRRuntimeException("Operation not supported");
if (!arg.allStyles.contains(newStyleName)) {
buildStyles(arg, Collections.singletonList(newElementStyle));
XWPFStyles styles = arg.getDocument().getStyles();
XWPFStyle style = styles.getStyle(newStyleName);
style.getCTStyle().addNewBasedOn().setVal(arg.remapStylesNameByJrStyle.get(frameStyle.getName()));
}
if (element instanceof JRTemplatePrintElement)
((JRTemplatePrintElement) element).getTemplate().setStyle(newElementStyle);
else
element.setStyle(newElementStyle);
}
}
element.accept(this, arg);
if (element instanceof JRTemplatePrintElement)
((JRTemplatePrintElement) element).getTemplate().setStyle(elementStyle);
else
element.setStyle(elementStyle);
}
}
public void visit(JRGenericPrintElement printElement, J2WDocxPrintElementVisitorContext arg) {
}
/**
* Found or built paragraph.
*/
protected static class FoundDocParagraph {
/** The doc paragraph */
private final CTP paragraph;
/** The table cell (can be {@code null}) */
private final CTTc cell;
/** The index in the document list objects */
private final int paragraphIndexInDoc;
/**
* Construct the found paragraph.
* @param cell The table cell (can be {@code null}) if the paragraph is outside a table.
* @param paragraph The doc paragraph.
* @param paragraphIndexInDoc The index in the jaxb document list objects.
*/
public FoundDocParagraph(CTTc cell, CTP paragraph, int paragraphIndexInDoc) {
this.paragraph = paragraph;
this.cell = cell;
this.paragraphIndexInDoc = paragraphIndexInDoc;
}
/**
* Return the paragraph.
* @return The paragraph.
*/
public CTP getParagraph() {
return paragraph;
}
/**
* Return the table cell.
* @return The table cell or {@code null}.
*/
public CTTc getCell() {
return cell;
}
/**
* Return if the paragraph is inside a table.
* @return {@code true} if in table, {@code false} otherwise.
*/
public boolean isTableCell() {
return cell != null;
}
/**
* Return the index in the jaxb document list objects.
* @return The index in the jaxb document list objects.
*/
public int getParagraphIndexInDoc() {
return paragraphIndexInDoc;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy