1 11 package org.eclipse.ui.internal.forms.widgets; 12 13 import java.io.ByteArrayInputStream ; 14 import java.io.IOException ; 15 import java.io.InputStream ; 16 import java.io.UnsupportedEncodingException ; 17 import java.util.Vector ; 18 19 import javax.xml.parsers.DocumentBuilder ; 20 import javax.xml.parsers.DocumentBuilderFactory ; 21 import javax.xml.parsers.ParserConfigurationException ; 22 23 import org.eclipse.swt.SWT; 24 import org.eclipse.ui.forms.HyperlinkSettings; 25 import org.w3c.dom.Document ; 26 import org.w3c.dom.NamedNodeMap ; 27 import org.w3c.dom.Node ; 28 import org.w3c.dom.NodeList ; 29 import org.xml.sax.InputSource ; 30 import org.xml.sax.SAXException ; 31 32 public class FormTextModel { 33 private static final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory 34 .newInstance(); 35 36 private boolean whitespaceNormalized = true; 37 38 private Vector paragraphs; 39 40 private IFocusSelectable[] selectableSegments; 41 42 private int selectedSegmentIndex = -1; 43 44 private int savedSelectedLinkIndex = -1; 45 46 private HyperlinkSettings hyperlinkSettings; 47 48 public static final String BOLD_FONT_ID = "f.____bold"; 50 52 54 56 public FormTextModel() { 57 reset(); 58 } 59 60 63 public Paragraph[] getParagraphs() { 64 if (paragraphs == null) 65 return new Paragraph[0]; 66 return (Paragraph[]) paragraphs 67 .toArray(new Paragraph[paragraphs.size()]); 68 } 69 70 public String getAccessibleText() { 71 if (paragraphs == null) 72 return ""; StringBuffer sbuf = new StringBuffer (); 74 for (int i = 0; i < paragraphs.size(); i++) { 75 Paragraph paragraph = (Paragraph) paragraphs.get(i); 76 String text = paragraph.getAccessibleText(); 77 sbuf.append(text); 78 } 79 return sbuf.toString(); 80 } 81 82 85 public void parseTaggedText(String taggedText, boolean expandURLs) { 86 if (taggedText == null) { 87 reset(); 88 return; 89 } 90 try { 91 InputStream stream = new ByteArrayInputStream (taggedText 92 .getBytes("UTF8")); parseInputStream(stream, expandURLs); 94 } catch (UnsupportedEncodingException e) { 95 SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT, e); 96 } 97 } 98 99 public void parseInputStream(InputStream is, boolean expandURLs) { 100 101 documentBuilderFactory.setNamespaceAware(true); 102 documentBuilderFactory.setIgnoringComments(true); 103 104 reset(); 105 try { 106 DocumentBuilder parser = documentBuilderFactory 107 .newDocumentBuilder(); 108 InputSource source = new InputSource (is); 109 Document doc = parser.parse(source); 110 processDocument(doc, expandURLs); 111 } catch (ParserConfigurationException e) { 112 SWT.error(SWT.ERROR_INVALID_ARGUMENT, e); 113 } catch (SAXException e) { 114 SWT.error(SWT.ERROR_INVALID_ARGUMENT, e); 115 } catch (IOException e) { 116 SWT.error(SWT.ERROR_IO, e); 117 } 118 } 119 120 private void processDocument(Document doc, boolean expandURLs) { 121 Node root = doc.getDocumentElement(); 122 NodeList children = root.getChildNodes(); 123 processSubnodes(paragraphs, children, expandURLs); 124 } 125 126 private void processSubnodes(Vector plist, NodeList children, boolean expandURLs) { 127 for (int i = 0; i < children.getLength(); i++) { 128 Node child = children.item(i); 129 if (child.getNodeType() == Node.TEXT_NODE) { 130 String text = getSingleNodeText(child); 132 if (text != null && !isIgnorableWhiteSpace(text, true)) { 133 Paragraph p = new Paragraph(true); 134 p.parseRegularText(text, expandURLs, true, 135 getHyperlinkSettings(), null); 136 plist.add(p); 137 } 138 } else if (child.getNodeType() == Node.ELEMENT_NODE) { 139 String tag = child.getNodeName().toLowerCase(); 140 if (tag.equals("p")) { Paragraph p = processParagraph(child, expandURLs); 142 if (p != null) 143 plist.add(p); 144 } else if (tag.equals("li")) { Paragraph p = processListItem(child, expandURLs); 146 if (p != null) 147 plist.add(p); 148 } 149 } 150 } 151 } 152 153 private Paragraph processParagraph(Node paragraph, boolean expandURLs) { 154 NodeList children = paragraph.getChildNodes(); 155 NamedNodeMap atts = paragraph.getAttributes(); 156 Node addSpaceAtt = atts.getNamedItem("addVerticalSpace"); boolean addSpace = true; 158 159 if (addSpaceAtt == null) 160 addSpaceAtt = atts.getNamedItem("vspace"); 162 if (addSpaceAtt != null) { 163 String value = addSpaceAtt.getNodeValue(); 164 addSpace = value.equalsIgnoreCase("true"); } 166 Paragraph p = new Paragraph(addSpace); 167 168 processSegments(p, children, expandURLs); 169 return p; 170 } 171 172 private Paragraph processListItem(Node listItem, boolean expandURLs) { 173 NodeList children = listItem.getChildNodes(); 174 NamedNodeMap atts = listItem.getAttributes(); 175 Node addSpaceAtt = atts.getNamedItem("addVerticalSpace"); Node styleAtt = atts.getNamedItem("style"); Node valueAtt = atts.getNamedItem("value"); Node indentAtt = atts.getNamedItem("indent"); Node bindentAtt = atts.getNamedItem("bindent"); int style = BulletParagraph.CIRCLE; 181 int indent = -1; 182 int bindent = -1; 183 String text = null; 184 boolean addSpace = true; 185 186 if (addSpaceAtt != null) { 187 String value = addSpaceAtt.getNodeValue(); 188 addSpace = value.equalsIgnoreCase("true"); } 190 if (styleAtt != null) { 191 String value = styleAtt.getNodeValue(); 192 if (value.equalsIgnoreCase("text")) { style = BulletParagraph.TEXT; 194 } else if (value.equalsIgnoreCase("image")) { style = BulletParagraph.IMAGE; 196 } else if (value.equalsIgnoreCase("bullet")) { style = BulletParagraph.CIRCLE; 198 } 199 } 200 if (valueAtt != null) { 201 text = valueAtt.getNodeValue(); 202 if (style == BulletParagraph.IMAGE) 203 text = "i." + text; } 205 if (indentAtt != null) { 206 String value = indentAtt.getNodeValue(); 207 try { 208 indent = Integer.parseInt(value); 209 } catch (NumberFormatException e) { 210 } 211 } 212 if (bindentAtt != null) { 213 String value = bindentAtt.getNodeValue(); 214 try { 215 bindent = Integer.parseInt(value); 216 } catch (NumberFormatException e) { 217 } 218 } 219 220 BulletParagraph p = new BulletParagraph(addSpace); 221 p.setIndent(indent); 222 p.setBulletIndent(bindent); 223 p.setBulletStyle(style); 224 p.setBulletText(text); 225 226 processSegments(p, children, expandURLs); 227 return p; 228 } 229 230 private void processSegments(Paragraph p, NodeList children, 231 boolean expandURLs) { 232 for (int i = 0; i < children.getLength(); i++) { 233 Node child = children.item(i); 234 ParagraphSegment segment = null; 235 236 if (child.getNodeType() == Node.TEXT_NODE) { 237 String value = getSingleNodeText(child); 238 239 if (value != null && !isIgnorableWhiteSpace(value, false)) { 240 p.parseRegularText(value, expandURLs, true, 241 getHyperlinkSettings(), null); 242 } 243 } else if (child.getNodeType() == Node.ELEMENT_NODE) { 244 String name = child.getNodeName(); 245 if (name.equalsIgnoreCase("img")) { segment = processImageSegment(child); 247 } else if (name.equalsIgnoreCase("a")) { segment = processHyperlinkSegment(child, 249 getHyperlinkSettings()); 250 } else if (name.equalsIgnoreCase("span")) { processTextSegment(p, expandURLs, child); 252 } else if (name.equalsIgnoreCase("b")) { String text = getNodeText(child); 254 String fontId = BOLD_FONT_ID; 255 p.parseRegularText(text, expandURLs, true, 256 getHyperlinkSettings(), fontId); 257 } else if (name.equalsIgnoreCase("br")) { segment = new BreakSegment(); 259 } else if (name.equalsIgnoreCase("control")) { segment = processControlSegment(child); 261 } 262 } 263 if (segment != null) { 264 p.addSegment(segment); 265 } 266 } 267 } 268 269 private boolean isIgnorableWhiteSpace(String text, boolean ignoreSpaces) { 270 for (int i = 0; i < text.length(); i++) { 271 char c = text.charAt(i); 272 if (ignoreSpaces && c == ' ') 273 continue; 274 if (c == '\n' || c == '\r' || c == '\f') 275 continue; 276 return false; 277 } 278 return true; 279 } 280 281 private ImageSegment processImageSegment(Node image) { 282 ImageSegment segment = new ImageSegment(); 283 processObjectSegment(segment, image, "i."); return segment; 285 } 286 287 private ControlSegment processControlSegment(Node control) { 288 ControlSegment segment = new ControlSegment(); 289 processObjectSegment(segment, control, "o."); Node fill = control.getAttributes().getNamedItem("fill"); if (fill!=null) { 292 String value = fill.getNodeValue(); 293 boolean doFill = value.equalsIgnoreCase("true"); segment.setFill(doFill); 295 } 296 try { 297 Node width = control.getAttributes().getNamedItem("width"); if (width!=null) { 299 String value = width.getNodeValue(); 300 int doWidth = Integer.parseInt(value); 301 segment.setWidth(doWidth); 302 } 303 Node height = control.getAttributes().getNamedItem("height"); if (height!=null) { 305 String value = height.getNodeValue(); 306 int doHeight = Integer.parseInt(value); 307 segment.setHeight(doHeight); 308 } 309 } 310 catch (NumberFormatException e) { 311 } 313 return segment; 314 } 315 316 private void processObjectSegment(ObjectSegment segment, Node object, String prefix) { 317 NamedNodeMap atts = object.getAttributes(); 318 Node id = atts.getNamedItem("href"); Node align = atts.getNamedItem("align"); if (id != null) { 321 String value = id.getNodeValue(); 322 segment.setObjectId(prefix + value); 323 } 324 if (align != null) { 325 String value = align.getNodeValue().toLowerCase(); 326 if (value.equals("top")) segment.setVerticalAlignment(ImageSegment.TOP); 328 else if (value.equals("middle")) segment.setVerticalAlignment(ImageSegment.MIDDLE); 330 else if (value.equals("bottom")) segment.setVerticalAlignment(ImageSegment.BOTTOM); 332 } 333 } 334 335 private void appendText(String value, StringBuffer buf, int[] spaceCounter) { 336 if (!whitespaceNormalized) 337 buf.append(value); 338 else { 339 for (int j = 0; j < value.length(); j++) { 340 char c = value.charAt(j); 341 if (c == ' ' || c == '\t') { 342 if (++spaceCounter[0] == 1) { 344 buf.append(c); 345 } 346 } else if (c == '\n' || c == '\r' || c == '\f') { 347 if (++spaceCounter[0] == 1) { 349 buf.append(' '); 350 } 351 } else { 352 spaceCounter[0] = 0; 354 buf.append(c); 355 } 356 } 357 } 358 } 359 360 private String getNormalizedText(String text) { 361 int[] spaceCounter = new int[1]; 362 StringBuffer buf = new StringBuffer (); 363 364 if (text == null) 365 return null; 366 appendText(text, buf, spaceCounter); 367 return buf.toString(); 368 } 369 370 private String getSingleNodeText(Node node) { 371 return getNormalizedText(node.getNodeValue()); 372 } 373 374 private String getNodeText(Node node) { 375 NodeList children = node.getChildNodes(); 376 StringBuffer buf = new StringBuffer (); 377 int[] spaceCounter = new int[1]; 378 379 for (int i = 0; i < children.getLength(); i++) { 380 Node child = children.item(i); 381 if (child.getNodeType() == Node.TEXT_NODE) { 382 String value = child.getNodeValue(); 383 appendText(value, buf, spaceCounter); 384 } 385 } 386 return buf.toString().trim(); 387 } 388 389 private ParagraphSegment processHyperlinkSegment(Node link, 390 HyperlinkSettings settings) { 391 NamedNodeMap atts = link.getAttributes(); 392 String href = null; 393 boolean wrapAllowed = true; 394 String boldFontId = null; 395 396 Node hrefAtt = atts.getNamedItem("href"); if (hrefAtt != null) { 398 href = hrefAtt.getNodeValue(); 399 } 400 Node boldAtt = atts.getNamedItem("bold"); if (boldAtt != null) { 402 boldFontId = BOLD_FONT_ID; 403 } 404 Node nowrap = atts.getNamedItem("nowrap"); if (nowrap != null) { 406 String value = nowrap.getNodeValue(); 407 if (value != null && value.equalsIgnoreCase("true")) wrapAllowed = false; 409 } 410 Object status = checkChildren(link); 411 if (status instanceof Node ) { 412 Node child = (Node )status; 413 ImageHyperlinkSegment segment = new ImageHyperlinkSegment(); 414 segment.setHref(href); 415 segment.setWordWrapAllowed(wrapAllowed); 416 Node alt = child.getAttributes().getNamedItem("alt"); if (alt!=null) 418 segment.setTooltipText(alt.getNodeValue()); 419 Node text = child.getAttributes().getNamedItem("text"); if (text!=null) 421 segment.setText(text.getNodeValue()); 422 processObjectSegment(segment, child, "i."); return segment; 424 } else if (status instanceof String ) { 425 String text = (String ) status; 426 TextHyperlinkSegment segment = new TextHyperlinkSegment(text, 427 settings, null); 428 segment.setHref(href); 429 segment.setFontId(boldFontId); 430 Node alt = atts.getNamedItem("alt"); if (alt!=null) 432 segment.setTooltipText(alt.getNodeValue()); 433 segment.setWordWrapAllowed(wrapAllowed); 434 return segment; 435 } else { 436 AggregateHyperlinkSegment parent = new AggregateHyperlinkSegment(); 437 parent.setHref(href); 438 NodeList children = link.getChildNodes(); 439 for (int i = 0; i < children.getLength(); i++) { 440 Node child = children.item(i); 441 if (child.getNodeType() == Node.TEXT_NODE) { 442 String value = child.getNodeValue(); 443 TextHyperlinkSegment ts = new TextHyperlinkSegment( 444 getNormalizedText(value), settings, null); 445 Node alt = atts.getNamedItem("alt"); if (alt!=null) 447 ts.setTooltipText(alt.getNodeValue()); 448 ts.setWordWrapAllowed(wrapAllowed); 449 parent.add(ts); 450 } else if (child.getNodeType() == Node.ELEMENT_NODE) { 451 String name = child.getNodeName(); 452 if (name.equalsIgnoreCase("img")) { ImageHyperlinkSegment is = new ImageHyperlinkSegment(); 454 processObjectSegment(is, child, "i."); Node alt = child.getAttributes().getNamedItem("alt"); if (alt!=null) 457 is.setTooltipText(alt.getNodeValue()); 458 parent.add(is); 459 is.setWordWrapAllowed(wrapAllowed); 460 } 461 } 462 } 463 return parent; 464 } 465 } 466 467 private Object checkChildren(Node node) { 468 boolean text = false; 469 Node imgNode = null; 470 472 NodeList children = node.getChildNodes(); 473 for (int i = 0; i < children.getLength(); i++) { 474 Node child = children.item(i); 475 if (child.getNodeType() == Node.TEXT_NODE) 476 text = true; 477 else if (child.getNodeType() == Node.ELEMENT_NODE 478 && child.getNodeName().equalsIgnoreCase("img")) { imgNode = child; 480 } 481 } 482 if (text && imgNode == null) 483 return getNodeText(node); 484 else if (!text && imgNode != null) 485 return imgNode; 486 else return null; 487 } 488 489 private void processTextSegment(Paragraph p, boolean expandURLs, 490 Node textNode) { 491 String text = getNodeText(textNode); 492 493 NamedNodeMap atts = textNode.getAttributes(); 494 Node font = atts.getNamedItem("font"); Node color = atts.getNamedItem("color"); boolean wrapAllowed=true; 497 Node nowrap = atts.getNamedItem("nowrap"); if (nowrap != null) { 499 String value = nowrap.getNodeValue(); 500 if (value != null && value.equalsIgnoreCase("true")) wrapAllowed = false; 502 } 503 String fontId = null; 504 String colorId = null; 505 if (font != null) { 506 fontId = "f." + font.getNodeValue(); } 508 if (color != null) { 509 colorId = "c." + color.getNodeValue(); } 511 p.parseRegularText(text, expandURLs, wrapAllowed, getHyperlinkSettings(), fontId, 512 colorId); 513 } 514 515 public void parseRegularText(String regularText, boolean convertURLs) { 516 reset(); 517 518 if (regularText == null) 519 return; 520 521 regularText = getNormalizedText(regularText); 522 523 Paragraph p = new Paragraph(true); 524 paragraphs.add(p); 525 int pstart = 0; 526 527 for (int i = 0; i < regularText.length(); i++) { 528 char c = regularText.charAt(i); 529 if (p == null) { 530 p = new Paragraph(true); 531 paragraphs.add(p); 532 } 533 if (c == '\n') { 534 String text = regularText.substring(pstart, i); 535 pstart = i + 1; 536 p.parseRegularText(text, convertURLs, true, getHyperlinkSettings(), 537 null); 538 p = null; 539 } 540 } 541 if (p != null) { 542 String text = regularText.substring(pstart); 544 p.parseRegularText(text, convertURLs, true, getHyperlinkSettings(), null); 545 } 546 } 547 548 public HyperlinkSettings getHyperlinkSettings() { 549 if (hyperlinkSettings==null) 551 hyperlinkSettings = new HyperlinkSettings(SWTUtil.getStandardDisplay()); 552 return hyperlinkSettings; 553 } 554 555 public void setHyperlinkSettings(HyperlinkSettings settings) { 556 this.hyperlinkSettings = settings; 557 } 558 559 private void reset() { 560 if (paragraphs == null) 561 paragraphs = new Vector (); 562 paragraphs.clear(); 563 selectedSegmentIndex = -1; 564 savedSelectedLinkIndex = -1; 565 selectableSegments = null; 566 } 567 568 IFocusSelectable[] getFocusSelectableSegments() { 569 if (selectableSegments != null || paragraphs == null) 570 return selectableSegments; 571 Vector result = new Vector (); 572 for (int i = 0; i < paragraphs.size(); i++) { 573 Paragraph p = (Paragraph) paragraphs.get(i); 574 ParagraphSegment[] segments = p.getSegments(); 575 for (int j = 0; j < segments.length; j++) { 576 if (segments[j] instanceof IFocusSelectable) 577 result.add(segments[j]); 578 } 579 } 580 selectableSegments = (IFocusSelectable[]) result 581 .toArray(new IFocusSelectable[result.size()]); 582 return selectableSegments; 583 } 584 585 public IHyperlinkSegment getHyperlink(int index) { 586 IFocusSelectable[] selectables = getFocusSelectableSegments(); 587 if (selectables.length>index) { 588 IFocusSelectable link = selectables[index]; 589 if (link instanceof IHyperlinkSegment) 590 return (IHyperlinkSegment)link; 591 } 592 return null; 593 } 594 595 public IHyperlinkSegment findHyperlinkAt(int x, int y) { 596 IFocusSelectable[] selectables = getFocusSelectableSegments(); 597 for (int i = 0; i < selectables.length; i++) { 598 IFocusSelectable segment = selectables[i]; 599 if (segment instanceof IHyperlinkSegment) { 600 IHyperlinkSegment link = (IHyperlinkSegment)segment; 601 if (link.contains(x, y)) 602 return link; 603 } 604 } 605 return null; 606 } 607 608 public int getHyperlinkCount() { 609 return getFocusSelectableSegments().length; 610 } 611 612 public int indexOf(IHyperlinkSegment link) { 613 IFocusSelectable[] selectables = getFocusSelectableSegments(); 614 for (int i = 0; i < selectables.length; i++) { 615 IFocusSelectable segment = selectables[i]; 616 if (segment instanceof IHyperlinkSegment) { 617 IHyperlinkSegment l = (IHyperlinkSegment)segment; 618 if (link==l) 619 return i; 620 } 621 } 622 return -1; 623 } 624 625 public ParagraphSegment findSegmentAt(int x, int y) { 626 for (int i = 0; i < paragraphs.size(); i++) { 627 Paragraph p = (Paragraph) paragraphs.get(i); 628 ParagraphSegment segment = p.findSegmentAt(x, y); 629 if (segment != null) 630 return segment; 631 } 632 return null; 633 } 634 635 public void clearCache(String fontId) { 636 for (int i = 0; i < paragraphs.size(); i++) { 637 Paragraph p = (Paragraph) paragraphs.get(i); 638 p.clearCache(fontId); 639 } 640 } 641 642 public IFocusSelectable getSelectedSegment() { 643 if (selectableSegments==null || selectedSegmentIndex == -1) 644 return null; 645 return selectableSegments[selectedSegmentIndex]; 646 } 647 648 public int getSelectedSegmentIndex() { 649 return selectedSegmentIndex; 650 } 651 652 public boolean linkExists(IHyperlinkSegment link) { 653 if (selectableSegments==null) 654 return false; 655 for (int i=0; i<selectableSegments.length; i++) { 656 if (selectableSegments[i]==link) 657 return true; 658 } 659 return false; 660 } 661 662 public boolean traverseFocusSelectableObjects(boolean next) { 663 IFocusSelectable[] selectables = getFocusSelectableSegments(); 664 if (selectables == null) 665 return false; 666 int size = selectables.length; 667 if (next) { 668 selectedSegmentIndex++; 669 } else 670 selectedSegmentIndex--; 671 672 if (selectedSegmentIndex < 0 || selectedSegmentIndex > size - 1) { 673 selectedSegmentIndex = -1; 674 } 675 return selectedSegmentIndex != -1; 676 } 677 678 public IFocusSelectable getNextFocusSegment(boolean next) { 679 IFocusSelectable[] selectables = getFocusSelectableSegments(); 680 if (selectables == null) 681 return null; 682 int nextIndex = next?selectedSegmentIndex+1:selectedSegmentIndex-1; 683 684 if (nextIndex < 0 || nextIndex > selectables.length - 1) { 685 return null; 686 } 687 return selectables[nextIndex]; 688 } 689 690 public boolean restoreSavedLink() { 691 if (savedSelectedLinkIndex!= -1) { 692 selectedSegmentIndex = savedSelectedLinkIndex; 693 return true; 694 } 695 return false; 696 } 697 698 public void selectLink(IHyperlinkSegment link) { 699 if (link == null) { 700 savedSelectedLinkIndex = selectedSegmentIndex; 701 selectedSegmentIndex = -1; 702 } 703 else { 704 select(link); 705 706 } 707 } 708 709 public void select(IFocusSelectable selectable) { 710 IFocusSelectable[] selectables = getFocusSelectableSegments(); 711 selectedSegmentIndex = -1; 712 if (selectables == null) 713 return; 714 for (int i = 0; i < selectables.length; i++) { 715 if (selectables[i].equals(selectable)) { 716 selectedSegmentIndex = i; 717 break; 718 } 719 } 720 } 721 722 public boolean hasFocusSegments() { 723 IFocusSelectable[] segments = getFocusSelectableSegments(); 724 if (segments.length > 0) 725 return true; 726 return false; 727 } 728 729 public void dispose() { 730 paragraphs = null; 731 selectedSegmentIndex = -1; 732 savedSelectedLinkIndex = -1; 733 selectableSegments = null; 734 } 735 736 739 public boolean isWhitespaceNormalized() { 740 return whitespaceNormalized; 741 } 742 743 747 public void setWhitespaceNormalized(boolean whitespaceNormalized) { 748 this.whitespaceNormalized = whitespaceNormalized; 749 } 750 } 751 | Popular Tags |