1 19 20 package org.netbeans.editor.ext; 21 22 import java.io.IOException ; 23 import java.io.Writer ; 24 import java.util.List ; 25 import java.util.ArrayList ; 26 import java.util.HashMap ; 27 import java.util.Iterator ; 28 import javax.swing.text.BadLocationException ; 29 import javax.swing.text.Document ; 30 import javax.swing.text.Position ; 31 import org.netbeans.editor.BaseKit; 32 import org.netbeans.editor.BaseDocument; 33 import org.netbeans.editor.Syntax; 34 import org.netbeans.editor.SettingsNames; 35 import org.netbeans.editor.TokenID; 36 import org.netbeans.editor.TokenContextPath; 37 import org.netbeans.editor.TokenItem; 38 import org.netbeans.editor.Utilities; 39 import org.netbeans.editor.EditorDebug; 40 41 61 62 public final class FormatWriter extends Writer { 63 64 65 public static final boolean debug 66 = Boolean.getBoolean("netbeans.debug.editor.format"); 68 69 public static final boolean debugModify 70 = Boolean.getBoolean("netbeans.debug.editor.format.modify"); 72 private static final char[] EMPTY_BUFFER = new char[0]; 73 74 75 private ExtFormatter formatter; 76 77 78 private Document doc; 79 80 81 private int offset; 82 83 84 private Writer underWriter; 85 86 99 private Syntax syntax; 100 101 107 private boolean indentOnly; 108 109 110 private char[] buffer; 111 112 113 private int bufferSize; 114 115 116 private FormatTokenPositionSupport ftps; 117 118 119 private int offsetPreScan; 120 121 124 private boolean firstFlush; 125 126 127 private ExtTokenItem lastToken; 128 129 130 private FormatTokenPosition formatStartPosition; 131 132 133 private FormatTokenPosition textStartPosition; 134 135 139 private boolean chainModified; 140 141 142 private boolean restartFormat; 143 144 147 private boolean lastFlush; 148 149 155 private int indentShift; 156 157 160 private boolean simple; 161 162 163 private boolean reformatting; 164 165 void setReformatting(boolean reformatting) { 166 this.reformatting = reformatting; 167 } 168 169 174 FormatWriter(ExtFormatter formatter, Document doc, int offset, 175 Writer underWriter, boolean indentOnly) { 176 this.formatter = formatter; 177 this.doc = doc; 178 this.offset = offset; 179 this.underWriter = underWriter; 180 this.setIndentOnly(indentOnly); 181 182 if (debug) { 183 System.err.println("FormatWriter() created, formatter=" + formatter + ", document=" + doc.getClass() + ", expandTabs=" + formatter.expandTabs() + ", spacesPerTab=" + formatter.getSpacesPerTab() + ", tabSize=" + ((doc instanceof BaseDocument) ? ((BaseDocument)doc).getTabSize() : formatter.getTabSize()) 188 + ", shiftWidth=" + ((doc instanceof BaseDocument) ? ((BaseDocument)doc).getShiftWidth() : formatter.getShiftWidth()) 190 ); 191 } 192 193 if (formatter.isSimple()) { 195 simple = true; 196 return; 197 } 198 199 buffer = EMPTY_BUFFER; 200 firstFlush = true; 201 202 Class kitClass = (doc instanceof BaseDocument) 204 ? ((BaseDocument)doc).getKitClass() 205 : formatter.getKitClass(); 206 207 if (kitClass != null && BaseKit.class.isAssignableFrom(kitClass)) { 208 syntax = BaseKit.getKit(kitClass).createFormatSyntax(doc); 209 } else { 210 simple = true; 211 return; 212 } 213 214 if (!formatter.acceptSyntax(syntax)) { 215 simple = true; return; 217 } 218 219 ftps = new FormatTokenPositionSupport(this); 220 221 if (doc instanceof BaseDocument) { 222 try { 223 BaseDocument bdoc = (BaseDocument)doc; 224 225 230 bdoc.getSyntaxSupport().initSyntax(syntax, offset, offset, false, true); 231 offsetPreScan = syntax.getPreScan(); 232 233 if (debug) { 234 System.err.println("FormatWriter: preScan=" + offsetPreScan + " at offset=" + offset); 235 } 236 237 if (offset > 0) { ExtSyntaxSupport sup = (ExtSyntaxSupport)bdoc.getSyntaxSupport(); 239 Integer lines = (Integer )bdoc.getProperty(SettingsNames.LINE_BATCH_SIZE); 240 241 int startOffset = Utilities.getRowStart(bdoc, 242 Math.max(offset - offsetPreScan, 0), 243 -Math.max(lines.intValue(), 1) 244 ); 245 246 if (startOffset < 0) { startOffset = 0; 248 } 249 250 TokenItem ti = sup.getTokenChain(startOffset, offset); 252 253 if (ti != null && ti.getOffset() < offset - offsetPreScan) { 254 lastToken = new FilterDocumentItem(ti, null, false); 255 256 if (debug) { 257 System.err.println("FormatWriter: first doc token=" + lastToken); } 259 260 while (lastToken.getNext() != null 262 && lastToken.getNext().getOffset() < offset - offsetPreScan 263 ) { 264 lastToken = (ExtTokenItem)lastToken.getNext(); 265 266 if (debug) { 267 System.err.println("FormatWriter: doc token=" + lastToken); } 269 } 270 271 ((FilterDocumentItem)lastToken).terminate(); 274 275 } 276 } 277 278 } catch (BadLocationException e) { 279 Utilities.annotateLoggable(e); 280 } 281 282 } else { try { 284 String text = doc.getText(0, offset); 285 char[] buffer = text.toCharArray(); 286 287 syntax.load(null, buffer, 0, buffer.length, false, 0); 289 290 TokenID tokenID = syntax.nextToken(); 291 while (tokenID != null) { 292 int tokenOffset = syntax.getTokenOffset(); 293 lastToken = new FormatTokenItem(tokenID, 294 syntax.getTokenContextPath(), 295 tokenOffset, 296 text.substring(tokenOffset, tokenOffset + syntax.getTokenLength()), 297 lastToken 298 ); 299 300 if (debug) { 301 System.err.println("FormatWriter: non-bd token=" + lastToken); 302 } 303 304 ((FormatTokenItem)lastToken).markWritten(); 305 tokenID = syntax.nextToken(); 306 } 307 308 offsetPreScan = syntax.getPreScan(); 310 311 } catch (BadLocationException e) { 312 Utilities.annotateLoggable(e); 313 } 314 } 315 316 char[] buf = syntax.getBuffer(); 318 int bufOffset = syntax.getOffset(); 319 320 if (debug) { 321 System.err.println("FormatWriter: writing preScan chars='" + EditorDebug.debugChars(buf, bufOffset - offsetPreScan, 323 offsetPreScan) + "'" + ", length=" + offsetPreScan ); 326 } 327 328 addToBuffer(buf, bufOffset - offsetPreScan, offsetPreScan); 330 } 331 332 public final ExtFormatter getFormatter() { 333 return formatter; 334 } 335 336 337 public final Document getDocument() { 338 return doc; 339 } 340 341 342 public final int getOffset() { 343 return offset; 344 } 345 346 351 public final boolean isIndentOnly() { 352 return indentOnly; 353 } 354 355 359 public void setIndentOnly(boolean indentOnly) { 360 this.indentOnly = indentOnly; 361 } 362 363 372 public FormatTokenPosition getFormatStartPosition() { 373 return formatStartPosition; 374 } 375 376 380 public FormatTokenPosition getTextStartPosition() { 381 return textStartPosition; 382 } 383 384 387 public TokenItem getLastToken() { 388 return lastToken; 389 } 390 391 399 public TokenItem findFirstToken(TokenItem token) { 400 if (token == null) { 401 token = (textStartPosition != null) 403 ? textStartPosition.getToken() : null; 404 405 if (token == null) { 406 token = formatStartPosition.getToken(); 408 if (token == null) { 409 token = lastToken; 410 if (token == null) { 411 return null; 412 } 413 } 414 } 415 } 416 417 while (token.getPrevious() != null) { 418 token = token.getPrevious(); 419 } 420 return token; 421 } 422 423 430 public boolean isAfter(TokenItem testedToken, TokenItem afterToken) { 431 while (afterToken != null) { 432 afterToken = afterToken.getNext(); 433 434 if (afterToken == testedToken) { 435 return true; 436 } 437 } 438 439 return false; 440 } 441 442 443 public boolean isAfter(FormatTokenPosition testedPosition, 444 FormatTokenPosition afterPosition) { 445 if (testedPosition.getToken() == afterPosition.getToken()) { 446 return (testedPosition.getOffset() > afterPosition.getOffset()); 447 448 } else { return isAfter(testedPosition.getToken(), afterPosition.getToken()); 450 } 451 } 452 453 461 public TokenItem findNonEmptyToken(TokenItem token, boolean backward) { 462 while (token != null && token.getImage().length() == 0) { 463 token = backward ? token.getPrevious() : token.getNext(); 464 } 465 466 return token; 467 } 468 469 478 public boolean canInsertToken(TokenItem beforeToken) { 479 return beforeToken== null || !((ExtTokenItem)beforeToken).isWritten(); 481 } 482 483 498 public TokenItem insertToken(TokenItem beforeToken, 499 TokenID tokenID, TokenContextPath tokenContextPath, String tokenImage) { 500 if (debugModify) { 501 System.err.println("FormatWriter.insertToken(): beforeToken=" + beforeToken + ", tokenID=" + tokenID + ", contextPath=" + tokenContextPath + ", tokenImage='" + tokenImage + "'" ); 505 } 506 507 if (!canInsertToken(beforeToken)) { 508 throw new IllegalStateException ("Can't insert token into chain"); } 510 511 if (reformatting) { 513 try { 514 doc.insertString(getDocOffset(beforeToken), tokenImage, null); 515 } catch (BadLocationException e) { 516 e.printStackTrace(); 517 } 518 } 519 520 FormatTokenItem fti; 521 if (beforeToken != null) { 522 fti = ((FormatTokenItem)beforeToken).insertToken(tokenID, 523 tokenContextPath, -1, tokenImage); 524 525 } else { fti = new FormatTokenItem(tokenID, tokenContextPath, -1, tokenImage, lastToken); 527 lastToken = fti; 528 } 529 530 ftps.tokenInsert(fti); 532 533 chainModified = true; 534 535 return fti; 536 } 537 538 539 private int getDocOffset(TokenItem token) { 540 int len = 0; 541 if (token != null) { 542 token = token.getPrevious(); 543 544 } else { token = lastToken; 546 } 547 548 while (token != null) { 549 len += token.getImage().length(); 550 if (token instanceof FilterDocumentItem) { 551 return len + token.getOffset(); 552 } 553 token = token.getPrevious(); 554 } 555 556 return len; 557 } 558 559 563 public boolean canRemoveToken(TokenItem token) { 564 return !((ExtTokenItem)token).isWritten(); 565 } 566 567 571 public void removeToken(TokenItem token) { 572 if (debugModify) { 573 System.err.println("FormatWriter.removeToken(): token=" + token); } 575 576 if (!canRemoveToken(token)) { 577 if (true) { return; 579 } 580 throw new IllegalStateException ("Can't remove token from chain"); } 582 583 if (reformatting) { 585 try { 586 doc.remove(getDocOffset(token), token.getImage().length()); 587 } catch (BadLocationException e) { 588 e.printStackTrace(); 589 } 590 } 591 592 ftps.tokenRemove(token); 594 595 if (lastToken == token) { 596 lastToken = (ExtTokenItem)token.getPrevious(); 597 } 598 ((FormatTokenItem)token).remove(); 600 chainModified = true; 601 } 602 603 public boolean canSplitStart(TokenItem token, int startLength) { 604 return !((ExtTokenItem)token).isWritten(); 605 } 606 607 616 public TokenItem splitStart(TokenItem token, int startLength, 617 TokenID newTokenID, TokenContextPath newTokenContextPath) { 618 if (!canSplitStart(token, startLength)) { 619 throw new IllegalStateException ("Can't split the token=" + token); } 621 622 String text = token.getImage(); 623 if (startLength > text.length()) { 624 throw new IllegalArgumentException ("startLength=" + startLength + " is greater than token length=" + text.length()); } 627 628 String newText = text.substring(0, startLength); 629 ExtTokenItem newToken = (ExtTokenItem)insertToken(token, 630 newTokenID, newTokenContextPath, newText); 631 632 ftps.splitStartTokenPositions(token, startLength); 634 635 remove(token, 0, startLength); 636 return newToken; 637 } 638 639 public boolean canSplitEnd(TokenItem token, int endLength) { 640 int splitOffset = token.getImage().length() - endLength; 641 return (((ExtTokenItem)token).getWrittenLength() <= splitOffset); 642 } 643 644 653 public TokenItem splitEnd(TokenItem token, int endLength, 654 TokenID newTokenID, TokenContextPath newTokenContextPath) { 655 if (!canSplitEnd(token, endLength)) { 656 throw new IllegalStateException ("Can't split the token=" + token); } 658 659 String text = token.getImage(); 660 if (endLength > text.length()) { 661 throw new IllegalArgumentException ("endLength=" + endLength + " is greater than token length=" + text.length()); } 664 665 String newText = text.substring(0, endLength); 666 ExtTokenItem newToken = (ExtTokenItem)insertToken(token.getNext(), 667 newTokenID, newTokenContextPath, newText); 668 669 ftps.splitEndTokenPositions(token, endLength); 671 672 remove(token, text.length() - endLength, endLength); 673 return newToken; 674 } 675 676 679 public boolean canModifyToken(TokenItem token, int offset) { 680 int wrLen = ((ExtTokenItem)token).getWrittenLength(); 681 return (offset >= 0 && wrLen <= offset); 682 } 683 684 693 public void insertString(TokenItem token, int offset, String text) { 694 if (debugModify) { 696 System.err.println("FormatWriter.insertString(): token=" + token + ", offset=" + offset + ", text='" + text + "'"); } 699 700 if (text.length() == 0) { 702 return; 703 } 704 705 if (!canModifyToken(token, offset)) { 707 if (true) { return; 709 } 710 throw new IllegalStateException ("Can't insert into token=" + token + ", at offset=" + offset + ", text='" + text + "'"); } 713 714 if (reformatting) { 716 try { 717 doc.insertString(getDocOffset(token) + offset, text, null); 718 } catch (BadLocationException e) { 719 e.printStackTrace(); 720 } 721 } 722 723 724 ftps.tokenTextInsert(token, offset, text.length()); 726 727 String image = token.getImage(); 728 ((ExtTokenItem)token).setImage(image.substring(0, offset) + text 729 + image.substring(offset)); 730 } 731 732 740 public void remove(TokenItem token, int offset, int length) { 741 if (debugModify) { 743 String removedText; 744 if (offset >= 0 && length >= 0 745 && offset + length <= token.getImage().length() 746 ) { 747 removedText = token.getImage().substring(offset, offset + length); 748 749 } else { 750 removedText = "<INVALID>"; } 752 753 System.err.println("FormatWriter.remove(): token=" + token + ", offset=" + offset + ", length=" + length + "removing text='" + removedText + "'"); } 757 758 if (length == 0) { 760 return; 761 } 762 763 if (!canModifyToken(token, offset)) { 765 if (true) { return; 767 } 768 throw new IllegalStateException ("Can't remove from token=" + token + ", at offset=" + offset + ", length=" + length); } 771 772 if (reformatting) { 774 try { 775 doc.remove(getDocOffset(token) + offset, length); 776 } catch (BadLocationException e) { 777 e.printStackTrace(); 778 } 779 } 780 781 ftps.tokenTextRemove(token, offset, length); 783 784 String text = token.getImage(); 785 ((ExtTokenItem)token).setImage(text.substring(0, offset) 786 + text.substring(offset + length)); 787 } 788 789 799 public FormatTokenPosition getPosition(TokenItem token, int offset, Position.Bias bias) { 800 return ftps.getTokenPosition(token, offset, bias); 801 } 802 803 804 public boolean isChainStartPosition(FormatTokenPosition pos) { 805 TokenItem token = pos.getToken(); 806 return (pos.getOffset() == 0) 807 && ((token == null && getLastToken() == null) || (token != null && token.getPrevious() == null)); 809 } 810 811 812 private void addToBuffer(char[] buf, int off, int len) { 813 if (len > buffer.length - bufferSize) { 815 char[] tmp = new char[len + 2 * buffer.length]; 816 System.arraycopy(buffer, 0, tmp, 0, bufferSize); 817 buffer = tmp; 818 } 819 820 System.arraycopy(buf, off, buffer, bufferSize, len); 822 bufferSize += len; 823 } 824 825 public void write(char[] cbuf, int off, int len) throws IOException { 826 if (simple) { 827 underWriter.write(cbuf, off, len); 828 return; 829 } 830 831 write(cbuf, off, len, null, null); 832 } 833 834 public synchronized void write(char[] cbuf, int off, int len, 835 int[] saveOffsets, Position.Bias [] saveBiases) throws IOException { 836 if (simple) { 837 underWriter.write(cbuf, off, len); 838 return; 839 } 840 841 if (saveOffsets != null) { 842 ftps.addSaveSet(bufferSize, len, saveOffsets, saveBiases); 843 } 844 845 lastFlush = false; 847 if (debug) { 848 System.err.println("FormatWriter.write(): '" + org.netbeans.editor.EditorDebug.debugChars(cbuf, off, len) 850 + "', length=" + len + ", bufferSize=" + bufferSize); } 852 853 addToBuffer(cbuf, off, len); 855 } 856 857 861 public boolean isChainModified() { 862 return chainModified; 863 } 864 865 public void setChainModified(boolean chainModified) { 866 this.chainModified = chainModified; 867 } 868 869 872 public boolean isRestartFormat() { 873 return restartFormat; 874 } 875 876 public void setRestartFormat(boolean restartFormat) { 877 this.restartFormat = restartFormat; 878 } 879 880 public int getIndentShift() { 881 return indentShift; 882 } 883 884 public void setIndentShift(int indentShift) { 885 this.indentShift = indentShift; 886 } 887 888 public void flush() throws IOException { 889 if (debug) { 890 System.err.println("FormatWriter.flush() called"); } 892 893 if (simple) { 894 underWriter.flush(); 895 return; 896 } 897 898 if (lastFlush) { return; 900 } 901 lastFlush = true; 903 int startOffset = 0; if (firstFlush) { startOffset = offsetPreScan; 906 } 907 908 syntax.relocate(buffer, startOffset, bufferSize - startOffset, true, -1); 909 910 formatStartPosition = null; 912 913 TokenID tokenID = syntax.nextToken(); 914 if (firstFlush) { if (startOffset > 0) { while(true) 917 { 918 String text = new String (buffer, syntax.getTokenOffset(), 919 syntax.getTokenLength()); 920 lastToken = new FormatTokenItem(tokenID, 922 syntax.getTokenContextPath(), -1, text, lastToken); 923 924 if (debug) { 925 System.err.println("FormatWriter.flush(): doc&format token=" + lastToken); 927 } 928 929 lastToken.setWrittenLength(startOffset); 931 932 if (text.length() > startOffset) { 934 formatStartPosition = getPosition(lastToken, startOffset, 935 Position.Bias.Backward); 936 } 937 938 tokenID = syntax.nextToken(); 940 if (text.length() >= startOffset) 947 break; 948 else 949 { 950 lastToken.setWrittenLength(Integer.MAX_VALUE); 951 startOffset -= text.length(); 952 } 953 } 954 955 } 956 } 957 958 while (tokenID != null) { 959 String text = new String (buffer, syntax.getTokenOffset(), 960 syntax.getTokenLength()); 961 lastToken = new FormatTokenItem(tokenID, 963 syntax.getTokenContextPath(), -1, text, lastToken); 964 965 if (formatStartPosition == null) { 966 formatStartPosition = getPosition(lastToken, 0, 967 Position.Bias.Backward); 968 } 969 970 if (debug) { 971 System.err.println("FormatWriter.flush(): format token=" + lastToken); 972 } 973 974 tokenID = syntax.nextToken(); 975 } 976 977 if (formatStartPosition == null) { 979 formatStartPosition = getPosition(null, 0, Position.Bias.Backward); 980 } 981 982 if (firstFlush) { 984 textStartPosition = formatStartPosition; 985 } 986 987 bufferSize = 0; 989 if (debug) { 990 System.err.println("FormatWriter.flush(): formatting ..."); 991 } 992 993 formatter.format(this); 995 996 StringBuffer sb = new StringBuffer (); 998 ExtTokenItem token = (ExtTokenItem)formatStartPosition.getToken(); 999 ExtTokenItem prevToken = null; 1000 if (token != null) { 1001 switch (token.getWrittenLength()) { 1003 case -1: sb.append(token.getImage()); 1005 break; 1006 1007 case Integer.MAX_VALUE: 1008 throw new IllegalStateException ("Wrong formatStartPosition"); 1010 default: 1011 sb.append(token.getImage().substring(formatStartPosition.getOffset())); 1012 break; 1013 } 1014 1015 token.markWritten(); 1016 prevToken = token; 1017 token = (ExtTokenItem)token.getNext(); 1018 1019 while (token != null) { 1021 prevToken.setWrittenLength(Integer.MAX_VALUE); 1023 1024 sb.append(token.getImage()); 1026 token.markWritten(); 1027 1028 prevToken = token; 1030 token = (ExtTokenItem)token.getNext(); 1031 } 1032 } 1033 1034 if (sb.length() > 0) { 1036 char[] outBuf = new char[sb.length()]; 1037 sb.getChars(0, outBuf.length, outBuf, 0); 1038 1039 if (debug) { 1040 System.err.println("FormatWriter.flush(): chars to underlying writer='" + EditorDebug.debugChars(outBuf, 0, outBuf.length) 1042 + "'"); } 1044 1045 underWriter.write(outBuf, 0, outBuf.length); 1046 } 1047 1048 underWriter.flush(); 1049 1050 firstFlush = false; } 1052 1053 public void close() throws IOException { 1054 if (debug) { 1055 System.err.println("FormatWriter: close() called (-> flush())"); } 1057 1058 flush(); 1059 underWriter.close(); 1060 } 1061 1062 1063 public void checkChain() { 1064 TokenItem lt = getLastToken(); 1066 if (lt.getNext() != null) { 1067 throw new IllegalStateException ("Successor of last token exists."); } 1069 1070 FormatTokenPosition fsp = getFormatStartPosition(); 1072 if (fsp == null) { 1073 throw new IllegalStateException ("getFormatStartPosition() returns null."); } 1075 1076 checkFSPFollowsTSP(); 1078 1079 } 1083 1084 1085 private void checkFSPFollowsTSP() { 1086 if (!(formatStartPosition.equals(textStartPosition) 1087 || isAfter(formatStartPosition, textStartPosition) 1088 )) { 1089 throw new IllegalStateException ( 1090 "formatStartPosition doesn't follow textStartPosition"); } 1092 } 1093 1094 public String chainToString(TokenItem token) { 1095 return chainToString(token, 5); 1096 } 1097 1098 1102 public String chainToString(TokenItem token, int maxDocumentTokens) { 1103 checkChain(); 1105 1106 StringBuffer sb = new StringBuffer (); 1107 sb.append("D - document tokens, W - written tokens, F - tokens being formatted\n"); 1109 checkFSPFollowsTSP(); 1111 1112 TokenItem tst = getTextStartPosition().getToken(); 1113 TokenItem fst = getFormatStartPosition().getToken(); 1114 1115 TokenItem t = tst; 1117 if (t == null) { 1118 t = getLastToken(); 1119 } 1120 1121 while (t != null && t.getPrevious() != null && --maxDocumentTokens > 0) { 1123 t = t.getPrevious(); 1124 } 1125 1126 while (t != tst) { 1128 sb.append((t == token) ? '>' : ' '); sb.append("D "); sb.append(t.toString()); 1131 sb.append('\n'); 1133 t = t.getNext(); 1134 } 1135 1136 while (t != fst) { 1137 sb.append((t == token) ? '>' : ' '); 1138 if (t == tst) { sb.append("D(" + getTextStartPosition().getOffset() + ')'); } 1141 sb.append("W "); sb.append(t.toString()); 1143 sb.append('\n'); 1145 t = t.getNext(); 1146 } 1147 1148 sb.append((t == token) ? '>' : ' '); 1149 if (getFormatStartPosition().getOffset() > 0) { 1150 if (fst == tst) { 1151 sb.append('D'); 1152 1153 } else { sb.append('W'); } 1156 } 1157 sb.append("F "); sb.append((t != null) ? t.toString() : "NULL"); sb.append('\n'); 1161 if (t != null) { 1162 t = t.getNext(); 1163 } 1164 1165 while (t != null) { 1166 sb.append((t == token) ? '>' : ' '); sb.append("F "); sb.append(t.toString()); 1169 sb.append('\n'); 1171 t = t.getNext(); 1172 } 1173 1174 return sb.toString(); 1175 } 1176 1177 1180 static class FormatTokenItem extends TokenItem.AbstractItem 1181 implements ExtTokenItem { 1182 1183 1189 int writtenLength = -1; 1190 1191 1192 TokenItem next; 1193 1194 1195 TokenItem previous; 1196 1197 1198 String image; 1199 1200 1204 int saveOffset; 1205 1206 FormatTokenItem(TokenID tokenID, TokenContextPath tokenContextPath, 1207 int offset, String image, TokenItem previous) { 1208 super(tokenID, tokenContextPath, offset, image); 1209 this.image = image; 1210 this.previous = previous; 1211 if (previous instanceof ExtTokenItem) { 1212 ((ExtTokenItem)previous).setNext(this); 1213 } 1214 } 1215 1216 public TokenItem getNext() { 1217 return next; 1218 } 1219 1220 public TokenItem getPrevious() { 1221 return previous; 1222 } 1223 1224 public void setNext(TokenItem next) { 1225 this.next = next; 1226 } 1227 1228 public void setPrevious(TokenItem previous) { 1229 this.previous = previous; 1230 } 1231 1232 public boolean isWritten() { 1233 return (writtenLength >= 0); 1234 } 1235 1236 public void markWritten() { 1237 if (writtenLength == Integer.MAX_VALUE) { 1238 throw new IllegalStateException ("Already marked unextendable."); } 1240 1241 writtenLength = getImage().length(); 1242 } 1243 1244 public int getWrittenLength() { 1245 return writtenLength; 1246 } 1247 1248 public void setWrittenLength(int writtenLength) { 1249 if (writtenLength <= this.writtenLength) { 1250 throw new IllegalArgumentException ( 1251 "this.writtenLength=" + this.writtenLength + " < writtenLength=" + writtenLength); } 1254 1255 this.writtenLength = writtenLength; 1256 } 1257 1258 public String getImage() { 1259 return image; 1260 } 1261 1262 public void setImage(String image) { 1263 this.image = image; 1264 } 1265 1266 FormatTokenItem insertToken(TokenID tokenID, TokenContextPath tokenContextPath, 1267 int offset, String image) { 1268 FormatTokenItem fti = new FormatTokenItem(tokenID, tokenContextPath, 1269 offset, image, previous); 1270 fti.next = this; 1271 this.previous = fti; 1272 return fti; 1273 } 1274 1275 void remove() { 1276 if (previous instanceof ExtTokenItem) { 1277 ((ExtTokenItem)this.previous).setNext(next); 1278 } 1279 if (next instanceof ExtTokenItem) { 1280 ((ExtTokenItem)this.next).setPrevious(previous); 1281 } 1282 } 1283 1284 int getSaveOffset() { 1285 return saveOffset; 1286 } 1287 1288 void setSaveOffset(int saveOffset) { 1289 this.saveOffset = saveOffset; 1290 } 1291 1292 } 1293 1294 1297 static class FilterDocumentItem extends TokenItem.FilterItem 1298 implements ExtTokenItem { 1299 1300 private static final FilterDocumentItem NULL_ITEM 1301 = new FilterDocumentItem(null, null, false); 1302 1303 private TokenItem previous; 1304 1305 private TokenItem next; 1306 1307 FilterDocumentItem(TokenItem delegate, FilterDocumentItem neighbour, boolean isNeighbourPrevious) { 1308 super(delegate); 1309 if (neighbour != null) { 1310 if (isNeighbourPrevious) { 1311 previous = neighbour; 1312 1313 } else { next = neighbour; 1315 } 1316 } 1317 } 1318 1319 public TokenItem getNext() { 1320 if (next == null) { 1321 TokenItem ti = super.getNext(); 1322 if (ti != null) { 1323 next = new FilterDocumentItem(ti, this, true); 1324 } 1325 } 1326 1327 return (next != NULL_ITEM) ? next : null; 1328 } 1329 1330 public void setNext(TokenItem next) { 1331 this.next = next; 1332 } 1333 1334 1335 public void terminate() { 1336 setNext(NULL_ITEM); 1337 } 1338 1339 public void setPrevious(TokenItem previous) { 1340 this.previous = previous; 1341 } 1342 1343 public boolean isWritten() { 1344 return true; 1345 } 1346 1347 public void markWritten() { 1348 } 1349 1350 public int getWrittenLength() { 1351 return Integer.MAX_VALUE; 1352 } 1353 1354 public void setWrittenLength(int writtenLength) { 1355 if (writtenLength != Integer.MAX_VALUE) { 1356 throw new IllegalArgumentException ("Wrong writtenLength=" + writtenLength); 1358 } 1359 } 1360 1361 public void setImage(String image) { 1362 throw new IllegalStateException ("Cannot set image of the document-token."); } 1364 1365 public TokenItem getPrevious() { 1366 if (previous == null) { 1367 TokenItem ti = super.getPrevious(); 1368 if (ti != null) { 1369 previous = new FilterDocumentItem(ti, this, false); 1370 } 1371 } 1372 1373 return previous; 1374 } 1375 1376 } 1377 1378 interface ExtTokenItem extends TokenItem { 1379 1380 1381 public void setNext(TokenItem next); 1382 1383 1384 public void setPrevious(TokenItem previous); 1385 1386 1389 public boolean isWritten(); 1390 1391 1392 public void markWritten(); 1393 1394 1403 public int getWrittenLength(); 1404 1405 1406 public void setWrittenLength(int writtenLength); 1407 1408 1409 public void setImage(String image); 1410 1411 } 1412 1413 1414} 1415 | Popular Tags |