Skip to content

Commit

Permalink
Trying to support newer word versions, does not yet work.
Browse files Browse the repository at this point in the history
  • Loading branch information
hvbtup authored and hvbargen committed Mar 30, 2021
1 parent d9439c7 commit 8f5862c
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 115 deletions.
Expand Up @@ -9,30 +9,33 @@
* Actuate Corporation - initial API and implementation
*******************************************************************************/

package org.eclipse.birt.report.engine.emitter.config.docx;

import static org.eclipse.birt.report.engine.api.DocxRenderOption.OPTION_EMBED_HTML;
import org.eclipse.birt.report.engine.api.IRenderOption;
import org.eclipse.birt.report.engine.api.RenderOption;
import org.eclipse.birt.report.engine.emitter.config.AbstractConfigurableOptionObserver;
package org.eclipse.birt.report.engine.emitter.config.docx;

import static org.eclipse.birt.report.engine.api.DocxRenderOption.OPTION_EMBED_HTML;
import static org.eclipse.birt.report.engine.api.DocxRenderOption.OPTION_WORD_VERSION;
import org.eclipse.birt.report.engine.api.IRenderOption;
import org.eclipse.birt.report.engine.api.RenderOption;
import org.eclipse.birt.report.engine.emitter.config.AbstractConfigurableOptionObserver;
import org.eclipse.birt.report.engine.emitter.config.AbstractEmitterDescriptor;
import org.eclipse.birt.report.engine.emitter.config.ConfigurableOption;
import org.eclipse.birt.report.engine.emitter.config.IConfigurableOption;
import org.eclipse.birt.report.engine.emitter.config.IConfigurableOptionObserver;
import org.eclipse.birt.report.engine.emitter.config.IOptionValue;
import org.eclipse.birt.report.engine.emitter.config.docx.i18n.Messages;


import org.eclipse.birt.report.engine.emitter.config.IConfigurableOption;
import org.eclipse.birt.report.engine.emitter.config.IConfigurableOptionObserver;
import org.eclipse.birt.report.engine.emitter.config.IOptionValue;
import org.eclipse.birt.report.engine.emitter.config.OptionValue;
import org.eclipse.birt.report.engine.emitter.config.docx.i18n.Messages;


/**
* This class is a descriptor of word emitter.
*/
public class DocxEmitterDescriptor extends AbstractEmitterDescriptor
{
protected static final String CHART_DPI = "ChartDpi";
protected static final String EMBED_HTML = "EmbedHtml";

protected void initOptions( )
{
{
protected static final String CHART_DPI = "ChartDpi";
protected static final String EMBED_HTML = "EmbedHtml";
protected static final String WORD_VERSION = "WordVersion";

protected void initOptions( )
{
loadDefaultValues( "org.eclipse.birt.report.engine.emitter.config.docx" );
// Initializes the option for chart DPI.
ConfigurableOption chartDpi = new ConfigurableOption( CHART_DPI );
Expand All @@ -47,14 +50,24 @@ protected void initOptions( )
embedHtml.setDisplayName( getMessage( "OptionDisplayValue.EmbedHtml" ) ); //$NON-NLS-1$
embedHtml.setDataType( IConfigurableOption.DataType.BOOLEAN );
embedHtml.setDisplayType( IConfigurableOption.DisplayType.CHECKBOX );
embedHtml.setDefaultValue( new Boolean(Boolean.TRUE) );
embedHtml.setToolTip( getMessage( "Tooltip.EmbedHtml" ) );
embedHtml.setDescription( getMessage( "OptionDescription.EmbedHtml" ) ); //$NON-NLS-1$

options = new IConfigurableOption[]{chartDpi, embedHtml};
applyDefaultValues( );
}
@Override
embedHtml.setDefaultValue( new Boolean(Boolean.TRUE) );
embedHtml.setToolTip( getMessage( "Tooltip.EmbedHtml" ) );
embedHtml.setDescription( getMessage( "OptionDescription.EmbedHtml" ) ); //$NON-NLS-1$

ConfigurableOption wordVersion = new ConfigurableOption( WORD_VERSION );
wordVersion.setDisplayName( getMessage( "OptionDisplayValue.WordVersion" ) ); //$NON-NLS-1$
wordVersion.setDataType( IConfigurableOption.DataType.INTEGER );
wordVersion.setDisplayType( IConfigurableOption.DisplayType.TEXT );
wordVersion.setDefaultValue( new Integer( 2016 ) );
IOptionValue[] choices = { new OptionValue(2010), new OptionValue(2016) };
wordVersion.setChoices(choices);
wordVersion.setToolTip( getMessage( "Tooltip.WordVersion" ) );
wordVersion.setDescription( getMessage( "OptionDescription.WordVersion" ) ); //$NON-NLS-1$

options = new IConfigurableOption[]{chartDpi, embedHtml, wordVersion};
applyDefaultValues( );
}
@Override
public IConfigurableOptionObserver createOptionObserver( )
{
return new DocxOptionObserver( );
Expand Down Expand Up @@ -107,12 +120,17 @@ public String getRenderOptionName( String name )
}

if ( EMBED_HTML.equals( name ) )
{
return OPTION_EMBED_HTML;
}
return name;
}

{
return OPTION_EMBED_HTML;
}

if ( WORD_VERSION.equals( name ) )
{
return OPTION_WORD_VERSION;
}
return name;
}

