All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.odftoolkit.odfdom.converter.internal.xhtml.ElementVisitorForXHTML Maven / Gradle / Ivy

/**
 * Copyright (C) 2011-2012 The XDocReport Team 
 *
 * All rights reserved.
 *
 * Permission is hereby granted, free  of charge, to any person obtaining
 * a  copy  of this  software  and  associated  documentation files  (the
 * "Software"), to  deal in  the Software without  restriction, including
 * without limitation  the rights to  use, copy, modify,  merge, publish,
 * distribute,  sublicense, and/or sell  copies of  the Software,  and to
 * permit persons to whom the Software  is furnished to do so, subject to
 * the following conditions:
 *
 * The  above  copyright  notice  and  this permission  notice  shall  be
 * included in all copies or substantial portions of the Software.
 *
 * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
 * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
 * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package org.odftoolkit.odfdom.converter.internal.xhtml;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.odftoolkit.odfdom.converter.core.ElementVisitorConverter;
import org.odftoolkit.odfdom.converter.core.IURIResolver;
import org.odftoolkit.odfdom.converter.core.utils.ODFUtils;
import org.odftoolkit.odfdom.converter.core.utils.StringUtils;
import org.odftoolkit.odfdom.converter.xhtml.XHTMLOptions;
import org.odftoolkit.odfdom.doc.OdfDocument;
import org.odftoolkit.odfdom.dom.element.OdfStylableElement;
import org.odftoolkit.odfdom.dom.element.draw.DrawFrameElement;
import org.odftoolkit.odfdom.dom.element.draw.DrawImageElement;
import org.odftoolkit.odfdom.dom.element.office.OfficeMasterStylesElement;
import org.odftoolkit.odfdom.dom.element.office.OfficeTextElement;
import org.odftoolkit.odfdom.dom.element.style.StyleFooterElement;
import org.odftoolkit.odfdom.dom.element.style.StyleHeaderElement;
import org.odftoolkit.odfdom.dom.element.style.StyleMasterPageElement;
import org.odftoolkit.odfdom.dom.element.style.StyleTableColumnPropertiesElement;
import org.odftoolkit.odfdom.dom.element.table.TableTableCellElement;
import org.odftoolkit.odfdom.dom.element.table.TableTableColumnElement;
import org.odftoolkit.odfdom.dom.element.table.TableTableElement;
import org.odftoolkit.odfdom.dom.element.table.TableTableRowElement;
import org.odftoolkit.odfdom.dom.element.text.TextAElement;
import org.odftoolkit.odfdom.dom.element.text.TextHElement;
import org.odftoolkit.odfdom.dom.element.text.TextLineBreakElement;
import org.odftoolkit.odfdom.dom.element.text.TextListElement;
import org.odftoolkit.odfdom.dom.element.text.TextListItemElement;
import org.odftoolkit.odfdom.dom.element.text.TextListLevelStyleElementBase;
import org.odftoolkit.odfdom.dom.element.text.TextListLevelStyleNumberElement;
import org.odftoolkit.odfdom.dom.element.text.TextPElement;
import org.odftoolkit.odfdom.dom.element.text.TextSpanElement;
import org.odftoolkit.odfdom.dom.style.OdfStyleFamily;
import org.odftoolkit.odfdom.incubator.doc.style.OdfStyle;
import org.odftoolkit.odfdom.incubator.doc.text.OdfTextListStyle;
import org.odftoolkit.odfdom.pkg.OdfElement;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

import fr.opensagres.xdocreport.xhtml.extension.StringEscapeUtils;
import fr.opensagres.xdocreport.xhtml.extension.XHTMLConstants;
import fr.opensagres.xdocreport.xhtml.extension.XHTMLPageContentBuffer;

public class ElementVisitorForXHTML
    extends ElementVisitorConverter
    implements XHTMLConstants
{

    private static final String _100 = "100%;";

    private static final String CHARACTER = "character";

    private static final String BLOCK = "block";

    private String masterPageLayoutName = null;

    private String currentMasterPageLayoutName = null;

    private final ODFXHTMLPage xhtml;

    private XHTMLPageContentBuffer currentXHTMLContent;

    public ElementVisitorForXHTML( ODFXHTMLPage xhtml, XHTMLOptions options, OdfDocument odfDocument, OutputStream out,
                                   Writer writer )
    {
        super( odfDocument, options != null ? options.getExtractor() : null, out, writer );
        this.xhtml = xhtml;
        this.currentXHTMLContent = null;
    }

    // ---------------------- visit root
    // styles.xml//office:document-styles/office:master-styles

    @Override
    public void visit( OfficeMasterStylesElement ele )
    {
        super.visit( ele );
    }

    // ---------------------- visit root
    // styles.xml//office:document-styles/office:master-styles/style:master-page

    /**
     * Generate XHTML page footer + header
     */
    @Override
    public void visit( StyleMasterPageElement ele )
    {
        currentMasterPageLayoutName = ele.getStylePageLayoutNameAttribute();
        if ( masterPageLayoutName == null )
        {
            masterPageLayoutName = currentMasterPageLayoutName;
            xhtml.getPageBeforeBody().setBodyClass( xhtml.getStyleEngine().getClassName( OdfStyleFamily.List.getName(),
                                                                                         masterPageLayoutName ) );
        }
        super.visit( ele );
    }

    // ---------------------- visit
    // styles.xml//office:document-styles/office:master-styles/style:master-page/style-header

    @Override
    public void visit( StyleHeaderElement ele )
    {
        currentXHTMLContent = xhtml.getPageBodyContentHeader();
        visitMasterPageHeaderFooter( ele,
                                     xhtml.getStyleEngine().getMasterPageHeaderStyleName( currentMasterPageLayoutName ) );
    }

    // ---------------------- visit
    // styles.xml//office:document-styles/office:master-styles/style:master-page/style-footer

    @Override
    public void visit( StyleFooterElement ele )
    {
        currentXHTMLContent = xhtml.getPageBodyContentFooter();
        visitMasterPageHeaderFooter( ele,
                                     xhtml.getStyleEngine().getMasterPageFooterStyleName( currentMasterPageLayoutName ) );
    }

    private void visitMasterPageHeaderFooter( OdfElement ele, String styleName )
    {
        String styleFamilyName = OdfStyleFamily.List.getName();
        visit( DIV_ELEMENT, ele, styleName, styleFamilyName );
    }

    // ---------------------- visit root //office-body/office-text

    @Override
    public void visit( OfficeTextElement ele )
    {
        currentXHTMLContent = xhtml.getPageBodyContentBody();
        // String styleName = masterPageLayoutName;
        // String styleFamilyName = OdfStyleFamily.List.getName();
        visit( DIV_ELEMENT, ele, null, null );
    }

    // ---------------------- visit //text:h

    @Override
    public void visit( TextHElement ele )
    {
        // Get level (Heading levels go only to 6 in XHTML)).
        int level = 1;
        Integer levelAsInteger = ele.getTextOutlineLevelAttribute();
        if ( levelAsInteger != null && levelAsInteger <= 6 )
        {
            level = levelAsInteger;
        }
        visit( H_ELEMENT + level, ele );
    }

    // ---------------------- visit //text:p

    @Override
    public void visit( TextPElement ele )
    {
        boolean addNbsp = ele.getFirstChild() == null;
        visit( P_ELEMENT, ele, addNbsp );
    }

    // ---------------------- visit //text:span

    @Override
    public void visit( TextSpanElement ele )
    {
        boolean addNbsp = ele.getFirstChild() == null;
        visit( SPAN_ELEMENT, ele, addNbsp );
    }

    // ---------------------- visit //text:a

    @Override
    public void visit( TextAElement ele )
    {
        String href = ele.getXlinkHrefAttribute();
        Collection attributes = new ArrayList();
        attributes.add( HREF_ATTR );
        attributes.add( href );
        visit( A_ELEMENT, ele, attributes.toArray( StringUtils.EMPTY_STRING_ARRAY ) );
    }

    // ---------------------- visit text:list

    @Override
    public void visit( TextListElement ele )
    {
        int level = 1;
        boolean numberedList = false;
        String styleName = ele.getTextStyleNameAttribute();
        if ( StringUtils.isNotEmpty( styleName ) )
        {
            try
            {
                OdfTextListStyle listStyle = odfDocument.getContentDom().getAutomaticStyles().getListStyle( styleName );
                if ( listStyle != null )
                {
                    TextListLevelStyleElementBase levelListStyle = listStyle.getLevel( level );
                    numberedList =
                        ( levelListStyle != null && TextListLevelStyleNumberElement.ELEMENT_NAME.equals( levelListStyle.getOdfName() ) );
                }

            }
            catch ( Exception e )
            {
                // Do nothing
            }
        }

        String elementName = numberedList ? OL_ELEMENT : UL_ELEMENT;
        startVisit( elementName, ele );
        // String styleName = null;
        // String styleFamilyName = "";
        // currentXHTMLContent.getStyleEngine().applyStyles(styleName,
        // styleFamilyName,
        // xhtml);
        endVisit( elementName, ele );
    }

    // ---------------------- visit text:listitem

    @Override
    public void visit( TextListItemElement ele )
    {
        visit( LI_ELEMENT, ele, null, null );
    }

    // ---------------------- visit table:table (ex : )

    private List columnsWidth;

    @Override
    public void visit( TableTableElement ele )
    {
        try
        {
            columnsWidth = ODFUtils.getColumnWidthsAsString( ele, odfDocument );
            visit( TABLE_ELEMENT, ele );
        }
        finally
        {
            if ( columnsWidth != null )
            {
                columnsWidth = null;
            }
        }
    }

    // ---------------------- visit table:table-column

    @Override
    public void visit( TableTableColumnElement ele )
    {
        String[] attributes = null;
        OdfStyle style = ele.getAutomaticStyle();
        if ( style != null )
        {
            Node node = null;
            NodeList nodes = style.getChildNodes();
            for ( int i = 0; i < nodes.getLength(); i++ )
            {
                node = nodes.item( i );
                if ( StyleTableColumnPropertiesElement.ELEMENT_NAME.getLocalName().equals( node.getLocalName() ) )
                {
                    StyleTableColumnPropertiesElement columnPropertiesElement =
                        (StyleTableColumnPropertiesElement) node;

                    // width
                    String width = columnPropertiesElement.getStyleRelColumnWidthAttribute();
                    if ( StringUtils.isEmpty( width ) )
                    {
                        width = columnPropertiesElement.getStyleColumnWidthAttribute();
                    }
                    if ( StringUtils.isNotEmpty( width ) )
                    {
                        attributes = new String[2];
                        attributes[0] = WIDTH_ATTR;
                        attributes[1] = ODFUtils.getDimensionAsPixel( width );
                    }
                    break;
                }
            }
        }

        Integer numberColumnsRepeated = ele.getTableNumberColumnsRepeatedAttribute();
        if ( numberColumnsRepeated == null )
        {
            numberColumnsRepeated = 1;
        }
        for ( int i = 0; i < numberColumnsRepeated; i++ )
        {
            startVisit( COL_ELEMENT, ele, attributes );
            endVisit( COL_ELEMENT, ele );
        }
    }

    // ---------------------- visit table:table-row

    private int cellIndex = -1;

    @Override
    public void visit( TableTableRowElement ele )
    {
        try
        {
            cellIndex = -1;
            visit( TR_ELEMENT, ele );
        }
        finally
        {
            if ( cellIndex != -1 )
            {
                cellIndex = -1;
            }
        }
    }

    // ---------------------- visit table:table-cell

    @Override
    public void visit( TableTableCellElement ele )
    {

        Collection attributes = new ArrayList();

        // table:number-columns-spanned
        Integer colSpan = ele.getTableNumberColumnsSpannedAttribute();
        if ( colSpan != null && colSpan != 1 )
        {
            attributes.add( COLSPAN_ATTR );
            attributes.add( String.valueOf( colSpan ) );
        }

        // table:number-rows-spanned
        Integer rowSpan = ele.getTableNumberRowsSpannedAttribute();
        if ( rowSpan != null && rowSpan != 1 )
        {
            attributes.add( ROWSPAN_ATTR );
            attributes.add( String.valueOf( rowSpan ) );
        }

        // // compute width
        // cellIndex++;
        // String width = null;
        // if (columnsWidth != null && columnsWidth.size() > cellIndex) {
        // String columnWidth = columnsWidth.get(cellIndex);
        // // if (colSpan != null) {
        // // columnWidth = columnWidth * colSpan;
        // // }
        // attributes.add(WIDTH_ATTR);
        // attributes.add(String.valueOf(columnWidth));
        // }

        visit( TD_ELEMENT, ele, attributes.toArray( StringUtils.EMPTY_STRING_ARRAY ) );
    }

    // ---------------------- visit draw:frame

    @Override
    public void visit( DrawFrameElement ele )
    {
        // ex : 
        Collection attributes = new ArrayList();

        // draw:name
        String name = ele.getDrawNameAttribute();
        if ( !StringUtils.isEmpty( name ) )
        {
            attributes.add( NAME_ATTR );
            attributes.add( name );
        }

        StringBuilder htmlStyle = new StringBuilder();
        // svg:x
        String x = ele.getSvgXAttribute();
        if ( !StringUtils.isEmpty( x ) )
        {
            htmlStyle.append( "left:" );
            htmlStyle.append( x );
            htmlStyle.append( ';' );
        }

        // svg:y
        String y = ele.getSvgYAttribute();
        if ( !StringUtils.isEmpty( y ) )
        {
            htmlStyle.append( "top:" );
            htmlStyle.append( y );
            htmlStyle.append( ';' );
        }

        // svg:width
        String width = ele.getSvgWidthAttribute();
        if ( !StringUtils.isEmpty( width ) )
        {
            htmlStyle.append( "width:" );
            htmlStyle.append( width );
            htmlStyle.append( ';' );
        }

        // svg:height
        String height = ele.getSvgHeightAttribute();
        if ( !StringUtils.isEmpty( height ) )
        {
            htmlStyle.append( "height:" );
            htmlStyle.append( height );
            htmlStyle.append( ';' );
        }

        // draw:z-index
        Integer zIndex = ele.getDrawZIndexAttribute();
        if ( zIndex != null )
        {
            htmlStyle.append( "z-index:" );
            htmlStyle.append( String.valueOf( zIndex ) );
            htmlStyle.append( ';' );
        }
        if ( htmlStyle.length() > 0 )
        {
            attributes.add( STYLE_ATTR );
            attributes.add( htmlStyle.toString() );
        }

        visit( DIV_ELEMENT, ele, attributes.toArray( StringUtils.EMPTY_STRING_ARRAY ) );
    }

    // ---------------------- visit draw:image

    @Override
    protected void visitImage( DrawImageElement ele, String href, byte[] imageStream )
    {
        Collection attributes = new ArrayList();

        // src
        String src = ele.getXlinkHrefAttribute();
        IURIResolver uriResolver = xhtml.getStyleEngine().getURIResolver();
        src = uriResolver.resolve( src );
        attributes.add( SRC_ATTR );
        attributes.add( src );

        // other attributes
        Node parentNode = ele.getParentNode();
        if ( parentNode instanceof DrawFrameElement )
        {
            DrawFrameElement frameElement = (DrawFrameElement) parentNode;

            attributes.add( STYLE_ATTR );
            StringBuilder styleAttr = new StringBuilder();

            // width
            styleAttr.append( WIDTH_ATTR );
            styleAttr.append( ':' );
            styleAttr.append( _100 );

            // height
            styleAttr.append( HEIGHT_ATTR );
            styleAttr.append( ':' );
            styleAttr.append( _100 );

            String anchorType = frameElement.getTextAnchorTypeAttribute();
            if ( !CHARACTER.equals( anchorType ) )
            {
                styleAttr.append( DISPLAY_ATTR );
                styleAttr.append( ':' );
                styleAttr.append( BLOCK );
            }
            attributes.add( styleAttr.toString() );
        }

        visit( IMG_ELEMENT, ele, null, null, attributes.toArray( StringUtils.EMPTY_STRING_ARRAY ) );
    }

    // ---------------------- visit text:line-break

    @Override
    public void visit( TextLineBreakElement ele )
    {
        currentXHTMLContent.startEndElement( BR_ELEMENT );
    }

    private void visit( String elementName, OdfStylableElement ele, String... attributes )
    {
        visit( elementName, ele, false, attributes );
    }

    private void visit( String elementName, OdfStylableElement ele, boolean addNbsp, String... attributes )
    {
        String styleName = ele.getStyleName();
        String styleFamily = ele.getStyleFamily() != null ? ele.getStyleFamily().getName() : null;
        visit( elementName, ele, addNbsp, styleName, styleFamily, attributes );
    }

    private void visit( String elementName, OdfElement ele, String styleName, String styleFamily, String... attributes )
    {
        visit( elementName, ele, false, styleName, styleFamily, attributes );
    }

    private void visit( String elementName, OdfElement ele, boolean addNbsp, String styleName, String styleFamily,
                        String... attributes )
    {
        startVisit( elementName, ele, attributes );
        xhtml.getStyleEngine().applyStyles( styleFamily, styleName, currentXHTMLContent );
        endVisit( elementName, ele, addNbsp );
    }

    private void startVisit( String elementName, OdfElement element, String... attributes )
    {
        currentXHTMLContent.startElementNotEnclosed( elementName );
        if ( attributes != null )
        {
            String value = null;
            String name = null;
            for ( int i = 0; i < attributes.length; i++ )
            {
                String attr = attributes[i];
                if ( i % 2 == 0 )
                {
                    // Attribute name
                    name = attr;
                }
                else
                {
                    // Attribute value
                    value = attr;
                    currentXHTMLContent.setAttribute( name, value );
                    name = null;
                    value = null;
                }
            }
        }
    }

    private void endVisit( String elementName, OdfElement element )
    {
        endVisit( elementName, element, false );
    }

    private void endVisit( String elementName, OdfElement element, boolean addNbsp )
    {
        currentXHTMLContent.endElementNotEnclosed();
        super.visit( element );
        if ( addNbsp )
        {
            currentXHTMLContent.setText( " " );
        }
        currentXHTMLContent.endElement( elementName );
    }

    @Override
    public void save()
        throws IOException
    {
        if ( writer != null )
        {
            xhtml.save( writer );
        }
        else
        {
            xhtml.save( out );
        }
        super.save();
    }

    @Override
    protected void processTextNode( Text node )
    {
        String content = node.getTextContent();
        if ( StringUtils.isNotEmpty( content ) )
        {
            // Escape with HTML characters
            currentXHTMLContent.setText( StringEscapeUtils.escapeHtml( content ) );
        }
        else
        {
            currentXHTMLContent.setText( " " );
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy