org.docx4j.convert.out.fo.LayoutMasterSetBuilder 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.
/*
Licensed to Plutext Pty Ltd under one or more contributor license agreements.
* This file is part of docx4j.
docx4j is licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package org.docx4j.convert.out.fo;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.docx4j.UnitsOfMeasurement;
import org.docx4j.XmlUtils;
import org.docx4j.convert.out.common.AbstractWmlConversionContext;
import org.docx4j.convert.out.common.ConversionSectionWrapper;
import org.docx4j.jaxb.Context;
import org.docx4j.model.structure.HeaderFooterPolicy;
import org.docx4j.model.structure.PageDimensions;
import org.plutext.jaxb.xslfo.ConditionalPageMasterReference;
import org.plutext.jaxb.xslfo.LayoutMasterSet;
import org.plutext.jaxb.xslfo.ObjectFactory;
import org.plutext.jaxb.xslfo.OddOrEvenType;
import org.plutext.jaxb.xslfo.PagePositionType;
import org.plutext.jaxb.xslfo.PageSequenceMaster;
import org.plutext.jaxb.xslfo.RegionAfter;
import org.plutext.jaxb.xslfo.RegionBefore;
import org.plutext.jaxb.xslfo.RegionBody;
import org.plutext.jaxb.xslfo.RepeatablePageMasterAlternatives;
import org.plutext.jaxb.xslfo.SimplePageMaster;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Node;
/**
* A description of how this stuff works
* can be found at /docs/headers_footers.docx
*
* @author jharrop
*
*/
public class LayoutMasterSetBuilder {
protected static Logger log = LoggerFactory.getLogger(LayoutMasterSetBuilder.class);
private static org.plutext.jaxb.xslfo.ObjectFactory factory;
public static DocumentFragment getLayoutMasterSetFragment(AbstractWmlConversionContext context) {
LayoutMasterSet lms = getFoLayoutMasterSet(context);
org.w3c.dom.Document document = XmlUtils.marshaltoW3CDomDocument(lms, Context.getXslFoContext() );
DocumentFragment docfrag = document.createDocumentFragment();
docfrag.appendChild(document.getDocumentElement());
return docfrag;
}
/**
* For XSLFOExporterNonXSLT
* @since 3.0
*
*/
public static void appendLayoutMasterSetFragment(AbstractWmlConversionContext context, Node foRoot) {
LayoutMasterSet lms = getFoLayoutMasterSet(context);
org.w3c.dom.Document document = XmlUtils.marshaltoW3CDomDocument(lms, Context.getXslFoContext() );
XmlUtils.treeCopy(document.getDocumentElement(), foRoot);
}
private static LayoutMasterSet getFoLayoutMasterSet(AbstractWmlConversionContext context) {
LayoutMasterSet lms = getFactory().createLayoutMasterSet();
List sections = context.getSections().getList();
ConversionSectionWrapper section = null;
for(int i=0; i
*
*
* the default one is treated as odd.
*/
if (hf.getEvenHeader()!=null || hf.getEvenFooter()!=null) {
lms.getSimplePageMasterOrPageSequenceMaster().add(
createSimplePageMaster(sectionName + "-evenpage",
section.getPageDimensions(),
"evenpage",
(hf.getEvenHeader()!=null),
(hf.getEvenFooter()!=null) ));
// the xslt outputs a "-default" page as the odd-page
}
if (hf.getDefaultHeader()!=null
|| hf.getDefaultFooter()!=null) {
lms.getSimplePageMasterOrPageSequenceMaster().add(
createSimplePageMaster(sectionName + "-default",
section.getPageDimensions(),
"default",
(hf.getDefaultHeader()!=null),
(hf.getDefaultFooter()!=null) ));
}
// simple: no headers and footers - after the first page anyway/
// We still need this where there is just a first page header/footer,
// since otherwise there'd be no page sequence for any content
// after the first page, and you'd get:
// org.apache.fop.fo.pagination.PageProductionException:
// Subsequences exhausted in page-sequence-master ..., cannot recover.
//
//
//
//
if (
(hf.getDefaultHeader() == null) && (hf.getDefaultFooter() == null)) {
lms.getSimplePageMasterOrPageSequenceMaster().add(
createSimplePageMaster(sectionName + "-simple",
section.getPageDimensions(),
"simple",
true, true));
}
// SECOND, create page-sequence-masters
lms.getSimplePageMasterOrPageSequenceMaster().add(
createPageSequenceMaster(hf, sectionName ) );
}
return lms;
}
private static PageSequenceMaster createPageSequenceMaster(HeaderFooterPolicy hf,
String sectionName ) {
boolean noHeadersFootersAfterFirstPage = true;
PageSequenceMaster psm = getFactory().createPageSequenceMaster();
psm.setMasterName(sectionName);
RepeatablePageMasterAlternatives rpma = getFactory().createRepeatablePageMasterAlternatives();
psm.getSinglePageMasterReferenceOrRepeatablePageMasterReferenceOrRepeatablePageMasterAlternatives().add(rpma);
// has first header or footer?
if (hf.getFirstHeader()!=null || hf.getFirstFooter()!=null) {
ConditionalPageMasterReference cpmr1 = getFactory().createConditionalPageMasterReference();
cpmr1.setMasterReference(sectionName+"-firstpage");
cpmr1.setPagePosition(PagePositionType.FIRST);
rpma.getConditionalPageMasterReference().add(cpmr1);
}
if (hf.getEvenHeader()!=null || hf.getEvenFooter()!=null) {
ConditionalPageMasterReference cpmr2 = getFactory().createConditionalPageMasterReference();
cpmr2.setMasterReference(sectionName+"-evenpage");
//cpmr2.setPagePosition(PagePositionType.FIRST);
cpmr2.setOddOrEven(OddOrEvenType.EVEN);
rpma.getConditionalPageMasterReference().add(cpmr2);
// the xslt outputs a "-default" page as the odd-page
ConditionalPageMasterReference cpmr3 = getFactory().createConditionalPageMasterReference();
cpmr3.setMasterReference(sectionName+"-default");
//cpmr3.setPagePosition(PagePositionType.FIRST);
cpmr3.setOddOrEven(OddOrEvenType.ODD);
rpma.getConditionalPageMasterReference().add(cpmr3);
noHeadersFootersAfterFirstPage = false;
} else if (hf.getDefaultHeader()!=null || hf.getDefaultFooter()!=null) {
ConditionalPageMasterReference cpmr4 = getFactory().createConditionalPageMasterReference();
cpmr4.setMasterReference(sectionName+"-default");
//cpmr4.setPagePosition(PagePositionType.FIRST);
rpma.getConditionalPageMasterReference().add(cpmr4);
noHeadersFootersAfterFirstPage = false;
}
if (noHeadersFootersAfterFirstPage) {
ConditionalPageMasterReference cpmr5 = getFactory().createConditionalPageMasterReference();
cpmr5.setMasterReference(sectionName+"-simple");
//cpmr5.setPagePosition(PagePositionType.FIRST);
rpma.getConditionalPageMasterReference().add(cpmr5);
}
return psm;
}
private static final int HEADER_PADDING_TWIP = 360;
private static final int FOOTER_PADDING_TWIP = 360;
private static final int MIN_PAGE_MARGIN = 360;
private static SimplePageMaster createSimplePageMaster(
String masterName, PageDimensions page, String appendRegionName,
boolean needBefore, boolean needAfter) {
SimplePageMaster spm = getFactory().createSimplePageMaster();
spm.setMasterName(masterName);
// dimensions.
//
//
spm.setPageHeight( UnitsOfMeasurement.twipToBest(page.getPgSz().getH().intValue() ));
spm.setPageWidth( UnitsOfMeasurement.twipToBest(page.getPgSz().getW().intValue() ));
spm.setMarginLeft( UnitsOfMeasurement.twipToBest(page.getPgMar().getLeft().intValue() ) );
spm.setMarginRight( UnitsOfMeasurement.twipToBest(page.getPgMar().getRight().intValue()) );
/*
* Region before & after live in region body margins:
*
* Per http://www.w3.org/TR/xsl/#fo_region-body
*
* The body region should be sized and positioned within the fo:simple-page-master
* so that there is room for the areas returned by the flow that is assigned to the
* fo:region-body and for any desired side regions, that is, fo:region-before,
* fo:region-after, fo:region-start and fo:region-end's that are to be placed on the same page.
*
* These side regions are positioned within the content-rectangle of the page-reference-area.
* The margins on the fo:region-body are used to position the region-viewport-area for the
* fo:region-body and to leave space for the other regions that surround the fo:region-body.
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*
* The spacing between the last four regions and the fo:region-body is determined by subtracting
* the relevant extent trait on the side regions from the trait that corresponds to the "margin-x"
* property on the fo:region-body.
*/
RegionBody rb = getFactory().createRegionBody();
rb.setMarginLeft("0mm");
rb.setMarginRight("0mm");
spm.setRegionBody(rb);
if (needBefore) {
//Header
RegionBefore rBefore = getFactory().createRegionBefore();
rBefore.setRegionName("xsl-region-before-"+appendRegionName);
spm.setRegionBefore(rBefore);
// Make margin smaller, because header takes up space it would otherwise occupy
int marginTopTwips
= page.getPgMar().getTop().intValue()
- (HEADER_PADDING_TWIP + page.getHeaderExtent() + page.getHeaderMargin() );
if (marginTopTwips