001package com.hfg.xml.msofficexml.docx.wordprocessingml; 002 003import java.awt.*; 004import java.util.HashMap; 005import java.util.Map; 006 007import com.hfg.css.CSSDeclaration; 008import com.hfg.graphics.units.GfxSize; 009import com.hfg.graphics.units.GfxUnits; 010import com.hfg.graphics.units.Points; 011import com.hfg.graphics.ColorUtil; 012import com.hfg.xml.XMLName; 013import com.hfg.xml.XMLTag; 014import com.hfg.xml.XMLizable; 015import com.hfg.xml.msofficexml.docx.Docx; 016import com.hfg.xml.msofficexml.docx.wordprocessingml.style.WmlHighlightColor; 017import com.hfg.xml.msofficexml.docx.wordprocessingml.style.WmlShading; 018import com.hfg.xml.msofficexml.docx.wordprocessingml.style.WmlSpacing; 019import com.hfg.xml.msofficexml.docx.wordprocessingml.style.WmlTextBorder; 020 021//------------------------------------------------------------------------------ 022/** 023 Text run properties for Docx's Office Open XML documents. 024 025 @author J. Alex Taylor, hairyfatguy.com 026 */ 027//------------------------------------------------------------------------------ 028// com.hfg XML/HTML Coding Library 029// 030// This library is free software; you can redistribute it and/or 031// modify it under the terms of the GNU Lesser General Public 032// License as published by the Free Software Foundation; either 033// version 2.1 of the License, or (at your option) any later version. 034// 035// This library is distributed in the hope that it will be useful, 036// but WITHOUT ANY WARRANTY; without even the implied warranty of 037// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 038// Lesser General Public License for more details. 039// 040// You should have received a copy of the GNU Lesser General Public 041// License along with this library; if not, write to the Free Software 042// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 043// 044// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 045// jataylor@hairyfatguy.com 046//------------------------------------------------------------------------------ 047// 048// Note: In section 2.4.1 it states <span style='font-style:italic'>"It should also be noted that a pPr element 049// may contain a set of run properties within a rPr element - these properties 050// are applied to the run which contains the glyph which represents the paragraph 051// mark and not the entire paragraph."</span> It seems very inefficient to structure things 052// this way but the format seems to force you to duplicate the run properties for every text run in a paragraph. 053 054public class WmlTextRunProperties extends WmlXMLTag 055{ 056 057 private XMLTag mStyle; 058 private XMLTag mUnderlineTag; 059 private XMLTag mColorTag; 060 private XMLTag mRunFontsTag; 061 private XMLTag mShadowTag; 062 private XMLTag mHighlightTag; 063 private WmlShading mShadingTag; 064 private WmlSpacing mSpacingTag; 065 private XMLTag mSmallCapsTag; 066 private XMLTag mSizeTag; 067 private XMLTag mCsSizeTag; 068 private XMLTag mStrikeTag; 069 private XMLTag mVanishTag; 070 private XMLTag mVertAlignTag; 071 private WmlTextBorder mBorder; 072 private XMLTag mNoProof; 073 074 //########################################################################## 075 // CONSTRUCTORS 076 //########################################################################## 077 078 //--------------------------------------------------------------------------- 079 public WmlTextRunProperties(Docx inDocx) 080 { 081 super(WmlXML.RUN_PROPS, inDocx); 082 } 083 084 085 //########################################################################## 086 // PUBLIC METHODS 087 //########################################################################## 088 089 //--------------------------------------------------------------------------- 090 // For now we will just remove the subtags being overridden 091 public WmlTextRunProperties combine(WmlTextRunProperties inPropertiesToOverlay) 092 { 093 if (inPropertiesToOverlay != null) 094 { 095 Map<String, XMLizable> subtagMap = new HashMap<>(15); 096 for (XMLizable subtag : getSubtags()) 097 { 098 subtagMap.put(((XMLTag)subtag).getTagName(), subtag); 099 } 100 101 for (XMLizable subtag : inPropertiesToOverlay.getSubtags()) 102 { 103 XMLizable existingSubtag = subtagMap.get(((XMLTag)subtag).getTagName()); 104 if (existingSubtag != null) 105 { 106 removeSubtag(existingSubtag); 107 } 108 109 addSubtag(subtag); 110 } 111 } 112 113 return this; 114 } 115 116 //--------------------------------------------------------------------------- 117 public WmlTextRunProperties setStyle(String inStyleId) 118 { 119 if (null == mStyle) 120 { 121 mStyle = new XMLTag(WmlXML.RUN_STYLE); 122 addSubtag(0, mStyle); 123 } 124 125 mStyle.setAttribute(WmlXML.VALUE_ATT, inStyleId); 126 127 return this; 128 } 129 130 //--------------------------------------------------------------------------- 131 public WmlTextRunProperties setBold() 132 { 133 if (null == getOptionalSubtagByName(WmlXML.BOLD)) 134 { 135 addSubtag(new XMLTag(WmlXML.BOLD)); 136 } 137 138 return this; 139 } 140 141 //--------------------------------------------------------------------------- 142 public WmlTextRunProperties setComplexScriptBold() 143 { 144 if (null == getOptionalSubtagByName(WmlXML.COMPLEX_SCRIPT_BOLD)) 145 { 146 addSubtag(new XMLTag(WmlXML.COMPLEX_SCRIPT_BOLD)); 147 } 148 149 return this; 150 } 151 152 //--------------------------------------------------------------------------- 153 public WmlTextRunProperties setItalics() 154 { 155 if (null == getOptionalSubtagByName(WmlXML.ITALICS)) 156 { 157 addSubtag(new XMLTag(WmlXML.ITALICS)); 158 } 159 160 return this; 161 } 162 163 //--------------------------------------------------------------------------- 164 public WmlTextRunProperties setComplexScriptItalics() 165 { 166 if (null == getOptionalSubtagByName(WmlXML.COMPLEX_SCRIPT_ITALICS)) 167 { 168 addSubtag(new XMLTag(WmlXML.COMPLEX_SCRIPT_ITALICS)); 169 } 170 171 return this; 172 } 173 174 //--------------------------------------------------------------------------- 175 public WmlTextRunProperties setUnderline() 176 { 177 if (null == mUnderlineTag) 178 { 179 mUnderlineTag = new XMLTag(WmlXML.UNDERLINE); 180 addSubtag(mUnderlineTag); 181 } 182 183 mUnderlineTag.setAttribute(WmlXML.VALUE_ATT, "single"); 184 185 return this; 186 } 187 188 //--------------------------------------------------------------------------- 189 public WmlTextRunProperties setSuperscript() 190 { 191 if (null == mVertAlignTag) 192 { 193 mVertAlignTag = new XMLTag(WmlXML.VERT_ALIGN); 194 addSubtag(mVertAlignTag); 195 } 196 197 mVertAlignTag.setAttribute(WmlXML.VALUE_ATT, "superscript"); 198 199 return this; 200 } 201 202 //--------------------------------------------------------------------------- 203 public WmlTextRunProperties setSubscript() 204 { 205 if (null == mVertAlignTag) 206 { 207 mVertAlignTag = new XMLTag(WmlXML.VERT_ALIGN); 208 addSubtag(mVertAlignTag); 209 } 210 211 mVertAlignTag.setAttribute(WmlXML.VALUE_ATT, "subscript"); 212 213 return this; 214 } 215 216 //--------------------------------------------------------------------------- 217 public WmlTextRunProperties setShadow() 218 { 219 if (null == mShadowTag) 220 { 221 mShadowTag = new XMLTag(WmlXML.SHADOW); 222 addSubtag(mShadowTag); 223 } 224 225 mShadowTag.setAttribute(WmlXML.VALUE_ATT, "true"); 226 227 return this; 228 } 229 230 //--------------------------------------------------------------------------- 231 public WmlTextRunProperties setSmallCaps() 232 { 233 if (null == mSmallCapsTag) 234 { 235 mSmallCapsTag = new XMLTag(WmlXML.SMALL_CAPS); 236 addSubtag(mSmallCapsTag); 237 } 238 239 mSmallCapsTag.setAttribute(WmlXML.VALUE_ATT, "true"); 240 241 return this; 242 } 243 244 //--------------------------------------------------------------------------- 245 public WmlTextRunProperties setColor(Color inColor) 246 { 247 return setColor(WmlXML.VALUE_ATT, ColorUtil.colorToHex(inColor)); 248 } 249 250 //--------------------------------------------------------------------------- 251 public WmlTextRunProperties setAutoColor() 252 { 253 return setColor(WmlXML.VALUE_ATT, "auto"); 254 } 255 256 //--------------------------------------------------------------------------- 257 public WmlTextRunProperties setThemeColor(String inValue) 258 { 259 return setColor(WmlXML.THEME_COLOR_ATT, inValue); 260 } 261 262 //--------------------------------------------------------------------------- 263 public WmlTextRunProperties setThemeShade(String inValue) 264 { 265 return setColor(WmlXML.THEME_SHADE_ATT, inValue); 266 } 267 268 //--------------------------------------------------------------------------- 269 private WmlTextRunProperties setColor(XMLName inXMLAttrName, String inValue) 270 { 271 if (null == mColorTag) 272 { 273 // Check if it has been added via addSubtag()... 274 mColorTag = getOptionalSubtagByName(WmlXML.COLOR); 275 if (null == mColorTag) 276 { 277 mColorTag = new XMLTag(WmlXML.COLOR); 278 addSubtag(mColorTag); 279 } 280 } 281 282 mColorTag.setAttribute(inXMLAttrName, inValue); 283 284 return this; 285 } 286 287 288 //--------------------------------------------------------------------------- 289 public WmlTextRunProperties setFont(Font inFont) 290 { 291 setFont(inFont.getName()); 292 setSize(new Points(inFont.getSize())); 293 294 if (inFont.isBold()) 295 { 296 setBold(); 297 } 298 299 if (inFont.isItalic()) 300 { 301 setItalics(); 302 } 303 304 return this; 305 } 306 307 //--------------------------------------------------------------------------- 308 public WmlTextRunProperties setFont(String inFont) 309 { 310 setFont(WmlXML.ASCII_ATT, inFont); 311 return setFont(WmlXML.HIGH_ANSI_ATT, inFont); 312 } 313 314 //--------------------------------------------------------------------------- 315 public WmlTextRunProperties setAnsiThemeFont(String inValue) 316 { 317 return setFont(WmlXML.ANSI_THEME_ATT, inValue); 318 } 319 320 //--------------------------------------------------------------------------- 321 public WmlTextRunProperties setAsciiThemeFont(String inValue) 322 { 323 return setFont(WmlXML.ASCII_THEME_ATT, inValue); 324 } 325 326 //--------------------------------------------------------------------------- 327 public WmlTextRunProperties setComplexScriptThemeFont(String inValue) 328 { 329 return setFont(WmlXML.COMPLEX_SCRIPT_THEME_ATT, inValue); 330 } 331 332 //--------------------------------------------------------------------------- 333 public WmlTextRunProperties setEastAsiaThemeFont(String inValue) 334 { 335 return setFont(WmlXML.EAST_ASIA_THEME_ATT, inValue); 336 } 337 338 339 //--------------------------------------------------------------------------- 340 private WmlTextRunProperties setFont(XMLName inXMLAttrName, String inValue) 341 { 342 if (null == mRunFontsTag) 343 { 344 // Check if it has been added via addSubtag()... 345 mRunFontsTag = getOptionalSubtagByName(WmlXML.RUN_FONTS); 346 if (null == mRunFontsTag) 347 { 348 mRunFontsTag = new XMLTag(WmlXML.RUN_FONTS); 349 addSubtag(mRunFontsTag); 350 } 351 } 352 353 mRunFontsTag.setAttribute(inXMLAttrName, inValue); 354 355 return this; 356 } 357 358 359 //--------------------------------------------------------------------------- 360 /** 361 * Specifies a positive measurement of font size. 362 * @param inValue the font size expressed in any units that extend GfxSize 363 * @return this text run properties object to enable method chaining 364 */ 365 public WmlTextRunProperties setSize(GfxSize inValue) 366 { 367 if (null == mSizeTag) 368 { 369 mSizeTag = new XMLTag(WmlXML.SIZE); 370 addSubtag(mSizeTag); 371 } 372 373 mSizeTag.setAttribute(WmlXML.VALUE_ATT, inValue.to(GfxUnits.half_points)); 374 375 return this; 376 } 377 378 //--------------------------------------------------------------------------- 379 /** 380 * Specifies a positive measurement of complex script font size. 381 * @param inValue the complex script font size expressed in any units that extend GfxSize 382 * @return this text run properties object to enable method chaining 383 */ 384 public WmlTextRunProperties setComplexScriptSize(GfxSize inValue) 385 { 386 if (null == mCsSizeTag) 387 { 388 mCsSizeTag = new XMLTag(WmlXML.COMPLEX_SCRIPT_FONT_SIZE); 389 addSubtag(mCsSizeTag); 390 } 391 392 mSizeTag.setAttribute(WmlXML.VALUE_ATT, inValue.to(GfxUnits.half_points)); 393 394 return this; 395 } 396 397 //--------------------------------------------------------------------------- 398 public WmlTextRunProperties setStrikeThrough() 399 { 400 if (null == mStrikeTag) 401 { 402 mStrikeTag = new XMLTag(WmlXML.STRIKE); 403 addSubtag(mStrikeTag); 404 } 405 406 mStrikeTag.setAttribute(WmlXML.VALUE_ATT, "true"); 407 408 return this; 409 } 410 411 //--------------------------------------------------------------------------- 412 /** 413 Specifies a highlighting color to be applied as background behind the contents: 414 <w:highlight w:val="red"/> This element will supersede any background shading 415 specified in shd. 416 * @param inColor Only the colors specified by this enum are allowed 417 * @return this text run properties object (facilitates chaining) 418 */ 419 public WmlTextRunProperties setHighlight(WmlHighlightColor inColor) 420 { 421 if (null == inColor) 422 { 423 // Clear the highlight tag if present 424 425 // Check it it has been added via addSubtag()... 426 XMLTag highlightTag = getOptionalSubtagByName(WmlXML.HIGHLIGHT); 427 if (highlightTag != null) 428 { 429 removeSubtag(highlightTag); 430 mHighlightTag = null; 431 } 432 } 433 else 434 { 435 if (null == mHighlightTag) 436 { 437 // Check it it has been added via addSubtag()... 438 mHighlightTag = getOptionalSubtagByName(WmlXML.HIGHLIGHT); 439 if (null == mHighlightTag) 440 { 441 mHighlightTag = new XMLTag(WmlXML.HIGHLIGHT); 442 addSubtag(mHighlightTag); 443 } 444 } 445 446 mHighlightTag.setAttribute(WmlXML.VALUE_ATT, inColor.name()); 447 } 448 449 return this; 450 } 451 452 453 //--------------------------------------------------------------------------- 454 public WmlTextRunProperties disableSpellingAndGrammarChecks() 455 { 456 if (null == mNoProof) 457 { 458 // Check if it has been added via addSubtag()... 459 mNoProof = getOptionalSubtagByName(WmlXML.NO_PROOF); 460 if (null == mNoProof) 461 { 462 mNoProof = new XMLTag(WmlXML.NO_PROOF); 463 addSubtag(mNoProof); 464 } 465 } 466 467 return this; 468 } 469 470 //--------------------------------------------------------------------------- 471 public WmlTextRunProperties vanish() 472 { 473 if (null == mVanishTag) 474 { 475 // Check if it has been added via addSubtag()... 476 mVanishTag = getOptionalSubtagByName(WmlXML.VANISH); 477 if (null == mVanishTag) 478 { 479 mVanishTag = new XMLTag(WmlXML.VANISH); 480 addSubtag(mVanishTag); 481 } 482 } 483 484 return this; 485 } 486 487 488 //--------------------------------------------------------------------------- 489 public WmlTextBorder getBorder() 490 { 491 if (null == mBorder) 492 { 493 // Check if it has been added via addSubtag()... 494 mBorder = getOptionalSubtagByName(WmlXML.BORDER); 495 if (null == mBorder) 496 { 497 mBorder = new WmlTextBorder(getParentDoc()); 498 addSubtag(mBorder); 499 } 500 } 501 502 return mBorder; 503 } 504 505 506 //--------------------------------------------------------------------------- 507 public WmlTextBorder getBorder(CSSDeclaration inCSSDeclaration) 508 { 509 if (null == mBorder) 510 { 511 // Check if it has been added via addSubtag()... 512 mBorder = getOptionalSubtagByName(WmlXML.BORDER); 513 if (null == mBorder) 514 { 515 mBorder = new WmlTextBorder(getParentDoc(), inCSSDeclaration); 516 addSubtag(mBorder); 517 } 518 } 519 520 return mBorder; 521 } 522 523 //--------------------------------------------------------------------------- 524 public WmlShading getShading() 525 { 526 if (null == mShadingTag) 527 { 528 // Check if it has been added via addSubtag()... 529 mShadingTag = getOptionalSubtagByName(WmlXML.SHADING); 530 if (null == mShadingTag) 531 { 532 mShadingTag = new WmlShading(); 533 addSubtag(mShadingTag); 534 } 535 } 536 537 return mShadingTag; 538 } 539 540 //--------------------------------------------------------------------------- 541 public WmlSpacing getSpacing() 542 { 543 if (null == mSpacingTag) 544 { 545 // Check if it has been added via addSubtag()... 546 mSpacingTag = getOptionalSubtagByName(WmlXML.SPACING); 547 if (null == mSpacingTag) 548 { 549 mSpacingTag = new WmlSpacing(); 550 addSubtag(mSpacingTag); 551 } 552 } 553 554 return mSpacingTag; 555 } 556}