/************************************************************************ * * 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-2008 by Henrik Just * * All Rights Reserved. * * Version 1.0 (2008-11-23) * */ package writer2latex.latex; import org.w3c.dom.Element; import writer2latex.util.*; import writer2latex.office.*; import writer2latex.latex.util.BeforeAfter; import writer2latex.latex.util.Context; /**
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:
*Constructs a new TableConverter
.
Process a table (table:table or table:sub-table tag)
* @param node The element containing the table * @param ldp theLaTeXDocumentPortion
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 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);
// Convert table
if (formatter.isSupertabular()) {
handleSupertabular(ldp,ic);
}
else if (formatter.isLongtable()) {
handleLongtable(ldp,ic);
}
else if (config.floatTables() && !ic.isInFrame() && !table.isSubTable()) {
handleTableFloat(ldp,ic);
}
else {
handleTabular(ldp,ic);
}
// Insert any pending footnotes
palette.getNoteCv().flushFootnotes(ldp,oc);
}
private void handleSupertabular(LaTeXDocumentPortion ldp, Context oc) {
ldp.append(baTableAlign.getBefore());
// Caption
if (caption!=null) {
handleCaption(bCaptionAbove ? "\\topcaption" : "\\bottomcaption",
ldp,oc);
}
// Table head
ldp.append("\\tablehead{");
handleHeaderRows(ldp,oc);
ldp.append("}");
// The table
handleHyperTarget(ldp);
ldp.append(baTable.getBefore()).nl();
handleBodyRows(ldp,oc);
ldp.append(baTable.getAfter()).nl();
ldp.append(baTableAlign.getAfter());
}
private void handleLongtable(LaTeXDocumentPortion ldp, Context oc) {
handleHyperTarget(ldp);
ldp.append(baTable.getBefore()).nl();
// Caption above
if (caption!=null && bCaptionAbove) {
handleCaption("\\caption",ldp,oc);
ldp.append("\\\\").nl();
handleHeaderRows(ldp,oc);
ldp.nl().append("\\endfirsthead").nl();
}
// Table head
if (table.getFirstBodyRow()>0) {
handleHeaderRows(ldp,oc);
ldp.nl().append("\\endhead").nl();
}
// Caption below
if (caption!=null && !bCaptionAbove) {
handleCaption("\\caption",ldp,oc);
ldp.append("\\endlastfoot").nl();
}
// Table body
handleBodyRows(ldp,oc);
ldp.append(baTable.getAfter()).nl();
}
private void handleTableFloat(LaTeXDocumentPortion ldp, Context oc) {
ldp.append("\\begin{table}");
if (config.getFloatOptions().length()>0) {
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();
handleHeaderRows(ldp,oc);
ldp.nl();
handleBodyRows(ldp,oc);
ldp.append(baTable.getAfter()).nl();
// Caption below
if (caption!=null && !bCaptionAbove) {
handleCaption("\\caption",ldp,oc);
}
ldp.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();
if (table.getFirstBodyRow()>0) {
handleHeaderRows(ldp,oc);
ldp.nl();
}
handleBodyRows(ldp,oc);
ldp.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 handleHeaderRows(LaTeXDocumentPortion ldp, Context oc) {
// Note: does *not* add newline after last row
if (table.getFirstBodyRow()>0) {
// Add interrow material before first row:
String sInter = formatter.getInterrowMaterial(0);
if (sInter.length()>0) {
ldp.append(sInter).nl();
}
// Add header rows
handleRows(0,table.getFirstBodyRow(),ldp,oc);
}
}
private void handleBodyRows(LaTeXDocumentPortion ldp, Context oc) {
if (table.getFirstBodyRow()==0) {
// No head, add interrow material before first row:
String sInter = formatter.getInterrowMaterial(0);
if (sInter.length()>0) {
ldp.append(sInter).nl();
}
}
// Add body rows
handleRows(table.getFirstBodyRow(),table.getRowCount(),ldp,oc);
ldp.nl();
}
private void handleRows(int nStart, int nEnd, LaTeXDocumentPortion ldp, Context oc) {
int nColCount = table.getColCount();
for (int nRow=nStart; nRow