org.docx4j.model.PropertyResolver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of docx4j Show documentation
Show all versions of docx4j Show documentation
docx4j is a library which helps you to work with the Office Open
XML file format as used in docx
documents, pptx presentations, and xlsx spreadsheets.
package org.docx4j.model;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Stack;
import org.docx4j.XmlUtils;
import org.docx4j.jaxb.Context;
import org.docx4j.model.styles.StyleUtil;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.ThemePart;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.openpackaging.parts.WordprocessingML.NumberingDefinitionsPart;
import org.docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart;
import org.docx4j.wml.BooleanDefaultTrue;
import org.docx4j.wml.CTLanguage;
import org.docx4j.wml.CTTblPrBase;
import org.docx4j.wml.DocDefaults;
import org.docx4j.wml.HpsMeasure;
import org.docx4j.wml.PPr;
import org.docx4j.wml.PPrBase.NumPr.NumId;
import org.docx4j.wml.ParaRPr;
import org.docx4j.wml.RPr;
import org.docx4j.wml.Style;
import org.docx4j.wml.TblPr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class works out the actual set of properties (paragraph or run)
* which apply, following the order specified in ECMA-376.
*
* From ECMA-376 > Part3 > 2 Introduction to WordprocessingML > 2.8 Styles > 2.8.10 Style Application
* at http://www.documentinteropinitiative.org/implnotes/ecma-376/P3-2.8.10.aspx
*
* (See also Part 4, 2.7.2 which is the normative bit...)
With the various flavors of styles available, multiple style types can be
applied to the same content within a file, which means that properties must
be applied in a specific deterministic order. As with inheritance, the
resulting formatting properties set by one type can be unchanged, removed,
or altered by following types.
The following table illustrates the order of application of these defaults,
and which properties are impacted by each:
This process can be described as follows:
First, the document defaults are applied to all runs and paragraphs in
the document.
Next, the table style properties are applied to each table in the document,
following the conditional formatting inclusions and exclusions specified
per table.
Next, numbered item and paragraph properties are applied to each paragraph
formatted with a numbering style.
Next, paragraph and run properties are
applied to each paragraph as defined by the paragraph style.
Next, run properties are applied to each run with a specific character style
applied.
Finally, we apply direct formatting (paragraph or run properties not from
styles).
-----------
Things which are unclear:
- the role of w:link on a paragraph style (eg Heading1 links to "Heading1char"),
experimentation in Word 2007 suggests the w:link is not used at all
- indeed, "Heading1char" is not used at all?
-----------
docx4all does not use this; its org.docx4all.swing.text.StyleSheet
uses MutableAttributeSet's resolve function to climb the style hierarchy.
This is most relevant to XSLFO, which unlike CSS, doesn't have a concept of
style. HTML NG2 uses CSS inheritance, and so doesn't need it.
* @author jharrop
*
*/
public class PropertyResolver {
private static Logger log = LoggerFactory.getLogger(PropertyResolver.class);
// private DocDefaults docDefaults;
private PPr documentDefaultPPr;
private RPr documentDefaultRPr;
public RPr getDocumentDefaultRPr() {
return documentDefaultRPr;
}
public PPr getDocumentDefaultPPr() {
return documentDefaultPPr;
}
private StyleDefinitionsPart styleDefinitionsPart;
private WordprocessingMLPackage wordMLPackage;
/**
* All styles in the Style Definitions Part.
*/
private org.docx4j.wml.Styles styles;
/**
* Map of all styles in the Style Definitions Part.
* Note, you need to manually keep this up to date
*/
private java.util.Map liveStyles = null;
private ThemePart themePart;
private NumberingDefinitionsPart numberingDefinitionsPart;
private java.util.Map resolvedStylePPrComponent = new HashMap();
/**
* This map also contains the rPr component of a pPr
*/
private java.util.Map resolvedStyleRPrComponent = new HashMap();
public PropertyResolver(WordprocessingMLPackage wordMLPackage) throws Docx4JException {
this.wordMLPackage = wordMLPackage;
MainDocumentPart mdp = wordMLPackage.getMainDocumentPart();
styleDefinitionsPart = mdp.getStyleDefinitionsPart(true);
themePart = mdp.getThemePart();
numberingDefinitionsPart = mdp.getNumberingDefinitionsPart();
if (wordMLPackage.getMainDocumentPart().getDocumentSettingsPart()!=null
&& wordMLPackage.getMainDocumentPart().getDocumentSettingsPart().getContents()!=null) {
themeFontLang = wordMLPackage.getMainDocumentPart().getDocumentSettingsPart().getContents().getThemeFontLang();
}
init();
}
CTLanguage themeFontLang = null;
// public PropertyResolver(StyleDefinitionsPart styleDefinitionsPart,
// ThemePart themePart,
// NumberingDefinitionsPart numberingDefinitionsPart) throws Docx4JException {
//
// this.styleDefinitionsPart= styleDefinitionsPart;
// this.themePart = themePart;
// this.numberingDefinitionsPart = numberingDefinitionsPart;
// init();
// }
String defaultParagraphStyleId; // "Normal" in English, but ...
String defaultCharacterStyleId;
private void init() throws Docx4JException {
// styleDefinitionsPart.createVirtualStylesForDocDefaults();
try {
defaultParagraphStyleId = this.styleDefinitionsPart.getDefaultParagraphStyle().getStyleId();
} catch (NullPointerException npe) {
log.warn("No default paragraph style!!");
}
try {
defaultCharacterStyleId = this.styleDefinitionsPart.getDefaultCharacterStyle().getStyleId();
} catch (NullPointerException npe) {
log.warn("No default character style!!");
}
// Initialise styles
styles = (org.docx4j.wml.Styles)styleDefinitionsPart.getJaxbElement();
initialiseLiveStyles();
// Style docDefaults = styleDefinitionsPart.getStyleById("DocDefaults");
DocDefaults docDefaults = styleDefinitionsPart.getJaxbElement().getDocDefaults();
if(log.isDebugEnabled()) {
log.debug(XmlUtils.marshaltoString(docDefaults, true, true));
}
documentDefaultPPr = new PPr();
documentDefaultRPr = new RPr();
if (docDefaults!=null
&& docDefaults.getPPrDefault()!=null
&& docDefaults.getPPrDefault().getPPr()!=null) {
documentDefaultPPr = docDefaults.getPPrDefault().getPPr();
}
if (docDefaults!=null
&& docDefaults.getRPrDefault()!=null
&& docDefaults.getRPrDefault().getRPr()!=null) {
documentDefaultRPr = docDefaults.getRPrDefault().getRPr();
}
if (documentDefaultRPr.getSz()==null) {
// Make Word default explicit
HpsMeasure sz20 = new HpsMeasure();
sz20.setVal(BigInteger.valueOf(20));
documentDefaultRPr.setSz(sz20);
}
addNormalToResolvedStylePPrComponent();
addDefaultParagraphFontToResolvedStyleRPrComponent();
}
private void addNormalToResolvedStylePPrComponent() {
Stack pPrStack = new Stack();
// String styleId = "Normal";
String styleId = defaultParagraphStyleId;
fillPPrStack(styleId, pPrStack);
pPrStack.push(documentDefaultPPr);
PPr effectivePPr = factory.createPPr();
// Now, apply the properties starting at the top of the stack
while (!pPrStack.empty() ) {
PPr pPr = pPrStack.pop();
applyPPr(pPr, effectivePPr);
}
resolvedStylePPrComponent.put(styleId, effectivePPr);
}
private void addDefaultParagraphFontToResolvedStyleRPrComponent() {
Stack rPrStack = new Stack();
fillRPrStack(defaultParagraphStyleId, rPrStack);
// Since default font size might be in there.
fillRPrStack(defaultCharacterStyleId, rPrStack);
rPrStack.push(documentDefaultRPr);
RPr effectiveRPr = factory.createRPr();
// Now, apply the properties starting at the top of the stack
while (!rPrStack.empty() ) {
RPr rPr = rPrStack.pop();
applyRPr(rPr, effectiveRPr);
}
resolvedStyleRPrComponent.put(defaultCharacterStyleId, effectiveRPr);
}
public Style getEffectiveTableStyle(TblPr tblPr) {
// OK to pass this a null tblPr.
Stack