Package writer2latex.latex.content

Source Code of writer2latex.latex.content.BlockConverter

/************************************************************************
*
*  BlockConverter.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-2006 by Henrik Just
*
*  All Rights Reserved.
*
*  Version 0.4b (2006-11-03)
*
*/

package writer2latex.latex.content;

import org.w3c.dom.Node;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import writer2latex.util.Misc;
import writer2latex.util.Config;
import writer2latex.office.XMLString;
import writer2latex.office.TableGridModel;
import writer2latex.latex.Context;
import writer2latex.latex.LaTeXDocumentPortion;
import writer2latex.latex.HeadingMap;
import writer2latex.latex.ConverterHelper;
import writer2latex.latex.ConverterPalette;
import writer2latex.latex.style.BeforeAfter;
import writer2latex.latex.style.StyleMap;
import writer2latex.latex.style.TableFormatter;

/**
<p>This class handles basic block content, including the main text body,
*  sections, tables, lists, headings and paragraphs.</p>
*/
public class BlockConverter extends ConverterHelper {

    public BlockConverter(Config config, ConverterPalette palette) {
        super(config,palette);
    }

    /** <p> Traverse block text (eg. content of body, section, list item).
     * This is traversed in logical order and dedicated handlers take care of
     * each block element.</p>
     * <p> (Note: As a rule, all handling of block level elements should add a
     * newline to the LaTeX document at the end of the block)</p>
     * @param <code>node</code> The element containing the block text
     * @param <code>ldp</code> the <code>LaTeXDocumentPortion</code> to which
     * LaTeX code should be added
     * @param <code>oc</code> the current context
     */
    public void traverseBlockText(Element node, LaTeXDocumentPortion ldp, Context oc) {
        // The current paragraph block:
        StyleMap blockMap = config.getParBlockStyleMap();
        String sBlockName = null;

        if (node.hasChildNodes()) {
            NodeList list = node.getChildNodes();
            int nLen = list.getLength();
           
            for (int i = 0; i < nLen; i++) {
                Node childNode = list.item(i);
       
                if (childNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element child = (Element)childNode;
                    String sTagName = child.getTagName();

                    palette.getInfo().addDebugInfo(child,ldp);
               
                    // Start/End a paragraph block
                    if (sTagName.equals(XMLString.TEXT_P)) {
                        String sStyleName = child.getAttribute(XMLString.TEXT_STYLE_NAME);
                        if (sBlockName!=null && !blockMap.isNext(sBlockName,sStyleName)) {
                            // end current block
                            String sAfter = blockMap.getAfter(sBlockName);
                            if (sAfter.length()>0) ldp.append(sAfter).nl();
                            sBlockName = null;
                        }
                        if (sBlockName==null && blockMap.contains(sStyleName)) {
                            // start a new block
                            sBlockName = sStyleName;
                            String sBefore = blockMap.getBefore(sBlockName);
                            if (sBefore.length()>0) ldp.append(sBefore).nl();
                        }
                    }
                    else if (sBlockName!=null) {
                        // non-paragraph: end current block
                        String sAfter = blockMap.getAfter(sBlockName);
                        if (sAfter.length()>0) ldp.append(sAfter).nl();
                        sBlockName = null;
                    }
         

                    // Basic block content; handle by this class
                    if (sTagName.equals(XMLString.TEXT_P)) {
                        handleParagraph(child,ldp,oc,i==nLen-1);
                    }

                    else if(sTagName.equals(XMLString.TEXT_H)) {
                        handleHeading(child,ldp,oc);
                    }
                   
                    else if (sTagName.equals(XMLString.TEXT_UNORDERED_LIST)) {
                        handleList(child,ldp,oc,false);
                    }
                   
                    else if (sTagName.equals(XMLString.TEXT_ORDERED_LIST)) {
                        handleList(child,ldp,oc,true);
                    }
                    else if (sTagName.equals(XMLString.TABLE_TABLE)) {
                        handleTable(child,ldp,oc);
                    }

                    else if (sTagName.equals(XMLString.TABLE_SUB_TABLE)) {
                        handleTable(child,ldp,oc);
                    }

                    else if (sTagName.equals(XMLString.TEXT_SECTION)) {
                        handleSection(child,ldp,oc);
                    }

                    // Draw elements may appear in block context if they are
                    // anchored to page
                    else if (sTagName.startsWith("draw:")) {
                        palette.getDrawCv().handleDrawElement(child,ldp,oc);
                    }
         
                    // Indexes
                    else if (sTagName.equals(XMLString.TEXT_TABLE_OF_CONTENT)) {
                        palette.getIndexCv().handleTOC(child,ldp,oc);
                    }

                    else if (sTagName.equals(XMLString.TEXT_ILLUSTRATION_INDEX)) {
                        palette.getIndexCv().handleLOF(child,ldp,oc);
                    }

                    else if (sTagName.equals(XMLString.TEXT_TABLE_INDEX)) {
                        palette.getIndexCv().handleLOT(child,ldp,oc);
                    }

                    else if (sTagName.equals(XMLString.TEXT_OBJECT_INDEX)) {
                        palette.getIndexCv().handleObjectIndex(child,ldp,oc);
                    }

                    else if (sTagName.equals(XMLString.TEXT_USER_INDEX)) {
                        palette.getIndexCv().handleUserIndex(child,ldp,oc);
                    }

                    else if (sTagName.equals(XMLString.TEXT_ALPHABETICAL_INDEX)) {
                        palette.getIndexCv().handleAlphabeticalIndex(child,ldp,oc);
                    }

                    else if (sTagName.equals(XMLString.TEXT_BIBLIOGRAPHY)) {
                        palette.getIndexCv().handleBibliography(child,ldp,oc);
                    }

                    // Sequence declarations appear in the main text body
                    else if (sTagName.equals(XMLString.TEXT_SEQUENCE_DECLS)) {
                        //handleSeqeuenceDecls(child);
                    }
                    // other tags are ignored
                }
            }
        }

        if (sBlockName!=null) {
            // end current block
            String sAfter = blockMap.getAfter(sBlockName);
            if (sAfter.length()>0) ldp.append(sAfter).nl();
            sBlockName = null;
        }

    }

