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

org.docx4j.model.PropertyResolver Maven / Gradle / Ivy

Go to download

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.

There is a newer version: 6.1.2
Show newest version
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