/************************************************************************ * * TableConverter.java * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Copyright: 2002-2009 by Henrik Just * * All Rights Reserved. * * Version 1.2 (2009-08-23) * */ package writer2latex.latex; import org.w3c.dom.Element; import org.w3c.dom.Node; import writer2latex.util.*; import writer2latex.office.*; import writer2latex.latex.util.BeforeAfter; import writer2latex.latex.util.Context; enum RowType { FIRST_HEAD, HEAD, BODY, FOOT, LAST_FOOT; } /**

This class converts OpenDocument tables to LaTeX.

*

The following LaTeX packages are used; some of them are optional

*

array.sty, longtable.sty, supertabular.sty, tabulary.sty, hhline.sty, * colortbl.sty.

*

Options:

* * */ public class TableConverter extends ConverterHelper { private boolean bNeedLongtable = false; private boolean bNeedSupertabular = false; private boolean bNeedTabulary = false; private boolean bNeedColortbl = false; private boolean bContainsTables = false; /**

Constructs a new TableConverter.

*/ public TableConverter(OfficeReader ofr, LaTeXConfig config, ConverterPalette palette) { super(ofr,config,palette); } public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) { pack.append("\\usepackage{array}").nl(); // TODO: Make this optional if (bNeedLongtable) { pack.append("\\usepackage{longtable}").nl(); } if (bNeedSupertabular) { pack.append("\\usepackage{supertabular}").nl(); } if (bNeedTabulary) { pack.append("\\usepackage{tabulary}").nl(); } pack.append("\\usepackage{hhline}").nl(); // TODO: Make this optional if (bNeedColortbl) { pack.append("\\usepackage{colortbl}").nl(); } // Set padding for table cells (1mm is default in OOo!) // For vertical padding we can only specify a relative size if (bContainsTables) { decl.append("\\setlength\\tabcolsep{1mm}").nl(); decl.append("\\renewcommand\\arraystretch{1.3}").nl(); } } // Export a lonely table caption public void handleCaption(Element node, LaTeXDocumentPortion ldp, Context oc) { ldp.append("\\captionof{table}"); palette.getCaptionCv().handleCaptionBody(node,ldp,oc,true); } /**

Process a table (table:table or table:sub-table tag)

* @param node The element containing the table * @param ldp the LaTeXDocumentPortion to which * LaTeX code should be added * @param oc the current context */ public void handleTable(Element node, Element caption, boolean bCaptionAbove, LaTeXDocumentPortion ldp, Context oc) { // Export table, if allowed by the configuration switch (config.tableContent()) { case LaTeXConfig.ACCEPT: new SingleTableConverter().handleTable(node,caption,bCaptionAbove,ldp,oc); bContainsTables = true; break; case LaTeXConfig.IGNORE: // Ignore table silently break; case LaTeXConfig.WARNING: System.err.println("Warning: Tables are not allowed"); break; case LaTeXConfig.ERROR: ldp.append("% Error in document: A table was ignored"); } } // Inner class to convert a single table private class SingleTableConverter { private TableReader table; private TableFormatter formatter; private Element caption; private boolean bCaptionAbove; private BeforeAfter baTable; private BeforeAfter baTableAlign; private RowType[] rowTypes; // Return the paragraph style of the first paragraph/heading within this block text private String getFirstParStyle(Element node) { Node child = node.getFirstChild(); while (child!=null) { if (Misc.isElement(child, XMLString.TEXT_P) || Misc.isElement(child, XMLString.TEXT_H)) { String sStyleName = Misc.getAttribute(child, XMLString.TEXT_STYLE_NAME); if (sStyleName!=null) { StyleWithProperties style = ofr.getParStyle(sStyleName); if (style!=null) { if (style.isAutomatic()) { sStyleName = style.getParentName(); } return ofr.getParStyles().getDisplayName(sStyleName); } } return null; } else if (OfficeReader.isTextElement(child)) { return getFirstParStyle((Element)child); } child = child.getNextSibling(); } return null; } private boolean hasRowType(RowType test) { for (RowType type : rowTypes) { if (type==test) { return true; } } return false; } private void handleTable(Element node, Element caption, boolean bCaptionAbove, LaTeXDocumentPortion ldp, Context oc) { // Store the caption this.caption = caption; this.bCaptionAbove = bCaptionAbove; // Read the table table = ofr.getTableReader(node); // Get formatter and update flags according to formatter formatter = new TableFormatter(ofr,config,palette,table,!oc.isInMulticols(),oc.isInTable()); bContainsTables = true; bNeedLongtable |= formatter.isLongtable(); bNeedSupertabular |= formatter.isSupertabular(); bNeedTabulary |= formatter.isTabulary(); bNeedColortbl |= formatter.isColortbl(); // Update the context Context ic = (Context) oc.clone(); ic.setInTable(true); ic.setInSimpleTable(formatter.isSimple()); // Never allow footnotes in tables // (longtable.sty *does* allow footnotes in body, but not in head - // only consistent solution is to disallow all footnotes) ic.setNoFootnotes(true); // Get table declarations baTable = new BeforeAfter(); baTableAlign = new BeforeAfter(); formatter.applyTableStyle(baTable,baTableAlign,config.floatTables() && !ic.isInFrame() && !table.isSubTable()); // Identify the row types rowTypes = new RowType[table.getRowCount()]; for (int nRow=0; nRow0) { ldp.append("[").append(config.getFloatOptions()).append("]"); } ldp.nl(); ldp.append(baTableAlign.getBefore()); // Caption above if (caption!=null && bCaptionAbove) { handleCaption("\\caption",ldp,oc); } // The table handleHyperTarget(ldp); ldp.append(baTable.getBefore()).nl(); handleRows(ldp,oc,RowType.HEAD,true,true); ldp.nl(); handleRows(ldp,oc,RowType.BODY,!hasRowType(RowType.HEAD),true); ldp.append(baTable.getAfter()).nl(); // Caption below if (caption!=null && !bCaptionAbove) { handleCaption("\\caption",ldp,oc); } ldp.nl().append(baTableAlign.getAfter()); ldp.append("\\end{table}").nl(); } private void handleTabular(LaTeXDocumentPortion ldp, Context oc) { ldp.append(baTableAlign.getBefore()); // Caption above if (caption!=null && bCaptionAbove) { TableConverter.this.handleCaption(caption,ldp,oc); } // The table handleHyperTarget(ldp); ldp.append(baTable.getBefore()).nl(); handleRows(ldp,oc,RowType.HEAD,true,true); ldp.nl(); handleRows(ldp,oc,RowType.BODY,!hasRowType(RowType.HEAD),true); ldp.nl().append(baTable.getAfter()).nl(); // Caption below if (caption!=null && !bCaptionAbove) { TableConverter.this.handleCaption(caption,ldp,oc); } ldp.append(baTableAlign.getAfter()); } private void handleCaption(String sCommand, LaTeXDocumentPortion ldp, Context oc) { ldp.append(sCommand); palette.getCaptionCv().handleCaptionBody(caption,ldp,oc,false); } private void handleHyperTarget(LaTeXDocumentPortion ldp) { // We may need a hyperlink target if (!table.isSubTable()) { palette.getFieldCv().addTarget(table.getTableName(),"|table",ldp); } } private void handleRows(LaTeXDocumentPortion ldp, Context oc, RowType rowType, boolean bLineBefore, boolean bLineAfter) { int nRowCount = table.getRowCount(); int nColCount = table.getColCount(); boolean bFirst = true; int nPreviousRow = -1; for (int nRow=0; nRow-1) { ldp.append(formatter.getInterrowMaterial(nPreviousRow+1)).nl(); } nPreviousRow = nRow; // If it's the first row, add top interrow material if (bFirst && bLineBefore) { String sInter = formatter.getInterrowMaterial(nRow); if (sInter.length()>0) { ldp.append(sInter).nl(); } bFirst=false; } // Export columns in this row Context icRow = (Context) oc.clone(); BeforeAfter baRow = new BeforeAfter(); formatter.applyRowStyle(nRow,baRow,icRow); if (!baRow.isEmpty()) { ldp.append(baRow.getBefore()); if (!formatter.isSimple()) { ldp.nl(); } } int nCol = 0; while (nCol-1 && bLineAfter) { ldp.append(formatter.getInterrowMaterial(nPreviousRow+1)); } } } }