class DocxOptionObserver extends AbstractConfigurableOptionObserver
{

Expand Down
Expand Up @@ -15,16 +15,19 @@ DocxEmitter.Description=Configure options for rendering a report in XML Document
DocxEmitter.DisplayName=Word (DOCX)

###########################################################
#Option Display Value
OptionDisplayValue.ChartDpi=Chart DPI
OptionDisplayValue.EmbedHtml=Embed HTML

###########################################################
#Option Description
OptionDescription.ChartDpi=The DPI used to generate chart.
OptionDescription.EmbedHtml=Allow DOCX to use embedded HTML

###########################################################
#tooltip
Tooltip.ChartDpi=The DPI which chart engine uses to generate charts. For example, 192.
Tooltip.EmbedHtml=If HTML content should be embedded directly to DOCX output
#Option Display Value
OptionDisplayValue.ChartDpi=Chart DPI
OptionDisplayValue.EmbedHtml=Embed HTML
OptionDisplayValue.WordVersion=Word Version

###########################################################
#Option Description
OptionDescription.ChartDpi=The DPI used to generate chart.
OptionDescription.EmbedHtml=Allow DOCX to use embedded HTML
OptionDescription.WordVersion=Compatibility of .docx to which word version

###########################################################
#tooltip
Tooltip.ChartDpi=The DPI which chart engine uses to generate charts. For example, 192.
Tooltip.EmbedHtml=If HTML content should be embedded directly to DOCX output
Tooltip.WordVersion=MS changed word behavior with Word 2013, so usually 2016 is the best choice.
Expand Up @@ -44,20 +44,30 @@ public DocxEmitterImpl( ContentEmitterVisitor contentVisitor )

public void initialize( IEmitterServices service ) throws EngineException
{
super.initialize( service );
String tempFileDir = service.getReportEngine( ).getConfig( )
.getTempDir( );
wordWriter = new DocxWriter( out, tempFileDir, getCompressionMode( service )
.getValue( ) );
IRenderOption renderOption = service.getRenderOption( );
Object value = renderOption.getOption( DocxRenderOption.OPTION_EMBED_HTML );
if ( value instanceof Boolean )
{
this.embedHtml = (Boolean) value;
}
}

private CompressionMode getCompressionMode( IEmitterServices service )
super.initialize( service );
String tempFileDir = service.getReportEngine( ).getConfig( )
.getTempDir( );

IRenderOption renderOption = service.getRenderOption( );
Object value = renderOption.getOption( DocxRenderOption.OPTION_WORD_VERSION );
if (value instanceof Integer) {
setWordVersion((Integer)value);
System.out.println("Setting the Word version to " + String.valueOf(value));
} else {
setWordVersion(2010);
System.out.println("Using default Word version "+ String.valueOf(getWordVersion()));
}
value = renderOption.getOption( DocxRenderOption.OPTION_EMBED_HTML );
if ( value instanceof Boolean )
{
this.embedHtml = (Boolean) value;
}

wordWriter = new DocxWriter( out, tempFileDir, getCompressionMode( service )
.getValue( ), getWordVersion() );
}

