| 1 | /* |
|---|
| 2 | * Copyright 2007-2008, Plutext Pty Ltd. |
|---|
| 3 | * |
|---|
| 4 | * This file is part of docx4j. |
|---|
| 5 | |
|---|
| 6 | docx4j is licensed under the Apache License, Version 2.0 (the "License"); |
|---|
| 7 | you may not use this file except in compliance with the License. |
|---|
| 8 | |
|---|
| 9 | You may obtain a copy of the License at |
|---|
| 10 | |
|---|
| 11 | http://www.apache.org/licenses/LICENSE-2.0 |
|---|
| 12 | |
|---|
| 13 | Unless required by applicable law or agreed to in writing, software |
|---|
| 14 | distributed under the License is distributed on an "AS IS" BASIS, |
|---|
| 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|---|
| 16 | See the License for the specific language governing permissions and |
|---|
| 17 | limitations under the License. |
|---|
| 18 | |
|---|
| 19 | */ |
|---|
| 20 | |
|---|
| 21 | package org.docx4j.openpackaging.parts.WordprocessingML; |
|---|
| 22 | |
|---|
| 23 | import java.io.IOException; |
|---|
| 24 | |
|---|
| 25 | import org.apache.log4j.Logger; |
|---|
| 26 | import org.docx4j.XmlUtils; |
|---|
| 27 | import org.docx4j.jaxb.Context; |
|---|
| 28 | import org.docx4j.openpackaging.exceptions.Docx4JException; |
|---|
| 29 | import org.docx4j.openpackaging.exceptions.InvalidFormatException; |
|---|
| 30 | import org.docx4j.openpackaging.packages.WordprocessingMLPackage; |
|---|
| 31 | import org.docx4j.openpackaging.parts.JaxbXmlPart; |
|---|
| 32 | import org.docx4j.openpackaging.parts.PartName; |
|---|
| 33 | import org.docx4j.openpackaging.parts.relationships.Namespaces; |
|---|
| 34 | import org.docx4j.wml.DocDefaults; |
|---|
| 35 | import org.docx4j.wml.PPr; |
|---|
| 36 | import org.docx4j.wml.RPr; |
|---|
| 37 | import org.docx4j.wml.Style; |
|---|
| 38 | import org.docx4j.wml.Styles; |
|---|
| 39 | import org.docx4j.wml.Style.BasedOn; |
|---|
| 40 | |
|---|
| 41 | import javax.xml.bind.JAXBContext; |
|---|
| 42 | import javax.xml.bind.JAXBException; |
|---|
| 43 | import javax.xml.bind.Unmarshaller; |
|---|
| 44 | |
|---|
| 45 | |
|---|
| 46 | public final class StyleDefinitionsPart extends JaxbXmlPart<Styles> { |
|---|
| 47 | |
|---|
| 48 | private static Logger log = Logger.getLogger(StyleDefinitionsPart.class); |
|---|
| 49 | |
|---|
| 50 | public StyleDefinitionsPart(PartName partName) throws InvalidFormatException { |
|---|
| 51 | super(partName); |
|---|
| 52 | init(); |
|---|
| 53 | } |
|---|
| 54 | |
|---|
| 55 | public StyleDefinitionsPart() throws InvalidFormatException { |
|---|
| 56 | super(new PartName("/word/styles.xml")); |
|---|
| 57 | init(); |
|---|
| 58 | } |
|---|
| 59 | |
|---|
| 60 | public void init() { |
|---|
| 61 | // Used if this Part is added to [Content_Types].xml |
|---|
| 62 | setContentType(new org.docx4j.openpackaging.contenttype.ContentType( |
|---|
| 63 | org.docx4j.openpackaging.contenttype.ContentTypes.WORDPROCESSINGML_STYLES)); |
|---|
| 64 | |
|---|
| 65 | // Used when this Part is added to a rels |
|---|
| 66 | setRelationshipType(Namespaces.STYLES); |
|---|
| 67 | } |
|---|
| 68 | |
|---|
| 69 | // A variety of pre-defined styles, available for use in a StyleDefinitionsPart. |
|---|
| 70 | private static java.util.Map<String, org.docx4j.wml.Style> knownStyles = null; |
|---|
| 71 | |
|---|
| 72 | // private PropertyResolver propertyResolver; |
|---|
| 73 | |
|---|
| 74 | |
|---|
| 75 | |
|---|
| 76 | // @Override |
|---|
| 77 | // public Styles unmarshal(org.w3c.dom.Element el) throws JAXBException { |
|---|
| 78 | // |
|---|
| 79 | // // Note: This is used when we read in a pkg:package |
|---|
| 80 | // |
|---|
| 81 | // try { |
|---|
| 82 | // |
|---|
| 83 | // Unmarshaller u = jc.createUnmarshaller(); |
|---|
| 84 | // |
|---|
| 85 | // u.setEventHandler(new org.docx4j.jaxb.JaxbValidationEventHandler()); |
|---|
| 86 | // |
|---|
| 87 | // jaxbElement = (Styles) u.unmarshal( el ); |
|---|
| 88 | // |
|---|
| 89 | // return jaxbElement; |
|---|
| 90 | // |
|---|
| 91 | // } catch (JAXBException e) { |
|---|
| 92 | // // TODO Auto-generated catch block |
|---|
| 93 | // e.printStackTrace(); |
|---|
| 94 | // return null; |
|---|
| 95 | // } |
|---|
| 96 | // } |
|---|
| 97 | |
|---|
| 98 | |
|---|
| 99 | /** |
|---|
| 100 | * Unmarshal a default set of styles, useful when creating this |
|---|
| 101 | * part from scratch. |
|---|
| 102 | * |
|---|
| 103 | * @return the newly created root object of the java content tree |
|---|
| 104 | * |
|---|
| 105 | * @throws JAXBException |
|---|
| 106 | * If any unexpected errors occur while unmarshalling |
|---|
| 107 | */ |
|---|
| 108 | public Object unmarshalDefaultStyles() throws JAXBException { |
|---|
| 109 | |
|---|
| 110 | |
|---|
| 111 | // Throwable t = new Throwable(); |
|---|
| 112 | // t.printStackTrace(); |
|---|
| 113 | |
|---|
| 114 | java.io.InputStream is = null; |
|---|
| 115 | try { |
|---|
| 116 | //Works in Eclipse if the resource is in source/main/java |
|---|
| 117 | //is = getResource("styles.xml"); |
|---|
| 118 | |
|---|
| 119 | // Works in Eclipse - not absence of leading '/' |
|---|
| 120 | is = org.docx4j.utils.ResourceUtils.getResource( |
|---|
| 121 | "org/docx4j/openpackaging/parts/WordprocessingML/styles.xml"); |
|---|
| 122 | |
|---|
| 123 | // styles.xml defines a small subset of common styles |
|---|
| 124 | // (it is a much smaller set of styles than KnownStyles.xml) |
|---|
| 125 | |
|---|
| 126 | } catch (IOException e) { |
|---|
| 127 | // TODO Auto-generated catch block |
|---|
| 128 | e.printStackTrace(); |
|---|
| 129 | } |
|---|
| 130 | |
|---|
| 131 | return unmarshal( is ); // side-effect is to set jaxbElement |
|---|
| 132 | } |
|---|
| 133 | |
|---|
| 134 | private static void initKnownStyles() { |
|---|
| 135 | |
|---|
| 136 | // Throwable t = new Throwable(); |
|---|
| 137 | // t.printStackTrace(); |
|---|
| 138 | |
|---|
| 139 | java.io.InputStream is = null; |
|---|
| 140 | try { |
|---|
| 141 | is = org.docx4j.utils.ResourceUtils.getResource( |
|---|
| 142 | "org/docx4j/openpackaging/parts/WordprocessingML/KnownStyles.xml"); |
|---|
| 143 | |
|---|
| 144 | JAXBContext jc = Context.jc; |
|---|
| 145 | Unmarshaller u = jc.createUnmarshaller(); |
|---|
| 146 | u.setEventHandler(new org.docx4j.jaxb.JaxbValidationEventHandler()); |
|---|
| 147 | |
|---|
| 148 | org.docx4j.wml.Styles styles = (org.docx4j.wml.Styles)u.unmarshal( is ); |
|---|
| 149 | |
|---|
| 150 | knownStyles = new java.util.HashMap<String, org.docx4j.wml.Style>(); |
|---|
| 151 | |
|---|
| 152 | for ( org.docx4j.wml.Style s : styles.getStyle() ) { |
|---|
| 153 | knownStyles.put(s.getStyleId(), s); |
|---|
| 154 | } |
|---|
| 155 | |
|---|
| 156 | } catch (Exception e) { |
|---|
| 157 | // TODO Auto-generated catch block |
|---|
| 158 | e.printStackTrace(); |
|---|
| 159 | } |
|---|
| 160 | |
|---|
| 161 | |
|---|
| 162 | } |
|---|
| 163 | |
|---|
| 164 | public static java.util.Map<String, org.docx4j.wml.Style> getKnownStyles() { |
|---|
| 165 | if (knownStyles==null) { |
|---|
| 166 | initKnownStyles(); |
|---|
| 167 | } |
|---|
| 168 | return knownStyles; |
|---|
| 169 | } |
|---|
| 170 | |
|---|
| 171 | /* |
|---|
| 172 | * Manufacture styles from the following, so they can be used as the |
|---|
| 173 | * roots of our style trees. |
|---|
| 174 | * |
|---|
| 175 | * <w:docDefaults> |
|---|
| 176 | <w:rPrDefault> |
|---|
| 177 | <w:rPr> |
|---|
| 178 | <w:rFonts w:asciiTheme="minorHAnsi" w:eastAsiaTheme="minorHAnsi" w:hAnsiTheme="minorHAnsi" w:cstheme="minorBidi" /> |
|---|
| 179 | <w:sz w:val="22" /> |
|---|
| 180 | <w:szCs w:val="22" /> |
|---|
| 181 | <w:lang w:val="en-US" w:eastAsia="en-US" w:bidi="ar-SA" /> |
|---|
| 182 | </w:rPr> |
|---|
| 183 | </w:rPrDefault> |
|---|
| 184 | <w:pPrDefault> |
|---|
| 185 | <w:pPr> |
|---|
| 186 | <w:spacing w:after="200" w:line="276" w:lineRule="auto" /> |
|---|
| 187 | </w:pPr> |
|---|
| 188 | </w:pPrDefault> |
|---|
| 189 | </w:docDefaults> |
|---|
| 190 | |
|---|
| 191 | */ |
|---|
| 192 | protected void createVirtualStylesForDocDefaults() throws Docx4JException { |
|---|
| 193 | |
|---|
| 194 | Style pDefault = Context.getWmlObjectFactory().createStyle(); |
|---|
| 195 | |
|---|
| 196 | String ROOT_NAME = "DocDefaults"; |
|---|
| 197 | |
|---|
| 198 | pDefault.setStyleId(ROOT_NAME); |
|---|
| 199 | pDefault.setType("paragraph"); |
|---|
| 200 | |
|---|
| 201 | // Initialise docDefaults |
|---|
| 202 | DocDefaults docDefaults = this.jaxbElement.getDocDefaults(); |
|---|
| 203 | |
|---|
| 204 | if (docDefaults == null) { |
|---|
| 205 | // The only way this can happen is if the |
|---|
| 206 | // styles definition part is missing the docDefaults element |
|---|
| 207 | // (these are present in docs created from Word, and |
|---|
| 208 | // in our default styles, so maybe the user created it using |
|---|
| 209 | // some 3rd party program?) |
|---|
| 210 | try { |
|---|
| 211 | |
|---|
| 212 | docDefaults = (DocDefaults) XmlUtils |
|---|
| 213 | .unmarshalString(docDefaultsString); |
|---|
| 214 | } catch (JAXBException e) { |
|---|
| 215 | throw new Docx4JException("Problem unmarshalling " |
|---|
| 216 | + docDefaultsString, e); |
|---|
| 217 | } |
|---|
| 218 | } |
|---|
| 219 | |
|---|
| 220 | // Setup documentDefaultPPr |
|---|
| 221 | PPr documentDefaultPPr; |
|---|
| 222 | if (docDefaults.getPPrDefault() == null) { |
|---|
| 223 | try { |
|---|
| 224 | documentDefaultPPr = (PPr) XmlUtils |
|---|
| 225 | .unmarshalString(pPrDefaultsString); |
|---|
| 226 | } catch (JAXBException e) { |
|---|
| 227 | throw new Docx4JException("Problem unmarshalling " |
|---|
| 228 | + pPrDefaultsString, e); |
|---|
| 229 | } |
|---|
| 230 | |
|---|
| 231 | } else { |
|---|
| 232 | documentDefaultPPr = docDefaults.getPPrDefault().getPPr(); |
|---|
| 233 | } |
|---|
| 234 | |
|---|
| 235 | // Setup documentDefaultRPr |
|---|
| 236 | RPr documentDefaultRPr; |
|---|
| 237 | if (docDefaults.getRPrDefault() == null) { |
|---|
| 238 | try { |
|---|
| 239 | documentDefaultRPr = (RPr) XmlUtils |
|---|
| 240 | .unmarshalString(rPrDefaultsString); |
|---|
| 241 | } catch (JAXBException e) { |
|---|
| 242 | throw new Docx4JException("Problem unmarshalling " |
|---|
| 243 | + rPrDefaultsString, e); |
|---|
| 244 | } |
|---|
| 245 | } else { |
|---|
| 246 | documentDefaultRPr = docDefaults.getRPrDefault().getRPr(); |
|---|
| 247 | } |
|---|
| 248 | |
|---|
| 249 | pDefault.setPPr(documentDefaultPPr); |
|---|
| 250 | pDefault.setRPr(documentDefaultRPr); |
|---|
| 251 | |
|---|
| 252 | // Now point Normal at this |
|---|
| 253 | Style normal = getDefaultParagraphStyle(); |
|---|
| 254 | if (normal==null) { |
|---|
| 255 | log.warn("No default paragraph style!!"); |
|---|
| 256 | normal = Context.getWmlObjectFactory().createStyle(); |
|---|
| 257 | normal.setType("paragraph"); |
|---|
| 258 | normal.setStyleId("Normal"); |
|---|
| 259 | |
|---|
| 260 | org.docx4j.wml.Style.Name n = Context.getWmlObjectFactory().createStyleName(); |
|---|
| 261 | n.setVal("Normal"); |
|---|
| 262 | normal.setName(n); |
|---|
| 263 | this.jaxbElement.getStyle().add(normal); |
|---|
| 264 | } |
|---|
| 265 | |
|---|
| 266 | BasedOn based = Context.getWmlObjectFactory().createStyleBasedOn(); |
|---|
| 267 | based.setVal(ROOT_NAME); |
|---|
| 268 | normal.setBasedOn(based); |
|---|
| 269 | |
|---|
| 270 | // Finally, add it to styles |
|---|
| 271 | this.jaxbElement.getStyle().add(pDefault); |
|---|
| 272 | |
|---|
| 273 | } |
|---|
| 274 | |
|---|
| 275 | private Style getStyleById(String id) { |
|---|
| 276 | |
|---|
| 277 | for ( org.docx4j.wml.Style s : this.jaxbElement.getStyle() ) { |
|---|
| 278 | if( s.getStyleId().equals(id) ) { |
|---|
| 279 | return s; |
|---|
| 280 | } |
|---|
| 281 | } |
|---|
| 282 | return null; |
|---|
| 283 | } |
|---|
| 284 | |
|---|
| 285 | private Style defaultCharacterStyle; |
|---|
| 286 | public Style getDefaultCharacterStyle() { |
|---|
| 287 | |
|---|
| 288 | if (defaultCharacterStyle==null) { |
|---|
| 289 | defaultCharacterStyle = getDefaultStyle("character"); |
|---|
| 290 | } |
|---|
| 291 | // OpenOffice conversion to docx |
|---|
| 292 | // doesn't necessarily contain a default character style |
|---|
| 293 | // so manufacture one |
|---|
| 294 | if (defaultCharacterStyle==null) { |
|---|
| 295 | try { |
|---|
| 296 | defaultCharacterStyle = (Style)XmlUtils.unmarshalString(DEFAULT_CHARACTER_STYLE_DEFAULT); |
|---|
| 297 | this.jaxbElement.getStyle().add(defaultCharacterStyle); |
|---|
| 298 | } catch (JAXBException e) { |
|---|
| 299 | e.printStackTrace(); |
|---|
| 300 | } |
|---|
| 301 | } |
|---|
| 302 | return defaultCharacterStyle; |
|---|
| 303 | } |
|---|
| 304 | |
|---|
| 305 | private final static String DEFAULT_CHARACTER_STYLE_DEFAULT = "<w:style w:type=\"character\" w:default=\"1\" w:styleId=\"DefaultParagraphFont\" " + Namespaces.W_NAMESPACE_DECLARATION + "><w:name w:val=\"Default Paragraph Font\" /></w:style>"; |
|---|
| 306 | |
|---|
| 307 | |
|---|
| 308 | private Style defaultParagraphStyle; |
|---|
| 309 | public Style getDefaultParagraphStyle() { |
|---|
| 310 | |
|---|
| 311 | if (defaultParagraphStyle==null) { |
|---|
| 312 | defaultParagraphStyle = getDefaultStyle("paragraph"); |
|---|
| 313 | } |
|---|
| 314 | // OpenOffice conversion to docx |
|---|
| 315 | // doesn't set default, so use name |
|---|
| 316 | // (alternatively, could use id=style0) |
|---|
| 317 | if (defaultParagraphStyle==null) { |
|---|
| 318 | for ( org.docx4j.wml.Style s : this.jaxbElement.getStyle() ) { |
|---|
| 319 | if( s.getType().equals("paragraph") |
|---|
| 320 | && s.getName().getVal().equals("Default") ) { |
|---|
| 321 | log.info("Style with name " + s.getName().getVal() + ", id '" + s.getStyleId() + "' is default " + s.getType() + " style"); |
|---|
| 322 | defaultParagraphStyle=s; |
|---|
| 323 | break; |
|---|
| 324 | } |
|---|
| 325 | } |
|---|
| 326 | } |
|---|
| 327 | // try using id=style0 |
|---|
| 328 | if (defaultParagraphStyle==null) { |
|---|
| 329 | for ( org.docx4j.wml.Style s : this.jaxbElement.getStyle() ) { |
|---|
| 330 | if( s.getType().equals("paragraph") |
|---|
| 331 | && s.getStyleId().equals("style0") ) { |
|---|
| 332 | log.info("Style with name " + s.getName().getVal() + ", id '" + s.getStyleId() + "' is default " + s.getType() + " style"); |
|---|
| 333 | defaultParagraphStyle=s; |
|---|
| 334 | break; |
|---|
| 335 | } |
|---|
| 336 | } |
|---|
| 337 | } |
|---|
| 338 | |
|---|
| 339 | return defaultParagraphStyle; |
|---|
| 340 | } |
|---|
| 341 | private Style getDefaultStyle(String type) { |
|---|
| 342 | |
|---|
| 343 | for ( org.docx4j.wml.Style s : this.jaxbElement.getStyle() ) { |
|---|
| 344 | if( s.isDefault() && s.getType().equals(type)) { |
|---|
| 345 | log.info("Style with name " + s.getName().getVal() + ", id '" + s.getStyleId() + "' is default " + s.getType() + " style"); |
|---|
| 346 | return s; |
|---|
| 347 | } |
|---|
| 348 | } |
|---|
| 349 | return null; |
|---|
| 350 | } |
|---|
| 351 | |
|---|
| 352 | |
|---|
| 353 | final static String wNamespaceDec = " xmlns:w=\"" + Namespaces.NS_WORD12 + "\""; |
|---|
| 354 | |
|---|
| 355 | public final static String rPrDefaultsString = "<w:rPr" + wNamespaceDec + ">" |
|---|
| 356 | // Word 2007 still uses Times New Roman if there is no theme part, and we'd like to replicate that |
|---|
| 357 | // + "<w:rFonts w:asciiTheme=\"minorHAnsi\" w:eastAsiaTheme=\"minorHAnsi\" w:hAnsiTheme=\"minorHAnsi\" w:cstheme=\"minorBidi\" />" |
|---|
| 358 | + "<w:sz w:val=\"22\" />" |
|---|
| 359 | + "<w:szCs w:val=\"22\" />" |
|---|
| 360 | + "<w:lang w:val=\"en-US\" w:eastAsia=\"en-US\" w:bidi=\"ar-SA\" />" |
|---|
| 361 | + "</w:rPr>"; |
|---|
| 362 | public final static String pPrDefaultsString = "<w:pPr" + wNamespaceDec + ">" |
|---|
| 363 | + "<w:spacing w:after=\"200\" w:line=\"276\" w:lineRule=\"auto\" />" |
|---|
| 364 | + "</w:pPr>"; |
|---|
| 365 | public final static String docDefaultsString = "<w:docDefaults" + wNamespaceDec + ">" |
|---|
| 366 | + "<w:rPrDefault>" |
|---|
| 367 | + rPrDefaultsString |
|---|
| 368 | + "</w:rPrDefault>" |
|---|
| 369 | + "<w:pPrDefault>" |
|---|
| 370 | + pPrDefaultsString |
|---|
| 371 | + "</w:pPrDefault>" |
|---|
| 372 | + "</w:docDefaults>"; |
|---|
| 373 | |
|---|
| 374 | |
|---|
| 375 | |
|---|
| 376 | // public static void main(String[] args) throws Exception { |
|---|
| 377 | // |
|---|
| 378 | // StyleDefinitionsPart sdp = new StyleDefinitionsPart (); |
|---|
| 379 | // sdp.initKnownStyles(); |
|---|
| 380 | // |
|---|
| 381 | // } |
|---|
| 382 | } |
|---|