diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 5da84b934..74812dc6e 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 51134 - Support for adding Numbering and Styles to a XWPF document that doesn't already have them 51273 - Formula Value Cache fix for repeated evaluations 51171 - Improved performance of SharedValueManager 51236 - XSSF set colour support for black/white to match getter diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java index a1f23cef8..f138a6dfc 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java @@ -62,6 +62,7 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSdtBlock; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyles; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.NumberingDocument; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CommentsDocument; import org.openxmlformats.schemas.wordprocessingml.x2006.main.DocumentDocument; import org.openxmlformats.schemas.wordprocessingml.x2006.main.EndnotesDocument; @@ -644,6 +645,23 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { out.close(); } + /** + * Gets the index of the relation we're trying to create + * @param relation + * @return i + */ + private int getRelationIndex(XWPFRelation relation) { + List relations = getRelations(); + int i = 1; + for (Iterator it = relations.iterator(); it.hasNext() ; ) { + POIXMLDocumentPart item = it.next(); + if (item.getPackageRelationship().getRelationshipType().equals(relation.getRelation())) { + i++; + } + } + return i; + } + /** * Appends a new paragraph to this document * @return a new paragraph @@ -654,7 +672,58 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { paragraphs.add(p); return p; } - + + /** + * Creates an empty numbering if one does not already exist and sets the numbering member + * @return numbering + */ + public XWPFNumbering createNumbering() { + if(numbering == null) { + NumberingDocument numberingDoc = NumberingDocument.Factory.newInstance(); + + XWPFRelation relation = XWPFRelation.NUMBERING; + int i = getRelationIndex(relation); + + XWPFNumbering wrapper = (XWPFNumbering)createRelationship(relation, XWPFFactory.getInstance(), i); + wrapper.setNumbering(numberingDoc.addNewNumbering()); + numbering = wrapper; + } + + return numbering; + } + + /** + * Creates an empty styles for the document if one does not already exist + * @return styles + */ + public XWPFStyles createStyles() { + if(styles == null) { + StylesDocument stylesDoc = StylesDocument.Factory.newInstance(); + + XWPFRelation relation = XWPFRelation.STYLES; + int i = getRelationIndex(relation); + + XWPFStyles wrapper = (XWPFStyles)createRelationship(relation, XWPFFactory.getInstance(), i); + wrapper.setStyles(stylesDoc.addNewStyles()); + styles = wrapper; + } + + return styles; + } + + + public XWPFFootnote addEndnote(CTFtnEdn note) { + XWPFFootnote footnote = new XWPFFootnote(this, note); + footnotes.put(note.getId().intValue(), footnote); + return footnote; + } + + public XWPFFootnote addFootnote(CTFtnEdn note) { + XWPFFootnote endnote = new XWPFFootnote(this, note); + endnotes.put(note.getId().intValue(), endnote); + return endnote; + } + /** * remove a BodyElement from bodyElements array list * @param pos diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java index e1f2a9046..9e4fc7d08 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java @@ -57,7 +57,16 @@ public class XWPFNumbering extends POIXMLDocumentPart { isNew = true; onDocumentRead(); } - + + /** + * create a new XWPFNumbering object for use in a new document + */ + public XWPFNumbering(){ + abstractNums = new ArrayList(); + nums = new ArrayList(); + isNew = true; + } + /** * read numbering form an existing package */ @@ -108,6 +117,14 @@ public class XWPFNumbering extends POIXMLDocumentPart { out.close(); } + + /** + * Sets the ctNumbering + * @param numbering + */ + public void setNumbering(CTNumbering numbering){ + ctNumbering = numbering; + } /** @@ -149,6 +166,19 @@ public class XWPFNumbering extends POIXMLDocumentPart { return ctNum.getNumId(); } + /** + * Add a new num with an abstractNumID and a numID + * @param abstractNumId + * @param numID + */ + public void addNum(BigInteger abstractNumID, BigInteger numID){ + CTNum ctNum = this.ctNumbering.addNewNum(); + ctNum.addNewAbstractNumId(); + ctNum.getAbstractNumId().setVal(abstractNumID); + ctNum.setNumId(numID); + XWPFNum num = new XWPFNum(ctNum, this); + nums.add(num); + } /** * get Num by NumID @@ -207,9 +237,13 @@ public class XWPFNumbering extends POIXMLDocumentPart { */ public BigInteger addAbstractNum(XWPFAbstractNum abstractNum){ int pos = abstractNums.size(); - ctNumbering.addNewAbstractNum(); - abstractNum.getAbstractNum().setAbstractNumId(BigInteger.valueOf(pos)); - ctNumbering.setAbstractNumArray(pos, abstractNum.getAbstractNum()); + if(abstractNum.getAbstractNum() != null){ // Use the current CTAbstractNum if it exists + ctNumbering.addNewAbstractNum().set(abstractNum.getAbstractNum()); + } else { + ctNumbering.addNewAbstractNum(); + abstractNum.getAbstractNum().setAbstractNumId(BigInteger.valueOf(pos)); + ctNumbering.setAbstractNumArray(pos, abstractNum.getAbstractNum()); + } abstractNums.add(abstractNum); return abstractNum.getCTAbstractNum().getAbstractNumId(); } diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java index 46198823a..86895032e 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.lang.String; import javax.xml.namespace.QName; @@ -38,6 +39,11 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyle; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyles; import org.openxmlformats.schemas.wordprocessingml.x2006.main.StylesDocument; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPrDefault; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTLanguage; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFonts; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDocDefaults; /** * @author Philipp Epp * @@ -58,6 +64,14 @@ public class XWPFStyles extends POIXMLDocumentPart{ super(part, rel); onDocumentRead(); } + + /** + * Construct XWPFStyles from scratch for a new document. + */ + public XWPFStyles() { + listStyle = new ArrayList(); + } + /** * Read document */ @@ -95,7 +109,13 @@ public class XWPFStyles extends POIXMLDocumentPart{ } - + /** + * Sets the ctStyles + * @param styles + */ + public void setStyles(CTStyles styles) { + ctStyles = styles; + } /** * checks whether style with styleID exist @@ -173,6 +193,97 @@ public class XWPFStyles extends POIXMLDocumentPart{ return usedStyleList; } + /** + * Sets the default spelling language on ctStyles DocDefaults parameter + * @param strSpellingLanguage + */ + public void setSpellingLanguage(String strSpellingLanguage) { + CTDocDefaults docDefaults = null; + CTRPr runProps = null; + CTLanguage lang = null; + + // Just making sure we use the members that have already been defined + if(ctStyles.isSetDocDefaults()) { + docDefaults = ctStyles.getDocDefaults(); + if(docDefaults.isSetRPrDefault()) { + CTRPrDefault RPrDefault = docDefaults.getRPrDefault(); + if(RPrDefault.isSetRPr()) { + runProps = RPrDefault.getRPr(); + if(runProps.isSetLang()) + lang = runProps.getLang(); + } + } + } + + if(docDefaults == null) + docDefaults = ctStyles.addNewDocDefaults(); + if(runProps == null) + runProps = docDefaults.addNewRPrDefault().addNewRPr(); + if(lang == null) + lang = runProps.addNewLang(); + + lang.setVal(strSpellingLanguage); + lang.setBidi(strSpellingLanguage); + } + + /** + * Sets the default East Asia spelling language on ctStyles DocDefaults parameter + * @param strEastAsia + */ + public void setEastAsia(String strEastAsia) { + CTDocDefaults docDefaults = null; + CTRPr runProps = null; + CTLanguage lang = null; + + // Just making sure we use the members that have already been defined + if(ctStyles.isSetDocDefaults()) { + docDefaults = ctStyles.getDocDefaults(); + if(docDefaults.isSetRPrDefault()) { + CTRPrDefault RPrDefault = docDefaults.getRPrDefault(); + if(RPrDefault.isSetRPr()) { + runProps = RPrDefault.getRPr(); + if(runProps.isSetLang()) + lang = runProps.getLang(); + } + } + } + + if(docDefaults == null) + docDefaults = ctStyles.addNewDocDefaults(); + if(runProps == null) + runProps = docDefaults.addNewRPrDefault().addNewRPr(); + if(lang == null) + lang = runProps.addNewLang(); + + lang.setEastAsia(strEastAsia); + } + + /** + * Sets the default font on ctStyles DocDefaults parameter + * @param fonts + */ + public void setDefaultFonts(CTFonts fonts) { + CTDocDefaults docDefaults = null; + CTRPr runProps = null; + + // Just making sure we use the members that have already been defined + if(ctStyles.isSetDocDefaults()) { + docDefaults = ctStyles.getDocDefaults(); + if(docDefaults.isSetRPrDefault()) { + CTRPrDefault RPrDefault = docDefaults.getRPrDefault(); + if(RPrDefault.isSetRPr()) { + runProps = RPrDefault.getRPr(); + } + } + } + + if(docDefaults == null) + docDefaults = ctStyles.addNewDocDefaults(); + if(runProps == null) + runProps = docDefaults.addNewRPrDefault().addNewRPr(); + + runProps.setRFonts(fonts); + } /**