package ro.nextreports.engine.exporter;
import java.awt.Color;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.bind.JAXBElement;
import org.docx4j.dml.wordprocessingDrawing.Inline;
import org.docx4j.docProps.core.CoreProperties;
import org.docx4j.docProps.core.dc.elements.SimpleLiteral;
import org.docx4j.jaxb.Context;
import org.docx4j.model.structure.PageDimensions;
import org.docx4j.model.structure.PageSizePaper;
import org.docx4j.model.structure.SectionWrapper;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.exceptions.InvalidFormatException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.DocPropsCorePart;
import org.docx4j.openpackaging.parts.Part;
import org.docx4j.openpackaging.parts.WordprocessingML.AltChunkType;
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
import org.docx4j.openpackaging.parts.WordprocessingML.FooterPart;
import org.docx4j.openpackaging.parts.WordprocessingML.HeaderPart;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.openpackaging.parts.relationships.Namespaces;
import org.docx4j.relationships.Relationship;
import org.docx4j.wml.CTBackground;
import org.docx4j.vml.CTFill;
import org.docx4j.wml.Body;
import org.docx4j.wml.BooleanDefaultTrue;
import org.docx4j.wml.Br;
import org.docx4j.wml.CTBorder;
import org.docx4j.wml.CTShd;
import org.docx4j.wml.CTSimpleField;
import org.docx4j.wml.CTVerticalJc;
import org.docx4j.wml.Drawing;
import org.docx4j.wml.FooterReference;
import org.docx4j.wml.Ftr;
import org.docx4j.wml.Hdr;
import org.docx4j.wml.HdrFtrRef;
import org.docx4j.wml.HeaderReference;
import org.docx4j.wml.HpsMeasure;
import org.docx4j.wml.Jc;
import org.docx4j.wml.JcEnumeration;
import org.docx4j.wml.ObjectFactory;
import org.docx4j.wml.P;
import org.docx4j.wml.PPr;
import org.docx4j.wml.PPrBase;
import org.docx4j.wml.RStyle;
import org.docx4j.wml.PPrBase.Spacing;
import org.docx4j.wml.R;
import org.docx4j.wml.RFonts;
import org.docx4j.wml.RPr;
import org.docx4j.wml.STBorder;
import org.docx4j.wml.STBrType;
import org.docx4j.wml.STVerticalJc;
import org.docx4j.wml.SectPr;
import org.docx4j.wml.SectPr.PgMar;
import org.docx4j.wml.Tbl;
import org.docx4j.wml.TblPr;
import org.docx4j.wml.TblWidth;
import org.docx4j.wml.Tc;
import org.docx4j.wml.TcMar;
import org.docx4j.wml.TcPr;
import org.docx4j.wml.TcPrInner.GridSpan;
import org.docx4j.wml.TcPrInner.TcBorders;
import org.docx4j.wml.TcPrInner.VMerge;
import org.docx4j.wml.Text;
import org.docx4j.wml.TextDirection;
import org.docx4j.wml.Tr;
import org.docx4j.wml.TrPr;
import org.docx4j.wml.U;
import org.docx4j.wml.UnderlineEnumeration;
import ro.nextreports.engine.ReleaseInfoAdapter;
import ro.nextreports.engine.Report;
import ro.nextreports.engine.ReportLayout;
import ro.nextreports.engine.band.Band;
import ro.nextreports.engine.band.BandElement;
import ro.nextreports.engine.band.ExpressionBandElement;
import ro.nextreports.engine.band.Hyperlink;
import ro.nextreports.engine.band.HyperlinkBandElement;
import ro.nextreports.engine.band.ImageBandElement;
import ro.nextreports.engine.band.ImageColumnBandElement;
import ro.nextreports.engine.band.Padding;
import ro.nextreports.engine.band.ReportBandElement;
import ro.nextreports.engine.band.VariableBandElement;
import ro.nextreports.engine.exporter.util.StyleFormatConstants;
import ro.nextreports.engine.exporter.util.variable.PageNoVariable;
import ro.nextreports.engine.exporter.util.variable.VariableFactory;
import ro.nextreports.engine.queryexec.QueryException;
import ro.nextreports.engine.util.ColorUtil;
import ro.nextreports.engine.util.StringUtil;
public class DocxExporter extends ResultExporter {
private WordprocessingMLPackage wordMLPackage;
private ObjectFactory factory;
private Tbl table;
private Tbl tableHeader;
private Tbl tableFooter;
private Tr tableRow;
private int fragmentsize = 15000;
private int[] headerwidths;
private int A4_PORTRAIT_DXA = 11906;
private int A4_LANDSCAPE_DXA = 16838;
private int rowNo = 0;
// for a master report it is computed, for a subreport it is given
private int currentWidth = -1;
private boolean hasPageNoHeader = false;
private boolean hasPageNoFooter = false;
private Map<Integer, Integer> rowSpanForColumn = new HashMap<Integer, Integer>();
public DocxExporter(ExporterBean bean) {
super(bean);
}
public DocxExporter(ExporterBean bean, int currentWidth) {
super(bean);
this.currentWidth = currentWidth;
}
@Override
protected void exportCell(String bandName, BandElement bandElement, Object value, int gridRow, int row, int column, int cols,
int rowSpan, int colSpan, boolean isImage) {
if (newRow) {
// rowNo for a table (it is reset in createTable)
rowNo++;
// for first row in page header and page footer we do not add the table row because it will be duplicated
if ( ((!ReportLayout.PAGE_HEADER_BAND_NAME.equals(bandName) && !ReportLayout.PAGE_FOOTER_BAND_NAME.equals(bandName))) || (rowNo>1)) {
if (tableRow != null) {
if (ReportLayout.PAGE_HEADER_BAND_NAME.equals(bandName)) {
tableHeader.getContent().add(tableRow);
} else if (ReportLayout.PAGE_FOOTER_BAND_NAME.equals(bandName)) {
tableFooter.getContent().add(tableRow);
} else {
table.getContent().add(tableRow);
}
}
tableRow = factory.createTr();
}
// create table header to be available on every page
if (bean.getReportLayout().isHeaderOnEveryPage()) {
if (ReportLayout.HEADER_BAND_NAME.equals(bandName)) {
TrPr rowProperties = new TrPr();
BooleanDefaultTrue bdt = Context.getWmlObjectFactory().createBooleanDefaultTrue();
rowProperties.getCnfStyleOrDivIdOrGridBefore().add(Context.getWmlObjectFactory().createCTTrPrBaseTblHeader(bdt));
tableRow.setTrPr(rowProperties);
}
}
}
renderDocxCell(bandName,bandElement, value, gridRow, rowSpan, colSpan, isImage, column);
}
private void renderDocxCell(String bandName, BandElement bandElement, Object value, int gridRow, int rowSpan, int colSpan, boolean image, int column) {
Map<String, Object> style = buildCellStyleMap(bandElement, value, gridRow, column, colSpan);
String verticalMergedVal = null;
if (rowSpan > 1) {
verticalMergedVal = "restart";
rowSpanForColumn.put(column, rowSpan);
} else {
int span = rowSpanForColumn.get(column);
if (span > 1) {
rowSpanForColumn.put(column, span-1);
if (span == 2) {
// last cell to merge vertically
verticalMergedVal = "close";
} else {
verticalMergedVal = "";
}
}
}
int width = headerwidths[column];
if (colSpan > 1) {
for (int i=1; i<colSpan; i++) {
width += headerwidths[column+i];
}
}
if (image) {
if (value == null) {
addTableCell(tableRow, bandElement, "", width, style, colSpan, verticalMergedVal);
} else {
ImageBandElement ibe = (ImageBandElement)bandElement;
P pImage;
try {
byte[] imageD = getImage((String) value);
byte[] imageBytes = getImage(imageD, ibe.getWidth(), ibe.getHeight());
int imageW;
if (ibe.getWidth() == null) {
imageW = getRealImageSize(imageBytes)[0];
} else {
imageW = ibe.getWidth();
}
pImage = newImage(wordMLPackage, imageBytes, null, null, 0, 1, pixelsToDxa(imageW));
addTableCell(tableRow, bandElement, pImage, width, style, colSpan, verticalMergedVal, true);
} catch (Exception e) {
e.printStackTrace();
}
}
} else if (bandElement instanceof HyperlinkBandElement) {
Hyperlink hyperlink = ((HyperlinkBandElement)bandElement).getHyperlink();
addHyperlinkTableCell(tableRow, bandElement, hyperlink, width, style, colSpan, verticalMergedVal);
} else if (bandElement instanceof ReportBandElement) {
Report report = ((ReportBandElement)bandElement).getReport();
ExporterBean eb = null;
try {
eb = getSubreportExporterBean(report);
DocxExporter subExporter = new DocxExporter(eb, width);
subExporter.export();
Tbl innerTable = subExporter.getTable();
addSubreportTableCell(tableRow, bandElement, innerTable, width, style, colSpan, verticalMergedVal);
} catch (Exception e) {
addTableCell(tableRow, bandElement, "", width, style, colSpan, verticalMergedVal);
e.printStackTrace();
} finally {
if ((eb != null) && (eb.getResult() != null)) {
eb.getResult().close();
}
}
} else if ( ((bandElement instanceof VariableBandElement) &&
(VariableFactory.getVariable(((VariableBandElement) bandElement).getVariable()) instanceof PageNoVariable)) ||
((bandElement instanceof ExpressionBandElement) &&
((ExpressionBandElement)bandElement).getExpression().contains(PageNoVariable.PAGE_NO_PARAM))) {
// limitation: if header or footer contains PAGE_NO varaible, only this will be shown,
// all other cells from header/footer will be ignored
if (ReportLayout.PAGE_HEADER_BAND_NAME.equals(bandName)) {
hasPageNoHeader = true;
} else if (ReportLayout.PAGE_FOOTER_BAND_NAME.equals(bandName)) {
hasPageNoFooter = true;
}
// does not work (we should add pageNo to header or footer directly and not inside a table
// P numP = createPageNumParagraph();
// addTableCell(tableRow, bandElement, bandElement.getText(), numP, width, style, colSpan, verticalMergedVal);
} else if (bandElement instanceof ImageColumnBandElement) {
try {
String v = StringUtil.getValueAsString(value, null);
if(StringUtil.BLOB.equals(v)) {
addTableCell(tableRow, bandElement, StringUtil.BLOB, width, style, colSpan, verticalMergedVal);
} else {
ImageColumnBandElement icbe = (ImageColumnBandElement) bandElement;
byte[] imageD = StringUtil.decodeImage(v);
byte[] imageBytes = getImage(imageD, icbe.getWidth(), icbe.getHeight());
int imageW;
if (icbe.getWidth() == null) {
imageW = getRealImageSize(imageBytes)[0];
} else {
imageW = icbe.getWidth();
}
P pImage = newImage(wordMLPackage, imageBytes, null, null, 0, 1, pixelsToDxa(imageW));
addTableCell(tableRow, bandElement, pImage, width, style, colSpan, verticalMergedVal, true);
}
} catch (Exception e) {
e.printStackTrace();
addTableCell(tableRow, bandElement, IMAGE_NOT_LOADED, width, style, colSpan, verticalMergedVal);
}
} else {
String stringValue;
if (style.containsKey(StyleFormatConstants.PATTERN)) {
stringValue = StringUtil.getValueAsString(value, (String) style.get(StyleFormatConstants.PATTERN), getReportLanguage());
} else {
stringValue = StringUtil.getValueAsString(value, null, getReportLanguage());
}
if (stringValue == null) {
stringValue = "";
}
addTableCell(tableRow, bandElement, stringValue, width, style, colSpan, verticalMergedVal);
}
}
@Override
protected void initExport() throws QueryException {
try {
factory = Context.getWmlObjectFactory();
for (int i=0; i<bean.getReportLayout().getColumnCount(); i++) {
rowSpanForColumn.put(i, 1);
}
if (!bean.isSubreport()) {
boolean landscape = (bean.getReportLayout().getOrientation() == LANDSCAPE);
wordMLPackage = WordprocessingMLPackage.createPackage(PageSizePaper.A4, landscape);
setPageMargins();
addMetadata();
}
table = createTable(PRINT_DOCUMENT);
} catch (InvalidFormatException e) {
e.printStackTrace();
throw new QueryException(e);
}
}
@Override
protected void finishExport() {
if (table != null) {
table.getContent().add(tableRow);
}
if (!bean.isSubreport()) {
if (table != null) {
wordMLPackage.getMainDocumentPart().addObject(table);
} else {
wordMLPackage.getMainDocumentPart().addParagraphOfText("");
}
table = null;
try {
addPageHeaderFooter();
//addBackgroundImage();
} catch (Exception ex) {
ex.printStackTrace();
}
try {
wordMLPackage.save(getOut());
} catch (Docx4JException e) {
e.printStackTrace();
}
}
}
@Override
protected void close() {
}
@Override
protected void flush() {
if (!bean.isSubreport()) {
if (resultSetRow % fragmentsize == fragmentsize - 1) {
flushNow();
}
}
}
@Override
protected void flushNow() {
table.getContent().add(tableRow);
if (!bean.isSubreport()) {
wordMLPackage.getMainDocumentPart().addObject(table);
table = createTable(PRINT_DOCUMENT);
tableRow = null;
}
}
@Override
protected Set<CellElement> getIgnoredCells(Band band) {
return getIgnoredCellElementsForColSpan(band);
}
@Override
protected void afterRowExport() {
}
@Override
protected String getNullElement() {
return "";
}
@Override
protected void newPage() {
flushNow();
Br objBr = new Br();
objBr.setType(STBrType.PAGE);
P para = createParagraph();
para.getContent().add(objBr);
wordMLPackage.getMainDocumentPart().getContent().add(para);
if (bean.getReportLayout().isHeaderOnEveryPage()) {
try {
printHeaderBand();
newRow = true;
} catch (QueryException e) {
e.printStackTrace();
}
}
}
private void setPageMargins() {
try {
Body body = wordMLPackage.getMainDocumentPart().getContents().getBody();
Padding padding = bean.getReportLayout().getPagePadding();
PageDimensions page = new PageDimensions();
PgMar pgMar = page.getPgMar();
pgMar.setBottom(BigInteger.valueOf(pixelsToDxa(padding.getBottom())));
pgMar.setTop(BigInteger.valueOf(pixelsToDxa(padding.getTop())));
pgMar.setLeft(BigInteger.valueOf(pixelsToDxa(padding.getLeft())));
pgMar.setRight(BigInteger.valueOf(pixelsToDxa(padding.getRight())));
SectPr sectPr = factory.createSectPr();
body.setSectPr(sectPr);
sectPr.setPgMar(pgMar);
} catch (Docx4JException e) {
e.printStackTrace();
}
}
private void addMetadata() {
try {
DocPropsCorePart docPropsCorePart = wordMLPackage.getDocPropsCorePart();
CoreProperties coreProps = (CoreProperties) docPropsCorePart.getContents();
org.docx4j.docProps.core.ObjectFactory CorePropsfactory = new org.docx4j.docProps.core.ObjectFactory();
org.docx4j.docProps.core.dc.elements.ObjectFactory dcElfactory = new org.docx4j.docProps.core.dc.elements.ObjectFactory();
SimpleLiteral desc = dcElfactory.createSimpleLiteral();
desc.getContent().add("Created by NextReports Designer" + ReleaseInfoAdapter.getVersionNumber());
coreProps.setDescription(dcElfactory.createDescription(desc));
SimpleLiteral title = dcElfactory.createSimpleLiteral();
title.getContent().add(getDocumentTitle());
coreProps.setTitle(dcElfactory.createTitle(title));
SimpleLiteral author = dcElfactory.createSimpleLiteral();
author.getContent().add(ReleaseInfoAdapter.getCompany());
coreProps.setCreator(author);
SimpleLiteral subject = dcElfactory.createSimpleLiteral();
subject.getContent().add("Created by NextReports Designer" + ReleaseInfoAdapter.getVersionNumber());
coreProps.setSubject(subject);
coreProps.setKeywords(ReleaseInfoAdapter.getHome());
} catch (Docx4JException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private Tbl createTable(int type) {
rowNo = 0;
List<Band> bands = new ArrayList<Band>();
if (type == PRINT_PAGE_HEADER) {
bands.add(getReportLayout().getPageHeaderBand());
} else if (type == PRINT_PAGE_FOOTER) {
bands.add(getReportLayout().getPageFooterBand());
} else {
bands = getReportLayout().getDocumentBands();
}
int totalRows = 0;
int totalColumns = 0;
for (Band band : bands) {
totalRows += band.getRowCount();
int cols = band.getColumnCount();
if (cols > totalColumns) {
totalColumns = cols;
}
}
// no page header or no page footer
if (totalColumns == 0) {
return null;
}
headerwidths = new int[totalColumns];
boolean landscape = (bean.getReportLayout().getOrientation() == LANDSCAPE);
Padding padding = bean.getReportLayout().getPagePadding();
int margs = pixelsToDxa(padding.getLeft()+padding.getRight());
if (currentWidth == -1) {
currentWidth = landscape ? (A4_LANDSCAPE_DXA-margs) : (A4_PORTRAIT_DXA-margs);
}
int colWidth = currentWidth/totalColumns;
for (int i = 0; i < totalColumns; i++) {
if (bean.getReportLayout().isUseSize()) {
headerwidths[i] = pixelsToDxa(bean.getReportLayout().getColumnsWidth().get(i));
} else {
headerwidths[i] = colWidth;
}
}
Tbl resultTable = factory.createTbl();
// set table width
TblPr tblPr = factory.createTblPr();
TblWidth tblWidth = factory.createTblWidth();
if (bean.getReportLayout().isUseSize()) {
int sum = 0;
for (int i = 0; i < totalColumns; i++) {
sum += headerwidths[i];
}
currentWidth = sum;
}
tblWidth.setW(BigInteger.valueOf(currentWidth));
tblWidth.setType(TblWidth.TYPE_DXA);
tblPr.setTblW(tblWidth);
resultTable.setTblPr(tblPr);
return resultTable;
}
private void addHyperlinkTableCell(Tr tableRow, BandElement be, Hyperlink link, int width, Map<String, Object> style, int horizontalMergedCells, String verticalMergedVal) {
org.docx4j.wml.P.Hyperlink hyp = newHyperlink(wordMLPackage.getMainDocumentPart(), link.getText(), link.getUrl());
P paragraph = createParagraph(be);
paragraph.getContent().add(hyp);
addTableCell(tableRow, be, paragraph, width, style, horizontalMergedCells, verticalMergedVal, false);
}
private void addSubreportTableCell(Tr tableRow, BandElement be, Tbl table, int width, Map<String, Object> style, int horizontalMergedCells, String verticalMergedVal) {
Tc tableCell = factory.createTc();
tableCell.getContent().add(table);
tableCell.getContent().add(wordMLPackage.getMainDocumentPart().createParagraphOfText(""));
setCellWidth(tableCell, width);
setCellVMerge(tableCell, verticalMergedVal);
setCellHMerge(tableCell, horizontalMergedCells);
tableRow.getContent().add(tableCell);
}
private void addTableCell(Tr tableRow, BandElement be, P paragraph, int width, Map<String, Object> style, int horizontalMergedCells, String verticalMergedVal, boolean isImage) {
Tc tableCell = factory.createTc();
if (isImage) {
addImageCellStyle(tableCell, be, paragraph, style);
} else {
addHyperlinkCellStyle(tableCell, be, paragraph, style);
}
setCellWidth(tableCell, width);
setCellVMerge(tableCell, verticalMergedVal);
setCellHMerge(tableCell, horizontalMergedCells);
if (!isImage) {
if ((be != null) && !be.isWrapText()) {
setCellNoWrap(tableCell);
}
}
tableRow.getContent().add(tableCell);
}
private void addTableCell(Tr tableRow, BandElement be, String content, int width, Map<String, Object> style, int horizontalMergedCells, String verticalMergedVal) {
Tc tableCell = factory.createTc();
addCellStyle(tableCell, be, content, style);
setCellWidth(tableCell, width);
setCellVMerge(tableCell, verticalMergedVal);
setCellHMerge(tableCell, horizontalMergedCells);
if ((be != null) && !be.isWrapText()) {
setCellNoWrap(tableCell);
}
tableRow.getContent().add(tableCell);
}
private void addTableCell(Tr tableRow, BandElement be, String content, P p, int width, Map<String, Object> style, int horizontalMergedCells, String verticalMergedVal) {
Tc tableCell = factory.createTc();
addCellStyle(tableCell, be, content, p, style);
setCellWidth(tableCell, width);
setCellVMerge(tableCell, verticalMergedVal);
setCellHMerge(tableCell, horizontalMergedCells);
if ((be != null) && !be.isWrapText()) {
setCellNoWrap(tableCell);
}
tableRow.getContent().add(tableCell);
}
private void addImageCellStyle(Tc tableCell, BandElement be, P image, Map<String, Object> style) {
setCellMargins(tableCell, style);
setBackground(tableCell, style);
setVerticalAlignment(tableCell, style);
setHorizontalAlignment(image, style);
setCellBorders(tableCell, style);
tableCell.getContent().add(image);
}
private void addHyperlinkCellStyle(Tc tableCell, BandElement be, P hyperlink, Map<String, Object> style) {
setCellMargins(tableCell, style);
setBackground(tableCell, style);
setVerticalAlignment(tableCell, style);
setHorizontalAlignment(hyperlink, style);
setCellBorders(tableCell, style);
R run = (R) ((org.docx4j.wml.P.Hyperlink)hyperlink.getContent().get(0)).getContent().get(0);
RPr runProperties = run.getRPr();
setFont(tableCell, style, runProperties);
if (be != null) {
setTextDirection(tableCell, be.getTextRotation());
}
tableCell.getContent().add(hyperlink);
}
private void addCellStyle(Tc tableCell, BandElement be, String content, Map<String, Object> style) {
P paragraph = createParagraph(be);
addCellStyle(tableCell, be, content, paragraph, style);
}
private void addCellStyle(Tc tableCell, BandElement be, String content, P paragraph, Map<String, Object> style) {
if (style != null) {
// inner html text
if (content.startsWith("<html>")) {
try {
wordMLPackage.getMainDocumentPart().addAltChunk(AltChunkType.Html, content.getBytes(), tableCell);
tableCell.getContent().add(paragraph);
} catch (Docx4JException e) {
e.printStackTrace();
}
return;
}
Text text = factory.createText();
text.setValue(content);
R run = factory.createR();
run.getContent().add(text);
paragraph.getContent().add(run);
setHorizontalAlignment(paragraph, style);
RPr runProperties = factory.createRPr();
setFont(tableCell, style, runProperties);
setCellMargins(tableCell,style);
setBackground(tableCell, style);
setVerticalAlignment(tableCell, style);
setCellBorders(tableCell, style);
if (be != null) {
setTextDirection(tableCell, be.getTextRotation());
}
run.setRPr(runProperties);
tableCell.getContent().add(paragraph);
}
}
private void setBackground(Tc tableCell, Map<String, Object> style) {
// to see a background image all cells must not have any background!
if (bean.getReportLayout().getBackgroundImage() == null) {
if (style.containsKey(StyleFormatConstants.BACKGROUND_COLOR)) {
Color val = (Color) style.get(StyleFormatConstants.BACKGROUND_COLOR);
setCellColor(tableCell, ColorUtil.getHexColor(val).substring(1));
}
}
}
private void setFont(Tc tableCell, Map<String, Object> style, RPr runProperties ) {
if (style.containsKey(StyleFormatConstants.FONT_FAMILY_KEY)) {
String val = (String) style.get(StyleFormatConstants.FONT_FAMILY_KEY);
setFontFamily(runProperties, val);
}
if (style.containsKey(StyleFormatConstants.FONT_SIZE)) {
Float val = (Float) style.get(StyleFormatConstants.FONT_SIZE);
setFontSize(runProperties, String.valueOf( (int)(2*val)));
}
if (style.containsKey(StyleFormatConstants.FONT_COLOR)) {
Color val = (Color) style.get(StyleFormatConstants.FONT_COLOR);
setFontColor(runProperties, ColorUtil.getHexColor(val).substring(1));
}
if (style.containsKey(StyleFormatConstants.FONT_STYLE_KEY)) {
if (StyleFormatConstants.FONT_STYLE_BOLD.equals(style.get(StyleFormatConstants.FONT_STYLE_KEY))) {
addBoldStyle(runProperties);
}
if (StyleFormatConstants.FONT_STYLE_ITALIC.equals(style.get(StyleFormatConstants.FONT_STYLE_KEY))) {
addItalicStyle(runProperties);
}
if (StyleFormatConstants.FONT_STYLE_BOLDITALIC.equals(style.get(StyleFormatConstants.FONT_STYLE_KEY))) {
addBoldStyle(runProperties);
addItalicStyle(runProperties);
}
}
}
private void setTextDirection(Tc tableCell, short textRotation) {
String dir = null;
if (textRotation == 90) {
dir = "btLr";
} else if (textRotation == -90) {
dir = "tbRl";
}
if (dir != null) {
TcPr tableCellProperties = tableCell.getTcPr();
if (tableCellProperties == null) {
tableCellProperties = new TcPr();
tableCell.setTcPr(tableCellProperties);
}
TextDirection td = new TextDirection();
td.setVal(dir);
tableCellProperties.setTextDirection(td);
}
}
private void setCellBorders(Tc tableCell, Map<String, Object> style) {
TcPr tableCellProperties = tableCell.getTcPr();
if (tableCellProperties == null) {
tableCellProperties = new TcPr();
tableCell.setTcPr(tableCellProperties);
}
CTBorder border = new CTBorder();
// border.setColor("auto");
border.setSpace(new BigInteger("0"));
border.setVal(STBorder.SINGLE);
TcBorders borders = new TcBorders();
if (style.containsKey(StyleFormatConstants.BORDER_LEFT)) {
Float val = (Float) style.get(StyleFormatConstants.BORDER_LEFT);
border.setSz(BigInteger.valueOf((long) (val / 2)));
Color color = (Color) style.get(StyleFormatConstants.BORDER_LEFT_COLOR);
border.setColor(ColorUtil.getHexColor(color).substring(1));
borders.setLeft(border);
}
if (style.containsKey(StyleFormatConstants.BORDER_RIGHT)) {
Float val = (Float) style.get(StyleFormatConstants.BORDER_RIGHT);
border.setSz(BigInteger.valueOf((long) (val / 2)));
Color color = (Color) style.get(StyleFormatConstants.BORDER_RIGHT_COLOR);
border.setColor(ColorUtil.getHexColor(color).substring(1));
borders.setRight(border);
}
if (style.containsKey(StyleFormatConstants.BORDER_TOP)) {
Float val = (Float) style.get(StyleFormatConstants.BORDER_TOP);
border.setSz(BigInteger.valueOf((long) (val / 2)));
Color color = (Color) style.get(StyleFormatConstants.BORDER_TOP_COLOR);
border.setColor(ColorUtil.getHexColor(color).substring(1));
borders.setTop(border);
}
if (style.containsKey(StyleFormatConstants.BORDER_BOTTOM)) {
Float val = (Float) style.get(StyleFormatConstants.BORDER_BOTTOM);
border.setSz(BigInteger.valueOf((long) (val / 2)));
Color color = (Color) style.get(StyleFormatConstants.BORDER_BOTTOM_COLOR);
border.setColor(ColorUtil.getHexColor(color).substring(1));
borders.setBottom(border);
}
tableCellProperties.setTcBorders(borders);
}
private void setCellWidth(Tc tableCell, int width) {
if (width > 0) {
TcPr tableCellProperties = tableCell.getTcPr();
if (tableCellProperties == null) {
tableCellProperties = new TcPr();
tableCell.setTcPr(tableCellProperties);
}
TblWidth tableWidth = new TblWidth();
tableWidth.setType("dxa");
tableWidth.setW(BigInteger.valueOf(width));
tableCellProperties.setTcW(tableWidth);
}
}
private void setCellNoWrap(Tc tableCell) {
TcPr tableCellProperties = tableCell.getTcPr();
if (tableCellProperties == null) {
tableCellProperties = new TcPr();
tableCell.setTcPr(tableCellProperties);
}
BooleanDefaultTrue b = new BooleanDefaultTrue();
b.setVal(true);
tableCellProperties.setNoWrap(b);
}
private void setCellVMerge(Tc tableCell, String mergeVal) {
if (mergeVal != null) {
TcPr tableCellProperties = tableCell.getTcPr();
if (tableCellProperties == null) {
tableCellProperties = new TcPr();
tableCell.setTcPr(tableCellProperties);
}
VMerge merge = new VMerge();
if (!"close".equals(mergeVal)) {
merge.setVal(mergeVal);
}
tableCellProperties.setVMerge(merge);
}
}
private void setCellHMerge(Tc tableCell, int horizontalMergedCells) {
if (horizontalMergedCells > 1) {
TcPr tableCellProperties = tableCell.getTcPr();
if (tableCellProperties == null) {
tableCellProperties = new TcPr();
tableCell.setTcPr(tableCellProperties);
}
GridSpan gridSpan = new GridSpan();
gridSpan.setVal(new BigInteger(String.valueOf(horizontalMergedCells)));
tableCellProperties.setGridSpan(gridSpan);
tableCell.setTcPr(tableCellProperties);
}
}
private void setCellColor(Tc tableCell, String color) {
if (color != null) {
TcPr tableCellProperties = tableCell.getTcPr();
if (tableCellProperties == null) {
tableCellProperties = new TcPr();
tableCell.setTcPr(tableCellProperties);
}
CTShd shd = new CTShd();
shd.setFill(color);
tableCellProperties.setShd(shd);
}
}
private void setCellMargins(Tc tableCell, Map<String, Object> style) {
int top = 0, left = 0, bottom = 0 ,right = 0;
if (style.containsKey(StyleFormatConstants.PADDING_LEFT)) {
Float val = (Float) style.get(StyleFormatConstants.PADDING_LEFT);
left = val.intValue();
}
if (style.containsKey(StyleFormatConstants.PADDING_RIGHT)) {
Float val = (Float) style.get(StyleFormatConstants.PADDING_RIGHT);
right = val.intValue();
}
if (style.containsKey(StyleFormatConstants.PADDING_TOP)) {
Float val = (Float) style.get(StyleFormatConstants.PADDING_TOP);
top = val.intValue();
}
if (style.containsKey(StyleFormatConstants.PADDING_BOTTOM)) {
Float val = (Float) style.get(StyleFormatConstants.PADDING_BOTTOM);
bottom = val.intValue();
}
TcPr tableCellProperties = tableCell.getTcPr();
if (tableCellProperties == null) {
tableCellProperties = new TcPr();
tableCell.setTcPr(tableCellProperties);
}
TcMar margins = new TcMar();
if (bottom > 0) {
TblWidth bW = new TblWidth();
bW.setType("dxa");
bW.setW(BigInteger.valueOf(pixelsToDxa(bottom)));
margins.setBottom(bW);
}
if (top > 0) {
TblWidth tW = new TblWidth();
tW.setType("dxa");
tW.setW(BigInteger.valueOf(pixelsToDxa(top)));
margins.setTop(tW);
}
if (left > 0) {
TblWidth lW = new TblWidth();
lW.setType("dxa");
lW.setW(BigInteger.valueOf(pixelsToDxa(left)));
margins.setLeft(lW);
}
if (right > 0) {
TblWidth rW = new TblWidth();
rW.setType("dxa");
rW.setW(BigInteger.valueOf(pixelsToDxa(right)));
margins.setRight(rW);
}
tableCellProperties.setTcMar(margins);
}
private void setVerticalAlignment(Tc tableCell, Map<String, Object> style) {
if (style.containsKey(StyleFormatConstants.HORIZONTAL_ALIGN_KEY)) {
if (StyleFormatConstants.VERTICAL_ALIGN_TOP.equals(style.get(StyleFormatConstants.VERTICAL_ALIGN_KEY))) {
setVerticalAlignment(tableCell, STVerticalJc.TOP);
}
if (StyleFormatConstants.VERTICAL_ALIGN_MIDDLE.equals(style.get(StyleFormatConstants.VERTICAL_ALIGN_KEY))) {
setVerticalAlignment(tableCell, STVerticalJc.CENTER);
}
if (StyleFormatConstants.VERTICAL_ALIGN_BOTTOM.equals(style.get(StyleFormatConstants.VERTICAL_ALIGN_KEY))) {
setVerticalAlignment(tableCell, STVerticalJc.BOTTOM);
}
}
}
private void setVerticalAlignment(Tc tableCell, STVerticalJc align) {
if (align != null) {
TcPr tableCellProperties = tableCell.getTcPr();
if (tableCellProperties == null) {
tableCellProperties = new TcPr();
tableCell.setTcPr(tableCellProperties);
}
CTVerticalJc valign = new CTVerticalJc();
valign.setVal(align);
tableCellProperties.setVAlign(valign);
}
}
private void setFontSize(RPr runProperties, String fontSize) {
if (fontSize != null && !fontSize.isEmpty()) {
HpsMeasure size = new HpsMeasure();
size.setVal(new BigInteger(fontSize));
runProperties.setSz(size);
runProperties.setSzCs(size);
}
}
private void setFontFamily(RPr runProperties, String fontFamily) {
if (fontFamily != null) {
RFonts rf = runProperties.getRFonts();
if (rf == null) {
rf = new RFonts();
runProperties.setRFonts(rf);
}
rf.setAscii(fontFamily);
}
}
private void setFontColor(RPr runProperties, String color) {
if (color != null) {
org.docx4j.wml.Color c = new org.docx4j.wml.Color();
c.setVal(color);
runProperties.setColor(c);
}
}
private void setHorizontalAlignment(P paragraph, Map<String, Object> style) {
if (style.containsKey(StyleFormatConstants.HORIZONTAL_ALIGN_KEY)) {
if (StyleFormatConstants.HORIZONTAL_ALIGN_LEFT.equals(style.get(StyleFormatConstants.HORIZONTAL_ALIGN_KEY))) {
setHorizontalAlignment(paragraph, JcEnumeration.LEFT);
}
if (StyleFormatConstants.HORIZONTAL_ALIGN_RIGHT.equals(style.get(StyleFormatConstants.HORIZONTAL_ALIGN_KEY))) {
setHorizontalAlignment(paragraph, JcEnumeration.RIGHT);
}
if (StyleFormatConstants.HORIZONTAL_ALIGN_CENTER.equals(style.get(StyleFormatConstants.HORIZONTAL_ALIGN_KEY))) {
setHorizontalAlignment(paragraph, JcEnumeration.CENTER);
}
}
}
private void setHorizontalAlignment(P paragraph, JcEnumeration hAlign) {
if (hAlign != null) {
PPr pprop = paragraph.getPPr();
if (pprop == null) {
pprop = new PPr();
paragraph.setPPr(pprop);
}
Jc align = new Jc();
align.setVal(hAlign);
pprop.setJc(align);
paragraph.setPPr(pprop);
}
}
private void addBoldStyle(RPr runProperties) {
BooleanDefaultTrue b = new BooleanDefaultTrue();
b.setVal(true);
runProperties.setB(b);
}
private void addItalicStyle(RPr runProperties) {
BooleanDefaultTrue b = new BooleanDefaultTrue();
b.setVal(true);
runProperties.setI(b);
}
private void addUnderlineStyle(RPr runProperties) {
U val = new U();
val.setVal(UnderlineEnumeration.SINGLE);
runProperties.setU(val);
}
public P newImage(WordprocessingMLPackage wordMLPackage, byte[] bytes, String filenameHint, String altText, int id1, int id2, long cx) throws Exception {
BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, bytes);
Inline inline = imagePart.createImageInline(filenameHint, altText, id1, id2, cx, false);
// Now add the inline in w:p/w:r/w:drawing
ObjectFactory factory = Context.getWmlObjectFactory();
P p = createParagraph();
R run = factory.createR();
p.getContent().add(run);
Drawing drawing = factory.createDrawing();
run.getContent().add(drawing);
drawing.getAnchorOrInline().add(inline);
return p;
}
public org.docx4j.wml.P.Hyperlink newHyperlink(MainDocumentPart mdp, String text, String url) {
try {
// We need to add a relationship to word/_rels/document.xml.rels but since its external, we don't use
// the usual wordMLPackage.getMainDocumentPart().addTargetPart mechanism
org.docx4j.relationships.ObjectFactory factory = new org.docx4j.relationships.ObjectFactory();
org.docx4j.relationships.Relationship rel = factory.createRelationship();
rel.setType(Namespaces.HYPERLINK);
rel.setTarget(url);
rel.setTargetMode("External");
mdp.getRelationshipsPart().addRelationship(rel);
// addRelationship sets the rel's @Id
org.docx4j.wml.P.Hyperlink hyp = new org.docx4j.wml.P.Hyperlink();
hyp.setId(rel.getId());
R run = Context.getWmlObjectFactory().createR();
hyp.getContent().add(run);
RPr rpr = new RPr();
RStyle rStyle = new RStyle();
rStyle.setVal("Hyperlink");
rpr.setRStyle(rStyle);
run.setRPr(rpr);
Text t = new Text();
t.setValue(text);
run.getContent().add(t);
// String hpl = "<w:hyperlink r:id=\"" + rel.getId()
// + "\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" "
// + "xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" >" + "<w:r>" + "<w:rPr>"
// + "<w:rStyle w:val=\"Hyperlink\" />" +
// "</w:rPr>" + "<w:t>" + text + "</w:t>" + "</w:r>" + "</w:hyperlink>";
// return (org.docx4j.wml.P.Hyperlink) XmlUtils.unmarshalString(hpl);
return hyp;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private int pixelsToDxa(int pixels) {
return ( 1440 * pixels / getDPI() );
}
// create paraghraph with no space after
private P createParagraph() {
return createParagraph(null);
}
private P createParagraph(BandElement be) {
P paragraph = factory.createP();
PPr pPr = factory.createPPr();
Spacing spacing = new Spacing();
if ((be!= null) && be.isWrapText() && (be.getPercentLineSpacing() > 100)) {
spacing.setLine( BigInteger.valueOf( (be.getFont().getSize() * be.getPercentLineSpacing())/2) );
}
spacing.setAfter(BigInteger.ZERO);
pPr.setSpacing(spacing);
paragraph.setPPr(pPr);
return paragraph;
}
private Hdr getHdr(WordprocessingMLPackage wordprocessingMLPackage, Part sourcePart, Tbl table) throws Exception {
Hdr hdr = factory.createHdr();
if (hasPageNoHeader) {
hdr.getContent().add(createPageNumParagraph());
} else {
hdr.getContent().add(table);
}
return hdr;
}
private void createHeaderReference(WordprocessingMLPackage wordprocessingMLPackage, Relationship relationship)
throws InvalidFormatException {
List<SectionWrapper> sections = wordprocessingMLPackage.getDocumentModel().getSections();
SectPr sectPr = sections.get(sections.size() - 1).getSectPr();
// There is always a section wrapper, but it might not contain a sectPr
if (sectPr == null) {
sectPr = factory.createSectPr();
wordprocessingMLPackage.getMainDocumentPart().addObject(sectPr);
sections.get(sections.size() - 1).setSectPr(sectPr);
}
HeaderReference headerReference = factory.createHeaderReference();
headerReference.setId(relationship.getId());
headerReference.setType(HdrFtrRef.DEFAULT);
sectPr.getEGHdrFtrReferences().add(headerReference);
}
private Relationship createHeaderPart(WordprocessingMLPackage wordprocessingMLPackage, Tbl table) throws Exception {
HeaderPart headerPart = new HeaderPart();
Relationship rel = wordprocessingMLPackage.getMainDocumentPart().addTargetPart(headerPart);
// After addTargetPart, so image can be added properly
headerPart.setJaxbElement(getHdr(wordprocessingMLPackage, headerPart, table));
return rel;
}
private Ftr getFtr(WordprocessingMLPackage wordprocessingMLPackage, Part sourcePart, Tbl table) throws Exception {
Ftr ftr = factory.createFtr();
if (hasPageNoFooter) {
ftr.getContent().add(createPageNumParagraph());
} else {
ftr.getContent().add(table);
}
return ftr;
}
private void createFooterReference(WordprocessingMLPackage wordprocessingMLPackage, Relationship relationship)
throws InvalidFormatException {
List<SectionWrapper> sections = wordprocessingMLPackage.getDocumentModel().getSections();
SectPr sectPr = sections.get(sections.size() - 1).getSectPr();
// There is always a section wrapper, but it might not contain a sectPr
if (sectPr == null) {
sectPr = factory.createSectPr();
wordprocessingMLPackage.getMainDocumentPart().addObject(sectPr);
sections.get(sections.size() - 1).setSectPr(sectPr);
}
FooterReference footerReference = factory.createFooterReference();
footerReference.setId(relationship.getId());
footerReference.setType(HdrFtrRef.DEFAULT);
sectPr.getEGHdrFtrReferences().add(footerReference);
}
private Relationship createFooterPart(WordprocessingMLPackage wordprocessingMLPackage, Tbl table) throws Exception {
FooterPart footerPart = new FooterPart();
Relationship rel = wordprocessingMLPackage.getMainDocumentPart().addTargetPart(footerPart);
// After addTargetPart, so image can be added properly
footerPart.setJaxbElement(getFtr(wordprocessingMLPackage, footerPart, table));
return rel;
}
private void addPageHeaderFooter() throws Exception {
// Delete the Styles part, since it clutters up our output
// MainDocumentPart mdp = wordMLPackage.getMainDocumentPart();
// Relationship styleRel = mdp.getStyleDefinitionsPart().getSourceRelationships().get(0);
// mdp.getRelationshipsPart().removeRelationship(styleRel);
tableHeader = createTable(PRINT_PAGE_HEADER);
if (tableHeader != null) {
tableRow = factory.createTr();
printPageHeaderBand();
tableHeader.getContent().add(tableRow);
Relationship headerRel = createHeaderPart(wordMLPackage, tableHeader);
createHeaderReference(wordMLPackage, headerRel);
}
tableFooter = createTable(PRINT_PAGE_FOOTER);
if (tableFooter != null) {
tableRow = factory.createTr();
printPageFooterBand();
tableFooter.getContent().add(tableRow);
Relationship footerRel = createFooterPart(wordMLPackage, tableFooter);
createFooterReference(wordMLPackage, footerRel);
}
}
private void addBackgroundImage() throws Exception {
String image = bean.getReportLayout().getBackgroundImage();
if (image != null) {
byte[] imageBytes = getImage(image);
MainDocumentPart mdp = wordMLPackage.getMainDocumentPart();
BinaryPartAbstractImage imagePartBG = BinaryPartAbstractImage.createImagePart(wordMLPackage, imageBytes);
mdp.getContents().setBackground(createBackground(imagePartBG.getRelLast().getId()));
}
}
private CTBackground createBackground(String rId) {
org.docx4j.wml.ObjectFactory wmlObjectFactory = new org.docx4j.wml.ObjectFactory();
CTBackground background = wmlObjectFactory.createCTBackground();
background.setColor("FFFFFF");
org.docx4j.vml.ObjectFactory vmlObjectFactory = new org.docx4j.vml.ObjectFactory();
// Create object for background (wrapped in JAXBElement)
org.docx4j.vml.CTBackground background2 = vmlObjectFactory.createCTBackground();
JAXBElement<org.docx4j.vml.CTBackground> backgroundWrapped = vmlObjectFactory.createBackground(background2);
background.getAnyAndAny().add(backgroundWrapped);
background2.setTargetscreensize("1024,768");
background2.setVmlId("_x0000_s1025");
background2.setBwmode(org.docx4j.vml.officedrawing.STBWMode.WHITE);
// Create object for fill
CTFill fill = vmlObjectFactory.createCTFill();
background2.setFill(fill);
fill.setTitle("Alien 1");
fill.setId(rId);
fill.setType(org.docx4j.vml.STFillType.FRAME);
fill.setRecolor(org.docx4j.vml.STTrueFalse.T);
return background;
}
private P createPageNumParagraph() {
CTSimpleField pgnum = factory.createCTSimpleField();
pgnum.setInstr(" PAGE \\* MERGEFORMAT ");
RPr RPr = factory.createRPr();
RPr.setNoProof(new BooleanDefaultTrue());
PPr ppr = factory.createPPr();
Jc jc = factory.createJc();
jc.setVal(JcEnumeration.CENTER);
ppr.setJc(jc);
PPrBase.Spacing pprbase = factory.createPPrBaseSpacing();
pprbase.setBefore(BigInteger.valueOf(240));
pprbase.setAfter(BigInteger.valueOf(0));
ppr.setSpacing(pprbase);
R run = factory.createR();
run.getContent().add(RPr);
pgnum.getContent().add(run);
JAXBElement<CTSimpleField> fldSimple = factory.createPFldSimple(pgnum);
P para = createParagraph();
para.getContent().add(fldSimple);
para.setPPr(ppr);
return para;
}
public Tbl getTable() {
return table;
}
}