/** * In Word, adjacent paragraphs with the same borders are enclosed in a single border (unless * bullets/numbering apply). * * <p>Similarly with shading. (If the 2 paragraphs are shaded different colors, then the color of * the first extends to the start of the second, so there is no white strip between them). * * <p>To do the same in HTML and PDF output, we put matching paragraphs into a content control, * and set the border/shading on that. This gives us an appropriate div or fo:block. */ public static void groupAdjacentBorders(Body body) { List<Object> bodyElts = body.getContent(); List<Object> groupedContent = null; groupedContent = groupBodyContent(bodyElts); if (groupedContent != null) { body.getContent().clear(); body.getContent().addAll(groupedContent); } }
/** * Traverse the document, and return a map of all styles which are used directly in the document. * (IE this does not include styles on which others are just BasedOn). * * @return */ public Set<String> getStylesInUse() { org.docx4j.wml.Document wmlDocumentEl = (org.docx4j.wml.Document) this.getJaxbElement(); Body body = wmlDocumentEl.getBody(); List<Object> bodyChildren = body.getContent(); Set<String> stylesInUse = new HashSet<String>(); FontAndStyleFinder finder = new FontAndStyleFinder(null, null, stylesInUse); finder.defaultCharacterStyle = this.getStyleDefinitionsPart().getDefaultCharacterStyle(); finder.defaultParagraphStyle = this.getStyleDefinitionsPart().getDefaultParagraphStyle(); new TraversalUtil(bodyChildren, finder); finder.finish(); // Styles in headers, footers? RelationshipsPart rp = this.getRelationshipsPart(); if (rp != null) { for (Relationship r : rp.getRelationships().getRelationship()) { Part part = rp.getPart(r); if (part instanceof FooterPart) { Ftr ftr = ((FooterPart) part).getJaxbElement(); finder.walkJAXBElements(ftr); } else if (part instanceof HeaderPart) { Hdr hdr = ((HeaderPart) part).getJaxbElement(); finder.walkJAXBElements(hdr); } } } // Styles in endnotes, footnotes? if (this.getEndNotesPart() != null) { log.debug("Looking at endnotes"); CTEndnotes endnotes = this.getEndNotesPart().getJaxbElement(); finder.walkJAXBElements(endnotes); } if (this.getFootnotesPart() != null) { log.debug("Looking at footnotes"); CTFootnotes footnotes = this.getFootnotesPart().getJaxbElement(); finder.walkJAXBElements(footnotes); } // Comments if (this.getCommentsPart() != null) { log.debug("Looking at comments"); Comments comments = this.getCommentsPart().getJaxbElement(); finder.walkJAXBElements(comments); } return stylesInUse; }
protected String getMceIgnorable(Body body) { List<Object> content = body.getContent(); // To avoid the traversing a large docx, // we'll try to use a hack here. // The idea is to force JAXB to include // namespace declarations for w14 and w15, by // using them in an innocuous manner. // It works by adding the following to the first // paragraph encountered: // <w:p w14:textId="fdcbd571" w14:paraId="fdcbd571" > // <w:pPr> // <w15:collapsed w:val="false"/> // </w:pPr> // // If this turns out to cause problems, it could be // made configurable in docx4j.properties if (content.size() == 0) { return null; } P p = null; for (Object o : content) { if (o instanceof P) { p = (P) o; break; } } if (p == null) { // No top level paragraph, so // do the work of traversing the document log.debug("traversing for w14, w15"); IgnorablePrefixFinder finder = new IgnorablePrefixFinder(); if (body.getSectPr() != null && body.getSectPr().getFootnoteColumns() != null) { finder.needW15 = true; } new TraversalUtil(content, finder); String mceIgnorableVal = ""; if (finder.needW14) { mceIgnorableVal = "w14"; } if (finder.needW15) { mceIgnorableVal += " w15"; } return mceIgnorableVal; } else { // The quick hack // For W14, we'll check/set paraId, textId if (p.getParaId() == null) { // Values MUST be greater than 0 and less than 0x80000000 // So let's String uuid = java.util.UUID.randomUUID().toString(); // That's 32 digits, but 8'll do nicely /* * 8 can create a number too large - using 7 * Bob Fleischman - July 24, 2014 */ uuid = uuid.replace("-", "").substring(0, 7); p.setParaId(uuid); p.setTextId(uuid); } // For W15, collapse /* * Bob Fleischman - commented this out to generat docs without the namespace issue PPr ppr = p.getPPr(); if (ppr==null) { ppr = Context.getWmlObjectFactory().createPPr(); p.setPPr(ppr); } if (ppr.getCollapsed()==null) { BooleanDefaultTrue notCollapsed = new BooleanDefaultTrue(); notCollapsed.setVal(Boolean.FALSE); ppr.setCollapsed(notCollapsed); } */ } return "w14 w15"; }
/** * Traverse the document, looking for fonts which have been applied, either directly, or via a * style. * * @return */ public Set<String> fontsInUse() { log.info("fontsInUse.."); getPropertyResolver(); // this inits our virtual DocDefaults style // Setup Set<String> fontsDiscovered = new java.util.HashSet<String>(); // // Keep track of styles we encounter, so we can // // inspect these for fonts // Set<String> stylesInUse = new java.util.HashSet<String>(); // // org.docx4j.wml.Styles styles = null; // if (this.getStyleDefinitionsPart()!=null) { // styles = (org.docx4j.wml.Styles)this.getStyleDefinitionsPart().getJaxbElement(); // } // // It is convenient to have a HashMap of styles // Map<String, Style> stylesDefined = new java.util.HashMap<String, Style>(); // if (styles!=null) { // for (Iterator<Style> iter = styles.getStyle().iterator(); iter.hasNext();) { // Style s = iter.next(); // stylesDefined.put(s.getStyleId(), s); // } // } // // We need to know what fonts and styles are used in the document org.docx4j.wml.Document wmlDocumentEl = (org.docx4j.wml.Document) this.getJaxbElement(); Body body = wmlDocumentEl.getBody(); List<Object> bodyChildren = body.getContent(); FontDiscoveryCharacterVisitor visitor = new FontDiscoveryCharacterVisitor(fontsDiscovered); RunFontSelector runFontSelector = new RunFontSelector( (WordprocessingMLPackage) this.pack, visitor, RunFontActionType.DISCOVERY); FontAndStyleFinder finder = new FontAndStyleFinder(runFontSelector, fontsDiscovered, null); finder.defaultCharacterStyle = this.getStyleDefinitionsPart().getDefaultCharacterStyle(); finder.defaultParagraphStyle = this.getStyleDefinitionsPart().getDefaultParagraphStyle(); new TraversalUtil(bodyChildren, finder); // finder.finish(); fontsDiscovered.add(runFontSelector.getDefaultFont()); // fonts in headers, footers? RelationshipsPart rp = this.getRelationshipsPart(); if (rp != null) { for (Relationship r : rp.getRelationships().getRelationship()) { Part part = rp.getPart(r); if (part instanceof FooterPart) { Ftr ftr = ((FooterPart) part).getJaxbElement(); finder.walkJAXBElements(ftr); } else if (part instanceof HeaderPart) { Hdr hdr = ((HeaderPart) part).getJaxbElement(); finder.walkJAXBElements(hdr); } } } // Styles in endnotes, footnotes? if (this.getEndNotesPart() != null) { log.debug("Looking at endnotes"); CTEndnotes endnotes = this.getEndNotesPart().getJaxbElement(); finder.walkJAXBElements(endnotes); } if (this.getFootnotesPart() != null) { log.debug("Looking at footnotes"); CTFootnotes footnotes = this.getFootnotesPart().getJaxbElement(); finder.walkJAXBElements(footnotes); } // Comments if (this.getCommentsPart() != null) { log.debug("Looking at comments"); Comments comments = this.getCommentsPart().getJaxbElement(); finder.walkJAXBElements(comments); } // Add fonts used in the styles we discovered // .. 2013 03 10: no longer necessary // Fonts can also be used in the numbering part // For now, treat any font mentioned in that part as in use. // Ideally, we'd only register fonts used in numbering levels // that were actually used in the document if (getNumberingDefinitionsPart() != null) { Numbering numbering = getNumberingDefinitionsPart().getJaxbElement(); for (Numbering.AbstractNum abstractNumNode : numbering.getAbstractNum()) { for (Lvl lvl : abstractNumNode.getLvl()) { if (lvl.getRPr() != null && lvl.getRPr().getRFonts() != null) { String fontName = lvl.getRPr().getRFonts().getAscii(); if (fontName != null) { fontsDiscovered.add(fontName); log.debug( "Registered " + fontName + " for abstract list " + abstractNumNode.getAbstractNumId() + " lvl " + lvl.getIlvl()); } } } } } return fontsDiscovered; }
public static WordprocessingMLPackage createPackage(PageSizePaper sz, boolean landscape) throws InvalidFormatException { // Create a package WordprocessingMLPackage wmlPack = new WordprocessingMLPackage(); // Create main document part MainDocumentPart wordDocumentPart = new MainDocumentPart(); // Create main document part content org.docx4j.wml.ObjectFactory factory = Context.getWmlObjectFactory(); org.docx4j.wml.Body body = factory.createBody(); org.docx4j.wml.Document wmlDocumentEl = factory.createDocument(); wmlDocumentEl.setBody(body); // Create a basic sectPr using our Page model PageDimensions page = new PageDimensions(); page.setPgSize(sz, landscape); SectPr sectPr = factory.createSectPr(); body.setSectPr(sectPr); sectPr.setPgSz(page.getPgSz()); sectPr.setPgMar(page.getPgMar()); // Put the content in the part wordDocumentPart.setJaxbElement(wmlDocumentEl); // Add the main document part to the package relationships // (creating it if necessary) wmlPack.addTargetPart(wordDocumentPart); // Create a styles part Part stylesPart = new org.docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart(); try { ((org.docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart) stylesPart) .unmarshalDefaultStyles(); // Add the styles part to the main document part relationships // (creating it if necessary) wordDocumentPart.addTargetPart(stylesPart); // NB - add it to main doc part, not package! } catch (Exception e) { // TODO: handle exception // e.printStackTrace(); log.error(e.getMessage(), e); } // Metadata: docx4j 2.7.1 can populate some of this from docx4j.properties // See SaveToZipFile DocPropsCorePart core = new DocPropsCorePart(); org.docx4j.docProps.core.ObjectFactory coreFactory = new org.docx4j.docProps.core.ObjectFactory(); core.setJaxbElement(coreFactory.createCoreProperties()); wmlPack.addTargetPart(core); DocPropsExtendedPart app = new DocPropsExtendedPart(); org.docx4j.docProps.extended.ObjectFactory extFactory = new org.docx4j.docProps.extended.ObjectFactory(); app.setJaxbElement(extFactory.createProperties()); wmlPack.addTargetPart(app); // Return the new package return wmlPack; }
public static void main(String[] args) throws Exception { WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage(); MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart(); CTSettings ct = new CTSettings(); DocumentSettingsPart dsp = documentPart.getDocumentSettingsPart(); if (dsp == null) { dsp = new DocumentSettingsPart(); CTView ctView = Context.getWmlObjectFactory().createCTView(); ctView.setVal(STView.PRINT); ct.setView(ctView); BooleanDefaultTrue b = new BooleanDefaultTrue(); b.setVal(true); ct.setUpdateFields(b); dsp.setJaxbElement(ct); documentPart.addTargetPart(dsp); } org.docx4j.wml.Document wmlDocumentEl = (org.docx4j.wml.Document) documentPart.getJaxbElement(); Body body = wmlDocumentEl.getBody(); ObjectFactory factory = Context.getWmlObjectFactory(); /* * Create the following: * * <w:p> <w:r> <w:fldChar w:dirty="true" w:fldCharType="begin"/> * <w:instrText xml:space="preserve">TOC \o "1-3" \h \z \ u * \h</w:instrText> </w:r> <w:r/> <w:r> <w:fldChar w:fldCharType="end"/> * </w:r> </w:p> */ P paragraphForTOC = factory.createP(); R r = factory.createR(); FldChar fldchar = factory.createFldChar(); fldchar.setFldCharType(STFldCharType.BEGIN); fldchar.setDirty(true); r.getContent().add(getWrappedFldChar(fldchar)); paragraphForTOC.getContent().add(r); R r1 = factory.createR(); Text txt = new Text(); txt.setSpace("preserve"); txt.setValue("TOC \\o \"1-3\" \\h \\z \\u "); r.getContent().add(factory.createRInstrText(txt)); paragraphForTOC.getContent().add(r1); FldChar fldcharend = factory.createFldChar(); fldcharend.setFldCharType(STFldCharType.END); R r2 = factory.createR(); r2.getContent().add(getWrappedFldChar(fldcharend)); paragraphForTOC.getContent().add(r2); body.getContent().add(paragraphForTOC); documentPart.addStyledParagraphOfText("Heading1", "Hello 1"); documentPart.addStyledParagraphOfText("Heading2", "Hello 2"); documentPart.addStyledParagraphOfText("Heading3", "Hello 3"); documentPart.addStyledParagraphOfText("Heading1", "Hello 1"); wordMLPackage.save( new java.io.File(System.getProperty("user.dir") + "/OUT_TableOfContentsAdd.docx")); }
private void setPageMargins() { try { Body body = wordMLPackage.getMainDocumentPart().getContents().getBody(); Padding padding = bean.getReportLayout().getPagePadding(); PageDimensions page = new PageDimensions(); PgMar pgMar = page.getPgMar(); pgMar.setBottom(BigInteger.valueOf(pixelsToDxa(padding.getBottom()))); pgMar.setTop(BigInteger.valueOf(pixelsToDxa(padding.getTop()))); pgMar.setLeft(BigInteger.valueOf(pixelsToDxa(padding.getLeft()))); pgMar.setRight(BigInteger.valueOf(pixelsToDxa(padding.getRight()))); SectPr sectPr = factory.createSectPr(); body.setSectPr(sectPr); sectPr.setPgMar(pgMar); } catch (Docx4JException e) { e.printStackTrace(); } }