    /** <p> Process a section (text:section tag)</p>
     * @param <code>node</code> The element containing the section
     * @param <code>ldp</code> the <code>LaTeXDocumentPortion</code> to which
     * LaTeX code should be added
     * @param <code>oc</code> the current context
     */
    public void handleSection(Element node, LaTeXDocumentPortion ldp, Context oc) {
        // TODO: Support linked sections
   
        // We may need a hyperlink target
        palette.getFieldCv().addTarget(node,"|region",ldp);

        // Apply the style
        String sStyleName = node.getAttribute(XMLString.TEXT_STYLE_NAME);
        BeforeAfter ba = new BeforeAfter();
        Context ic = (Context) oc.clone();
        palette.getSectionSc().applySectionStyle(sStyleName,ba,ic);

        // Do conversion
        if (ba.getBefore().length()>0) { ldp.append(ba.getBefore()).nl(); }
        traverseBlockText(node,ldp,ic);
        if (ba.getAfter().length()>0) { ldp.append(ba.getAfter()).nl(); }
    }
 
    /** <p> Process a table (table:table or table:sub-table tag)</p>
     * @param <code>node</code> The element containing the table
     * @param <code>ldp</code> the <code>LaTeXDocumentPortion</code> to which
     * LaTeX code should be added
     * @param <code>oc</code> the current context
     */
    public void handleTable(Element node, LaTeXDocumentPortion ldp, Context oc) {
        // Get a grid model of the table
        TableGridModel table = new TableGridModel(node);
   
        // Update the context
        Context ic = (Context) oc.clone();
        ic.setInTable(true);
   
        // Apply table style
        boolean bApplyCellFormat = config.formatting()>=Config.CONVERT_MOST;
        TableFormatter formatter = palette.getTableSc().getTableFormatter(table,
            !ic.isInMulticols(), bApplyCellFormat);

        // We may need a hyperlink target
        if (!formatter.isSubtable()) {
            palette.getFieldCv().addTarget(node,"|table",ldp);
        }
   
        // Export table declaration
        BeforeAfter baTable = new BeforeAfter();
        formatter.applyTableStyle(baTable);
        ldp.append(baTable.getBefore()).nl();
   
        // Export rows
        if (bApplyCellFormat || !formatter.isLongtable()) { ic.setNoFootnotes(true); }
        int nRowCount = table.getRowCount();
        int nColCount = table.getColCount();
        boolean bInHeader = false;
        // Add interrow material before first row:
        ldp.append(formatter.getInterrowMaterial(0)).nl();
        for (int nRow=0; nRow<nRowCount; nRow++){
            // Longtables may have headers:
            if (formatter.isLongtable()) {
                if (nRow==0 && table.getRow(nRow).isHeader()) {
                    bInHeader = true;
                    if (!bApplyCellFormat) { ic.setNoFootnotes(true); }
                }
                else if (bInHeader && !table.getRow(nRow).isHeader()) {
                    bInHeader = false;
                    if (!bApplyCellFormat) { ic.setNoFootnotes(false); }
                    palette.getNoteCv().flushFootnotes(ldp,oc)
                    ldp.append("\\endhead").nl();
                }
            }
           
            // Export columns in this row
            int nCol = 0;
            while (nCol<nColCount) {
                Element cell = (Element) table.getCell(nRow,nCol);
                if (XMLString.TABLE_TABLE_CELL.equals(cell.getNodeName())) {
                    BeforeAfter baCell = new BeforeAfter();
                    formatter.applyCellStyle(nRow,nCol,baCell);
                    ldp.append(baCell.getBefore());
                    traverseBlockText(cell,ldp,ic);
                    ldp.append(baCell.getAfter());
                }
                // Otherwise ignore; the cell is covered by a \multicolumn entry.
                // (table:covered-table-cell)
                int nColSpan = Misc.getPosInteger(cell.getAttribute(
                                   XMLString.TABLE_NUMBER_COLUMNS_SPANNED),1);
                if (nCol+nColSpan<nColCount) { ldp.append("&").nl(); }
                nCol+=nColSpan;
            }
            ldp.append("\\\\").append(formatter.getInterrowMaterial(nRow+1)).nl();
        }

        // End table
        ldp.append(baTable.getAfter()).nl();
   
        // Footnotes are now allowed
        if (bApplyCellFormat || !formatter.isLongtable()) {
            palette.getNoteCv().flushFootnotes(ldp,oc);
        }
    }


