private static SdtBlock createSdt(String tagVal, RPr rPr) { // .. so create content control! SdtBlock sdtBlock = Context.getWmlObjectFactory().createSdtBlock(); SdtPr sdtPr = Context.getWmlObjectFactory().createSdtPr(); sdtBlock.setSdtPr(sdtPr); SdtContentBlock sdtContent = Context.getWmlObjectFactory().createSdtContentBlock(); sdtBlock.setSdtContent(sdtContent); // For borders/shading, we'll use the values in this first paragraph. // We'll use a tag, so the XSLT can detect that its supposed to do something special. Tag tag = Context.getWmlObjectFactory().createTag(); tag.setVal(tagVal); sdtPr.setTag(tag); if (rPr != null) { sdtPr.getRPrOrAliasOrLock().add((RPr) XmlUtils.deepCopy(rPr)); /* * ECMA-376 says "specifies the set of run properties which shall be applied to * the text entered into the parent structured document tag in replacement of * placeholder text. When placeholder text is present in a structured document * tag, its formatting is often different than the desired underlying formatting, * and this element specifies the formatting which shall be used for non-placeholder * text contents when they are initially added to the control. " * * Note that docx2fo.xslt is co-opting this to do something else. */ } return sdtBlock; }
private static void appendRun(SdtBlock currentBlock, List<Object> resultElts) { List<Object> blkElements = null; R run = null; RPr blockRPr = null; if (currentBlock != null) { blkElements = currentBlock.getSdtContent().getContent(); if (blkElements.size() == 1) { // If there is only one element, there is no need to use a sdtBlock resultElts.add(blkElements.get(0)); } else { resultElts.add(currentBlock); // Remove the borders of the child elements // (and the shading if it is the same as that of the container) blockRPr = findBlockRPr(currentBlock); for (Object elem : blkElements) { if (elem instanceof R) { run = (R) elem; if (run.getRPr() != null) { run.getRPr().setBdr(null); if (!shadingChanged(blockRPr.getShd(), run.getRPr().getShd())) { run.getRPr().setShd(null); } } } } } } }
private static RPr findBlockRPr(SdtBlock currentBlock) { for (Object obj : currentBlock.getSdtPr().getRPrOrAliasOrLock()) { if (obj instanceof RPr) { return (RPr) obj; } } return null; }
private static List<Object> groupRuns(List<Object> paragraphElts) { List<Object> resultElts = new ArrayList<Object>(); SdtBlock currentBlock = null; CTBorder lastBorder = null; CTBorder currentBorder = null; R run = null; // java.util.Stack stack = new java.util.Stack(); // stack.push(newList); for (Object o : paragraphElts) { if (o instanceof R) { run = (R) o; currentBorder = null; if (run.getRPr() != null) { currentBorder = run.getRPr().getBdr(); } if (borderChanged(currentBorder, lastBorder)) { appendRun(currentBlock, resultElts); currentBlock = null; // could mean null to borders; borders to null; or bordersA to bordersB if (currentBorder != null) { currentBlock = createSdt(TAG_RPR, run.getRPr()); } } } if (currentBlock != null) { currentBlock.getSdtContent().getContent().add(o); } else { resultElts.add(o); } // setup for next loop lastBorder = currentBorder; } appendRun(currentBlock, resultElts); return resultElts; }
private static List<Object> groupBodyContent(List<Object> bodyElts) { List<Object> resultElts = new ArrayList<Object>(); List<Object> paragraphElts = null; SdtBlock sdtBorders = null; SdtBlock sdtShading = null; PBdr lastBorders = null; PBdr currentBorders = null; CTShd lastShading = null; CTShd currentShading = null; P paragraph = null; for (Object o : bodyElts) { if (o instanceof JAXBElement) { o = ((JAXBElement) o).getValue(); } if (o instanceof P) { paragraph = (P) o; paragraphElts = groupRuns(paragraph.getContent()); paragraph.getContent().clear(); if (paragraphElts != null) { paragraph.getContent().addAll(paragraphElts); } currentBorders = null; currentShading = null; if (paragraph.getPPr() != null) { // TODO: use effective ppr properties! // ie take styles into account currentBorders = paragraph.getPPr().getPBdr(); currentShading = paragraph.getPPr().getShd(); } if (bordersChanged(currentBorders, lastBorders)) { // could mean null to borders; borders to null; or bordersA to bordersB if (currentBorders == null) { sdtBorders = null; } else { sdtBorders = createSdt(TAG_BORDERS); resultElts.add(sdtBorders); } } if (shadingChanged(currentShading, lastShading)) { // handle change to shading before addElement if (currentShading == null) { sdtShading = null; } else { sdtShading = createSdt(TAG_SHADING); // need to set margins, so there isn't a white strip // between paragraphs. hmm, model.properties.paragraph // won't translate this. so do it at the fo level if (sdtBorders != null) { sdtBorders.getSdtContent().getContent().add(sdtShading); } else { resultElts.add(sdtShading); } } } } else if (o instanceof Tbl) { groupTable((Tbl) o); } if (sdtShading != null) { sdtShading.getSdtContent().getContent().add(o); } else if (sdtBorders != null) { sdtBorders.getSdtContent().getContent().add(o); } else { resultElts.add(o); } // setup for next loop lastBorders = currentBorders; lastShading = currentShading; } return resultElts; }
protected static List<ConversionSectionWrapper> processComplete( WordprocessingMLPackage wmlPackage, Document document, RelationshipsPart rels, BooleanDefaultTrue evenAndOddHeaders, boolean dummyPageNumbering) { List<ConversionSectionWrapper> conversionSections = new ArrayList<ConversionSectionWrapper>(); List<Object> sectionContent = new ArrayList<Object>(); ConversionSectionWrapper currentSectionWrapper = null; HeaderFooterPolicy previousHF = null; int conversionSectionIndex = 0; // According to the ECMA-376 2ed, if type is not specified, read it as next page // However Word 2007 sometimes treats it as continuous, and sometimes doesn't?? // 20130216 Review above comment: ! In the Word UI, the Word "continuous" is shown where it is // effective. // In the XML, it is stored in the next following sectPr. // First, remove content controls, // since the P could be in a content control. // (It is easier to remove content controls, than // to make the code below TraversalUtil based) // RemovalHandler is an XSLT-based way of doing this, // but here we avoid introducing a dependency on // XSLT (Xalan) for PDF output. SdtBlockFinder sbr = new SdtBlockFinder(); new TraversalUtil(document.getContent(), sbr); for (int i = sbr.sdtBlocks.size() - 1; i >= 0; i--) { // Have to process in reverse order // so that parentList is correct for nested sdt SdtBlock sdtBlock = sbr.sdtBlocks.get(i); List<Object> parentList = null; if (sdtBlock.getParent() instanceof ArrayList) { parentList = (ArrayList) sdtBlock.getParent(); } else { log.error("Handle " + sdtBlock.getParent().getClass().getName()); } int index = parentList.indexOf(sdtBlock); parentList.remove(index); parentList.addAll(index, sdtBlock.getSdtContent().getContent()); } // if (log.isDebugEnabled()) { // log.debug(XmlUtils.marshaltoString(document, true, true)); // } // Make a list, so it is easy to look at the following sectPr, // which we need to do to handle continuous sections properly List<SectPr> sectPrs = new ArrayList<SectPr>(); for (Object o : document.getBody().getContent()) { if (o instanceof org.docx4j.wml.P) { if (((org.docx4j.wml.P) o).getPPr() != null) { org.docx4j.wml.PPr ppr = ((org.docx4j.wml.P) o).getPPr(); if (ppr.getSectPr() != null) { sectPrs.add(ppr.getSectPr()); } } } } if (document.getBody().getSectPr() != null) { // usual case sectPrs.add(document.getBody().getSectPr()); } else { log.debug("No body level sectPr in document"); // OK if the last object is w:p and it contains a sectPr. List<Object> all = document.getBody().getContent(); Object last = all.get(all.size() - 1); if (last instanceof P && ((P) last).getPPr() != null && ((P) last).getPPr().getSectPr() != null) { // ok log.debug( ".. but last p contains sectPr .. move it"); // so our assumption later about there // being a following section is correct SectPr thisSectPr = ((P) last).getPPr().getSectPr(); document.getBody().setSectPr(thisSectPr); ((P) last).getPPr().setSectPr(null); sectPrs.remove(thisSectPr); } else { document.getBody().setSectPr(Context.getWmlObjectFactory().createSectPr()); sectPrs.add(document.getBody().getSectPr()); } } int sectPrIndex = 0; // includes continuous ones for (Object o : document.getBody().getContent()) { if (o instanceof org.docx4j.wml.P) { if (((org.docx4j.wml.P) o).getPPr() != null) { org.docx4j.wml.PPr ppr = ((org.docx4j.wml.P) o).getPPr(); if (ppr.getSectPr() != null) { // If the *following* section is continuous, don't add *this* section boolean ignoreThisSection = false; SectPr followingSectPr = sectPrs.get(++sectPrIndex); if (followingSectPr.getType() != null && followingSectPr.getType().getVal().equals("continuous")) { ignoreThisSection = true; // If the w:pgSz on the two sections differs, // then Word inserts a page break (ie doesn't treat it as continuous). // If no w:pgSz element is present, then Word defaults // (presumably to Legal? TODO CHECK. There is no default setting in the docx). // Word always inserts a w:pgSz element? PgSz pgSzThis = ppr.getSectPr().getPgSz(); PgSz pgSzNext = followingSectPr.getPgSz(); if (pgSzThis != null && pgSzNext != null) { if (pgSzThis.getH().compareTo(pgSzNext.getH()) != 0) { ignoreThisSection = false; } if (pgSzThis.getW().compareTo(pgSzNext.getW()) != 0) { ignoreThisSection = false; } // Orientation:default is portrait boolean portraitThis = true; if (pgSzThis.getOrient() != null) { portraitThis = pgSzThis.getOrient().equals(STPageOrientation.PORTRAIT); } boolean portraitNext = true; if (pgSzNext.getOrient() != null) { portraitNext = pgSzNext.getOrient().equals(STPageOrientation.PORTRAIT); } if (portraitThis != portraitNext) { ignoreThisSection = false; } } // TODO: handle cases where one or both pgSz elements are missing, // or H or W is missing. // Treat pgSz element missing as Legal size? } if (ignoreThisSection) { // In case there are some headers/footers that get inherited by the next section previousHF = new HeaderFooterPolicy(ppr.getSectPr(), previousHF, rels, evenAndOddHeaders); } else { currentSectionWrapper = createSectionWrapper( ppr.getSectPr(), previousHF, rels, evenAndOddHeaders, ++conversionSectionIndex, sectionContent, dummyPageNumbering); conversionSections.add(currentSectionWrapper); previousHF = currentSectionWrapper.getHeaderFooterPolicy(); sectionContent = new ArrayList<Object>(); } } } } sectionContent.add(o); // System.out.println(XmlUtils.marshaltoString(o, true)); } currentSectionWrapper = createSectionWrapper( document.getBody().getSectPr(), previousHF, rels, evenAndOddHeaders, ++conversionSectionIndex, sectionContent, dummyPageNumbering); conversionSections.add(currentSectionWrapper); return conversionSections; }