1 7 package javax.swing.text.html; 8 9 import java.awt.Color ; 10 import java.awt.Component ; 11 import java.awt.font.TextAttribute ; 12 import java.util.*; 13 import java.net.URL ; 14 import java.net.URLEncoder ; 15 import java.net.MalformedURLException ; 16 import java.io.*; 17 import javax.swing.*; 18 import javax.swing.event.*; 19 import javax.swing.text.*; 20 import javax.swing.undo.*; 21 import java.text.Bidi ; 22 23 74 public class HTMLDocument extends DefaultStyledDocument { 75 81 public HTMLDocument() { 82 this(new GapContent(BUFFER_SIZE_DEFAULT), new StyleSheet ()); 83 } 84 85 94 public HTMLDocument(StyleSheet styles) { 95 this(new GapContent(BUFFER_SIZE_DEFAULT), styles); 96 } 97 98 106 public HTMLDocument(Content c, StyleSheet styles) { 107 super(c, styles); 108 } 109 110 122 public HTMLEditorKit.ParserCallback getReader(int pos) { 123 Object desc = getProperty(Document.StreamDescriptionProperty); 124 if (desc instanceof URL ) { 125 setBase((URL )desc); 126 } 127 HTMLReader reader = new HTMLReader(pos); 128 return reader; 129 } 130 131 151 public HTMLEditorKit.ParserCallback getReader(int pos, int popDepth, 152 int pushDepth, 153 HTML.Tag insertTag) { 154 return getReader(pos, popDepth, pushDepth, insertTag, true); 155 } 156 157 176 HTMLEditorKit.ParserCallback getReader(int pos, int popDepth, 177 int pushDepth, 178 HTML.Tag insertTag, 179 boolean insertInsertTag) { 180 Object desc = getProperty(Document.StreamDescriptionProperty); 181 if (desc instanceof URL ) { 182 setBase((URL )desc); 183 } 184 HTMLReader reader = new HTMLReader(pos, popDepth, pushDepth, 185 insertTag, insertInsertTag, false, 186 true); 187 return reader; 188 } 189 190 198 public URL getBase() { 199 return base; 200 } 201 202 212 public void setBase(URL u) { 213 base = u; 214 getStyleSheet().setBase(u); 215 } 216 217 231 protected void insert(int offset, ElementSpec[] data) throws BadLocationException { 232 super.insert(offset, data); 233 } 234 235 244 protected void insertUpdate(DefaultDocumentEvent chng, AttributeSet attr) { 245 if(attr == null) { 246 attr = contentAttributeSet; 247 } 248 249 else if (attr.isDefined(StyleConstants.ComposedTextAttribute)) { 251 ((MutableAttributeSet)attr).addAttributes(contentAttributeSet); 252 } 253 254 if (attr.isDefined(IMPLIED_CR)) { 255 ((MutableAttributeSet)attr).removeAttribute(IMPLIED_CR); 256 } 257 258 super.insertUpdate(chng, attr); 259 } 260 261 269 protected void create(ElementSpec[] data) { 270 super.create(data); 271 } 272 273 286 public void setParagraphAttributes(int offset, int length, AttributeSet s, 287 boolean replace) { 288 try { 289 writeLock(); 290 int end = Math.min(offset + length, getLength()); 292 Element e = getParagraphElement(offset); 293 offset = e.getStartOffset(); 294 e = getParagraphElement(end); 295 length = Math.max(0, e.getEndOffset() - offset); 296 DefaultDocumentEvent changes = 297 new DefaultDocumentEvent(offset, length, 298 DocumentEvent.EventType.CHANGE); 299 AttributeSet sCopy = s.copyAttributes(); 300 int lastEnd = Integer.MAX_VALUE; 301 for (int pos = offset; pos <= end; pos = lastEnd) { 302 Element paragraph = getParagraphElement(pos); 303 if (lastEnd == paragraph.getEndOffset()) { 304 lastEnd++; 305 } 306 else { 307 lastEnd = paragraph.getEndOffset(); 308 } 309 MutableAttributeSet attr = 310 (MutableAttributeSet) paragraph.getAttributes(); 311 changes.addEdit(new AttributeUndoableEdit(paragraph, sCopy, replace)); 312 if (replace) { 313 attr.removeAttributes(attr); 314 } 315 attr.addAttributes(s); 316 } 317 changes.end(); 318 fireChangedUpdate(changes); 319 fireUndoableEditUpdate(new UndoableEditEvent(this, changes)); 320 } finally { 321 writeUnlock(); 322 } 323 } 324 325 331 public StyleSheet getStyleSheet() { 332 return (StyleSheet ) getAttributeContext(); 333 } 334 335 345 public Iterator getIterator(HTML.Tag t) { 346 if (t.isBlock()) { 347 return null; 349 } 350 return new LeafIterator(t, this); 351 } 352 353 365 protected Element createLeafElement(Element parent, AttributeSet a, int p0, int p1) { 366 return new RunElement(parent, a, p0, p1); 367 } 368 369 378 protected Element createBranchElement(Element parent, AttributeSet a) { 379 return new BlockElement(parent, a); 380 } 381 382 388 protected AbstractElement createDefaultRoot() { 389 writeLock(); 394 MutableAttributeSet a = new SimpleAttributeSet(); 395 a.addAttribute(StyleConstants.NameAttribute, HTML.Tag.HTML); 396 BlockElement html = new BlockElement(null, a.copyAttributes()); 397 a.removeAttributes(a); 398 a.addAttribute(StyleConstants.NameAttribute, HTML.Tag.BODY); 399 BlockElement body = new BlockElement(html, a.copyAttributes()); 400 a.removeAttributes(a); 401 a.addAttribute(StyleConstants.NameAttribute, HTML.Tag.P); 402 getStyleSheet().addCSSAttributeFromHTML(a, CSS.Attribute.MARGIN_TOP, "0"); 403 BlockElement paragraph = new BlockElement(body, a.copyAttributes()); 404 a.removeAttributes(a); 405 a.addAttribute(StyleConstants.NameAttribute, HTML.Tag.CONTENT); 406 RunElement brk = new RunElement(paragraph, a, 0, 1); 407 Element[] buff = new Element[1]; 408 buff[0] = brk; 409 paragraph.replace(0, 0, buff); 410 buff[0] = paragraph; 411 body.replace(0, 0, buff); 412 buff[0] = body; 413 html.replace(0, 0, buff); 414 writeUnlock(); 415 return html; 416 } 417 418 424 public void setTokenThreshold(int n) { 425 putProperty(TokenThreshold, new Integer (n)); 426 } 427 428 435 public int getTokenThreshold() { 436 Integer i = (Integer ) getProperty(TokenThreshold); 437 if (i != null) { 438 return i.intValue(); 439 } 440 return Integer.MAX_VALUE; 441 } 442 443 452 public void setPreservesUnknownTags(boolean preservesTags) { 453 preservesUnknownTags = preservesTags; 454 } 455 456 463 public boolean getPreservesUnknownTags() { 464 return preservesUnknownTags; 465 } 466 467 507 public void processHTMLFrameHyperlinkEvent(HTMLFrameHyperlinkEvent e) { 508 String frameName = e.getTarget(); 509 Element element = e.getSourceElement(); 510 String urlStr = e.getURL().toString(); 511 512 if (frameName.equals("_self")) { 513 517 updateFrame(element, urlStr); 518 } else if (frameName.equals("_parent")) { 519 522 updateFrameSet(element.getParentElement(), urlStr); 523 } else { 524 527 Element targetElement = findFrame(frameName); 528 if (targetElement != null) { 529 updateFrame(targetElement, urlStr); 530 } 531 } 532 } 533 534 535 544 private Element findFrame(String frameName) { 545 ElementIterator it = new ElementIterator(this); 546 Element next = null; 547 548 while ((next = it.next()) != null) { 549 AttributeSet attr = next.getAttributes(); 550 if (matchNameAttribute(attr, HTML.Tag.FRAME)) { 551 String frameTarget = (String )attr.getAttribute(HTML.Attribute.NAME); 552 if (frameTarget != null && frameTarget.equals(frameName)) { 553 break; 554 } 555 } 556 } 557 return next; 558 } 559 560 569 static boolean matchNameAttribute(AttributeSet attr, HTML.Tag tag) { 570 Object o = attr.getAttribute(StyleConstants.NameAttribute); 571 if (o instanceof HTML.Tag ) { 572 HTML.Tag name = (HTML.Tag ) o; 573 if (name == tag) { 574 return true; 575 } 576 } 577 return false; 578 } 579 580 587 private void updateFrameSet(Element element, String url) { 588 try { 589 int startOffset = element.getStartOffset(); 590 int endOffset = Math.min(getLength(), element.getEndOffset()); 591 String html = "<frame"; 592 if (url != null) { 593 html += " SRC=\"" + url + "\""; 594 } 595 html += ">"; 596 installParserIfNecessary(); 597 setOuterHTML(element, html); 598 } catch (BadLocationException e1) { 599 } catch (IOException ioe) { 601 } 603 } 604 605 606 613 private void updateFrame(Element element, String url) { 614 615 try { 616 writeLock(); 617 DefaultDocumentEvent changes = new DefaultDocumentEvent(element.getStartOffset(), 618 1, 619 DocumentEvent.EventType.CHANGE); 620 AttributeSet sCopy = element.getAttributes().copyAttributes(); 621 MutableAttributeSet attr = (MutableAttributeSet) element.getAttributes(); 622 changes.addEdit(new AttributeUndoableEdit(element, sCopy, false)); 623 attr.removeAttribute(HTML.Attribute.SRC); 624 attr.addAttribute(HTML.Attribute.SRC, url); 625 changes.end(); 626 fireChangedUpdate(changes); 627 fireUndoableEditUpdate(new UndoableEditEvent(this, changes)); 628 } finally { 629 writeUnlock(); 630 } 631 } 632 633 634 638 boolean isFrameDocument() { 639 return frameDocument; 640 } 641 642 648 void setFrameDocumentState(boolean frameDoc) { 649 this.frameDocument = frameDoc; 650 } 651 652 658 void addMap(Map map) { 659 String name = map.getName(); 660 661 if (name != null) { 662 Object maps = getProperty(MAP_PROPERTY); 663 664 if (maps == null) { 665 maps = new Hashtable(11); 666 putProperty(MAP_PROPERTY, maps); 667 } 668 if (maps instanceof Hashtable) { 669 ((Hashtable)maps).put("#" + name, map); 670 } 671 } 672 } 673 674 678 void removeMap(Map map) { 679 String name = map.getName(); 680 681 if (name != null) { 682 Object maps = getProperty(MAP_PROPERTY); 683 684 if (maps instanceof Hashtable) { 685 ((Hashtable)maps).remove("#" + name); 686 } 687 } 688 } 689 690 696 Map getMap(String name) { 697 if (name != null) { 698 Object maps = getProperty(MAP_PROPERTY); 699 700 if (maps != null && (maps instanceof Hashtable)) { 701 return (Map )((Hashtable)maps).get(name); 702 } 703 } 704 return null; 705 } 706 707 712 Enumeration getMaps() { 713 Object maps = getProperty(MAP_PROPERTY); 714 715 if (maps instanceof Hashtable) { 716 return ((Hashtable)maps).elements(); 717 } 718 return null; 719 } 720 721 726 727 void setDefaultStyleSheetType(String contentType) { 728 putProperty(StyleType, contentType); 729 } 730 731 736 737 String getDefaultStyleSheetType() { 738 String retValue = (String )getProperty(StyleType); 739 if (retValue == null) { 740 return "text/css"; 741 } 742 return retValue; 743 } 744 745 757 public void setParser(HTMLEditorKit.Parser parser) { 758 this.parser = parser; 759 putProperty("__PARSER__", null); 760 } 761 762 769 public HTMLEditorKit.Parser getParser() { 770 Object p = getProperty("__PARSER__"); 771 772 if (p instanceof HTMLEditorKit.Parser ) { 773 return (HTMLEditorKit.Parser )p; 774 } 775 return parser; 776 } 777 778 795 public void setInnerHTML(Element elem, String htmlText) throws 796 BadLocationException, IOException { 797 verifyParser(); 798 if (elem != null && elem.isLeaf()) { 799 throw new IllegalArgumentException 800 ("Can not set inner HTML of a leaf"); 801 } 802 if (elem != null && htmlText != null) { 803 int oldCount = elem.getElementCount(); 804 int insertPosition = elem.getStartOffset(); 805 insertHTML(elem, elem.getStartOffset(), htmlText, true); 806 if (elem.getElementCount() > oldCount) { 807 removeElements(elem, elem.getElementCount() - oldCount, 809 oldCount); 810 } 811 } 812 } 813 814 839 public void setOuterHTML(Element elem, String htmlText) throws 840 BadLocationException, IOException { 841 verifyParser(); 842 if (elem != null && elem.getParentElement() != null && 843 htmlText != null) { 844 int start = elem.getStartOffset(); 845 int end = elem.getEndOffset(); 846 int startLength = getLength(); 847 boolean wantsNewline = !elem.isLeaf(); 850 if (!wantsNewline && (end > startLength || 851 getText(end - 1, 1).charAt(0) == NEWLINE[0])){ 852 wantsNewline = true; 853 } 854 Element parent = elem.getParentElement(); 855 int oldCount = parent.getElementCount(); 856 insertHTML(parent, start, htmlText, wantsNewline); 857 int newLength = getLength(); 859 if (oldCount != parent.getElementCount()) { 860 int removeIndex = parent.getElementIndex(start + newLength - 861 startLength); 862 removeElements(parent, removeIndex, 1); 863 } 864 } 865 } 866 867 881 public void insertAfterStart(Element elem, String htmlText) throws 882 BadLocationException, IOException { 883 verifyParser(); 884 if (elem != null && elem.isLeaf()) { 885 throw new IllegalArgumentException 886 ("Can not insert HTML after start of a leaf"); 887 } 888 insertHTML(elem, elem.getStartOffset(), htmlText, false); 889 } 890 891 909 public void insertBeforeEnd(Element elem, String htmlText) throws 910 BadLocationException, IOException { 911 verifyParser(); 912 if (elem != null && elem.isLeaf()) { 913 throw new IllegalArgumentException 914 ("Can not set inner HTML before end of leaf"); 915 } 916 int offset = elem.getEndOffset(); 917 if (elem.getElement(elem.getElementIndex(offset - 1)).isLeaf() && 918 getText(offset - 1, 1).charAt(0) == NEWLINE[0]) { 919 offset--; 920 } 921 insertHTML(elem, offset, htmlText, false); 922 } 923 924 938 public void insertBeforeStart(Element elem, String htmlText) throws 939 BadLocationException, IOException { 940 verifyParser(); 941 if (elem != null) { 942 Element parent = elem.getParentElement(); 943 944 if (parent != null) { 945 insertHTML(parent, elem.getStartOffset(), htmlText, false); 946 } 947 } 948 } 949 950 964 public void insertAfterEnd(Element elem, String htmlText) throws 965 BadLocationException, IOException { 966 verifyParser(); 967 if (elem != null) { 968 Element parent = elem.getParentElement(); 969 970 if (parent != null) { 971 int offset = elem.getEndOffset(); 972 if (offset > getLength()) { 973 offset--; 974 } 975 else if (elem.isLeaf() && getText(offset - 1, 1). 976 charAt(0) == NEWLINE[0]) { 977 offset--; 978 } 979 insertHTML(parent, offset, htmlText, false); 980 } 981 } 982 } 983 984 1002 public Element getElement(String id) { 1003 if (id == null) { 1004 return null; 1005 } 1006 return getElement(getDefaultRootElement(), HTML.Attribute.ID, id, 1007 true); 1008 } 1009 1010 1024 public Element getElement(Element e, Object attribute, Object value) { 1025 return getElement(e, attribute, value, true); 1026 } 1027 1028 1045 private Element getElement(Element e, Object attribute, Object value, 1046 boolean searchLeafAttributes) { 1047 AttributeSet attr = e.getAttributes(); 1048 1049 if (attr != null && attr.isDefined(attribute)) { 1050 if (value.equals(attr.getAttribute(attribute))) { 1051 return e; 1052 } 1053 } 1054 if (!e.isLeaf()) { 1055 for (int counter = 0, maxCounter = e.getElementCount(); 1056 counter < maxCounter; counter++) { 1057 Element retValue = getElement(e.getElement(counter), attribute, 1058 value, searchLeafAttributes); 1059 1060 if (retValue != null) { 1061 return retValue; 1062 } 1063 } 1064 } 1065 else if (searchLeafAttributes && attr != null) { 1066 Enumeration names = attr.getAttributeNames(); 1069 if (names != null) { 1070 while (names.hasMoreElements()) { 1071 Object name = names.nextElement(); 1072 if ((name instanceof HTML.Tag ) && 1073 (attr.getAttribute(name) instanceof AttributeSet)) { 1074 1075 AttributeSet check = (AttributeSet)attr. 1076 getAttribute(name); 1077 if (check.isDefined(attribute) && 1078 value.equals(check.getAttribute(attribute))) { 1079 return e; 1080 } 1081 } 1082 } 1083 } 1084 } 1085 return null; 1086 } 1087 1088 1095 private void verifyParser() { 1096 if (getParser() == null) { 1097 throw new IllegalStateException ("No HTMLEditorKit.Parser"); 1098 } 1099 } 1100 1101 1104 private void installParserIfNecessary() { 1105 if (getParser() == null) { 1106 setParser(new HTMLEditorKit ().getParser()); 1107 } 1108 } 1109 1110 1116 private void insertHTML(Element parent, int offset, String html, 1117 boolean wantsTrailingNewline) 1118 throws BadLocationException, IOException { 1119 if (parent != null && html != null) { 1120 HTMLEditorKit.Parser parser = getParser(); 1121 if (parser != null) { 1122 int lastOffset = Math.max(0, offset - 1); 1123 Element charElement = getCharacterElement(lastOffset); 1124 Element commonParent = parent; 1125 int pop = 0; 1126 int push = 0; 1127 1128 if (parent.getStartOffset() > lastOffset) { 1129 while (commonParent != null && 1130 commonParent.getStartOffset() > lastOffset) { 1131 commonParent = commonParent.getParentElement(); 1132 push++; 1133 } 1134 if (commonParent == null) { 1135 throw new BadLocationException("No common parent", 1136 offset); 1137 } 1138 } 1139 while (charElement != null && charElement != commonParent) { 1140 pop++; 1141 charElement = charElement.getParentElement(); 1142 } 1143 if (charElement != null) { 1144 HTMLReader reader = new HTMLReader(offset, pop - 1, push, 1146 null, false, true, 1147 wantsTrailingNewline); 1148 1149 parser.parse(new StringReader(html), reader, true); 1150 reader.flush(); 1151 } 1152 } 1153 } 1154 } 1155 1156 1165 private void removeElements(Element e, int index, int count) throws BadLocationException { 1166 writeLock(); 1167 try { 1168 int start = e.getElement(index).getStartOffset(); 1169 int end = e.getElement(index + count - 1).getEndOffset(); 1170 if (end > getLength()) { 1171 removeElementsAtEnd(e, index, count, start, end); 1172 } 1173 else { 1174 removeElements(e, index, count, start, end); 1175 } 1176 } finally { 1177 writeUnlock(); 1178 } 1179 } 1180 1181 1191 private void removeElementsAtEnd(Element e, int index, int count, 1192 int start, int end) throws BadLocationException { 1193 boolean isLeaf = (e.getElement(index - 1).isLeaf()); 1195 DefaultDocumentEvent dde = new DefaultDocumentEvent( 1196 start - 1, end - start + 1, DocumentEvent. 1197 EventType.REMOVE); 1198 1199 if (isLeaf) { 1200 Element endE = getCharacterElement(getLength()); 1201 index--; 1203 if (endE.getParentElement() != e) { 1204 replace(dde, e, index, ++count, start, end, true, true); 1207 } 1208 else { 1209 replace(dde, e, index, count, start, end, true, false); 1214 } 1215 } 1216 else { 1217 Element newLineE = e.getElement(index - 1); 1220 while (!newLineE.isLeaf()) { 1221 newLineE = newLineE.getElement(newLineE.getElementCount() - 1); 1222 } 1223 newLineE = newLineE.getParentElement(); 1224 replace(dde, e, index, count, start, end, false, false); 1225 replace(dde, newLineE, newLineE.getElementCount() - 1, 1, start, 1226 end, true, true); 1227 } 1228 postRemoveUpdate(dde); 1229 dde.end(); 1230 fireRemoveUpdate(dde); 1231 fireUndoableEditUpdate(new UndoableEditEvent(this, dde)); 1232 } 1233 1234 1241 private void replace(DefaultDocumentEvent dde, Element e, int index, 1242 int count, int start, int end, boolean remove, 1243 boolean create) throws BadLocationException { 1244 Element[] added; 1245 AttributeSet attrs = e.getElement(index).getAttributes(); 1246 Element[] removed = new Element[count]; 1247 1248 for (int counter = 0; counter < count; counter++) { 1249 removed[counter] = e.getElement(counter + index); 1250 } 1251 if (remove) { 1252 UndoableEdit u = getContent().remove(start - 1, end - start); 1253 if (u != null) { 1254 dde.addEdit(u); 1255 } 1256 } 1257 if (create) { 1258 added = new Element[1]; 1259 added[0] = createLeafElement(e, attrs, start - 1, start); 1260 } 1261 else { 1262 added = new Element[0]; 1263 } 1264 dde.addEdit(new ElementEdit(e, index, removed, added)); 1265 ((AbstractDocument.BranchElement)e).replace( 1266 index, removed.length, added); 1267 } 1268 1269 1272 private void removeElements(Element e, int index, int count, 1273 int start, int end) throws BadLocationException { 1274 Element[] removed = new Element[count]; 1275 Element[] added = new Element[0]; 1276 for (int counter = 0; counter < count; counter++) { 1277 removed[counter] = e.getElement(counter + index); 1278 } 1279 DefaultDocumentEvent dde = new DefaultDocumentEvent 1280 (start, end - start, DocumentEvent.EventType.REMOVE); 1281 ((AbstractDocument.BranchElement)e).replace(index, removed.length, 1282 added); 1283 dde.addEdit(new ElementEdit(e, index, removed, added)); 1284 UndoableEdit u = getContent().remove(start, end - start); 1285 if (u != null) { 1286 dde.addEdit(u); 1287 } 1288 postRemoveUpdate(dde); 1289 dde.end(); 1290 fireRemoveUpdate(dde); 1291 if (u != null) { 1292 fireUndoableEditUpdate(new UndoableEditEvent(this, dde)); 1293 } 1294 } 1295 1296 1297 void obtainLock() { 1300 writeLock(); 1301 } 1302 1303 void releaseLock() { 1304 writeUnlock(); 1305 } 1306 1307 1311 1320 protected void fireChangedUpdate(DocumentEvent e) { 1321 super.fireChangedUpdate(e); 1322 } 1323 1324 1333 protected void fireUndoableEditUpdate(UndoableEditEvent e) { 1334 super.fireUndoableEditUpdate(e); 1335 } 1336 1337 boolean hasBaseTag() { 1338 return hasBaseTag; 1339 } 1340 1341 String getBaseTarget() { 1342 return baseTarget; 1343 } 1344 1345 1349 private boolean frameDocument = false; 1350 private boolean preservesUnknownTags = true; 1351 1352 1356 private HashMap radioButtonGroupsMap; 1357 1358 1362 static final String TokenThreshold = "token threshold"; 1363 1364 private static final int MaxThreshold = 10000; 1365 1366 private static final int StepThreshold = 5; 1367 1368 1369 1373 public static final String AdditionalComments = "AdditionalComments"; 1374 1375 1379 static final String StyleType = "StyleType"; 1380 1381 1387 URL base; 1388 1389 1392 boolean hasBaseTag = false; 1393 1394 1397 private String baseTarget = null; 1398 1399 1403 private HTMLEditorKit.Parser parser; 1404 1405 1408 private static AttributeSet contentAttributeSet; 1409 1410 1413 static String MAP_PROPERTY = "__MAP__"; 1414 1415 private static char[] NEWLINE; 1416 private static final String IMPLIED_CR = "CR"; 1417 1418 1423 private static final String I18NProperty = "i18n"; 1424 1425 private static final boolean isComplex(char ch) { 1426 return (ch >= '\u0900' && ch <= '\u0D7F') || (ch >= '\u0E00' && ch <= '\u0E7F'); } 1429 1430 private static final boolean isComplex(char[] text, int start, int limit) { 1431 for (int i = start; i < limit; ++i) { 1432 if (isComplex(text[i])) { 1433 return true; 1434 } 1435 } 1436 return false; 1437 } 1438 1439 static { 1440 contentAttributeSet = new SimpleAttributeSet(); 1441 ((MutableAttributeSet)contentAttributeSet). 1442 addAttribute(StyleConstants.NameAttribute, 1443 HTML.Tag.CONTENT); 1444 NEWLINE = new char[1]; 1445 NEWLINE[0] = '\n'; 1446 } 1447 1448 1449 1457 public static abstract class Iterator { 1458 1459 1464 public abstract AttributeSet getAttributes(); 1465 1466 1472 public abstract int getStartOffset(); 1473 1474 1480 public abstract int getEndOffset(); 1481 1482 1486 public abstract void next(); 1487 1488 1495 public abstract boolean isValid(); 1496 1497 1500 public abstract HTML.Tag getTag(); 1501 } 1502 1503 1506 static class LeafIterator extends Iterator { 1507 1508 LeafIterator(HTML.Tag t, Document doc) { 1509 tag = t; 1510 pos = new ElementIterator(doc); 1511 endOffset = 0; 1512 next(); 1513 } 1514 1515 1520 public AttributeSet getAttributes() { 1521 Element elem = pos.current(); 1522 if (elem != null) { 1523 AttributeSet a = (AttributeSet) 1524 elem.getAttributes().getAttribute(tag); 1525 return a; 1526 } 1527 return null; 1528 } 1529 1530 1536 public int getStartOffset() { 1537 Element elem = pos.current(); 1538 if (elem != null) { 1539 return elem.getStartOffset(); 1540 } 1541 return -1; 1542 } 1543 1544 1550 public int getEndOffset() { 1551 return endOffset; 1552 } 1553 1554 1558 public void next() { 1559 for (nextLeaf(pos); isValid(); nextLeaf(pos)) { 1560 Element elem = pos.current(); 1561 if (elem.getStartOffset() >= endOffset) { 1562 AttributeSet a = pos.current().getAttributes(); 1563 1564 if (a.isDefined(tag) || 1565 a.getAttribute(StyleConstants.NameAttribute) == tag) { 1566 1567 setEndOffset(); 1569 break; 1570 } 1571 } 1572 } 1573 } 1574 1575 1581 public HTML.Tag getTag() { 1582 return tag; 1583 } 1584 1585 1590 public boolean isValid() { 1591 return (pos.current() != null); 1592 } 1593 1594 1598 void nextLeaf(ElementIterator iter) { 1599 for (iter.next(); iter.current() != null; iter.next()) { 1600 Element e = iter.current(); 1601 if (e.isLeaf()) { 1602 break; 1603 } 1604 } 1605 } 1606 1607 1611 void setEndOffset() { 1612 AttributeSet a0 = getAttributes(); 1613 endOffset = pos.current().getEndOffset(); 1614 ElementIterator fwd = (ElementIterator) pos.clone(); 1615 for (nextLeaf(fwd); fwd.current() != null; nextLeaf(fwd)) { 1616 Element e = fwd.current(); 1617 AttributeSet a1 = (AttributeSet) e.getAttributes().getAttribute(tag); 1618 if ((a1 == null) || (! a1.equals(a0))) { 1619 break; 1620 } 1621 endOffset = e.getEndOffset(); 1622 } 1623 } 1624 1625 private int endOffset; 1626 private HTML.Tag tag; 1627 private ElementIterator pos; 1628 1629 } 1630 1631 1775 public class HTMLReader extends HTMLEditorKit.ParserCallback { 1776 1777 public HTMLReader(int offset) { 1778 this(offset, 0, 0, null); 1779 } 1780 1781 public HTMLReader(int offset, int popDepth, int pushDepth, 1782 HTML.Tag insertTag) { 1783 this(offset, popDepth, pushDepth, insertTag, true, false, true); 1784 } 1785 1786 1792 HTMLReader(int offset, int popDepth, int pushDepth, 1795 HTML.Tag insertTag, boolean insertInsertTag, 1796 boolean insertAfterImplied, boolean wantsTrailingNewline) { 1797 emptyDocument = (getLength() == 0); 1798 isStyleCSS = "text/css".equals(getDefaultStyleSheetType()); 1799 this.offset = offset; 1800 threshold = HTMLDocument.this.getTokenThreshold(); 1801 tagMap = new Hashtable(57); 1802 TagAction na = new TagAction(); 1803 TagAction ba = new BlockAction(); 1804 TagAction pa = new ParagraphAction(); 1805 TagAction ca = new CharacterAction(); 1806 TagAction sa = new SpecialAction(); 1807 TagAction fa = new FormAction(); 1808 TagAction ha = new HiddenAction(); 1809 TagAction conv = new ConvertAction(); 1810 1811 tagMap.put(HTML.Tag.A, new AnchorAction()); 1813 tagMap.put(HTML.Tag.ADDRESS, ca); 1814 tagMap.put(HTML.Tag.APPLET, ha); 1815 tagMap.put(HTML.Tag.AREA, new AreaAction()); 1816 tagMap.put(HTML.Tag.B, conv); 1817 tagMap.put(HTML.Tag.BASE, new BaseAction()); 1818 tagMap.put(HTML.Tag.BASEFONT, ca); 1819 tagMap.put(HTML.Tag.BIG, ca); 1820 tagMap.put(HTML.Tag.BLOCKQUOTE, ba); 1821 tagMap.put(HTML.Tag.BODY, ba); 1822 tagMap.put(HTML.Tag.BR, sa); 1823 tagMap.put(HTML.Tag.CAPTION, ba); 1824 tagMap.put(HTML.Tag.CENTER, ba); 1825 tagMap.put(HTML.Tag.CITE, ca); 1826 tagMap.put(HTML.Tag.CODE, ca); 1827 tagMap.put(HTML.Tag.DD, ba); 1828 tagMap.put(HTML.Tag.DFN, ca); 1829 tagMap.put(HTML.Tag.DIR, ba); 1830 tagMap.put(HTML.Tag.DIV, ba); 1831 tagMap.put(HTML.Tag.DL, ba); 1832 tagMap.put(HTML.Tag.DT, pa); 1833 tagMap.put(HTML.Tag.EM, ca); 1834 tagMap.put(HTML.Tag.FONT, conv); 1835 tagMap.put(HTML.Tag.FORM, new FormTagAction()); 1836 tagMap.put(HTML.Tag.FRAME, sa); 1837 tagMap.put(HTML.Tag.FRAMESET, ba); 1838 tagMap.put(HTML.Tag.H1, pa); 1839 tagMap.put(HTML.Tag.H2, pa); 1840 tagMap.put(HTML.Tag.H3, pa); 1841 tagMap.put(HTML.Tag.H4, pa); 1842 tagMap.put(HTML.Tag.H5, pa); 1843 tagMap.put(HTML.Tag.H6, pa); 1844 tagMap.put(HTML.Tag.HEAD, new HeadAction()); 1845 tagMap.put(HTML.Tag.HR, sa); 1846 tagMap.put(HTML.Tag.HTML, ba); 1847 tagMap.put(HTML.Tag.I, conv); 1848 tagMap.put(HTML.Tag.IMG, sa); 1849 tagMap.put(HTML.Tag.INPUT, fa); 1850 tagMap.put(HTML.Tag.ISINDEX, new IsindexAction()); 1851 tagMap.put(HTML.Tag.KBD, ca); 1852 tagMap.put(HTML.Tag.LI, ba); 1853 tagMap.put(HTML.Tag.LINK, new LinkAction()); 1854 tagMap.put(HTML.Tag.MAP, new MapAction()); 1855 tagMap.put(HTML.Tag.MENU, ba); 1856 tagMap.put(HTML.Tag.META, new MetaAction()); 1857 tagMap.put(HTML.Tag.NOBR, ca); 1858 tagMap.put(HTML.Tag.NOFRAMES, ba); 1859 tagMap.put(HTML.Tag.OBJECT, sa); 1860 tagMap.put(HTML.Tag.OL, ba); 1861 tagMap.put(HTML.Tag.OPTION, fa); 1862 tagMap.put(HTML.Tag.P, pa); 1863 tagMap.put(HTML.Tag.PARAM, new ObjectAction()); 1864 tagMap.put(HTML.Tag.PRE, new PreAction()); 1865 tagMap.put(HTML.Tag.SAMP, ca); 1866 tagMap.put(HTML.Tag.SCRIPT, ha); 1867 tagMap.put(HTML.Tag.SELECT, fa); 1868 tagMap.put(HTML.Tag.SMALL, ca); 1869 tagMap.put(HTML.Tag.SPAN, ca); 1870 tagMap.put(HTML.Tag.STRIKE, conv); 1871 tagMap.put(HTML.Tag.S, ca); 1872 tagMap.put(HTML.Tag.STRONG, ca); 1873 tagMap.put(HTML.Tag.STYLE, new StyleAction()); 1874 tagMap.put(HTML.Tag.SUB, conv); 1875 tagMap.put(HTML.Tag.SUP, conv); 1876 tagMap.put(HTML.Tag.TABLE, ba); 1877 tagMap.put(HTML.Tag.TD, ba); 1878 tagMap.put(HTML.Tag.TEXTAREA, fa); 1879 tagMap.put(HTML.Tag.TH, ba); 1880 tagMap.put(HTML.Tag.TITLE, new TitleAction()); 1881 tagMap.put(HTML.Tag.TR, ba); 1882 tagMap.put(HTML.Tag.TT, ca); 1883 tagMap.put(HTML.Tag.U, conv); 1884 tagMap.put(HTML.Tag.UL, ba); 1885 tagMap.put(HTML.Tag.VAR, ca); 1886 1887 if (insertTag != null) { 1888 this.insertTag = insertTag; 1889 this.popDepth = popDepth; 1890 this.pushDepth = pushDepth; 1891 this.insertInsertTag = insertInsertTag; 1892 foundInsertTag = false; 1893 } 1894 else { 1895 foundInsertTag = true; 1896 } 1897 if (insertAfterImplied) { 1898 this.popDepth = popDepth; 1899 this.pushDepth = pushDepth; 1900 this.insertAfterImplied = true; 1901 foundInsertTag = false; 1902 midInsert = false; 1903 this.insertInsertTag = true; 1904 this.wantsTrailingNewline = wantsTrailingNewline; 1905 } 1906 else { 1907 midInsert = (!emptyDocument && insertTag == null); 1908 if (midInsert) { 1909 generateEndsSpecsForMidInsert(); 1910 } 1911 } 1912 } 1913 1914 1918 private void generateEndsSpecsForMidInsert() { 1919 int count = heightToElementWithName(HTML.Tag.BODY, 1920 Math.max(0, offset - 1)); 1921 boolean joinNext = false; 1922 1923 if (count == -1 && offset > 0) { 1924 count = heightToElementWithName(HTML.Tag.BODY, offset); 1925 if (count != -1) { 1926 count = depthTo(offset - 1) - 1; 1929 joinNext = true; 1930 } 1931 } 1932 if (count == -1) { 1933 throw new RuntimeException ("Must insert new content into body element-"); 1934 } 1935 if (count != -1) { 1936 try { 1938 if (!joinNext && offset > 0 && 1939 !getText(offset - 1, 1).equals("\n")) { 1940 SimpleAttributeSet newAttrs = new SimpleAttributeSet(); 1941 newAttrs.addAttribute(StyleConstants.NameAttribute, 1942 HTML.Tag.CONTENT); 1943 ElementSpec spec = new ElementSpec(newAttrs, 1944 ElementSpec.ContentType, NEWLINE, 0, 1); 1945 parseBuffer.addElement(spec); 1946 } 1947 } catch (BadLocationException ble) {} 1949 while (count-- > 0) { 1950 parseBuffer.addElement(new ElementSpec 1951 (null, ElementSpec.EndTagType)); 1952 } 1953 if (joinNext) { 1954 ElementSpec spec = new ElementSpec(null, ElementSpec. 1955 StartTagType); 1956 1957 spec.setDirection(ElementSpec.JoinNextDirection); 1958 parseBuffer.addElement(spec); 1959 } 1960 } 1961 } 1964 1965 1968 private int depthTo(int offset) { 1969 Element e = getDefaultRootElement(); 1970 int count = 0; 1971 1972 while (!e.isLeaf()) { 1973 count++; 1974 e = e.getElement(e.getElementIndex(offset)); 1975 } 1976 return count; 1977 } 1978 1979 1985 private int heightToElementWithName(Object name, int offset) { 1986 Element e = getCharacterElement(offset).getParentElement(); 1987 int count = 0; 1988 1989 while (e != null && e.getAttributes().getAttribute 1990 (StyleConstants.NameAttribute) != name) { 1991 count++; 1992 e = e.getParentElement(); 1993 } 1994 return (e == null) ? -1 : count; 1995 } 1996 1997 2001 private void adjustEndElement() { 2002 int length = getLength(); 2003 if (length == 0) { 2004 return; 2005 } 2006 obtainLock(); 2007 try { 2008 Element[] pPath = getPathTo(length - 1); 2009 int pLength = pPath.length; 2010 if (pLength > 1 && pPath[1].getAttributes().getAttribute 2011 (StyleConstants.NameAttribute) == HTML.Tag.BODY && 2012 pPath[1].getEndOffset() == length) { 2013 String lastText = getText(length - 1, 1); 2014 DefaultDocumentEvent event = null; 2015 Element[] added; 2016 Element[] removed; 2017 int index; 2018 added = new Element[0]; 2020 removed = new Element[1]; 2021 index = pPath[0].getElementIndex(length); 2022 removed[0] = pPath[0].getElement(index); 2023 ((BranchElement)pPath[0]).replace(index, 1, added); 2024 ElementEdit firstEdit = new ElementEdit(pPath[0], index, 2025 removed, added); 2026 2027 SimpleAttributeSet sas = new SimpleAttributeSet(); 2030 sas.addAttribute(StyleConstants.NameAttribute, 2031 HTML.Tag.CONTENT); 2032 sas.addAttribute(IMPLIED_CR, Boolean.TRUE); 2033 added = new Element[1]; 2034 added[0] = createLeafElement(pPath[pLength - 1], 2035 sas, length, length + 1); 2036 index = pPath[pLength - 1].getElementCount(); 2037 ((BranchElement)pPath[pLength - 1]).replace(index, 0, 2038 added); 2039 event = new DefaultDocumentEvent(length, 1, 2040 DocumentEvent.EventType.CHANGE); 2041 event.addEdit(new ElementEdit(pPath[pLength - 1], 2042 index, new Element[0], added)); 2043 event.addEdit(firstEdit); 2044 event.end(); 2045 fireChangedUpdate(event); 2046 fireUndoableEditUpdate(new UndoableEditEvent(this, event)); 2047 2048 if (lastText.equals("\n")) { 2049 event = new DefaultDocumentEvent(length - 1, 1, 2052 DocumentEvent.EventType.REMOVE); 2053 removeUpdate(event); 2054 UndoableEdit u = getContent().remove(length - 1, 1); 2055 if (u != null) { 2056 event.addEdit(u); 2057 } 2058 postRemoveUpdate(event); 2059 event.end(); 2061 fireRemoveUpdate(event); 2062 fireUndoableEditUpdate(new UndoableEditEvent( 2063 this, event)); 2064 } 2065 } 2066 } 2067 catch (BadLocationException ble) { 2068 } 2069 finally { 2070 releaseLock(); 2071 } 2072 } 2073 2074 private Element[] getPathTo(int offset) { 2075 Stack elements = new Stack(); 2076 Element e = getDefaultRootElement(); 2077 int index; 2078 while (!e.isLeaf()) { 2079 elements.push(e); 2080 e = e.getElement(e.getElementIndex(offset)); 2081 } 2082 Element[] retValue = new Element[elements.size()]; 2083 elements.copyInto(retValue); 2084 return retValue; 2085 } 2086 2087 2089 2095 public void flush() throws BadLocationException { 2096 if (emptyDocument && !insertAfterImplied) { 2097 if (HTMLDocument.this.getLength() > 0 || 2098 parseBuffer.size() > 0) { 2099 flushBuffer(true); 2100 adjustEndElement(); 2101 } 2102 } 2104 else { 2105 flushBuffer(true); 2106 } 2107 } 2108 2109 2113 public void handleText(char[] data, int pos) { 2114 if (receivedEndHTML || (midInsert && !inBody)) { 2115 return; 2116 } 2117 2118 if(HTMLDocument.this.getProperty(I18NProperty).equals( Boolean.FALSE ) ) { 2120 Object d = getProperty(TextAttribute.RUN_DIRECTION); 2123 if ((d != null) && (d.equals(TextAttribute.RUN_DIRECTION_RTL))) { 2124 HTMLDocument.this.putProperty( I18NProperty, Boolean.TRUE); 2125 } else { 2126 if (Bidi.requiresBidi(data, 0, data.length) || 2127 isComplex(data, 0, data.length)) { 2128 HTMLDocument.this.putProperty( I18NProperty, Boolean.TRUE); 2130 } 2131 } 2132 } 2133 2134 if (inTextArea) { 2135 textAreaContent(data); 2136 } else if (inPre) { 2137 preContent(data); 2138 } else if (inTitle) { 2139 putProperty(Document.TitleProperty, new String (data)); 2140 } else if (option != null) { 2141 option.setLabel(new String (data)); 2142 } else if (inStyle) { 2143 if (styles != null) { 2144 styles.addElement(new String (data)); 2145 } 2146 } else if (inBlock > 0) { 2147 if (!foundInsertTag && insertAfterImplied) { 2148 foundInsertTag(false); 2150 foundInsertTag = true; 2151 inParagraph = impliedP = true; 2152 } 2153 if (data.length >= 1) { 2154 addContent(data, 0, data.length); 2155 } 2156 } 2157 } 2158 2159 2163 public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) { 2164 if (receivedEndHTML) { 2165 return; 2166 } 2167 if (midInsert && !inBody) { 2168 if (t == HTML.Tag.BODY) { 2169 inBody = true; 2170 inBlock++; 2175 } 2176 return; 2177 } 2178 if (!inBody && t == HTML.Tag.BODY) { 2179 inBody = true; 2180 } 2181 if (isStyleCSS && a.isDefined(HTML.Attribute.STYLE)) { 2182 String decl = (String )a.getAttribute(HTML.Attribute.STYLE); 2184 a.removeAttribute(HTML.Attribute.STYLE); 2185 styleAttributes = getStyleSheet().getDeclaration(decl); 2186 a.addAttributes(styleAttributes); 2187 } 2188 else { 2189 styleAttributes = null; 2190 } 2191 TagAction action = (TagAction) tagMap.get(t); 2192 2193 if (action != null) { 2194 action.start(t, a); 2195 } 2196 } 2197 2198 public void handleComment(char[] data, int pos) { 2199 if (receivedEndHTML) { 2200 addExternalComment(new String (data)); 2201 return; 2202 } 2203 if (inStyle) { 2204 if (styles != null) { 2205 styles.addElement(new String (data)); 2206 } 2207 } 2208 else if (getPreservesUnknownTags()) { 2209 if (inBlock == 0 && (foundInsertTag || 2210 insertTag != HTML.Tag.COMMENT)) { 2211 addExternalComment(new String (data)); 2214 return; 2215 } 2216 SimpleAttributeSet sas = new SimpleAttributeSet(); 2217 sas.addAttribute(HTML.Attribute.COMMENT, new String (data)); 2218 addSpecialElement(HTML.Tag.COMMENT, sas); 2219 } 2220 2221 TagAction action = (TagAction)tagMap.get(HTML.Tag.COMMENT); 2222 if (action != null) { 2223 action.start(HTML.Tag.COMMENT, new SimpleAttributeSet()); 2224 action.end(HTML.Tag.COMMENT); 2225 } 2226 } 2227 2228 2232 private void addExternalComment(String comment) { 2233 Object comments = getProperty(AdditionalComments); 2234 if (comments != null && !(comments instanceof Vector)) { 2235 return; 2237 } 2238 if (comments == null) { 2239 comments = new Vector(); 2240 putProperty(AdditionalComments, comments); 2241 } 2242 ((Vector)comments).addElement(comment); 2243 } 2244 2245 2249 public void handleEndTag(HTML.Tag t, int pos) { 2250 if (receivedEndHTML || (midInsert && !inBody)) { 2251 return; 2252 } 2253 if (t == HTML.Tag.HTML) { 2254 receivedEndHTML = true; 2255 } 2256 if (t == HTML.Tag.BODY) { 2257 inBody = false; 2258 if (midInsert) { 2259 inBlock--; 2260 } 2261 } 2262 TagAction action = (TagAction) tagMap.get(t); 2263 if (action != null) { 2264 action.end(t); 2265 } 2266 } 2267 2268 2272 public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos) { 2273 if (receivedEndHTML || (midInsert && !inBody)) { 2274 return; 2275 } 2276 2277 if (isStyleCSS && a.isDefined(HTML.Attribute.STYLE)) { 2278 String decl = (String )a.getAttribute(HTML.Attribute.STYLE); 2280 a.removeAttribute(HTML.Attribute.STYLE); 2281 styleAttributes = getStyleSheet().getDeclaration(decl); 2282 a.addAttributes(styleAttributes); 2283 } 2284 else { 2285 styleAttributes = null; 2286 } 2287 2288 TagAction action = (TagAction) tagMap.get(t); 2289 if (action != null) { 2290 action.start(t, a); 2291 action.end(t); 2292 } 2293 else if (getPreservesUnknownTags()) { 2294 addSpecialElement(t, a); 2296 } 2297 } 2298 2299 2307 public void handleEndOfLineString(String eol) { 2308 if (emptyDocument && eol != null) { 2309 putProperty(DefaultEditorKit.EndOfLineStringProperty, 2310 eol); 2311 } 2312 } 2313 2314 2316 2322 protected void registerTag(HTML.Tag t, TagAction a) { 2323 tagMap.put(t, a); 2324 } 2325 2326 2332 public class TagAction { 2333 2334 2342 public void start(HTML.Tag t, MutableAttributeSet a) { 2343 } 2344 2345 2353 public void end(HTML.Tag t) { 2354 } 2355 2356 } 2357 2358 public class BlockAction extends TagAction { 2359 2360 public void start(HTML.Tag t, MutableAttributeSet attr) { 2361 blockOpen(t, attr); 2362 } 2363 2364 public void end(HTML.Tag t) { 2365 blockClose(t); 2366 } 2367 } 2368 2369 2370 2374 private class FormTagAction extends BlockAction { 2375 public void start(HTML.Tag t, MutableAttributeSet attr) { 2376 super.start(t, attr); 2377 radioButtonGroupsMap = new HashMap(); 2384 } 2385 2386 public void end(HTML.Tag t) { 2387 super.end(t); 2388 radioButtonGroupsMap = null; 2391 } 2392 } 2393 2394 2395 public class ParagraphAction extends BlockAction { 2396 2397 public void start(HTML.Tag t, MutableAttributeSet a) { 2398 super.start(t, a); 2399 inParagraph = true; 2400 } 2401 2402 public void end(HTML.Tag t) { 2403 super.end(t); 2404 inParagraph = false; 2405 } 2406 } 2407 2408 public class SpecialAction extends TagAction { 2409 2410 public void start(HTML.Tag t, MutableAttributeSet a) { 2411 addSpecialElement(t, a); 2412 } 2413 2414 } 2415 2416 public class IsindexAction extends TagAction { 2417 2418 public void start(HTML.Tag t, MutableAttributeSet a) { 2419 blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet()); 2420 addSpecialElement(t, a); 2421 blockClose(HTML.Tag.IMPLIED); 2422 } 2423 2424 } 2425 2426 2427 public class HiddenAction extends TagAction { 2428 2429 public void start(HTML.Tag t, MutableAttributeSet a) { 2430 addSpecialElement(t, a); 2431 } 2432 2433 public void end(HTML.Tag t) { 2434 if (!isEmpty(t)) { 2435 MutableAttributeSet a = new SimpleAttributeSet(); 2436 a.addAttribute(HTML.Attribute.ENDTAG, "true"); 2437 addSpecialElement(t, a); 2438 } 2439 } 2440 2441 boolean isEmpty(HTML.Tag t) { 2442 if (t == HTML.Tag.APPLET || 2443 t == HTML.Tag.SCRIPT) { 2444 return false; 2445 } 2446 return true; 2447 } 2448 } 2449 2450 2451 2455 class MetaAction extends HiddenAction { 2456 2457 public void start(HTML.Tag t, MutableAttributeSet a) { 2458 Object equiv = a.getAttribute(HTML.Attribute.HTTPEQUIV); 2459 if (equiv != null) { 2460 equiv = ((String )equiv).toLowerCase(); 2461 if (equiv.equals("content-style-type")) { 2462 String value = (String )a.getAttribute 2463 (HTML.Attribute.CONTENT); 2464 setDefaultStyleSheetType(value); 2465 isStyleCSS = "text/css".equals 2466 (getDefaultStyleSheetType()); 2467 } 2468 else if (equiv.equals("default-style")) { 2469 defaultStyle = (String )a.getAttribute 2470 (HTML.Attribute.CONTENT); 2471 } 2472 } 2473 super.start(t, a); 2474 } 2475 2476 boolean isEmpty(HTML.Tag t) { 2477 return true; 2478 } 2479 } 2480 2481 2482 2488 class HeadAction extends BlockAction { 2489 2490 public void start(HTML.Tag t, MutableAttributeSet a) { 2491 inHead = true; 2492 if ((insertTag == null && !insertAfterImplied) || 2496 (insertTag == HTML.Tag.HEAD) || 2497 (insertAfterImplied && 2498 (foundInsertTag || !a.isDefined(IMPLIED)))) { 2499 super.start(t, a); 2500 } 2501 } 2502 2503 public void end(HTML.Tag t) { 2504 inHead = inStyle = false; 2505 if (styles != null) { 2507 boolean isDefaultCSS = isStyleCSS; 2508 for (int counter = 0, maxCounter = styles.size(); 2509 counter < maxCounter;) { 2510 Object value = styles.elementAt(counter); 2511 if (value == HTML.Tag.LINK) { 2512 handleLink((AttributeSet)styles. 2513 elementAt(++counter)); 2514 counter++; 2515 } 2516 else { 2517 String type = (String )styles.elementAt(++counter); 2520 boolean isCSS = (type == null) ? isDefaultCSS : 2521 type.equals("text/css"); 2522 while (++counter < maxCounter && 2523 (styles.elementAt(counter) 2524 instanceof String )) { 2525 if (isCSS) { 2526 addCSSRules((String )styles.elementAt 2527 (counter)); 2528 } 2529 } 2530 } 2531 } 2532 } 2533 if ((insertTag == null && !insertAfterImplied) || 2534 insertTag == HTML.Tag.HEAD || 2535 (insertAfterImplied && foundInsertTag)) { 2536 super.end(t); 2537 } 2538 } 2539 2540 boolean isEmpty(HTML.Tag t) { 2541 return false; 2542 } 2543 2544 private void handleLink(AttributeSet attr) { 2545 String type = (String )attr.getAttribute(HTML.Attribute.TYPE); 2547 if (type == null) { 2548 type = getDefaultStyleSheetType(); 2549 } 2550 if (type.equals("text/css")) { 2555 String rel = (String )attr.getAttribute(HTML.Attribute.REL); 2556 String title = (String )attr.getAttribute 2557 (HTML.Attribute.TITLE); 2558 String media = (String )attr.getAttribute 2559 (HTML.Attribute.MEDIA); 2560 if (media == null) { 2561 media = "all"; 2562 } 2563 else { 2564 media = media.toLowerCase(); 2565 } 2566 if (rel != null) { 2567 rel = rel.toLowerCase(); 2568 if ((media.indexOf("all") != -1 || 2569 media.indexOf("screen") != -1) && 2570 (rel.equals("stylesheet") || 2571 (rel.equals("alternate stylesheet") && 2572 title.equals(defaultStyle)))) { 2573 linkCSSStyleSheet((String )attr.getAttribute 2574 (HTML.Attribute.HREF)); 2575 } 2576 } 2577 } 2578 } 2579 } 2580 2581 2582 2587 class LinkAction extends HiddenAction { 2588 2589 public void start(HTML.Tag t, MutableAttributeSet a) { 2590 String rel = (String )a.getAttribute(HTML.Attribute.REL); 2591 if (rel != null) { 2592 rel = rel.toLowerCase(); 2593 if (rel.equals("stylesheet") || 2594 rel.equals("alternate stylesheet")) { 2595 if (styles == null) { 2596 styles = new Vector(3); 2597 } 2598 styles.addElement(t); 2599 styles.addElement(a.copyAttributes()); 2600 } 2601 } 2602 super.start(t, a); 2603 } 2604 } 2605 2606 class MapAction extends TagAction { 2607 2608 public void start(HTML.Tag t, MutableAttributeSet a) { 2609 lastMap = new Map ((String )a.getAttribute(HTML.Attribute.NAME)); 2610 addMap(lastMap); 2611 } 2612 2613 public void end(HTML.Tag t) { 2614 } 2615 } 2616 2617 2618 class AreaAction extends TagAction { 2619 2620 public void start(HTML.Tag t, MutableAttributeSet a) { 2621 if (lastMap != null) { 2622 lastMap.addArea(a.copyAttributes()); 2623 } 2624 } 2625 2626 public void end(HTML.Tag t) { 2627 } 2628 } 2629 2630 2631 class StyleAction extends TagAction { 2632 2633 public void start(HTML.Tag t, MutableAttributeSet a) { 2634 if (inHead) { 2635 if (styles == null) { 2636 styles = new Vector(3); 2637 } 2638 styles.addElement(t); 2639 styles.addElement(a.getAttribute(HTML.Attribute.TYPE)); 2640 inStyle = true; 2641 } 2642 } 2643 2644 public void end(HTML.Tag t) { 2645 inStyle = false; 2646 } 2647 2648 boolean isEmpty(HTML.Tag t) { 2649 return false; 2650 } 2651 } 2652 2653 2654 public class PreAction extends BlockAction { 2655 2656 public void start(HTML.Tag t, MutableAttributeSet attr) { 2657 inPre = true; 2658 blockOpen(t, attr); 2659 attr.addAttribute(CSS.Attribute.WHITE_SPACE, "pre"); 2660 blockOpen(HTML.Tag.IMPLIED, attr); 2661 } 2662 2663 public void end(HTML.Tag t) { 2664 blockClose(HTML.Tag.IMPLIED); 2665 inPre = false; 2668 blockClose(t); 2669 } 2670 } 2671 2672 public class CharacterAction extends TagAction { 2673 2674 public void start(HTML.Tag t, MutableAttributeSet attr) { 2675 pushCharacterStyle(); 2676 if (!foundInsertTag) { 2677 boolean insert = canInsertTag(t, attr, false); 2682 if (foundInsertTag) { 2683 if (!inParagraph) { 2684 inParagraph = impliedP = true; 2685 } 2686 } 2687 if (!insert) { 2688 return; 2689 } 2690 } 2691 if (attr.isDefined(IMPLIED)) { 2692 attr.removeAttribute(IMPLIED); 2693 } 2694 charAttr.addAttribute(t, attr.copyAttributes()); 2695 if (styleAttributes != null) { 2696 charAttr.addAttributes(styleAttributes); 2697 } 2698 } 2699 2700 public void end(HTML.Tag t) { 2701 popCharacterStyle(); 2702 } 2703 } 2704 2705 2710 class ConvertAction extends TagAction { 2711 2712 public void start(HTML.Tag t, MutableAttributeSet attr) { 2713 pushCharacterStyle(); 2714 if (!foundInsertTag) { 2715 boolean insert = canInsertTag(t, attr, false); 2720 if (foundInsertTag) { 2721 if (!inParagraph) { 2722 inParagraph = impliedP = true; 2723 } 2724 } 2725 if (!insert) { 2726 return; 2727 } 2728 } 2729 if (attr.isDefined(IMPLIED)) { 2730 attr.removeAttribute(IMPLIED); 2731 } 2732 if (styleAttributes != null) { 2733 charAttr.addAttributes(styleAttributes); 2734 } 2735 charAttr.addAttribute(t, attr.copyAttributes()); 2739 StyleSheet sheet = getStyleSheet(); 2740 if (t == HTML.Tag.B) { 2741 sheet.addCSSAttribute(charAttr, CSS.Attribute.FONT_WEIGHT, "bold"); 2742 } else if (t == HTML.Tag.I) { 2743 sheet.addCSSAttribute(charAttr, CSS.Attribute.FONT_STYLE, "italic"); 2744 } else if (t == HTML.Tag.U) { 2745 Object v = charAttr.getAttribute(CSS.Attribute.TEXT_DECORATION); 2746 String value = "underline"; 2747 value = (v != null) ? value + "," + v.toString() : value; 2748 sheet.addCSSAttribute(charAttr, CSS.Attribute.TEXT_DECORATION, value); 2749 } else if (t == HTML.Tag.STRIKE) { 2750 Object v = charAttr.getAttribute(CSS.Attribute.TEXT_DECORATION); 2751 String value = "line-through"; 2752 value = (v != null) ? value + "," + v.toString() : value; 2753 sheet.addCSSAttribute(charAttr, CSS.Attribute.TEXT_DECORATION, value); 2754 } else if (t == HTML.Tag.SUP) { 2755 Object v = charAttr.getAttribute(CSS.Attribute.VERTICAL_ALIGN); 2756 String value = "sup"; 2757 value = (v != null) ? value + "," + v.toString() : value; 2758 sheet.addCSSAttribute(charAttr, CSS.Attribute.VERTICAL_ALIGN, value); 2759 } else if (t == HTML.Tag.SUB) { 2760 Object v = charAttr.getAttribute(CSS.Attribute.VERTICAL_ALIGN); 2761 String value = "sub"; 2762 value = (v != null) ? value + "," + v.toString() : value; 2763 sheet.addCSSAttribute(charAttr, CSS.Attribute.VERTICAL_ALIGN, value); 2764 } else if (t == HTML.Tag.FONT) { 2765 String color = (String ) attr.getAttribute(HTML.Attribute.COLOR); 2766 if (color != null) { 2767 sheet.addCSSAttribute(charAttr, CSS.Attribute.COLOR, color); 2768 } 2769 String face = (String ) attr.getAttribute(HTML.Attribute.FACE); 2770 if (face != null) { 2771 sheet.addCSSAttribute(charAttr, CSS.Attribute.FONT_FAMILY, face); 2772 } 2773 String size = (String ) attr.getAttribute(HTML.Attribute.SIZE); 2774 if (size != null) { 2775 sheet.addCSSAttributeFromHTML(charAttr, CSS.Attribute.FONT_SIZE, size); 2776 } 2777 } 2778 } 2779 2780 public void end(HTML.Tag t) { 2781 popCharacterStyle(); 2782 } 2783 2784 } 2785 2786 class AnchorAction extends CharacterAction { 2787 2788 public void start(HTML.Tag t, MutableAttributeSet attr) { 2789 emptyAnchor = true; 2791 super.start(t, attr); 2792 } 2793 2794 public void end(HTML.Tag t) { 2795 if (emptyAnchor) { 2796 char[] one = new char[1]; 2800 one[0] = '\n'; 2801 addContent(one, 0, 1); 2802 } 2803 super.end(t); 2804 } 2805 } 2806 2807 class TitleAction extends HiddenAction { 2808 2809 public void start(HTML.Tag t, MutableAttributeSet attr) { 2810 inTitle = true; 2811 super.start(t, attr); 2812 } 2813 2814 public void end(HTML.Tag t) { 2815 inTitle = false; 2816 super.end(t); 2817 } 2818 2819 boolean isEmpty(HTML.Tag t) { 2820 return false; 2821 } 2822 } 2823 2824 2825 class BaseAction extends TagAction { 2826 2827 public void start(HTML.Tag t, MutableAttributeSet attr) { 2828 String href = (String ) attr.getAttribute(HTML.Attribute.HREF); 2829 if (href != null) { 2830 try { 2831 URL newBase = new URL (base, href); 2832 setBase(newBase); 2833 hasBaseTag = true; 2834 } catch (MalformedURLException ex) { 2835 } 2836 } 2837 baseTarget = (String ) attr.getAttribute(HTML.Attribute.TARGET); 2838 } 2839 } 2840 2841 class ObjectAction extends SpecialAction { 2842 2843 public void start(HTML.Tag t, MutableAttributeSet a) { 2844 if (t == HTML.Tag.PARAM) { 2845 addParameter(a); 2846 } else { 2847 super.start(t, a); 2848 } 2849 } 2850 2851 public void end(HTML.Tag t) { 2852 if (t != HTML.Tag.PARAM) { 2853 super.end(t); 2854 } 2855 } 2856 2857 void addParameter(AttributeSet a) { 2858 String name = (String ) a.getAttribute(HTML.Attribute.NAME); 2859 String value = (String ) a.getAttribute(HTML.Attribute.VALUE); 2860 if ((name != null) && (value != null)) { 2861 ElementSpec objSpec = (ElementSpec) parseBuffer.lastElement(); 2862 MutableAttributeSet objAttr = (MutableAttributeSet) objSpec.getAttributes(); 2863 objAttr.addAttribute(name, value); 2864 } 2865 } 2866 } 2867 2868 2917 public class FormAction extends SpecialAction { 2918 2919 public void start(HTML.Tag t, MutableAttributeSet attr) { 2920 if (t == HTML.Tag.INPUT) { 2921 String type = (String ) 2922 attr.getAttribute(HTML.Attribute.TYPE); 2923 2927 if (type == null) { 2928 type = "text"; 2929 attr.addAttribute(HTML.Attribute.TYPE, "text"); 2930 } 2931 setModel(type, attr); 2932 } else if (t == HTML.Tag.TEXTAREA) { 2933 inTextArea = true; 2934 textAreaDocument = new TextAreaDocument (); 2935 attr.addAttribute(StyleConstants.ModelAttribute, 2936 textAreaDocument); 2937 } else if (t == HTML.Tag.SELECT) { 2938 int size = HTML.getIntegerAttributeValue(attr, 2939 HTML.Attribute.SIZE, 2940 1); 2941 boolean multiple = ((String )attr.getAttribute(HTML.Attribute.MULTIPLE) != null); 2942 if ((size > 1) || multiple) { 2943 OptionListModel m = new OptionListModel (); 2944 if (multiple) { 2945 m.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 2946 } 2947 selectModel = m; 2948 } else { 2949 selectModel = new OptionComboBoxModel (); 2950 } 2951 attr.addAttribute(StyleConstants.ModelAttribute, 2952 selectModel); 2953 2954 } 2955 2956 if (t == HTML.Tag.OPTION) { 2958 option = new Option (attr); 2959 2960 if (selectModel instanceof OptionListModel ) { 2961 OptionListModel m = (OptionListModel )selectModel; 2962 m.addElement(option); 2963 if (option.isSelected()) { 2964 m.addSelectionInterval(optionCount, optionCount); 2965 m.setInitialSelection(optionCount); 2966 } 2967 } else if (selectModel instanceof OptionComboBoxModel ) { 2968 OptionComboBoxModel m = (OptionComboBoxModel )selectModel; 2969 m.addElement(option); 2970 if (option.isSelected()) { 2971 m.setSelectedItem(option); 2972 m.setInitialSelection(option); 2973 } 2974 } 2975 optionCount++; 2976 } else { 2977 super.start(t, attr); 2978 } 2979 } 2980 2981 public void end(HTML.Tag t) { 2982 if (t == HTML.Tag.OPTION) { 2983 option = null; 2984 } else { 2985 if (t == HTML.Tag.SELECT) { 2986 selectModel = null; 2987 optionCount = 0; 2988 } else if (t == HTML.Tag.TEXTAREA) { 2989 inTextArea = false; 2990 2991 2997 textAreaDocument.storeInitialText(); 2998 } 2999 super.end(t); 3000 } 3001 } 3002 3003 void setModel(String type, MutableAttributeSet attr) { 3004 if (type.equals("submit") || 3005 type.equals("reset") || 3006 type.equals("image")) { 3007 3008 attr.addAttribute(StyleConstants.ModelAttribute, 3010 new DefaultButtonModel()); 3011 } else if (type.equals("text") || 3012 type.equals("password")) { 3013 int maxLength = HTML.getIntegerAttributeValue( 3015 attr, HTML.Attribute.MAXLENGTH, -1); 3016 Document doc; 3017 3018 if (maxLength > 0) { 3019 doc = new FixedLengthDocument(maxLength); 3020 } 3021 else { 3022 doc = new PlainDocument(); 3023 } 3024 String value = (String ) 3025 attr.getAttribute(HTML.Attribute.VALUE); 3026 try { 3027 doc.insertString(0, value, null); 3028 } catch (BadLocationException e) { 3029 } 3030 attr.addAttribute(StyleConstants.ModelAttribute, doc); 3031 } else if (type.equals("file")) { 3032 attr.addAttribute(StyleConstants.ModelAttribute, 3034 new PlainDocument()); 3035 } else if (type.equals("checkbox") || 3036 type.equals("radio")) { 3037 JToggleButton.ToggleButtonModel model = new JToggleButton.ToggleButtonModel(); 3038 if (type.equals("radio")) { 3039 String name = (String ) attr.getAttribute(HTML.Attribute.NAME); 3040 if ( radioButtonGroupsMap == null ) { radioButtonGroupsMap = new HashMap(); 3042 } 3043 ButtonGroup radioButtonGroup = (ButtonGroup)radioButtonGroupsMap.get(name); 3044 if (radioButtonGroup == null) { 3045 radioButtonGroup = new ButtonGroup(); 3046 radioButtonGroupsMap.put(name,radioButtonGroup); 3047 } 3048 model.setGroup(radioButtonGroup); 3049 } 3050 boolean checked = (attr.getAttribute(HTML.Attribute.CHECKED) != null); 3051 model.setSelected(checked); 3052 attr.addAttribute(StyleConstants.ModelAttribute, model); 3053 } 3054 } 3055 3056 3062 Object selectModel; 3063 int optionCount; 3064 } 3065 3066 3067 3069 3073 protected void pushCharacterStyle() { 3074 charAttrStack.push(charAttr.copyAttributes()); 3075 } 3076 3077 3081 protected void popCharacterStyle() { 3082 if (!charAttrStack.empty()) { 3083 charAttr = (MutableAttributeSet) charAttrStack.peek(); 3084 charAttrStack.pop(); 3085 } 3086 } 3087 3088 3095 protected void textAreaContent(char[] data) { 3096 try { 3097 textAreaDocument.insertString(textAreaDocument.getLength(), new String (data), null); 3098 } catch (BadLocationException e) { 3099 } 3101 } 3102 3103 3109 protected void preContent(char[] data) { 3110 int last = 0; 3111 for (int i = 0; i < data.length; i++) { 3112 if (data[i] == '\n') { 3113 addContent(data, last, i - last + 1); 3114 blockClose(HTML.Tag.IMPLIED); 3115 MutableAttributeSet a = new SimpleAttributeSet(); 3116 a.addAttribute(CSS.Attribute.WHITE_SPACE, "pre"); 3117 blockOpen(HTML.Tag.IMPLIED, a); 3118 last = i + 1; 3119 } 3120 } 3121 if (last < data.length) { 3122 addContent(data, last, data.length - last); 3123 } 3124 } 3125 3126 3130 protected void blockOpen(HTML.Tag t, MutableAttributeSet attr) { 3131 if (impliedP) { 3132 blockClose(HTML.Tag.IMPLIED); 3133 } 3134 3135 inBlock++; 3136 3137 if (!canInsertTag(t, attr, true)) { 3138 return; 3139 } 3140 if (attr.isDefined(IMPLIED)) { 3141 attr.removeAttribute(IMPLIED); 3142 } 3143 lastWasNewline = false; 3144 attr.addAttribute(StyleConstants.NameAttribute, t); 3145 ElementSpec es = new ElementSpec( 3146 attr.copyAttributes(), ElementSpec.StartTagType); 3147 parseBuffer.addElement(es); 3148 } 3149 3150 3154 protected void blockClose(HTML.Tag t) { 3155 inBlock--; 3156 3157 if (!foundInsertTag) { 3158 return; 3159 } 3160 3161 if(!lastWasNewline) { 3168 pushCharacterStyle(); 3169 charAttr.addAttribute(IMPLIED_CR, Boolean.TRUE); 3170 addContent(NEWLINE, 0, 1, true); 3171 popCharacterStyle(); 3172 lastWasNewline = true; 3173 } 3174 3175 if (impliedP) { 3176 impliedP = false; 3177 inParagraph = false; 3178 if (t != HTML.Tag.IMPLIED) { 3179 blockClose(HTML.Tag.IMPLIED); 3180 } 3181 } 3182 ElementSpec prev = (parseBuffer.size() > 0) ? 3185 (ElementSpec) parseBuffer.lastElement() : null; 3186 if (prev != null && prev.getType() == ElementSpec.StartTagType) { 3187 char[] one = new char[1]; 3188 one[0] = ' '; 3189 addContent(one, 0, 1); 3190 } 3191 ElementSpec es = new ElementSpec( 3192 null, ElementSpec.EndTagType); 3193 parseBuffer.addElement(es); 3194 } 3195 3196 3201 protected void addContent(char[] data, int offs, int length) { 3202 addContent(data, offs, length, true); 3203 } 3204 3205 3210 protected void addContent(char[] data, int offs, int length, 3211 boolean generateImpliedPIfNecessary) { 3212 if (!foundInsertTag) { 3213 return; 3214 } 3215 3216 if (generateImpliedPIfNecessary && (! inParagraph) && (! inPre)) { 3217 blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet()); 3218 inParagraph = true; 3219 impliedP = true; 3220 } 3221 emptyAnchor = false; 3222 charAttr.addAttribute(StyleConstants.NameAttribute, HTML.Tag.CONTENT); 3223 AttributeSet a = charAttr.copyAttributes(); 3224 ElementSpec es = new ElementSpec( 3225 a, ElementSpec.ContentType, data, offs, length); 3226 parseBuffer.addElement(es); 3227 3228 if (parseBuffer.size() > threshold) { 3229 if ( threshold <= MaxThreshold ) { 3230 threshold *= StepThreshold; 3231 } 3232 try { 3233 flushBuffer(false); 3234 } catch (BadLocationException ble) { 3235 } 3236 } 3237 if(length > 0) { 3238 lastWasNewline = (data[offs + length - 1] == '\n'); 3239 } 3240 } 3241 3242 3246 protected void addSpecialElement(HTML.Tag t, MutableAttributeSet a) { 3247 if ((t != HTML.Tag.FRAME) && (! inParagraph) && (! inPre)) { 3248 blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet()); 3249 inParagraph = true; 3250 impliedP = true; 3251 } 3252 if (!canInsertTag(t, a, t.isBlock())) { 3253 return; 3254 } 3255 if (a.isDefined(IMPLIED)) { 3256 a.removeAttribute(IMPLIED); 3257 } 3258 emptyAnchor = false; 3259 a.addAttributes(charAttr); 3260 a.addAttribute(StyleConstants.NameAttribute, t); 3261 char[] one = new char[1]; 3262 one[0] = ' '; 3263 ElementSpec es = new ElementSpec( 3264 a.copyAttributes(), ElementSpec.ContentType, one, 0, 1); 3265 parseBuffer.addElement(es); 3266 if (t == HTML.Tag.FRAME) { 3269 lastWasNewline = true; 3270 } 3271 } 3272 3273 3277 void flushBuffer(boolean endOfStream) throws BadLocationException { 3278 int oldLength = HTMLDocument.this.getLength(); 3279 int size = parseBuffer.size(); 3280 if (endOfStream && (insertTag != null || insertAfterImplied) && 3281 size > 0) { 3282 adjustEndSpecsForPartialInsert(); 3283 size = parseBuffer.size(); 3284 } 3285 ElementSpec[] spec = new ElementSpec[size]; 3286 parseBuffer.copyInto(spec); 3287 3288 if (oldLength == 0 && (insertTag == null && !insertAfterImplied)) { 3289 create(spec); 3290 } else { 3291 insert(offset, spec); 3292 } 3293 parseBuffer.removeAllElements(); 3294 offset += HTMLDocument.this.getLength() - oldLength; 3295 flushCount++; 3296 } 3297 3298 3302 private void adjustEndSpecsForPartialInsert() { 3303 int size = parseBuffer.size(); 3304 if (insertTagDepthDelta < 0) { 3305 int removeCounter = insertTagDepthDelta; 3309 while (removeCounter < 0 && size >= 0 && 3310 ((ElementSpec)parseBuffer.elementAt(size - 1)). 3311 getType() == ElementSpec.EndTagType) { 3312 parseBuffer.removeElementAt(--size); 3313 removeCounter++; 3314 } 3315 } 3316 if (flushCount == 0 && (!insertAfterImplied || 3317 !wantsTrailingNewline)) { 3318 int index = 0; 3323 if (pushDepth > 0) { 3324 if (((ElementSpec)parseBuffer.elementAt(0)).getType() == 3325 ElementSpec.ContentType) { 3326 index++; 3327 } 3328 } 3329 index += (popDepth + pushDepth); 3330 int cCount = 0; 3331 int cStart = index; 3332 while (index < size && ((ElementSpec)parseBuffer.elementAt 3333 (index)).getType() == ElementSpec.ContentType) { 3334 index++; 3335 cCount++; 3336 } 3337 if (cCount > 1) { 3338 while (index < size && ((ElementSpec)parseBuffer.elementAt 3339 (index)).getType() == ElementSpec.EndTagType) { 3340 index++; 3341 } 3342 if (index == size) { 3343 char[] lastText = ((ElementSpec)parseBuffer.elementAt 3344 (cStart + cCount - 1)).getArray(); 3345 if (lastText.length == 1 && lastText[0] == NEWLINE[0]){ 3346 index = cStart + cCount - 1; 3347 while (size > index) { 3348 parseBuffer.removeElementAt(--size); 3349 } 3350 } 3351 } 3352 } 3353 } 3354 if (wantsTrailingNewline) { 3355 for (int counter = parseBuffer.size() - 1; counter >= 0; 3357 counter--) { 3358 ElementSpec spec = (ElementSpec)parseBuffer. 3359 elementAt(counter); 3360 if (spec.getType() == ElementSpec.ContentType) { 3361 if (spec.getArray()[spec.getLength() - 1] != '\n') { 3362 SimpleAttributeSet attrs =new SimpleAttributeSet(); 3363 3364 attrs.addAttribute(StyleConstants.NameAttribute, 3365 HTML.Tag.CONTENT); 3366 parseBuffer.insertElementAt(new ElementSpec( 3367 attrs, 3368 ElementSpec.ContentType, NEWLINE, 0, 1), 3369 counter + 1); 3370 } 3371 break; 3372 } 3373 } 3374 } 3375 } 3376 3377 3380 void addCSSRules(String rules) { 3381 StyleSheet ss = getStyleSheet(); 3382 ss.addRule(rules); 3383 } 3384 3385 3389 void linkCSSStyleSheet(String href) { 3390 URL url = null; 3391 try { 3392 url = new URL (base, href); 3393 } catch (MalformedURLException mfe) { 3394 try { 3395 url = new URL (href); 3396 } catch (MalformedURLException mfe2) { 3397 url = null; 3398 } 3399 } 3400 if (url != null) { 3401 getStyleSheet().importStyleSheet(url); 3402 } 3403 } 3404 3405 3410 private boolean canInsertTag(HTML.Tag t, AttributeSet attr, 3411 boolean isBlockTag) { 3412 if (!foundInsertTag) { 3413 if ((insertTag != null && !isInsertTag(t)) || 3414 (insertAfterImplied && (t == HTML.Tag.IMPLIED || 3415 (attr == null || attr.isDefined(IMPLIED))))) { 3416 return false; 3417 } 3418 foundInsertTag(isBlockTag); 3421 if (!insertInsertTag) { 3422 return false; 3423 } 3424 } 3425 return true; 3426 } 3427 3428 private boolean isInsertTag(HTML.Tag tag) { 3429 return (insertTag == tag); 3430 } 3431 3432 private void foundInsertTag(boolean isBlockTag) { 3433 foundInsertTag = true; 3434 if (!insertAfterImplied && (popDepth > 0 || pushDepth > 0)) { 3435 try { 3436 if (offset == 0 || !getText(offset - 1, 1).equals("\n")) { 3437 AttributeSet newAttrs = null; 3439 boolean joinP = true; 3440 3441 if (offset != 0) { 3442 Element charElement = getCharacterElement 3446 (offset - 1); 3447 AttributeSet attrs = charElement.getAttributes(); 3448 3449 if (attrs.isDefined(StyleConstants. 3450 ComposedTextAttribute)) { 3451 joinP = false; 3452 } 3453 else { 3454 Object name = attrs.getAttribute 3455 (StyleConstants.NameAttribute); 3456 if (name instanceof HTML.Tag ) { 3457 HTML.Tag tag = (HTML.Tag )name; 3458 if (tag == HTML.Tag.IMG || 3459 tag == HTML.Tag.HR || 3460 tag == HTML.Tag.COMMENT || 3461 (tag instanceof HTML.UnknownTag )) { 3462 joinP = false; 3463 } 3464 } 3465 } 3466 } 3467 if (!joinP) { 3468 newAttrs = new SimpleAttributeSet(); 3472 ((SimpleAttributeSet)newAttrs).addAttribute 3473 (StyleConstants.NameAttribute, 3474 HTML.Tag.CONTENT); 3475 } 3476 ElementSpec es = new ElementSpec(newAttrs, 3477 ElementSpec.ContentType, NEWLINE, 0, 3478 NEWLINE.length); 3479 if (joinP) { 3480 es.setDirection(ElementSpec. 3481 JoinPreviousDirection); 3482 } 3483 parseBuffer.addElement(es); 3484 } 3485 } catch (BadLocationException ble) {} 3486 } 3487 for (int counter = 0; counter < popDepth; counter++) { 3489 parseBuffer.addElement(new ElementSpec(null, ElementSpec. 3490 EndTagType)); 3491 } 3492 for (int counter = 0; counter < pushDepth; counter++) { 3494 ElementSpec es = new ElementSpec(null, ElementSpec. 3495 StartTagType); 3496 es.setDirection(ElementSpec.JoinNextDirection); 3497 parseBuffer.addElement(es); 3498 } 3499 insertTagDepthDelta = depthTo(Math.max(0, offset - 1)) - 3500 popDepth + pushDepth - inBlock; 3501 if (isBlockTag) { 3502 insertTagDepthDelta++; 3505 } 3506 else { 3507 insertTagDepthDelta--; 3510 inParagraph = true; 3511 lastWasNewline = false; 3512 } 3513 } 3514 3515 3518 private boolean receivedEndHTML; 3519 3520 private int flushCount; 3521 3524 private boolean insertAfterImplied; 3525 3527 private boolean wantsTrailingNewline; 3528 int threshold; 3529 int offset; 3530 boolean inParagraph = false; 3531 boolean impliedP = false; 3532 boolean inPre = false; 3533 boolean inTextArea = false; 3534 TextAreaDocument textAreaDocument = null; 3535 boolean inTitle = false; 3536 boolean lastWasNewline = true; 3537 boolean emptyAnchor; 3538 3540 boolean midInsert; 3541 3542 boolean inBody; 3543 3544 HTML.Tag insertTag; 3545 3547 boolean insertInsertTag; 3548 3549 boolean foundInsertTag; 3550 3560 int insertTagDepthDelta; 3561 3562 int popDepth; 3563 3565 int pushDepth; 3566 3567 Map lastMap; 3568 3569 boolean inStyle = false; 3570 3571 String defaultStyle; 3572 3579 Vector styles; 3580 3581 boolean inHead = false; 3582 3584 boolean isStyleCSS; 3585 3586 boolean emptyDocument; 3587 3588 AttributeSet styleAttributes; 3589 3590 3594 Option option; 3595 3596 protected Vector<ElementSpec> parseBuffer = new Vector(); protected MutableAttributeSet charAttr = new TaggedAttributeSet(); 3598 Stack charAttrStack = new Stack(); 3599 Hashtable tagMap; 3600 int inBlock = 0; 3601 } 3602 3603 3604 3608 static class TaggedAttributeSet extends SimpleAttributeSet { 3609 TaggedAttributeSet() { 3610 super(); 3611 } 3612 } 3613 3614 3615 3620 public class RunElement extends LeafElement { 3621 3622 3631 public RunElement(Element parent, AttributeSet a, int offs0, int offs1) { 3632 super(parent, a, offs0, offs1); 3633 } 3634 3635 3640 public String getName() { 3641 Object o = getAttribute(StyleConstants.NameAttribute); 3642 if (o != null) { 3643 return o.toString(); 3644 } 3645 return super.getName(); 3646 } 3647 3648 3655 public AttributeSet getResolveParent() { 3656 return null; 3657 } 3658 } 3659 3660 3664 public class BlockElement extends BranchElement { 3665 3666 3673 public BlockElement(Element parent, AttributeSet a) { 3674 super(parent, a); 3675 } 3676 3677 3682 public String getName() { 3683 Object o = getAttribute(StyleConstants.NameAttribute); 3684 if (o != null) { 3685 return o.toString(); 3686 } 3687 return super.getName(); 3688 } 3689 3690 3697 public AttributeSet getResolveParent() { 3698 return null; 3699 } 3700 3701 } 3702 3703 3704 3707 private static class FixedLengthDocument extends PlainDocument { 3708 private int maxLength; 3709 3710 public FixedLengthDocument(int maxLength) { 3711 this.maxLength = maxLength; 3712 } 3713 3714 public void insertString(int offset, String str, AttributeSet a) 3715 throws BadLocationException { 3716 if (str != null && str.length() + getLength() <= maxLength) { 3717 super.insertString(offset, str, a); 3718 } 3719 } 3720 } 3721} 3722 | Popular Tags |