    /** <p> Process a list (text:ordered-lst or text:unordered-list tag)</p>
     * @param <code>node</code> The element containing the list
     * @param <code>ldp</code> the <code>LaTeXDocumentPortion</code> to which
     * LaTeX code should be added
     * @param <code>oc</code> the current context
     * @param <code>bOrdered</code> true if this list is an ordered list
     */
    public void handleList(Element node, LaTeXDocumentPortion ldp, Context oc, boolean bOrdered) {
        // Set up new context
        Context ic = (Context) oc.clone();
        ic.incListLevel();

        // If the list contains headings, ignore it!       
        if (ic.isIgnoreLists() || listContainsHeadings(node)) {
            ic.setIgnoreLists(true);
            traverseList(node,ldp,ic);
            return;
        }

        // Get the style name, if we don't know it already
        if (ic.getListStyleName()==null) {
            ic.setListStyleName(node.getAttribute(XMLString.TEXT_STYLE_NAME));
        }

        // Apply the style
        BeforeAfter ba = new BeforeAfter();
        palette.getListSc().applyListStyle(ic.getListStyleName(),ic.getListLevel(),
            bOrdered,"true".equals(node.getAttribute(XMLString.TEXT_CONTINUE_NUMBERING)),
            ba);
     
        // Export the list
        if (ba.getBefore().length()>0) { ldp.append(ba.getBefore()).nl(); }
        traverseList(node,ldp,ic);
        if (ba.getAfter().length()>0) { ldp.append(ba.getAfter()).nl(); }
    }

