Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
fr.opensagres.xdocreport.document.docx.textstyling.DocxDocumentHandler Maven / Gradle / Ivy
/**
* Copyright (C) 2011-2015 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 fr.opensagres.xdocreport.document.docx.textstyling;
import java.io.IOException;
import java.util.Stack;
import fr.opensagres.xdocreport.core.utils.StringUtils;
import fr.opensagres.xdocreport.document.docx.preprocessor.DefaultStyle;
import fr.opensagres.xdocreport.document.docx.preprocessor.sax.hyperlinks.HyperlinkRegistry;
import fr.opensagres.xdocreport.document.docx.preprocessor.sax.hyperlinks.HyperlinkUtils;
import fr.opensagres.xdocreport.document.docx.preprocessor.sax.numbering.NumberingRegistry;
import fr.opensagres.xdocreport.document.docx.template.DocxContextHelper;
import fr.opensagres.xdocreport.document.preprocessor.sax.BufferedElement;
import fr.opensagres.xdocreport.document.textstyling.AbstractDocumentHandler;
import fr.opensagres.xdocreport.document.textstyling.properties.ContainerProperties;
import fr.opensagres.xdocreport.document.textstyling.properties.HeaderProperties;
import fr.opensagres.xdocreport.document.textstyling.properties.ListItemProperties;
import fr.opensagres.xdocreport.document.textstyling.properties.ListProperties;
import fr.opensagres.xdocreport.document.textstyling.properties.ParagraphProperties;
import fr.opensagres.xdocreport.document.textstyling.properties.SpanProperties;
import fr.opensagres.xdocreport.document.textstyling.properties.TableCellProperties;
import fr.opensagres.xdocreport.document.textstyling.properties.TableProperties;
import fr.opensagres.xdocreport.document.textstyling.properties.TableRowProperties;
import fr.opensagres.xdocreport.document.textstyling.properties.TextAlignment;
import fr.opensagres.xdocreport.template.IContext;
/**
* Document handler implementation to build docx fragment content.
*/
public class DocxDocumentHandler
extends AbstractDocumentHandler
{
private boolean bolding;
private boolean italicsing;
private boolean underlining;
private boolean striking;
private boolean subscripting;
private boolean superscripting;
private Stack paragraphsStack;
private Stack spansStack;
private HyperlinkRegistry hyperlinkRegistry;
protected final IDocxStylesGenerator styleGen;
private final NumberingRegistry numberingRegistry;
private DefaultStyle defaultStyle;
private boolean insideHeader;
private boolean paragraphWasInserted;
private int currentNumId;
private boolean haspPr;
private int addLineBreak;
public DocxDocumentHandler( BufferedElement parent, IContext context, String entryName )
{
super( parent, context, entryName );
this.styleGen = DocxContextHelper.getStylesGenerator( context );
this.defaultStyle = DocxContextHelper.getDefaultStyle( context );
this.numberingRegistry = getNumberingRegistry( context );
this.insideHeader = false;
this.paragraphWasInserted = false;
}
public void startDocument()
{
this.bolding = false;
this.italicsing = false;
this.underlining = false;
this.striking = false;
this.subscripting = false;
this.superscripting = false;
this.paragraphsStack = new Stack();
this.spansStack = new Stack();
this.addLineBreak = 0;
}
public void endDocument()
throws IOException
{
endParagraphIfNeeded();
this.spansStack.clear();
}
private void endParagraphIfNeeded()
throws IOException
{
if ( !paragraphsStack.isEmpty() )
{
paragraphsStack.size();
for ( int i = 0; i < paragraphsStack.size(); i++ )
{
endParagraph();
}
paragraphsStack.clear();
}
}
private void closeCurrentParagraph()
throws IOException
{
if ( !paragraphsStack.isEmpty() )
{
endParagraph();
}
}
public void startBold()
{
this.bolding = true;
}
public void endBold()
{
this.bolding = false;
}
public void startItalics()
{
this.italicsing = true;
}
public void endItalics()
{
this.italicsing = false;
}
public void startUnderline()
throws IOException
{
this.underlining = true;
}
public void endUnderline()
throws IOException
{
this.underlining = false;
}
public void startStrike()
throws IOException
{
this.striking = true;
}
public void endStrike()
throws IOException
{
this.striking = false;
}
public void startSubscript()
throws IOException
{
this.subscripting = true;
}
public void endSubscript()
throws IOException
{
this.subscripting = false;
}
public void startSuperscript()
throws IOException
{
this.superscripting = true;
}
public void endSuperscript()
throws IOException
{
this.superscripting = false;
}
@Override
public void handleString( String content )
throws IOException
{
// Re-escape DOCX special characters, xml parsing removes them.
content = StringUtils.xmlUnescape( content );
content = StringUtils.xmlEscape( content );
if ( insideHeader )
{
// Title of the Header.
super.write( content );
}
else
{
startParagraphIfNeeded();
boolean bold = bolding;
boolean italic = italicsing;
boolean underline = underlining;
boolean strike = striking;
boolean subscript = subscripting;
boolean superscript = superscripting;
SpanProperties properties = getCurrentSpanProperties();
if ( properties != null )
{
// ovveride properties declared in the span.
if ( !bold )
{
bold = properties.isBold();
}
if ( !italic )
{
italic = properties.isItalic();
}
if ( !underline )
{
underline = properties.isUnderline();
}
if ( !strike )
{
strike = properties.isStrike();
}
if ( !subscript )
{
subscript = properties.isSubscript();
}
if ( !superscript)
{
superscript = properties.isSuperscript();
}
}
super.write( "" );
// w:RP
processRunProperties( false, bold, italic, underline, strike, subscript, superscript );
// w:br
for ( int i = 0; i < addLineBreak; i++ )
{
super.write( " " );
}
addLineBreak = 0;
if(!content.isEmpty())
{
// w:t
super.write( "" );
super.write( content );
super.write( " " );
}
super.write( " " );
}
}
private void processRunProperties( boolean isInsidePPr, boolean bold, boolean italics, boolean underline,
boolean strike, boolean subscript, boolean superscript )
throws IOException
{
if ( bold || italics || underline || strike || subscript || superscript )
{
if ( isInsidePPr )
{
startPPrIfNeeded();
}
super.write( "" );
if ( bold )
{
super.write( " " );
}
if ( italics )
{
super.write( " " );
}
if ( underline )
{
super.write( " " );
}
if ( strike )
{
super.write( " " );
}
if (subscript) {
super.write( "" );
}
if (superscript) {
super.write( "" );
}
super.write( " " );
}
}
private void startParagraphIfNeeded()
throws IOException
{
if ( paragraphWasInserted && paragraphsStack.isEmpty() )
{
internalStartParagraph( null );
}
}
private void internalStartParagraph( ContainerProperties properties, String pStyle, boolean isList )
throws IOException
{
paragraphWasInserted = true;
super.setTextLocation( TextLocation.End );
super.write( "" );
processParagraphProperties( properties, pStyle, isList );
paragraphsStack.push( properties );
}
private void internalStartParagraph( ContainerProperties properties )
throws IOException
{
if (properties != null && properties.getStyleName() != null) {
internalStartParagraph(properties, properties.getStyleName(), false);
} else {
internalStartParagraph(properties, null, false);
}
}
public void startParagraph( ParagraphProperties properties )
throws IOException
{
processPageBreakBefore( properties );
closeCurrentParagraph();
internalStartParagraph( properties );
}
private void processPageBreakBefore( ContainerProperties properties )
throws IOException
{
if ( properties != null )
{
if ( properties.isPageBreakBefore() )
{
super.setTextLocation( TextLocation.End );
generatePageBreak();
}
}
}
private void processPageBreakAfter( ContainerProperties properties )
throws IOException
{
if ( properties != null )
{
if ( properties.isPageBreakAfter() )
{
super.setTextLocation( TextLocation.End );
generatePageBreak();
}
}
}
private void generatePageBreak()
throws IOException
{
super.write( "" );
super.write( "" );
super.write( " " );
super.write( " " );
super.write( " " );
}
public void endParagraph()
throws IOException
{
super.write( " " );
processPageBreakAfter( paragraphsStack.pop() );
}
public void startListItem( ListItemProperties properties )
throws IOException
{
// Close current paragraph
closeCurrentParagraph();
internalStartParagraph( properties, null, true );
}
/**
* Generate wpPr docx element.
*
* @param properties
* @param pStyle
* @param isList
* @throws IOException
*/
private void processParagraphProperties( ContainerProperties properties, String pStyle, boolean isList )
throws IOException
{
haspPr = false;
if ( pStyle != null )
{
startPPrIfNeeded();
super.write( " " );
}
if ( isList )
{
startPPrIfNeeded();
super.write( "" );
//
int ilvlVal = super.getCurrentListIndex();
super.write( " " );
// " "
int numIdVal = getCurrentNumId();
super.write( " " );
super.write( " " );
}
//
if ( properties != null )
{
// w:jc
TextAlignment textAlignment = properties.getTextAlignment();
if ( textAlignment != null )
{
switch ( textAlignment )
{
case Left:
startPPrIfNeeded();
super.write( "" );
break;
case Center:
startPPrIfNeeded();
super.write( "" );
break;
case Right:
startPPrIfNeeded();
super.write( "" );
break;
case Justify:
startPPrIfNeeded();
super.write( "" );
break;
}
}
// rPPr
processRunProperties( true, properties.isBold(), properties.isItalic(), properties.isUnderline(),
properties.isStrike(), properties.isSubscript(), properties.isSuperscript() );
}
endPPrIfNeeded();
}
private void startPPrIfNeeded()
throws IOException
{
if ( !haspPr )
{
super.write( "" );
}
haspPr = true;
}
private void endPPrIfNeeded()
throws IOException
{
if ( haspPr )
{
super.write( " " );
}
}
public void endListItem()
throws IOException
{
// endParagraph();
}
public void startHeading( int level, HeaderProperties properties )
throws IOException
{
// Close current paragraph
closeCurrentParagraph();
// In docx, title is a paragraph with a style.
/**
*
* Titre1
*/
String headingStyleName = styleGen.getHeaderStyleId( level, defaultStyle );
internalStartParagraph( properties, headingStyleName, false );
super.write( "" );
insideHeader = true;
}
public void endHeading( int level )
throws IOException
{
super.write( " " );
endParagraph();
insideHeader = false;
}
public void startSpan( SpanProperties properties )
throws IOException
{
spansStack.push( properties );
// startParagraphIfNeeded();
// super.write( "" );
// processRunProperties( false, properties.isBold(), properties.isItalic(), properties.isUnderline(),
// properties.isStrike() );
// super.write( "" );
// super.write( content );
// super.write( " " );
// super.write( " " );
}
private SpanProperties getCurrentSpanProperties()
{
if ( !spansStack.isEmpty() )
{
return spansStack.peek();
}
return null;
}
public void endSpan()
throws IOException
{
spansStack.pop();
}
@Override
protected void doStartOrderedList( ListProperties properties )
throws IOException
{
if(this.addLineBreak>0)
{
handleString("");
}
// if ( numbersStack.isEmpty() )
// {
if ( getCurrentListIndex() < 1 )
{
int abstractNumId = styleGen.getAbstractNumIdForList( true, defaultStyle );
int numId = getNumberingRegistry().addNum( abstractNumId, getMaxNumId(), true ).getNumId();
// numbersStack.push( numId );
currentNumId = numId;
}
// }
}
@Override
protected void doStartUnorderedList( ListProperties properties )
throws IOException
{
if(this.addLineBreak>0)
{
handleString("");
}
// if ( numbersStack.isEmpty() )
// {
if ( getCurrentListIndex() < 1 )
{
int abstractNumId = styleGen.getAbstractNumIdForList( false, defaultStyle );
int numId = getNumberingRegistry().addNum( abstractNumId, getMaxNumId(), false ).getNumId();
// numbersStack.push( numId );
currentNumId = numId;
}
// }
}
private Integer getMaxNumId()
{
if ( defaultStyle == null )
{
return null;
}
return defaultStyle.getMaxNumId();
}
@Override
protected void doEndUnorderedList()
throws IOException
{
// Close current paragraph
closeCurrentParagraph();
}
@Override
protected void doEndOrderedList()
throws IOException
{
// Close current paragraph
closeCurrentParagraph();
}
private int getCurrentNumId()
{
return currentNumId;// numbersStack.peek();
}
public void handleReference( String ref, String label )
throws IOException
{
if ( ref != null )
{
// 1) replace & with &
// fix issue http://code.google.com/p/xdocreport/issues/detail?id=147
ref = StringUtils.xmlUnescape( ref );
ref = StringUtils.xmlEscape( ref );
// fix issue http://code.google.com/p/xdocreport/issues/detail?id=154
label = StringUtils.xmlUnescape( label );
label = StringUtils.xmlEscape( label );
// 2) Update the hyperlink registry to modifiy the Hyperlink Relationship in the _rels/document.xml.rels
HyperlinkRegistry registry = getHyperlinkRegistry();
String rId = registry.registerHyperlink( ref );
// 3) Generate w:hyperlink
String hyperlinkStyleName = styleGen.getHyperLinkStyleId( defaultStyle );
super.write( " " );
super.write( " " );
super.write( "" );
super.write( "" );
super.write( " " );
super.write( " " );
super.write( "" );
super.write( label != null ? label : ref );
super.write( " " );
super.write( " " );
super.write( " " );
super.write( " " );
}
}
public void handleImage( String ref, String label )
throws IOException
{
}
private NumberingRegistry getNumberingRegistry()
{
return numberingRegistry;
}
private NumberingRegistry getNumberingRegistry( IContext context )
{
if ( context == null )
{
return new NumberingRegistry();
}
NumberingRegistry registry = DocxContextHelper.getNumberingRegistry( context );
if ( registry == null )
{
registry = new NumberingRegistry();
DocxContextHelper.putNumberingRegistry( context, registry );
}
return registry;
}
private HyperlinkRegistry getHyperlinkRegistry()
{
if ( hyperlinkRegistry != null )
{
return hyperlinkRegistry;
}
IContext context = getContext();
if ( context == null )
{
hyperlinkRegistry = new HyperlinkRegistry();
return hyperlinkRegistry;
}
String key = HyperlinkUtils.getHyperlinkRegistryKey( getEntryName() );
hyperlinkRegistry = (HyperlinkRegistry) context.get( key );
if ( hyperlinkRegistry == null )
{
hyperlinkRegistry = new HyperlinkRegistry();
context.put( key, hyperlinkRegistry );
}
return hyperlinkRegistry;
}
public void handleLineBreak()
throws IOException
{
//
this.addLineBreak++;
}
protected void doStartTable( TableProperties properties )
throws IOException
{
closeCurrentParagraph();
// ooxml table cannot be generated now, because here we don't know the table column count required to generate
// w:tblGrid
// that's here temp writer is used.
pushTempWriter();
}
public void doEndTable( TableProperties properties )
throws IOException
{
StringBuilder startTable = new StringBuilder( "" );
startTable.append( "" );
int count = properties.getColumnCount();
for ( int i = 0; i < count; i++ )
{
startTable.append( " " );
}
startTable.append( " " );
popTempWriter( startTable.toString() );
super.write( " " );
// if table is inside a table cell, a paragraph is required.
super.write( " " );
}
public void doStartTableRow( TableRowProperties properties )
throws IOException
{
super.write( "" );
}
public void doEndTableRow()
throws IOException
{
super.write( " " );
}
public void doStartTableCell( TableCellProperties properties )
throws IOException
{
super.write( "" );
/*
* super.write( "" ); super.write( " " ); super.write( " " );
*/
internalStartParagraph( null );
}
public void doEndTableCell()
throws IOException
{
endParagraph();
super.write( " " );
}
}