1 19 20 package org.netbeans.modules.xml.xam.dom; 21 22 import java.io.IOException ; 23 import java.net.URI ; 24 import java.net.URISyntaxException ; 25 import java.util.ArrayList ; 26 import java.util.HashMap ; 27 import java.util.List ; 28 import java.util.Map ; 29 import java.util.logging.Level ; 30 import java.util.logging.Logger ; 31 import javax.xml.XMLConstants ; 32 import javax.xml.namespace.QName ; 33 import org.netbeans.modules.xml.xam.AbstractComponent; 34 import org.netbeans.modules.xml.xam.EmbeddableRoot; 35 import org.netbeans.modules.xml.xam.locator.CatalogModel; 36 import org.netbeans.modules.xml.xam.locator.CatalogModelException; 37 import org.netbeans.modules.xml.xam.ModelSource; 38 import org.w3c.dom.Document ; 39 import org.w3c.dom.Node ; 40 import org.w3c.dom.Element ; 41 import org.w3c.dom.NamedNodeMap ; 42 import org.w3c.dom.NodeList ; 43 import org.w3c.dom.Text ; 44 45 52 public abstract class AbstractDocumentComponent<C extends DocumentComponent<C>> 53 extends AbstractComponent<C> implements DocumentComponent<C>, DocumentModelAccess.NodeUpdater { 54 private Element node; 55 56 protected abstract void populateChildren(List <C> children); 57 58 public AbstractDocumentComponent(AbstractDocumentModel model, org.w3c.dom.Element e) { 59 super(model); 60 setRef(e); 61 } 62 63 66 private void setRef(Element n) { 67 assert n != null : "n must not be null"; 68 node = n; 69 } 70 71 public synchronized Element getPeer() { 72 return node; 73 } 74 75 78 public String getAttribute(Attribute attr) { 79 return normalizeUndefinedAttributeValue( 80 getPeer().getAttribute(attr.getName())); 81 } 82 83 91 public void setAttribute(String eventPropertyName, Attribute attr, Object value) { 92 verifyWrite(); 93 Object old = null; 94 String s = getAttribute(attr); 95 if (s != null) { 96 try { 97 old = getAttributeValueOf(attr, s); 98 } catch(IllegalArgumentException ex) { 99 } 101 } 102 setAttributeQuietly(attr, value); 103 firePropertyChange(eventPropertyName, old, value); 104 fireValueChanged(); 105 } 106 107 abstract protected Object getAttributeValueOf(Attribute attr, String stringValue); 108 109 115 public String getAnyAttribute(QName attr) { 116 assert attr != null; 117 String name = attr.getLocalPart(); 118 String namespace = attr.getNamespaceURI(); 119 String prefix = namespace == null ? null : lookupPrefix(namespace); 120 String attrName = prefix == null ? name : prefix + ":" + name; return normalizeUndefinedAttributeValue( 122 getPeer().getAttribute(attrName)); 123 } 124 125 130 private String normalizeUndefinedAttributeValue(String value) { 131 String normalizedValue = value; 132 if (getModel() != null) { 133 normalizedValue = 134 getAccess().normalizeUndefinedAttributeValue(value); 135 } 136 return normalizedValue; 137 } 138 139 145 public void setAnyAttribute(QName attr, String value) { 146 setQNameAttribute(attr.getLocalPart(), attr, value); 147 } 148 149 protected void setQNameAttribute(String propertyName, QName attr, String value) { 150 assert attr != null; 151 152 verifyWrite(); 153 154 String name = getPrefixedName(attr, (value != null)); 155 String old = getAnyAttribute(attr); 156 if (value == null) { 157 removeAttribute(getPeer(), name); 158 } else { 159 setAttribute(getPeer(), name, value); 160 } 161 162 firePropertyChange(propertyName, old, value); 163 fireValueChanged(); 164 } 165 166 protected String getPrefixedName(QName q, boolean declarePrefix) { 167 String name = q.getLocalPart(); 168 String namespace = q.getNamespaceURI(); 169 String prefix = q.getPrefix(); 170 return getPrefixedName(namespace, name, prefix, declarePrefix); 171 } 172 173 174 protected String getPrefixedName(String namespace, String localName) { 175 return getPrefixedName(namespace, localName, null, false); 176 } 177 178 protected String getPrefixedName(String namespace, String name, String prefix, boolean declarePrefix) { 179 if (namespace == null || namespace.length() == 0) { 180 declarePrefix = false; 181 } 182 String existingPrefix = lookupPrefix(namespace); 183 AbstractDocumentComponent root = (AbstractDocumentComponent)getModel().getRootComponent(); 184 if (existingPrefix == null) { 185 existingPrefix = root.lookupPrefix(namespace); 187 } 188 if (existingPrefix != null) { 190 String localNS = lookupNamespaceURI(existingPrefix); 191 if (localNS != null && ! localNS.equals(namespace)) { 192 existingPrefix = null; 193 } 194 } 195 196 if (existingPrefix != null) { 197 prefix = existingPrefix; 198 } else if (declarePrefix) { 199 if (prefix == null) { 200 prefix = "ns"; } 202 if (prefix.length() > 0) { 203 prefix = root.ensureUnique(prefix, namespace); 204 } 205 if (isInDocumentModel()) { 206 root.addPrefix(prefix, namespace); 207 } else { 208 addPrefix(prefix, namespace); 209 } 210 } 211 212 if (prefix != null && prefix.length() > 0) { 213 name = prefix + ":" + name; } 215 216 return name; 217 } 218 219 222 protected String ensureUnique(String prefix, String namespace) { 223 assert namespace != null; 224 int count = 0; 225 String prefixN = prefix; 226 String existing = lookupNamespaceURI(prefixN); 227 while (existing != null && count < 100 && ! existing.equals(namespace)) { 228 ++count; 229 prefixN = prefix+count; 230 existing = lookupNamespaceURI(prefix+count); 231 } 232 if (count >= 100) { 233 Logger.getLogger(getClass().getName()).log( 234 Level.FINE, "Failed to generate unique prefix for "+namespace); } 236 return prefixN; 237 } 238 239 protected void setAttributeQuietly(Attribute type, Object newVal) { 240 if (newVal == null) { 241 removeAttribute(node, type.getName()); 242 } else { 243 String stringValue = newVal.toString(); 244 if (newVal instanceof NamedComponentReference) { 245 NamedComponentReference ref = (NamedComponentReference) newVal; 246 QName q = ref.getQName(); 247 stringValue = getPrefixedName(q.getNamespaceURI(), q.getLocalPart(), null, true); 248 if (getEffectiveParent() == null) { 249 Logger.getLogger(getClass().getName()).log(Level.FINE, 250 "Referencing while not in tree yet could result in unwanted prefix declaration"); } 252 ((AbstractNamedComponentReference) ref).refresh(); 253 } 254 setAttribute(node, type.getName(), stringValue); 255 } 256 } 257 258 protected void removeAttributeQuietly(Element element, String name) { 259 getAccess().removeAttribute(element, name, this); 260 } 261 262 protected void appendChildQuietly(C component, List <C> children) { 263 fixupPrefix(component); 264 getAccess().appendChild(getPeer(), component.getPeer(), this); 265 children.add(component); 266 } 267 268 protected void insertAtIndexQuietly(C newComponent, List <C> children, int index) { 269 if (index >= 0 && children.size() > 0 && index < children.size()) { 270 fixupPrefix(newComponent); 271 Node refChild = children.get(index).getPeer(); 272 insertBefore(newComponent.getPeer(), refChild); 273 children.add(index, newComponent); 274 } else { 275 appendChildQuietly(newComponent, children); 276 } 277 } 278 279 protected void removeChildQuietly(C component, List <C> children) { 280 removeChild(component.getPeer()); 281 children.remove(component); 282 } 283 284 protected String getNamespaceURI() { 285 String ns = getPeer().getNamespaceURI(); 286 if (ns == null && getEffectiveParent() != null) { 287 String prefix = getPeer().getPrefix(); 288 ns = lookupNamespaceURI(prefix); 289 } 290 return ns; 291 } 292 293 297 public String lookupNamespaceURI(String prefix, boolean optimized) { 298 if (optimized) { 299 String namespace = getPrefixes().get(prefix == null ? "" : prefix); 300 if (namespace == null && getEffectiveParent() != null) { 301 namespace = getEffectiveParent().lookupNamespaceURI(prefix, true); 302 } 303 return namespace; 304 } else { 305 return lookupNamespaceURI(prefix); 306 } 307 } 308 309 public String lookupNamespaceURI(String prefix) { 310 String ns = getPeer().lookupNamespaceURI(prefix); 311 if (ns == null && getEffectiveParent() != null) { 312 ns = getEffectiveParent().lookupNamespaceURI(prefix); 313 } 314 return ns; 315 } 316 317 public String lookupPrefix(String namespace){ 318 String prefix = getPeer().lookupPrefix(namespace); 319 if (prefix == null && getEffectiveParent() != null) { 320 prefix = getEffectiveParent().lookupPrefix(namespace); 321 } 322 return prefix; 323 } 324 325 328 protected String getXmlFragment() { 329 return getAccess().getXmlFragment(getPeer()); 330 } 331 332 335 public String getXmlFragmentInclusive() { 336 return getModel().getAccess().getXmlFragmentInclusive(getPeer()); 337 } 338 339 349 protected synchronized void setXmlFragment(String propertyName, String text) throws IOException { 350 verifyWrite(); 351 String oldVal = getText(); 352 getAccess().setXmlFragment(getPeer(), text, this); 353 firePropertyChange(propertyName, oldVal, text); 354 fireValueChanged(); 355 } 356 357 364 protected synchronized void setText(String propertyName, String text) { 365 verifyWrite(); 366 String oldVal = getText(); 367 getAccess().setText(getPeer(), text, this); 368 firePropertyChange(propertyName, oldVal, text); 369 fireValueChanged(); 370 } 371 372 377 protected String getText() { 378 return getText(getPeer()); 379 } 380 381 public static String getText(Element e) { 382 StringBuilder text = new StringBuilder (); 383 org.w3c.dom.NodeList nl = e.getChildNodes(); 384 for (int i = 0; i < nl.getLength(); i++) { 385 org.w3c.dom.Node n = nl.item(i); 386 if (n instanceof org.w3c.dom.Text ) { 387 text.append(n.getNodeValue()); 388 } 389 } 390 return text.toString(); 391 } 392 393 public AbstractDocumentModel getModel() { 394 return (AbstractDocumentModel) super.getModel(); 395 } 396 397 public boolean referencesSameNode(Node n) { 398 return getModel().areSameNodes(getPeer(), n); 399 } 400 401 public synchronized void updateReference(Element element) { 402 node = element; 403 } 404 405 412 public synchronized <N extends Node > void updateReference(List <N> pathToRoot) { 413 AbstractDocumentComponent current = this; 414 assert pathToRoot != null && pathToRoot.size() > 0; 415 for (int i=0; i<pathToRoot.size(); i++) { 416 assert pathToRoot.get(i) instanceof Element ; 417 Element e = (Element ) pathToRoot.get(i); 418 if (current.referencesSameNode(e)) { 419 current.updateReference(e, pathToRoot); 420 if (current.getEffectiveParent() != null) { 421 current = (AbstractDocumentComponent) current.getEffectiveParent(); 422 } else { 423 break; 424 } 425 } else if (i == pathToRoot.size()-1) { 426 throw new IllegalArgumentException ("Expect new reference node has same Id as current"); } 428 } 429 } 430 431 439 protected <N extends Node > void updateReference(Element peer, List <N> updatingPath) { 440 updateReference(peer); 441 } 442 443 protected DocumentModelAccess getAccess() { 444 getChildren(); return (DocumentModelAccess) getModel().getAccess(); 446 } 447 448 public int findPosition() { 449 if (getModel() == null) { 450 return 0; 451 } 452 return getAccess().findPosition(getPeer()); 453 } 454 455 private void removeAttribute(Element element, String name) { 456 getAccess().removeAttribute(element, name, this); 457 } 458 459 private void setAttribute(Element element, String name, String value) { 460 getAccess().setAttribute(element, name, value, this); 461 } 462 463 private void insertBefore(Node newChild, Node refChild) { 464 getAccess().insertBefore(node, newChild, refChild, this); 465 } 466 467 private void removeChild(Node child) { 468 getAccess().removeChild(node, child, this); 469 } 470 471 475 protected void updatePeer(String propertyName, org.w3c.dom.Element newPeer) { 476 AbstractDocumentComponent aParent = getEffectiveParent(); 477 Element parentPeer = aParent.getPeer(); 478 Element oldPeer = getPeer(); 479 getAccess().replaceChild(parentPeer, getPeer(), newPeer, aParent); 480 updateReference(newPeer); 481 firePropertyChange(propertyName, oldPeer, newPeer); 482 fireValueChanged(); 483 } 484 485 protected Attribute createPrefixAttribute(String prefix) { 486 assert prefix != null; 487 if (prefix.length() == 0) { 488 return new PrefixAttribute(XMLConstants.XMLNS_ATTRIBUTE); 489 } else { 490 return new PrefixAttribute("xmlns:"+prefix); } 492 } 493 494 497 public void addPrefix(String prefix, String namespace) { 498 Attribute a = createPrefixAttribute(prefix); 499 setAttribute(a.getName(), a, namespace); 500 } 501 502 505 public void removePrefix(String prefix) { 506 setAttribute(prefix, createPrefixAttribute(prefix), null); 507 } 508 509 512 public Map <String , String > getPrefixes() { 513 Map <String ,String > prefixes = new HashMap <String ,String >(); 514 NamedNodeMap nodes = getPeer().getAttributes(); 515 for (int i = 0; i < nodes.getLength(); i++) { 516 Node n = nodes.item(i); 517 String name = n.getLocalName(); 518 String prefix = n.getPrefix(); 519 final String xmlns = XMLConstants.XMLNS_ATTRIBUTE; if (xmlns.equals(name) || xmlns.equals(prefix)) { String ns = n.getNodeValue(); 523 prefixes.put(name, ns); 524 } 525 } 526 String defaultNamespace = prefixes.remove(XMLConstants.XMLNS_ATTRIBUTE); 527 if (defaultNamespace != null) { 528 prefixes.put(XMLConstants.DEFAULT_NS_PREFIX, defaultNamespace); 529 } 530 return prefixes; 531 } 532 533 public static class PrefixAttribute implements Attribute { 534 private String prefix; 535 public PrefixAttribute(String name) { 536 prefix = name; 537 } 538 public Class getType() { return String .class; } 539 public String getName() { return prefix; } 540 public Class getMemberType() { return null; } 541 } 542 543 547 private void fixupPrefix(C newComponent) { 548 if (getModel().inSync()) return; 549 550 AbstractDocumentComponent child = (AbstractDocumentComponent) newComponent; 551 Element e = child.getPeer(); 552 String childNS = child.getNamespaceURI(); 553 if (childNS == null || childNS.equals(XMLConstants.NULL_NS_URI)) { 554 return; 555 } 556 557 if (childNS.equals(getNamespaceURI())) { 558 e.setPrefix(getPeer().getPrefix()); 559 } else if (childNS.equals(lookupNamespaceURI(""))) { 560 e.setPrefix(null); 561 } else { 562 ensurePrefixDeclaredFor(e, childNS); 563 } 564 565 for (C c : newComponent.getChildren()) { 566 fixupPrefix(c); 567 } 568 } 569 570 private void ensurePrefixDeclaredFor(Element newComponentElement, String newComponentNS) { 571 String existingPrefix = lookupPrefix(newComponentNS); 572 String prefix = newComponentElement.getPrefix(); 573 if (existingPrefix == null) { 574 if (prefix == null) { 575 prefix = "ns"; } 577 prefix = ensureUnique(prefix, newComponentNS); 578 ((AbstractDocumentComponent)getModel().getRootComponent()).addPrefix(prefix, newComponentNS); 579 newComponentElement.setPrefix(prefix); 580 } else { 581 newComponentElement.setPrefix(existingPrefix); 582 } 583 } 584 585 protected void ensureValueNamespaceDeclared(String newNamespace, String oldNamespace, 586 String preferredPrefix) { 587 if (newNamespace == null) return; 588 String prefix = null; 589 if (oldNamespace != null) { 590 prefix = lookupPrefix(oldNamespace); 591 } 592 593 if (prefix == null) { 594 String tnsURI = lookupNamespaceURI(preferredPrefix); 596 if (tnsURI == null) { 597 prefix = preferredPrefix; 598 } else { 599 prefix = ensureUnique(preferredPrefix, newNamespace); 600 } 601 addPrefix(prefix, newNamespace); 602 } else { removePrefix(prefix); 604 addPrefix(prefix, newNamespace); 605 } 606 } 607 608 public C findChildComponent(Element e) { 609 for (C c : getChildren()) { 610 if (c.referencesSameNode(e)) { 611 return c; 612 } 613 } 614 return null; 615 } 616 617 public C findChildComponentByIdentity(Element e) { 618 ElementIdentity ei = getModel().getAccess().getElementIdentity(); 619 Document doc = getModel().getDocument(); 620 for (C c : getChildren()) { 621 if (ei.compareElement(c.getPeer(), e, doc, doc)) { 622 return c; 623 } 624 } 625 return null; 626 } 627 628 public DocumentComponent copy(C parent) { 629 if (getModel() == null) { 630 throw new IllegalStateException ("Cannot copy component already removed from model"); 631 } 632 Element newPeer = getAccess().duplicate(getPeer()); 633 DocumentModel<C> m = parent == null ? getModel() : (DocumentModel) parent.getModel(); 634 return m.createComponent(parent, newPeer); 635 } 636 637 protected void verifyWrite() { 638 if (getModel() == null) { 639 throw new IllegalStateException ("Cannot mutate a component already removed from model."); 640 } 641 if (isInDocumentModel()) { 642 getModel().validateWrite(); 643 } 644 } 645 646 protected void firePropertyChange(String propName, Object oldValue, Object newValue) { 647 if (isInDocumentModel()) { 648 super.firePropertyChange(propName, oldValue, newValue); 649 } 650 } 651 652 protected void fireValueChanged() { 653 if (isInDocumentModel()) { 654 super.fireValueChanged(); 655 } 656 } 657 658 protected void fireChildRemoved() { 659 if (isInDocumentModel()) { 660 super.fireChildRemoved(); 661 } 662 } 663 664 protected void fireChildAdded() { 665 if (isInDocumentModel()) { 666 super.fireChildAdded(); 667 } 668 } 669 670 673 public boolean isInDocumentModel() { 674 if (getModel() == null) return false; 675 AbstractDocumentComponent root = (AbstractDocumentComponent) getModel().getRootComponent(); 676 if (root == null) return false; 677 if (root == this) return true; 678 AbstractDocumentComponent myRoot = (AbstractDocumentComponent) getEffectiveParent(); 679 if (myRoot == null) return false; while (myRoot != null && myRoot.getEffectiveParent() != null) { 681 if (myRoot instanceof EmbeddableRoot) { 682 root = (AbstractDocumentComponent) myRoot.getEffectiveParent().getModel().getRootComponent(); 683 } 684 myRoot = (AbstractDocumentComponent) myRoot.getEffectiveParent(); 685 } 686 return root == myRoot; 687 } 688 689 public int findAttributePosition(String attributeName) { 690 org.w3c.dom.Attr a = getPeer().getAttributeNode(attributeName); 691 if (a != null) { 692 return getAccess().findPosition(a); 693 } else { 694 return -1; 695 } 696 } 697 698 701 public QName getQName() { 702 return getQName(getPeer()); 703 } 704 705 public static QName getQName(Node n) { 706 String namespace = n.getNamespaceURI(); 707 String localName = n.getLocalName(); 708 String prefix = n.getPrefix(); 709 assert(localName != null); 710 if (namespace == null && prefix == null) { 711 return new QName (localName); 712 } else if (namespace != null && prefix == null) { 713 return new QName (namespace, localName); 714 } else { 715 return new QName (namespace, localName, prefix); 716 } 717 } 718 719 private ModelSource resolveModelSource(String location, 720 ModelSource currentSource, CatalogModel currentCatalog) { 721 ModelSource ms = null; 722 try { 723 if (location != null) { 724 ms = currentCatalog.getModelSource(getURI(location), 725 currentSource); 726 } 727 } catch (CatalogModelException nse) { 728 Logger l = Logger.getLogger(AbstractDocumentComponent.class.getName()); 730 l.log(Level.FINE, nse.getMessage()); 731 } 732 return ms; 733 } 734 735 742 protected ModelSource resolveModel(String hint) throws CatalogModelException { 743 return _resolveModel(hint, null); 744 } 745 746 private ModelSource _resolveModel(String hint, String backup) throws CatalogModelException { 747 CatalogModel nr = (CatalogModel) 748 getModel().getModelSource().getLookup().lookup(CatalogModel.class); 749 750 ModelSource ms = resolveModelSource(hint, getModel().getModelSource(), 752 nr); 753 754 if (ms == null) { 756 ms = resolveModelSource(backup, getModel().getModelSource(), 757 nr); 758 } 759 760 if (ms == null) { 762 String msg = "Cannot resolve file using hint = " + hint + " backup = " + backup; throw new CatalogModelException(msg); 765 } 766 767 return ms; 768 } 769 770 private static URI getURI(String s) throws CatalogModelException { 771 try { 772 return new URI (s); 773 } catch (URISyntaxException ex) { 774 throw new CatalogModelException(ex); 775 } 776 } 777 778 public Map <QName ,String > getAttributeMap() { 779 return getModel().getAccess().getAttributeMap(getPeer()); 780 } 781 782 786 protected int findDomainIndex(Element e) { 787 if (! getModel().isDomainElement(e)) { 788 return -1; 789 } 790 int domainInsertIndex = 0; 791 NodeList nl = getPeer().getChildNodes(); 792 for (int i=0; i<nl.getLength(); i++) { 793 if (nl.item(i) == e) { 794 return domainInsertIndex; 795 } 796 if (getModel().isDomainElement(nl.item(i))) { 797 domainInsertIndex++; 798 } 799 } 800 return -1; 801 } 802 803 protected AbstractDocumentComponent getEffectiveParent() { 804 AbstractDocumentComponent p = (AbstractDocumentComponent) getParent(); 805 if (p == null && this instanceof EmbeddableRoot) { 806 p = (AbstractDocumentComponent) ((EmbeddableRoot)this).getForeignParent(); 807 } 808 return p; 809 } 810 811 812 protected Element getChildElement(QName qname) { 813 NodeList nl = getPeer().getElementsByTagName(qname.getLocalPart()); 814 Element ret = null; 815 if (nl != null) { 816 for (int i=0; i<nl.getLength(); i++) { 817 if (qname.equals(getQName(nl.item(i)))) { 818 ret = (Element ) nl.item(i); 819 break; 820 } 821 } 822 } 823 return ret; 824 } 825 826 831 protected String getChildElementText(QName qname) { 832 Element ret = getChildElement(qname); 833 return ret == null ? null : getText(ret); 834 } 835 836 843 protected void setChildElementText(String propertyName, String text, QName qname) { 844 verifyWrite(); 845 Element childElement = getChildElement(qname); 846 String oldVal = childElement == null ? null : getText(childElement); 847 848 if (text == null) { 849 if (childElement == null) return; 850 removeChild(childElement); 851 if (oldVal == null) return; 852 } else if (text.length() == 0) { 853 if (childElement != null) { 854 removeChild(childElement); 855 } 856 childElement = getModel().getDocument().createElementNS(qname.getNamespaceURI(), qname.getLocalPart()); 857 getModel().getAccess().appendChild(getPeer(), childElement, this); 858 } else { 859 if (text.equals(oldVal)) return; 860 if (childElement == null) { 861 childElement = getModel().getDocument().createElementNS(qname.getNamespaceURI(), qname.getLocalPart()); 862 getModel().getAccess().appendChild(getPeer(), childElement, this); 863 } 864 getModel().getAccess().setText(childElement, text, this); 865 } 866 firePropertyChange(propertyName, oldVal, text); 867 fireValueChanged(); 868 } 869 870 875 protected String getLeadingText(C child) { 876 return getText(child, true, true); 877 } 878 879 884 protected void setLeadingText(String propName, String text, C child) { 885 setText(propName, text, child, true, true); 886 } 887 888 893 protected String getTrailingText(C child) { 894 return getText(child, false, true); 895 } 896 897 902 protected void setTrailingText(String propName, String text, C child) { 903 setText(propName, text, child, false, true); 904 } 905 906 protected String getText(C child, boolean leading, boolean includeComments) { 907 int domIndex = getNodeIndexOf(getPeer(), child.getPeer()); 908 if (domIndex < 0) { 909 throw new IllegalArgumentException ("Child peer node is not part of children nodes"); 910 } 911 912 StringBuilder value = null; 913 NodeList nl = getPeer().getChildNodes(); 914 915 for (int i = (leading ? domIndex-1 : domIndex+1); 916 i > -1 && i < nl.getLength(); i = leading ? --i : ++i) 917 { 918 Node n = nl.item(i); 919 if (n instanceof Element ) { 920 break; 921 } 922 923 if (n instanceof Text && (includeComments || n.getNodeType() != Node.COMMENT_NODE)) { 924 if (value == null) value = new StringBuilder (); 925 if (leading) { 926 value.insert(0, n.getNodeValue()); 927 } else { 928 value.append(n.getNodeValue()); 929 } 930 } 931 } 932 return value == null ? null : value.toString(); 933 } 934 935 protected void setText(String propName, String value, C child, final boolean leading, boolean includeComments) { 936 verifyWrite(); 937 StringBuilder oldValue = null; 938 ArrayList <Node > toRemove = new ArrayList <Node >(); 939 NodeList nl = getPeer().getChildNodes(); 940 int domIndex = getNodeIndexOf(getPeer(), child.getPeer()); 941 if (domIndex < 0) { 942 throw new IllegalArgumentException ("Child peer node is not part of children nodes"); 943 } 944 945 Element ref = leading ? child.getPeer() : null; 946 for (int i = leading ? domIndex-1 : domIndex+1; 947 i > -1 && i < nl.getLength(); i = leading ? --i : ++i) 948 { 949 Node n = nl.item(i); 950 if (n != null && n.getNodeType() == Node.ELEMENT_NODE) { 951 if (leading) { 952 ref = child.getPeer(); 953 } else { 954 ref = (Element ) n; 955 } 956 break; 957 } 958 if (n instanceof Text && (includeComments || n.getNodeType() != Node.COMMENT_NODE)) { 959 toRemove.add(n); 960 if (oldValue == null) oldValue = new StringBuilder (); 961 if (leading) { 962 oldValue.insert(0, n.getNodeValue()); 963 } else { 964 oldValue.append(n.getNodeValue()); 965 } 966 } 967 } 968 969 getModel().getAccess().removeChildren(getPeer(), toRemove, this); 970 if (value != null) { 971 Text newNode = getModel().getDocument().createTextNode(value); 972 if (ref != null) { 973 getModel().getAccess().insertBefore(getPeer(), newNode, ref, this); 974 } else { 975 getModel().getAccess().appendChild(getPeer(), newNode, this); 976 } 977 } 978 979 firePropertyChange(propName, oldValue == null ? null : oldValue.toString(), value); 980 fireValueChanged(); 981 } 982 983 protected int getNodeIndexOf(Node parent, Node child) { 984 if (child == null) { 985 return -1; 986 } 987 int nodeIndex = -1; 988 for (int i = 0; i < parent.getChildNodes().getLength(); i++) { 989 Node n = parent.getChildNodes().item(i); 990 nodeIndex++; 991 if (getAccess().areSameNodes(n, child)) { 992 return nodeIndex; 993 } 994 } 995 return -1; 996 } 997 998 } 999 1000 | Popular Tags |