    /*
     * Process the contents of a list
     */
    private void traverseList (Element node, LaTeXDocumentPortion ldp, Context oc) {
        if (node.hasChildNodes()) {
            NodeList list = node.getChildNodes();
            int nLen = list.getLength();
           
            for (int i = 0; i < nLen; i++) {
                Node child = list.item(i);
               
                if (child.getNodeType() == Node.ELEMENT_NODE) {
                    String nodeName = child.getNodeName();
         
                    palette.getInfo().addDebugInfo((Element)child,ldp);
                   
                    if (nodeName.equals(XMLString.TEXT_LIST_ITEM)) {
                        handleListItem((Element)child,ldp,oc);
                    }
                    if (nodeName.equals(XMLString.TEXT_LIST_HEADER)) {
                        handleListItem((Element)child,ldp,oc);
                    }
                }
            }
        }
    }
   
    private void handleListItem(Element node, LaTeXDocumentPortion ldp, Context oc) {
        // Are we ignoring this list?
        if (oc.isIgnoreLists()) {
            traverseBlockText(node,ldp,oc);
            return;
        }
       
        // Apply the style
        BeforeAfter ba = new BeforeAfter();
        palette.getListSc().applyListItemStyle(
            oc.getListStyleName(), oc.getListLevel(),
            node.getNodeName().equals(XMLString.TEXT_LIST_HEADER),
            "true".equals(node.getAttribute(XMLString.TEXT_RESTART_NUMBERING)),
            Misc.getPosInteger(node.getAttribute(XMLString.TEXT_START_VALUE),1)-1,
            ba);
     
        // export the list item
        if (ba.getBefore().length()>0) {
            ldp.append(ba.getBefore());
            if (config.formatting()>=Config.CONVERT_MOST) { ldp.nl(); }
        }
        traverseBlockText(node,ldp,oc);
        if (ba.getAfter().length()>0) { ldp.append(ba.getAfter()).nl(); }
    }

    /*
     * Helper: Check to see, if this list contains headings
     * (in that case we will ignore the list!) 
     */
    private boolean listContainsHeadings (Node node) {
        if (node.hasChildNodes()) {
            NodeList nList = node.getChildNodes();
            int len = nList.getLength();
            for (int i = 0; i < len; i++) {
                Node child = nList.item(i);
                if (child.getNodeType() == Node.ELEMENT_NODE) {
                    String nodeName = child.getNodeName();
                    if (nodeName.equals(XMLString.TEXT_LIST_ITEM)) {
                        if (listItemContainsHeadings(child)) return true;
                    }
                    if (nodeName.equals(XMLString.TEXT_LIST_HEADER)) {
                        if (listItemContainsHeadings(child)) return true;
                    }
                }
            }
        }
        return false;
    }
   
    private boolean listItemContainsHeadings(Node node) {
        if (node.hasChildNodes()) {
            NodeList nList = node.getChildNodes();
            int len = nList.getLength();
            for (int i = 0; i < len; i++) {
                Node child = nList.item(i);
                if (child.getNodeType() == Node.ELEMENT_NODE) {
                    String nodeName = child.getNodeName();
                    if(nodeName.equals(XMLString.TEXT_H)) {
                        return true;
                    }
                    if (nodeName.equals(XMLString.TEXT_ORDERED_LIST)) {
                        if (listContainsHeadings(child)) return true;
                    }
                    if (nodeName.equals(XMLString.TEXT_UNORDERED_LIST)) {
                        if (listContainsHeadings(child)) return true;
                    }
                }
            }
        }
        return false;
    }