private CompressionMode getCompressionMode( IEmitterServices service )
{
RenderOption renderOption = (RenderOption) service.getRenderOption( );
CompressionMode compressionMode = CompressionMode.BEST_COMPRESSION;
Expand Down
Expand Up @@ -41,21 +41,24 @@ public class Document extends BasicComponent
private int headerId = 1;

private int footerId = 1;

private int mhtId = 1;

Document( IPart part, String backgroundColor, String backgroundImageUrl,
String backgroundHeight, String backgroundWidth,
boolean rtl ) throws IOException
{
super( part );
this.backgroundColor = backgroundColor;
this.backgroundImageImgUrl = backgroundImageUrl;
this.backgroundHeight = backgroundHeight;
this.backgroundWidth = backgroundWidth;
this.rtl = rtl;
writeStylesPart( );
writeSettingsPart( );

private int mhtId = 1;

private int wordVersion;

Document( IPart part, String backgroundColor, String backgroundImageUrl,
String backgroundHeight, String backgroundWidth,
boolean rtl, int wordVersion ) throws IOException
{
super( part );
this.backgroundColor = backgroundColor;
this.backgroundImageImgUrl = backgroundImageUrl;
this.backgroundHeight = backgroundHeight;
this.backgroundWidth = backgroundWidth;
this.wordVersion = wordVersion;
this.rtl = rtl;
writeStylesPart( );
writeSettingsPart( );
}

void start( )
Expand Down Expand Up @@ -203,24 +206,58 @@ private void writeSettingsPart( ) throws IOException
try
{
settingsPartWriter = settingsPart.getWriter( );
settingsPartWriter.startWriter( );
settingsPartWriter.openTag( "w:settings" );
settingsPartWriter.nameSpace( "w", NameSpaces.WORD_PROCESSINGML );
settingsPartWriter.openTag( "w:zoom" );
settingsPartWriter.attribute( "w:percent", "100" );
settingsPartWriter.closeTag( "w:zoom" );
settingsPartWriter.startWriter( );
settingsPartWriter.openTag( "w:settings" );
settingsPartWriter.nameSpace( "w", NameSpaces.WORD_PROCESSINGML );
settingsPartWriter.nameSpace( "o", NameSpaces.OFFICE );
settingsPartWriter.nameSpace( "r", NameSpaces.RELATIONSHIPS);
if (wordVersion > 2010) {
settingsPartWriter.nameSpace( "mc", NameSpaces.MARKUP_COMPATIBILITY );
settingsPartWriter.nameSpace( "w10", NameSpaces.W10 );
settingsPartWriter.nameSpace( "w14", NameSpaces.W14 );
settingsPartWriter.nameSpace( "w15", NameSpaces.W15 );
settingsPartWriter.nameSpace( "w16", NameSpaces.W16 );
settingsPartWriter.nameSpace( "w16cid", NameSpaces.W16CID );
settingsPartWriter.nameSpace( "w16se", NameSpaces.W16SE );
settingsPartWriter.nameSpace( "w16cex", NameSpaces.W16CEX );
settingsPartWriter.nameSpace( "sl", NameSpaces.SCHEMA_LIBRARY );
settingsPartWriter.attribute( "mc:ignorable", "w14 w15 w16se w16cid w16 w16cex" );
}
settingsPartWriter.openTag( "w:zoom" );
settingsPartWriter.attribute( "w:percent", "100" );
settingsPartWriter.closeTag( "w:zoom" );
settingsPartWriter.openTag( "w:displayBackgroundShape" );
settingsPartWriter.closeTag( "w:displayBackgroundShape" );
// settingsPartWriter.openTag( "w:proofState" );
// settingsPartWriter.attribute( "w:spelling", "clean" );
// settingsPartWriter.attribute( "w:grammar", "clean" );
// settingsPartWriter.closeTag( "w:proofState" );
settingsPartWriter.openTag( "w:view" );
settingsPartWriter.attribute( "w:val", "print" );
settingsPartWriter.closeTag( "w:view" );
settingsPartWriter.closeTag( "w:settings" );
settingsPartWriter.endWriter( );
}
settingsPartWriter.openTag( "w:view" );
settingsPartWriter.attribute( "w:val", "print" );
settingsPartWriter.closeTag( "w:view" );

// Word compatibility settings
settingsPartWriter.openTag( "w:compat" );
switch (wordVersion) {
case 2010:
settingsPartWriter.openTag( "w:compatSetting" );
settingsPartWriter.attribute( "w:name", "w:compatibilityMode" );
settingsPartWriter.attribute( "w:uri", "http://schemas.microsoft.com/office/word" );
settingsPartWriter.attribute( "w:val", "12" );
settingsPartWriter.closeTag( "w:compatSetting" );
break;
default:
settingsPartWriter.openTag( "w:compatSetting" );
settingsPartWriter.attribute( "w:name", "w:compatibilityMode" );
settingsPartWriter.attribute( "w:uri", "http://schemas.microsoft.com/office/word" );
settingsPartWriter.attribute( "w:val", "15" );
settingsPartWriter.closeTag( "w:compatSetting" );
}
settingsPartWriter.closeTag( "w:compat" );

settingsPartWriter.closeTag( "w:settings" );
settingsPartWriter.endWriter( );
}
finally
{
if ( settingsPartWriter != null )
Expand Down
Expand Up @@ -40,17 +40,20 @@ public class DocxWriter implements IWordWriter

private BasicComponent currentComponent;

private boolean rtl = false;

private boolean showHeaderOnFirst;

public DocxWriter( OutputStream out, String tempFileDir, int compressionMode )
{
pkg = Package.createInstance( out, tempFileDir, compressionMode );
pkg.setExtensionData( new ImageManager( ) );
}

public void start( boolean rtl, String creator, String title,
private boolean rtl = false;

private boolean showHeaderOnFirst;

private int wordVersion;

public DocxWriter( OutputStream out, String tempFileDir, int compressionMode, int wordVersion )
{
pkg = Package.createInstance( out, tempFileDir, compressionMode );
pkg.setExtensionData( new ImageManager( ) );
this.wordVersion = wordVersion;
}

public void start( boolean rtl, String creator, String title,
String description, String subject ) throws IOException
{
this.rtl = rtl;
Expand Down Expand Up @@ -116,13 +119,13 @@ private void initializeDocumentPart( String backgroundColor,
{
String uri = "word/document.xml";
String type = ContentTypes.WORD_PROCESSINGML;
String relationshipType = RelationshipTypes.DOCUMENT;
IPart documentPart = pkg.getPart( uri, type, relationshipType );
document = new Document( documentPart, backgroundColor,
backgroundImageUrl, backgroundHeight, backgroundWidth, rtl );
document.start( );
currentComponent = document;
}
String relationshipType = RelationshipTypes.DOCUMENT;
IPart documentPart = pkg.getPart( uri, type, relationshipType );
document = new Document( documentPart, backgroundColor,
backgroundImageUrl, backgroundHeight, backgroundWidth, rtl, wordVersion );
document.start( );
currentComponent = document;
}

public void startSectionInParagraph( )
{
Expand Down
Expand Up @@ -199,6 +199,25 @@ public static enum TextFlag {

protected int reportDpi;

/**
* The original DOCX emitters generated output for word version 2010.
* Newer version of Microsoft Word render these files incorrectly
* the compatibility mode is activated manually after opening the file.
*
* The original WPML emitter generated the same WordProcessing ML.
*
* When wordVersion is set to a value of 2016, the resulting XML file
* is a bit different (mainly some XML schema names changed).
*
* If you want the document generated by BIRT to look correctly
* in MS Word, you should no longer user 2010, but 2016.
*
* Since this file is shared by the DOCX emitter and the WPML emitter
* (Word 2003 XML, uncompressed) and we don't want to touch the WPML
* emitter, the default here is still 2010.
*/
private int wordVersion = 2010;

protected static final String EMPTY_FOOTER = " ";

public void initialize( IEmitterServices service ) throws EngineException
Expand Down Expand Up @@ -1395,6 +1414,14 @@ private int[] computeTblColumnWidths( ITableContent table, int tblWidth )
total );
}

public int getWordVersion() {
return wordVersion;
}

public void setWordVersion(int wordVersion) {
this.wordVersion = wordVersion;
}

static class TocInfo
{

Expand Down

0 comments on commit 8f5862c

Please sign in to comment.