1 28 package net.sf.jasperreports.engine.util; 29 30 import java.awt.Color ; 31 import java.awt.GraphicsEnvironment ; 32 import java.awt.font.TextAttribute ; 33 import java.io.IOException ; 34 import java.io.StringReader ; 35 import java.text.AttributedCharacterIterator ; 36 import java.util.HashMap ; 37 import java.util.List ; 38 import java.util.Map ; 39 import java.util.StringTokenizer ; 40 41 import javax.xml.parsers.DocumentBuilder ; 42 import javax.xml.parsers.DocumentBuilderFactory ; 43 import javax.xml.parsers.ParserConfigurationException ; 44 45 import net.sf.jasperreports.engine.JRRuntimeException; 46 import net.sf.jasperreports.engine.xml.JRXmlConstants; 47 48 import org.w3c.dom.Document ; 49 import org.w3c.dom.NamedNodeMap ; 50 import org.w3c.dom.Node ; 51 import org.w3c.dom.NodeList ; 52 import org.xml.sax.InputSource ; 53 import org.xml.sax.SAXException ; 54 55 56 60 public class JRStyledTextParser 61 { 62 63 66 private static final String ROOT_START = "<st>"; 67 private static final String ROOT_END = "</st>"; 68 private static final String NODE_style = "style"; 69 private static final String NODE_bold = "b"; 70 private static final String NODE_italic = "i"; 71 private static final String NODE_underline = "u"; 72 private static final String NODE_sup = "sup"; 73 private static final String NODE_sub = "sub"; 74 private static final String NODE_font = "font"; 75 private static final String NODE_br = "br"; 76 private static final String NODE_li = "li"; 77 private static final String ATTRIBUTE_fontName = "fontName"; 78 private static final String ATTRIBUTE_fontFace = "face"; 79 private static final String ATTRIBUTE_color = "color"; 80 private static final String ATTRIBUTE_size = "size"; 81 private static final String ATTRIBUTE_isBold = "isBold"; 82 private static final String ATTRIBUTE_isItalic = "isItalic"; 83 private static final String ATTRIBUTE_isUnderline = "isUnderline"; 84 private static final String ATTRIBUTE_isStrikeThrough = "isStrikeThrough"; 85 private static final String ATTRIBUTE_forecolor = "forecolor"; 86 private static final String ATTRIBUTE_backcolor = "backcolor"; 87 private static final String ATTRIBUTE_pdfFontName = "pdfFontName"; 88 private static final String ATTRIBUTE_pdfEncoding = "pdfEncoding"; 89 private static final String ATTRIBUTE_isPdfEmbedded = "isPdfEmbedded"; 90 91 private static final String SPACE = " "; 92 private static final String EQUAL_QUOTE = "=\""; 93 private static final String QUOTE = "\""; 94 private static final String SHARP = "#"; 95 private static final String LESS = "<"; 96 private static final String LESS_SLASH = "</"; 97 private static final String GREATER = ">"; 98 private static final String SIX_ZEROS = "000000"; 99 private static final int colorMask = Integer.parseInt("FFFFFF", 16); 100 101 104 private DocumentBuilder documentBuilder = null; 105 106 107 110 public JRStyledTextParser() 111 { 112 try 113 { 114 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 115 documentBuilder = factory.newDocumentBuilder(); 116 } 117 catch (ParserConfigurationException e) 118 { 119 throw new JRRuntimeException(e); 120 } 121 } 122 123 124 127 public JRStyledText parse(Map attributes, String text) throws SAXException 128 { 129 JRStyledText styledText = new JRStyledText(); 130 131 Document document = null; 132 133 try 134 { 135 document = documentBuilder.parse(new InputSource (new StringReader (ROOT_START + text + ROOT_END))); 136 } 137 catch (IOException e) 138 { 139 throw new JRRuntimeException(e); 140 } 141 142 parseStyle(styledText, document.getDocumentElement()); 143 144 styledText.addRun(new JRStyledText.Run(attributes, 0, styledText.length())); 145 146 return styledText; 147 } 148 149 152 public String write(Map parentAttrs, AttributedCharacterIterator iterator, String text) 153 { 154 StringBuffer sbuffer = new StringBuffer (); 155 156 int runLimit = 0; 157 158 while(runLimit < iterator.getEndIndex() && (runLimit = iterator.getRunLimit()) <= iterator.getEndIndex()) 159 { 160 String chunk = text.substring(iterator.getIndex(), runLimit); 161 Map attrs = iterator.getAttributes(); 162 163 StringBuffer styleBuffer = writeStyleAttributes(parentAttrs, attrs); 164 if (styleBuffer.length() > 0) 165 { 166 sbuffer.append(LESS); 167 sbuffer.append(NODE_style); 168 sbuffer.append(styleBuffer.toString()); 169 sbuffer.append(GREATER); 170 writeChunk(sbuffer, parentAttrs, attrs, chunk); 171 sbuffer.append(LESS_SLASH); 172 sbuffer.append(NODE_style); 173 sbuffer.append(GREATER); 174 } 175 else 176 { 177 writeChunk(sbuffer, parentAttrs, attrs, chunk); 178 } 179 180 iterator.setIndex(runLimit); 181 } 182 183 return sbuffer.toString(); 184 } 185 186 189 public void writeChunk(StringBuffer sbuffer, Map parentAttrs, Map attrs, String chunk) 190 { 191 Object value = attrs.get(TextAttribute.SUPERSCRIPT); 192 Object oldValue = parentAttrs.get(TextAttribute.SUPERSCRIPT); 193 194 boolean isSuper = false; 195 boolean isSub = false; 196 197 if (value != null && !value.equals(oldValue)) 198 { 199 isSuper=TextAttribute.SUPERSCRIPT_SUPER.equals(value); 200 isSub=TextAttribute.SUPERSCRIPT_SUB.equals(value); 201 } 202 203 204 if (isSuper || isSub) 205 { 206 String node = isSuper?NODE_sup:NODE_sub; 207 sbuffer.append(LESS); 208 sbuffer.append(node); 209 sbuffer.append(GREATER); 210 sbuffer.append(chunk); 211 sbuffer.append(LESS_SLASH); 212 sbuffer.append(node); 213 sbuffer.append(GREATER); 214 } 215 else 216 { 217 sbuffer.append(chunk); 218 } 219 } 220 221 224 private void parseStyle(JRStyledText styledText, Node parentNode) throws SAXException 225 { 226 NodeList nodeList = parentNode.getChildNodes(); 227 for(int i = 0; i < nodeList.getLength(); i++) 228 { 229 Node node = nodeList.item(i); 230 if (node.getNodeType() == Node.TEXT_NODE) 231 { 232 styledText.append(node.getNodeValue()); 233 } 234 else if ( 235 node.getNodeType() == Node.ELEMENT_NODE 236 && NODE_style.equals(node.getNodeName()) 237 ) 238 { 239 NamedNodeMap nodeAttrs = node.getAttributes(); 240 241 Map styleAttrs = new HashMap (); 242 243 if (nodeAttrs.getNamedItem(ATTRIBUTE_fontName) != null) 244 { 245 styleAttrs.put( 246 TextAttribute.FAMILY, 247 nodeAttrs.getNamedItem(ATTRIBUTE_fontName).getNodeValue() 248 ); 249 } 250 251 if (nodeAttrs.getNamedItem(ATTRIBUTE_isBold) != null) 252 { 253 styleAttrs.put( 254 TextAttribute.WEIGHT, 255 Boolean.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_isBold).getNodeValue()).booleanValue() 256 ? TextAttribute.WEIGHT_BOLD : TextAttribute.WEIGHT_REGULAR 257 ); 258 } 259 260 if (nodeAttrs.getNamedItem(ATTRIBUTE_isItalic) != null) 261 { 262 styleAttrs.put( 263 TextAttribute.POSTURE, 264 Boolean.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_isItalic).getNodeValue()).booleanValue() 265 ? TextAttribute.POSTURE_OBLIQUE : TextAttribute.POSTURE_REGULAR 266 ); 267 } 268 269 if (nodeAttrs.getNamedItem(ATTRIBUTE_isUnderline) != null) 270 { 271 styleAttrs.put( 272 TextAttribute.UNDERLINE, 273 Boolean.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_isUnderline).getNodeValue()).booleanValue() 274 ? TextAttribute.UNDERLINE_ON : null 275 ); 276 } 277 278 if (nodeAttrs.getNamedItem(ATTRIBUTE_isStrikeThrough) != null) 279 { 280 styleAttrs.put( 281 TextAttribute.STRIKETHROUGH, 282 Boolean.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_isStrikeThrough).getNodeValue()).booleanValue() 283 ? TextAttribute.STRIKETHROUGH_ON : null 284 ); 285 } 286 287 if (nodeAttrs.getNamedItem(ATTRIBUTE_size) != null) 288 { 289 styleAttrs.put( 290 TextAttribute.SIZE, 291 new Float (nodeAttrs.getNamedItem(ATTRIBUTE_size).getNodeValue()) 292 ); 293 } 294 295 if (nodeAttrs.getNamedItem(ATTRIBUTE_pdfFontName) != null) 296 { 297 styleAttrs.put( 298 JRTextAttribute.PDF_FONT_NAME, 299 nodeAttrs.getNamedItem(ATTRIBUTE_pdfFontName).getNodeValue() 300 ); 301 } 302 303 if (nodeAttrs.getNamedItem(ATTRIBUTE_pdfEncoding) != null) 304 { 305 styleAttrs.put( 306 JRTextAttribute.PDF_ENCODING, 307 nodeAttrs.getNamedItem(ATTRIBUTE_pdfEncoding).getNodeValue() 308 ); 309 } 310 311 if (nodeAttrs.getNamedItem(ATTRIBUTE_isPdfEmbedded) != null) 312 { 313 styleAttrs.put( 314 JRTextAttribute.IS_PDF_EMBEDDED, 315 Boolean.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_isPdfEmbedded).getNodeValue()) 316 ); 317 } 318 319 if (nodeAttrs.getNamedItem(ATTRIBUTE_forecolor) != null) 320 { 321 Color color = 322 JRXmlConstants.getColor( 323 nodeAttrs.getNamedItem(ATTRIBUTE_forecolor).getNodeValue(), 324 Color.black 325 ); 326 styleAttrs.put( 327 TextAttribute.FOREGROUND, 328 color 329 ); 330 } 331 332 if (nodeAttrs.getNamedItem(ATTRIBUTE_backcolor) != null) 333 { 334 Color color = 335 JRXmlConstants.getColor( 336 nodeAttrs.getNamedItem(ATTRIBUTE_backcolor).getNodeValue(), 337 Color.black 338 ); 339 styleAttrs.put( 340 TextAttribute.BACKGROUND, 341 color 342 ); 343 } 344 345 int startIndex = styledText.length(); 346 347 parseStyle(styledText, node); 348 349 styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length())); 350 } 351 else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_bold.equalsIgnoreCase(node.getNodeName())) 352 { 353 Map styleAttrs = new HashMap (); 354 styleAttrs.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); 355 356 int startIndex = styledText.length(); 357 358 parseStyle(styledText, node); 359 360 styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length())); 361 } 362 else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_italic.equalsIgnoreCase(node.getNodeName())) 363 { 364 Map styleAttrs = new HashMap (); 365 styleAttrs.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); 366 367 int startIndex = styledText.length(); 368 369 parseStyle(styledText, node); 370 371 styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length())); 372 } 373 else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_underline.equalsIgnoreCase(node.getNodeName())) 374 { 375 Map styleAttrs = new HashMap (); 376 styleAttrs.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); 377 378 int startIndex = styledText.length(); 379 380 parseStyle(styledText, node); 381 382 styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length())); 383 } 384 else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_sup.equalsIgnoreCase(node.getNodeName())) 385 { 386 Map styleAttrs = new HashMap (); 387 styleAttrs.put(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUPER); 388 389 int startIndex = styledText.length(); 390 391 parseStyle(styledText, node); 392 393 styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length())); 394 } 395 else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_sub.equalsIgnoreCase(node.getNodeName())) 396 { 397 Map styleAttrs = new HashMap (); 398 styleAttrs.put(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUB); 399 400 int startIndex = styledText.length(); 401 402 parseStyle(styledText, node); 403 404 styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length())); 405 } 406 else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_font.equalsIgnoreCase(node.getNodeName())) 407 { 408 NamedNodeMap nodeAttrs = node.getAttributes(); 409 410 Map styleAttrs = new HashMap (); 411 412 if (nodeAttrs.getNamedItem(ATTRIBUTE_fontFace) != null) 413 { 414 styleAttrs.put( 415 JRTextAttribute.HTML_FONT_FACE, 416 nodeAttrs.getNamedItem(ATTRIBUTE_fontFace).getNodeValue() 417 ); 418 } 419 if (nodeAttrs.getNamedItem(ATTRIBUTE_size) != null) 420 { 421 styleAttrs.put( 422 TextAttribute.SIZE, 423 new Float (nodeAttrs.getNamedItem(ATTRIBUTE_size).getNodeValue()) 424 ); 425 } 426 427 if (nodeAttrs.getNamedItem(ATTRIBUTE_color) != null) 428 { 429 Color color = 430 JRXmlConstants.getColor( 431 nodeAttrs.getNamedItem(ATTRIBUTE_color).getNodeValue(), 432 Color.black 433 ); 434 styleAttrs.put( 435 TextAttribute.FOREGROUND, 436 color 437 ); 438 } 439 440 if (nodeAttrs.getNamedItem(ATTRIBUTE_fontFace) != null) { 441 String [] fontList = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); 442 String fontFaces = nodeAttrs.getNamedItem(ATTRIBUTE_fontFace).getNodeValue(); 443 444 StringTokenizer t = new StringTokenizer (fontFaces, ","); 445 label:while (t.hasMoreTokens()) { 446 String face = t.nextToken().trim(); 447 for (int j = 0; j < fontList.length; j++) 448 if (fontList[j].equals(face)) { 449 styleAttrs.put(TextAttribute.FAMILY, face); 450 break label; 451 } 452 } 453 } 454 int startIndex = styledText.length(); 455 456 parseStyle(styledText, node); 457 458 styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length())); 459 460 } 461 else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_br.equalsIgnoreCase(node.getNodeName())) 462 { 463 styledText.append("\n"); 464 465 int startIndex = styledText.length(); 466 resizeRuns(styledText.getRuns(), startIndex, 1); 467 468 parseStyle(styledText, node); 469 styledText.addRun(new JRStyledText.Run(new HashMap (), startIndex, styledText.length())); 470 471 if (startIndex < styledText.length()) { 472 styledText.append("\n"); 473 resizeRuns(styledText.getRuns(), startIndex, 1); 474 } 475 } 476 else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_li.equalsIgnoreCase(node.getNodeName())) 477 { 478 styledText.append("\n \u2022 "); 479 480 int startIndex = styledText.length(); 481 resizeRuns(styledText.getRuns(), startIndex, 1); 482 483 parseStyle(styledText, node); 484 styledText.addRun(new JRStyledText.Run(new HashMap (), startIndex, styledText.length())); 485 486 styledText.append("\n"); 487 resizeRuns(styledText.getRuns(), startIndex, 1); 488 } 489 else if (node.getNodeType() == Node.ELEMENT_NODE) 490 { 491 String nodeName = "<" + node.getNodeName() + ">"; 492 throw new SAXException ("Tag " + nodeName + " is not a valid styled text tag."); 493 } 494 } 495 } 496 497 500 private void resizeRuns(List runs, int startIndex, int count) 501 { 502 for (int j = 0; j < runs.size(); j++) 503 { 504 JRStyledText.Run run = (JRStyledText.Run) runs.get(j); 505 if (run.startIndex <= startIndex && run.endIndex > startIndex - count) 506 run.endIndex += count; 507 } 508 } 509 510 511 514 private StringBuffer writeStyleAttributes(Map parentAttrs, Map attrs) 515 { 516 StringBuffer sbuffer = new StringBuffer (); 517 518 Object value = attrs.get(TextAttribute.FAMILY); 519 Object oldValue = parentAttrs.get(TextAttribute.FAMILY); 520 521 if (value != null && !value.equals(oldValue)) 522 { 523 sbuffer.append(SPACE); 524 sbuffer.append(ATTRIBUTE_fontName); 525 sbuffer.append(EQUAL_QUOTE); 526 sbuffer.append(value); 527 sbuffer.append(QUOTE); 528 } 529 530 value = attrs.get(TextAttribute.WEIGHT); 531 oldValue = parentAttrs.get(TextAttribute.WEIGHT); 532 533 if (value != null && !value.equals(oldValue)) 534 { 535 sbuffer.append(SPACE); 536 sbuffer.append(ATTRIBUTE_isBold); 537 sbuffer.append(EQUAL_QUOTE); 538 sbuffer.append(value.equals(TextAttribute.WEIGHT_BOLD)); 539 sbuffer.append(QUOTE); 540 } 541 542 value = attrs.get(TextAttribute.POSTURE); 543 oldValue = parentAttrs.get(TextAttribute.POSTURE); 544 545 if (value != null && !value.equals(oldValue)) 546 { 547 sbuffer.append(SPACE); 548 sbuffer.append(ATTRIBUTE_isItalic); 549 sbuffer.append(EQUAL_QUOTE); 550 sbuffer.append(value.equals(TextAttribute.POSTURE_OBLIQUE)); 551 sbuffer.append(QUOTE); 552 } 553 554 value = attrs.get(TextAttribute.UNDERLINE); 555 oldValue = parentAttrs.get(TextAttribute.UNDERLINE); 556 557 if ( 558 (value == null && oldValue != null) 559 || (value != null && !value.equals(oldValue)) 560 ) 561 { 562 sbuffer.append(SPACE); 563 sbuffer.append(ATTRIBUTE_isUnderline); 564 sbuffer.append(EQUAL_QUOTE); 565 sbuffer.append(value != null); 566 sbuffer.append(QUOTE); 567 } 568 569 value = attrs.get(TextAttribute.STRIKETHROUGH); 570 oldValue = parentAttrs.get(TextAttribute.STRIKETHROUGH); 571 572 if ( 573 (value == null && oldValue != null) 574 || (value != null && !value.equals(oldValue)) 575 ) 576 { 577 sbuffer.append(SPACE); 578 sbuffer.append(ATTRIBUTE_isStrikeThrough); 579 sbuffer.append(EQUAL_QUOTE); 580 sbuffer.append(value != null); 581 sbuffer.append(QUOTE); 582 } 583 584 value = attrs.get(TextAttribute.SIZE); 585 oldValue = parentAttrs.get(TextAttribute.SIZE); 586 587 if (value != null && !value.equals(oldValue)) 588 { 589 sbuffer.append(SPACE); 590 sbuffer.append(ATTRIBUTE_size); 591 sbuffer.append(EQUAL_QUOTE); 592 sbuffer.append(((Float )value).intValue()); 593 sbuffer.append(QUOTE); 594 } 595 596 value = attrs.get(JRTextAttribute.PDF_FONT_NAME); 597 oldValue = parentAttrs.get(JRTextAttribute.PDF_FONT_NAME); 598 599 if (value != null && !value.equals(oldValue)) 600 { 601 sbuffer.append(SPACE); 602 sbuffer.append(ATTRIBUTE_pdfFontName); 603 sbuffer.append(EQUAL_QUOTE); 604 sbuffer.append(value); 605 sbuffer.append(QUOTE); 606 } 607 608 value = attrs.get(JRTextAttribute.PDF_ENCODING); 609 oldValue = parentAttrs.get(JRTextAttribute.PDF_ENCODING); 610 611 if (value != null && !value.equals(oldValue)) 612 { 613 sbuffer.append(SPACE); 614 sbuffer.append(ATTRIBUTE_pdfEncoding); 615 sbuffer.append(EQUAL_QUOTE); 616 sbuffer.append(value); 617 sbuffer.append(QUOTE); 618 } 619 620 value = attrs.get(JRTextAttribute.IS_PDF_EMBEDDED); 621 oldValue = parentAttrs.get(JRTextAttribute.IS_PDF_EMBEDDED); 622 623 if (value != null && !value.equals(oldValue)) 624 { 625 sbuffer.append(SPACE); 626 sbuffer.append(ATTRIBUTE_isPdfEmbedded); 627 sbuffer.append(EQUAL_QUOTE); 628 sbuffer.append(value); 629 sbuffer.append(QUOTE); 630 } 631 632 value = attrs.get(TextAttribute.FOREGROUND); 633 oldValue = parentAttrs.get(TextAttribute.FOREGROUND); 634 635 if (value != null && !value.equals(oldValue)) 636 { 637 sbuffer.append(SPACE); 638 sbuffer.append(ATTRIBUTE_forecolor); 639 sbuffer.append(EQUAL_QUOTE); 640 sbuffer.append(SHARP); 641 sbuffer.append(getHexaColor((Color )value)); 642 sbuffer.append(QUOTE); 643 } 644 645 value = attrs.get(TextAttribute.BACKGROUND); 646 oldValue = parentAttrs.get(TextAttribute.BACKGROUND); 647 648 if (value != null && !value.equals(oldValue)) 649 { 650 sbuffer.append(SPACE); 651 sbuffer.append(ATTRIBUTE_backcolor); 652 sbuffer.append(EQUAL_QUOTE); 653 sbuffer.append(SHARP); 654 sbuffer.append(getHexaColor((Color )value)); 655 sbuffer.append(QUOTE); 656 } 657 658 return sbuffer; 659 } 660 661 664 private String getHexaColor(Color color) 665 { 666 String hexa = Integer.toHexString(color.getRGB() & colorMask).toUpperCase(); 667 return (SIX_ZEROS + hexa).substring(hexa.length()); 668 } 669 670 } 671 | Popular Tags |