    /** <p>Process a heading.</p>
     @param <code>node</code> The text:h element node containing the heading
     *  @param <code>ldp</code> The <code>LaTeXDocumentPortion</code> to add LaTeX code to
     *  @param <code>oc</code> The current context
     */
    public void handleHeading(Element node, LaTeXDocumentPortion ldp, Context oc) {
        // Get the level, the heading map and the style name
        int nLevel = Misc.getPosInteger(node.getAttribute(XMLString.TEXT_LEVEL),1);
        HeadingMap hm = config.getHeadingMap();
        String sStyleName = node.getAttribute(XMLString.TEXT_STYLE_NAME);

        if (nLevel<=hm.getMaxLevel()) {
            // Always push the font used
            palette.getI18n().pushSpecialTable(palette.getParSc().getFontName(sStyleName));

            // Apply style
            BeforeAfter baHardPage = new BeforeAfter();
            BeforeAfter baHardChar = new BeforeAfter();
            Context ic = (Context) oc.clone();
            // Footnotes with multiple paragraphs does not work in sections
            ic.setNoFootnotes(true);
            palette.getParSc().applyHardHeadingStyle(nLevel, sStyleName,
                baHardPage, baHardChar, ic);

            // Export the heading
            ldp.append(baHardPage.getBefore());
            ldp.append("\\"+hm.getName(nLevel));
            // If this heading contains formatting, add optional argument:
            if (baHardChar.getBefore().length()>0 || containsElements(node)) {
                ldp.append("[");
                palette.getInlineCv().traversePlainInlineText(node,ldp,ic);
                ldp.append("]");
            }
            ldp.append("{").append(baHardChar.getBefore());
            palette.getInlineCv().traverseInlineText(node,ldp,ic,false);
            ldp.append(baHardChar.getAfter()).append("}").nl();
            ldp.append(baHardPage.getAfter());
     
            // Flush pending footnotes
            palette.getNoteCv().flushFootnotes(ldp,oc);

            // Include any floating frames
            palette.getDrawCv().flushFloatingFrames(ldp,ic);

            // Pop the font name
            palette.getI18n().popSpecialTable();
        }
        else { // beyond supported headings - export as ordinary paragraph
            handleParagraph(node,ldp,oc,false);
        }
    }

    /* Check to see if this node contains any element nodes, except reference marks */
    private boolean containsElements(Node node) {
        if (!node.hasChildNodes()) { return false; }
        NodeList list = node.getChildNodes();
        int nLen = list.getLength();
        for (int i = 0; i < nLen; i++) {
            Node child = list.item(i);
            if (child.getNodeType()==Node.ELEMENT_NODE &&
                !child.getNodeName().startsWith(XMLString.TEXT_REFERENCE_MARK)) {
                return true;
            }
        }
        return false;
    }
 
    /**
     * <p> Process a text:p tag</p>
     @param <code>node</code> The text:h element node containing the heading
     *  @param <code>ldp</code> The <code>LaTeXDocumentPortion</code> to add LaTeX code to
     *  @param <code>oc</code> The current context
     *  @param <code>bLastInBlock</code> If this is true, the paragraph is the
     *  last one in a block, and we need no trailing blank line (eg. right before
     *  \end{enumerate}).
     */
    public void handleParagraph(Element node, LaTeXDocumentPortion ldp, Context oc, boolean bLastInBlock) {
        // Empty paragraphs are often used to achieve vertical spacing in WYSIWYG
        // word processors. Hence we translate an empty paragraph to \bigskip.
        // This also solves the problem that LaTeX ignores empty paragraphs, Writer doesn't.
        // In a well-structured document, an empty paragraph is probably a mistake,
        // hence the configuration can specify that it should be ignored.
        if (!node.hasChildNodes()) {
            if (!config.ignoreEmptyParagraphs()) {
                ldp.nl().append("\\bigskip").nl();
                if (!bLastInBlock) { ldp.nl(); }
            }
            return;
        }

        // Get the style name for this paragraph
        String sStyleName = node.getAttribute(XMLString.TEXT_STYLE_NAME);
   
        // Always push the font used
        palette.getI18n().pushSpecialTable(palette.getParSc().getFontName(sStyleName));

        // Apply the style
        BeforeAfter ba = new BeforeAfter();
        Context ic = (Context) oc.clone();
        palette.getParSc().applyParStyle(sStyleName,ba,ic);
   
        // Do conversion
        ldp.append(ba.getBefore());
        if (ic.isVerbatim()) {
            palette.getInlineCv().traverseVerbatimInlineText(node,ldp,ic,false);
        }
        else {
            palette.getInlineCv().traverseInlineText(node,ldp,ic,false);
        }
        ldp.append(ba.getAfter());
        // Add a blank line except within verbatim and last in a block:
        if (!bLastInBlock && !ic.isVerbatim()) { ldp.nl(); }
   
        // Flush any floating frames from this paragraph
        palette.getDrawCv().flushFloatingFrames(ldp,ic);

        // pop the font name
        palette.getI18n().popSpecialTable();
    }
  
}
TOP

Related Classes of writer2latex.latex.content.BlockConverter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.