001package Torello.HTML.NodeSearch; 002 003import java.util.*; 004 005import java.util.function.Predicate; 006 007import Torello.HTML.*; 008 009import Torello.Java.LV; 010 011/** 012 * Abstract parent-class for both of the types of HTML-{@code Iterator's} 013 * 014 * <EMBED CLASS='external-html' DATA-FILE-ID=AbstractHNLI> 015 * 016 * @param <E> This must be either {@link TagNode}, {@link TextNode} or {@link CommentNode}. 017 * This is type of the <I><B>query-specifier {@code Predicate}</B></I> being used. 018 * 019 * @param <F> This is the actual-type that will be iterated. For instances of {@link HNLI}, 020 * both type-parameters {@code 'E'} and {@code 'F'} are identical. The {@code Predicate's} 021 * will be querrying for a certain type of {@code HTMLNode}, and the {@code Iterator} will be 022 * iterating that type of {@code HTMLNode} too. 023 * 024 * <BR /><BR />However, for instances of {@link HNLIInclusive}, the query-specifier is 025 * (automatically-required) to be set to {@code TagNode}, and the {@code Iterator} shall be 026 * returning instances of {@code Vector<HTMLNode>}. Generic Type-Parameter {@code 'F'} is 027 * automatically set to {@code Vector<HTMLNode>} for instances of {@code HNLIInclusive}. 028 */ 029@SuppressWarnings("unchecked") 030@Torello.JavaDoc.JDHeaderBackgroundImg 031public abstract class AbstractHNLI<E extends HTMLNode, F> implements ListIterator<F> 032{ 033 // ******************************************************************************************** 034 // ******************************************************************************************** 035 // FIELDS 036 // ******************************************************************************************** 037 // ******************************************************************************************** 038 039 040 /** The internal, underlying instance of {@code Vector} that this {@code Iterator} is using. */ 041 @SuppressWarnings("rawtypes") 042 protected Vector v; 043 044 /** This {@code Predicate} is the test for identifying {@code Iterator} node-matches */ 045 protected Predicate<E> p; 046 047 /** This is the type of {@code HTMLNode} being iterated */ 048 protected Class<E> c; 049 050 /** 051 * Internal {@code 'cursor'} field. 052 * 053 * <BR /><BR />It is initialized to -1, which allows the iterator to identify whether it has 054 * been used yet. 055 */ 056 protected int cursor = -1; 057 058 /** 059 * This identifies whether one of the {@code Iterator's} html modification methods 060 * ({@code set, remove, add}) have been invoked. Multiple invocations of these methods 061 * after a single iteration causes a {@code SecondModificationException} 062 * 063 * <BR /><BR />Initializing this to {@code TRUE} prevents the programmer from calling any of 064 * the modification methods without first finding a match. 065 */ 066 protected boolean modifiedSince = true; 067 068 /** 069 * The maximum boundary for the {@code Cursor Boundary Window}. 070 * 071 * <BR /><BR />Initialized to {@code '-1'} means the default setting is for the 072 * {@code Iterator} is not to use a {@code Cursor Boundaries}. One may be assigned 073 * using the {@code restrictCursor(...)} methods. 074 * 075 * @see #restrictCursor(DotPair) 076 * @see #restrictCursor(int, int) 077 * @see #clearCursorBounds() 078 */ 079 protected int maxCursor = -1; 080 081 /** 082 * The minimum boundary for the {@code Cursor Boundary Window}. 083 * 084 * <BR /><BR />Initialized to {@code '-1'} means the default setting is for the 085 * {@code Iterator} is not to use a {@code Cursor Boundaries}. One may be assigned 086 * using the {@code restrictCursor(...)} methods. 087 * 088 * @see #restrictCursor(DotPair) 089 * @see #restrictCursor(int, int) 090 * @see #clearCursorBounds() 091 */ 092 protected int minCursor = -1; 093 094 /** This is an attempt to monitor outside modifications to an HTML {@code Vector} */ 095 protected int expectedSize; 096 097 098 // ******************************************************************************************** 099 // ******************************************************************************************** 100 // Only Constructor, and 2 Abstract-Methods 101 // ******************************************************************************************** 102 // ******************************************************************************************** 103 104 105 /** 106 * Constructs an instance of this class using an HTML {@code Vector}, and a 107 * {@code Predicate} for testing the nodes in that {@code Vector} for matches. 108 * The third parameter {@code 'c'} is only necessary because of Java's type-erasure 109 * problem. 110 * 111 * @param html Any vectorized HTML page or sub-page. 112 * 113 * @param p A {@code java.util.function.Predicate} for testing the nodes in the html 114 * {@code Vector} for matches. 115 * 116 * @param c The sub-class of {@code HTMLNode} that this {@code HNLI} shall be searching. 117 * The values for parameter {@code 'c'} include: {@code TagNode.class, TextNode}, and 118 * {@code CommentNode.class} 119 */ 120 protected AbstractHNLI(Vector<?> html, Predicate<E> p, Class<E> c) 121 { 122 this.expectedSize = html.size(); 123 this.v = html; 124 this.p = p; 125 this.c = c; 126 } 127 128 // Implemented by both sub-classes 129 abstract void RESET_MATCHES(); 130 131 // Implemented by both sub-classes 132 abstract int REMOVE(); 133 134 135 // ******************************************************************************************** 136 // ******************************************************************************************** 137 // Stuff 138 // ******************************************************************************************** 139 // ******************************************************************************************** 140 141 142 protected final void MODIFIED() 143 { 144 modifiedSince = true; 145 expectedSize = v.size(); 146 147 RESET_MATCHES(); 148 } 149 150 /** 151 * This removes the last match that was returned by the {@code Iterator} out of the 152 * underlying {@code Vector}. 153 * 154 * @throws SecondModificationException <EMBED CLASS='external-html' DATA-FILE-ID=SEC_MOD_EX> 155 * @throws IllegalStateException <EMBED CLASS='external-html' DATA-FILE-ID=HNLI_ILST_EX> 156 * 157 * @throws ConcurrentModificationException 158 * <EMBED CLASS='external-html' DATA-FILE-ID=CONC_MOD_EX> 159 * 160 * @see #CHECK_EXCEPTIONS() 161 * @see #MODIFIED() 162 */ 163 public void remove() 164 { 165 CHECK_EXCEPTIONS(); 166 167 int numRemoved = REMOVE(); 168 169 if (maxCursor != -1) maxCursor -= numRemoved; 170 171 MODIFIED(); 172 } 173 174 175 // ******************************************************************************************** 176 // ******************************************************************************************** 177 // Cursor-Methods 178 // ******************************************************************************************** 179 // ******************************************************************************************** 180 181 182 /** 183 * Convenience Method. 184 * <BR />Invokes: {@link #moveCursor(int)} 185 * <BR />Uses minimum cursor-bound for parameter {@code 'location'}, which would 186 * be zero, unless a cursor-window has been set. 187 */ 188 public void moveCursorToStart() 189 { moveCursor((minCursor == -1) ? 0 : minCursor); } 190 191 /** 192 * Convenience Method. 193 * <BR />Invokes: {@link #moveCursor(int)} 194 * <BR />Uses minimum cursor-bound for parameter {@code 'location'}, which would 195 * be {@code v.size() - 1}, unless a cursor-window has been set. 196 */ 197 public void moveCursorToEnd() 198 { moveCursor((maxCursor == -1) ? (v.size() - 1) : maxCursor); } 199 200 /** 201 * Sets the internal state of this {@code Iterator's} cursor location. The next invocation of 202 * {@code next, previous}, etc... will return the nearest match to this {@code Vector}-index. 203 * 204 * <EMBED CLASS='external-html' DATA-FILE-ID=CMERESET> 205 * 206 * @param location Any index into the underlying HTML {@code Vector} 207 * 208 * @throws IndexOutOfBoundsException This shall throw if the value passed to parameter 209 * {@code 'location'} is negative, or past the end of the underlying html {@code Vector}. 210 * 211 * @throws CursorException <EMBED CLASS='external-html' DATA-FILE-ID=CURSOR_EX> 212 */ 213 public void moveCursor(int location) 214 { 215 if (location < 0) throw new IndexOutOfBoundsException 216 ("You have passed a negative value to the cursor location: [" + location + "]."); 217 218 if (location > v.size()) throw new IndexOutOfBoundsException( 219 "You have passed a cursor location value [" + location + "] that is larger than the " + 220 "size of the underlying Vector [" + v.size() + "]" 221 ); 222 223 CursorException.check(minCursor, maxCursor, location); 224 225 cursor = location; 226 modifiedSince = true; 227 expectedSize = v.size(); 228 229 RESET_MATCHES(); 230 } 231 232 /** 233 * Convenience Method. 234 * <BR />Accepts: {@code DotPair} 235 * <BR />Invokes: {@link #restrictCursor(int, int)} 236 */ 237 public void restrictCursor(DotPair cursorBounds) 238 { restrictCursor(cursorBounds.start, cursorBounds.end); } 239 240 /** 241 * Convenience Method. 242 * <BR />Accepts: {@code LV} 243 * <BR />Invokes: {@link #restrictCursor(int, int)} 244 */ 245 public void restrictCursor(LV loopVariable) 246 { restrictCursor(loopVariable.start, loopVariable.end - 1); } 247 248 /** 249 * Restrict the internal {@code cursor} boundaries to a window defined by the parameters 250 * {@code 'maxCursorBounds'}, and {@code 'minCursorBounds'}. When the {@code cursor} 251 * bounds are restricted, any matches that would be returned by this {@code Iterator} 252 * which lay outside the boundaries of this window shall be skipped or avoided. 253 * 254 * <BR /><BR />If the {@code cursor} is currently located outside the boundaries of the 255 * given window, it shall be moved to within it. 256 * 257 * <EMBED CLASS='external-html' DATA-FILE-ID=CMERESET> 258 * 259 * @param minCursorBounds This shall set a minimum {@code cursor}-index value that restricts 260 * the returned matches generated by this {@code HTML Node List Iterator} to indices less 261 * than {@code minCursorBounds}. This is an <I><B>inclusive bound</B></I>. Matches falling 262 * directly on this index may be included in a result set. 263 * 264 * @param maxCursorBounds This shall set a maximum {@code cursor}-index value that restricts 265 * the returned matches generated by this {@code HTML Node List Iterator} to indices greater 266 * than {@code maxCursorBounds}. This is <B>*also*</B> an <I><B>inclusive bound</B></I>. 267 * Matches falling directly on this index may be included in a result set. 268 * 269 * @throws IndexOutOfBoundsException If the bounds provided by the {@code 'cursorBounds'} 270 * input parameter extend past the end of the current underlying {@code Vector}, then this 271 * exception shall throw. 272 */ 273 public void restrictCursor(int minCursorBounds, int maxCursorBounds) 274 { 275 if (minCursorBounds < 0) throw new IndexOutOfBoundsException 276 ("The value for parameter 'minPos' [" + minCursorBounds + "] cannot be negative"); 277 278 if (maxCursorBounds >= v.size()) throw new IndexOutOfBoundsException( 279 "The value for parameter 'maxPos' [" + maxCursorBounds + "] is larger than " + 280 "(or equal to) the size of the underlying Vector [" + v.size() + "]." 281 ); 282 283 this.minCursor = minCursorBounds; 284 this.maxCursor = maxCursorBounds; 285 286 if (this.cursor < this.minCursor) 287 { RESET_MATCHES(); this.cursor = this.minCursor; } 288 289 else if (this.cursor > this.maxCursor) 290 { RESET_MATCHES(); this.cursor = this.maxCursor; } 291 } 292 293 /** Eliminates the <B>Cursor Boundary Window</B>, if one had been set. */ 294 public void clearCursorBounds() 295 { this.maxCursor = this.minCursor = -1; } 296 297 /** 298 * Retrieves the current location of the cursor. 299 * 300 * @return The current location of {@code 'this' Iterator's} cursor. If {@code hasNext()} 301 * or {@code hasPrevious()} has just been called, for example, the cursor will be pointing 302 * to the next (or previous) node-match in the HTML {@code Vector}. 303 */ 304 public int cursorLocation() 305 { return cursor; } 306 307 308 // ******************************************************************************************** 309 // ******************************************************************************************** 310 // ADD 311 // ******************************************************************************************** 312 // ******************************************************************************************** 313 314 315 /** 316 * Convenience Method. 317 * <BR />Invokes: {@link #addHTMLNode(HTMLNode)} 318 */ 319 public void add(E e) { addHTMLNode(e); } 320 321 /** 322 * This provides a way to <B><I>insert</I></B> an HTML node into the HTML-{@code Vector}. The 323 * node is at the current {@code cursor}-index. The cursor should be pointing to the location 324 * of the last returned match. 325 * 326 * @param n <EMBED CLASS='external-html' DATA-FILE-ID=HNLIN> 327 * 328 * @throws SecondModificationException <EMBED CLASS='external-html' DATA-FILE-ID=SEC_MOD_EX> 329 * @throws IllegalStateException <EMBED CLASS='external-html' DATA-FILE-ID=HNLI_ILST_EX> 330 * 331 * @throws ConcurrentModificationException 332 * <EMBED CLASS='external-html' DATA-FILE-ID=CONC_MOD_EX> 333 * 334 * @see #CHECK_EXCEPTIONS() 335 * @see #MODIFIED() 336 */ 337 public void addHTMLNode(HTMLNode n) 338 { 339 CHECK_EXCEPTIONS(); 340 341 v.add(cursor, n); 342 343 if (maxCursor != -1) maxCursor++; 344 345 cursor++; 346 347 MODIFIED(); 348 } 349 350 /** 351 * This provides a way to <B><I>insert</I></B> {@code String}-represented HTML. The HTML will 352 * placed in the underlying HTML-{@code Vector} directly before the current 353 * {@code cursor}-index. The {@code cursor} is situated at the location of the last match 354 * returned by the {@code Iterator}. 355 * 356 * <EMBED CLASS='external-html' DATA-FILE-ID=HTMLSTR> 357 * 358 * @param html This is any valid, parse-able HTML section represented as a 359 * {@code java.lang.String}. The {@code String} will be converted to vectorized-html before 360 * insertion. 361 * 362 * @throws SecondModificationException <EMBED CLASS='external-html' DATA-FILE-ID=SEC_MOD_EX> 363 * @throws IllegalStateException <EMBED CLASS='external-html' DATA-FILE-ID=HNLI_ILST_EX> 364 * 365 * @throws ConcurrentModificationException 366 * <EMBED CLASS='external-html' DATA-FILE-ID=CONC_MOD_EX> 367 * 368 * @see HTMLPage#getPageTokens(CharSequence, boolean) 369 */ 370 public void add(String html) { add(HTMLPage.getPageTokens(html, false)); } 371 372 /** 373 * Adds vectorized-HTML at the current {@code cursor} position. 374 * 375 * @param html This may be any vectorized HTML page or sub-page. It will be inserted at the 376 * the location of the last returned match. 377 * 378 * @throws SecondModificationException <EMBED CLASS='external-html' DATA-FILE-ID=SEC_MOD_EX> 379 * @throws IllegalStateException <EMBED CLASS='external-html' DATA-FILE-ID=HNLI_ILST_EX> 380 * 381 * @throws ConcurrentModificationException 382 * <EMBED CLASS='external-html' DATA-FILE-ID=CONC_MOD_EX> 383 * 384 * @see #CHECK_EXCEPTIONS() 385 * @see #MODIFIED() 386 */ 387 public void add(Vector<HTMLNode> html) 388 { 389 CHECK_EXCEPTIONS(); 390 391 v.addAll(cursor, html); 392 393 cursor += html.size(); 394 395 if (maxCursor != -1) maxCursor += html.size(); 396 397 MODIFIED(); 398 } 399 400 401 // ******************************************************************************************** 402 // ******************************************************************************************** 403 // SET 404 // ******************************************************************************************** 405 // ******************************************************************************************** 406 407 408 /** 409 * Convenience Method. 410 * <BR />Invokes: {@link #setHTMLNode(HTMLNode)} 411 */ 412 public void set(E e) { setHTMLNode(e); } 413 414 /** 415 * This provides a way to <B><I>replace</I></B> the previous match with an instance of 416 * {@code HTMLNode.} The match that is replaced is the one that was last returned from a 417 * call to any of: {@code next(), previous(), nextIndex(), previousIndex(),} etc... 418 * 419 * @param n <EMBED CLASS='external-html' DATA-FILE-ID=HNLIN> 420 * 421 * @throws SecondModificationException <EMBED CLASS='external-html' DATA-FILE-ID=SEC_MOD_EX> 422 * @throws IllegalStateException <EMBED CLASS='external-html' DATA-FILE-ID=HNLI_ILST_EX> 423 * 424 * @throws ConcurrentModificationException 425 * <EMBED CLASS='external-html' DATA-FILE-ID=CONC_MOD_EX> 426 * 427 * @see #remove() 428 * @see #cursor 429 * @see #expectedSize 430 * @see #maxCursor 431 */ 432 public void setHTMLNode(HTMLNode n) 433 { 434 remove(); 435 436 v.add(cursor, n); 437 438 cursor++; 439 440 expectedSize++; 441 442 if (maxCursor != -1) maxCursor++; 443 } 444 445 /** 446 * Convenience Method. 447 * <BR />Invokes: (Parses HTML) {@link HTMLPage#getPageTokens(CharSequence, boolean)} 448 * <BR />And-Then: {@link #set(Vector)} 449 * <BR /><BR /><B CLASS=JDDescLabel>Efficiency Warning:</B> 450 * <BR />This method will will parse (and re-parse) the HTML inside parameter {@code 'html'} 451 * everytime this method is invoked! 452 */ 453 public void set(String html) { set(HTMLPage.getPageTokens(html, false)); } 454 455 /** 456 * Replaces the last returned match with the contents of parameter {@code 'html'}. 457 * 458 * @param html This may be any-sized html page, or sub-page. 459 * 460 * @throws SecondModificationException <EMBED CLASS='external-html' DATA-FILE-ID=SEC_MOD_EX> 461 * @throws IllegalStateException <EMBED CLASS='external-html' DATA-FILE-ID=HNLI_ILST_EX> 462 * 463 * @see Util.Remove#range(Vector, DotPair) 464 * @see #remove() 465 * @see #cursor 466 * @see #expectedSize 467 * @see #maxCursor 468 */ 469 public void set(Vector<HTMLNode> html) 470 { 471 remove(); 472 473 v.addAll(cursor, html); 474 475 cursor += html.size(); 476 477 expectedSize += html.size(); 478 479 if (maxCursor != -1) maxCursor += + html.size(); 480 } 481 482 483 // ******************************************************************************************** 484 // ******************************************************************************************** 485 // INSERT-AT 486 // ******************************************************************************************** 487 // ******************************************************************************************** 488 489 490 /** 491 * Inserts parameter {@code HTMLNode n} into the underlying vectorized-html at 492 * {@code Vector}-index {@code 'pos'}. 493 * 494 * @param n <EMBED CLASS='external-html' DATA-FILE-ID=HNLIN> 495 * 496 * @param pos This is the location in the underlying {@code Vector} being iterated where the 497 * passed parameter {@code 'n'} shall be inserted. 498 * 499 * @throws CursorException <EMBED CLASS='external-html' DATA-FILE-ID=CURSOR_EX> 500 * @throws SecondModificationException <EMBED CLASS='external-html' DATA-FILE-ID=SEC_MOD_EX> 501 * @throws IllegalStateException <EMBED CLASS='external-html' DATA-FILE-ID=HNLI_ILST_EX> 502 * @throws IteratorOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=IOOB_EX> 503 * 504 * @throws ConcurrentModificationException 505 * <EMBED CLASS='external-html' DATA-FILE-ID=CONC_MOD_EX> 506 * 507 * @see #CHECK_EXCEPTIONS(int) 508 * @see #MODIFIED() 509 */ 510 public void insertAt(HTMLNode n, int pos) 511 { 512 CHECK_EXCEPTIONS(pos); 513 514 v.add(pos, n); 515 516 if (pos < cursor) cursor++; 517 518 if (maxCursor != -1) maxCursor++; 519 520 MODIFIED(); 521 } 522 523 /** 524 * Convenience Method. 525 * <BR />Invokes: (Parses HTML) {@link HTMLPage#getPageTokens(CharSequence, boolean)} 526 * <BR />And-Then: {@link #insertAt(Vector, int)}. 527 * <BR /><BR /><B CLASS=JDDescLabel>Efficiency Warning:</B> 528 * <BR />This method will will parse (and re-parse) the HTML inside parameter {@code 'html'} 529 * everytime this method is invoked! 530 */ 531 public void insertAt(String html, int pos) 532 { insertAt(HTMLPage.getPageTokens(html, false), pos); } 533 534 /** 535 * Insert the contents of vectorized-html parameter {@code 'html'} into the underlying html 536 * {@code Vector}, beginning at position {@code 'pos'}. 537 * 538 * @param html This may be any HTML page or sub-page. 539 * 540 * @param pos This is the location in the underlying {@code Vector} being iterated where the 541 * passed parameter {@code 'html'} shall be inserted. 542 * 543 * @throws CursorException <EMBED CLASS='external-html' DATA-FILE-ID=CURSOR_EX> 544 * @throws SecondModificationException <EMBED CLASS='external-html' DATA-FILE-ID=SEC_MOD_EX> 545 * @throws IllegalStateException <EMBED CLASS='external-html' DATA-FILE-ID=HNLI_ILST_EX> 546 * @throws IteratorOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=IOOB_EX> 547 * 548 * @throws ConcurrentModificationException 549 * <EMBED CLASS='external-html' DATA-FILE-ID=CONC_MOD_EX> 550 * 551 * @see #CHECK_EXCEPTIONS(int) 552 * @see #MODIFIED() 553 */ 554 public void insertAt(Vector<? extends HTMLNode> html, int pos) 555 { 556 CHECK_EXCEPTIONS(pos); 557 558 v.addAll(pos, html); 559 560 if (pos < cursor) cursor += html.size(); 561 562 if (maxCursor != -1) maxCursor += html.size(); 563 564 MODIFIED(); 565 } 566 567 568 // ******************************************************************************************** 569 // ******************************************************************************************** 570 // REPLACE 571 // ******************************************************************************************** 572 // ******************************************************************************************** 573 574 575 /** 576 * Convenience Method. 577 * <BR />Invokes: {@link #replaceRange(DotPair, Vector)} 578 * <BR /><BR /><B CLASS=JDDescLabel>Off-By-One Mistake:</B> 579 * <BR />{@code ePos} is decremented by 1, since {@code DotPair.end} is always an 580 * <I>inclusive</I> value, while {@code ePos} is always <I>exclusive</I>. 581 */ 582 public void replaceRange(int sPos, int ePos, Vector<HTMLNode> newNodes) 583 { replaceRange(new DotPair(sPos, ePos - 1), newNodes); } 584 585 /** 586 * This replaces a specified sub-range of nodes in the underlying vectorized-html with the 587 * nodes in {@code 'newNodes'}. 588 * 589 * @param range This is the sub-range or "sub-section" of the underlying vectorized-html page 590 * that is going to be replaced by the {@code 'newNodes'}. 591 * 592 * @param newNodes These are the nodes to be inserted into the location where the old range is. 593 * 594 * @throws CursorException <EMBED CLASS='external-html' DATA-FILE-ID=CURSOR_EX> 595 * @throws SecondModificationException <EMBED CLASS='external-html' DATA-FILE-ID=SEC_MOD_EX> 596 * @throws IllegalStateException <EMBED CLASS='external-html' DATA-FILE-ID=HNLI_ILST_EX> 597 * @throws IteratorOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=IOOB_EX> 598 * 599 * @throws ConcurrentModificationException 600 * <EMBED CLASS='external-html' DATA-FILE-ID=CONC_MOD_EX> 601 * 602 * @see Util.Remove#range(Vector, DotPair) 603 * @see DotPair#isInside(int) 604 * @see DotPair#size() 605 * @see #CHECK_EXCEPTIONS(DotPair) 606 * @see #MODIFIED() 607 */ 608 public void replaceRange(DotPair range, Vector<HTMLNode> newNodes) 609 { 610 CHECK_EXCEPTIONS(range); 611 612 Util.replaceRange(v, range, newNodes); 613 614 int sizeChange = newNodes.size() - range.size(); 615 616 if (range.isInside(cursor)) cursor = range.start; 617 else if(cursor > range.end) cursor += sizeChange; 618 619 if (maxCursor != -1) maxCursor += sizeChange; 620 621 MODIFIED(); 622 } 623 624 625 // ******************************************************************************************** 626 // ******************************************************************************************** 627 // REMOVE 628 // ******************************************************************************************** 629 // ******************************************************************************************** 630 631 632 /** 633 * This removes the node at a specified index in the underlying vectorized-html. 634 * 635 * @param pos This is the index into the underlying vectorized-html page to be removed. 636 * 637 * @throws CursorException <EMBED CLASS='external-html' DATA-FILE-ID=CURSOR_EX> 638 * @throws SecondModificationException <EMBED CLASS='external-html' DATA-FILE-ID=SEC_MOD_EX> 639 * @throws IllegalStateException <EMBED CLASS='external-html' DATA-FILE-ID=HNLI_ILST_EX> 640 * @throws IteratorOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=IOOB_EX> 641 * 642 * @throws ConcurrentModificationException 643 * <EMBED CLASS='external-html' DATA-FILE-ID=CONC_MOD_EX> 644 * 645 * @see #CHECK_EXCEPTIONS(int) 646 * @see #MODIFIED() 647 */ 648 public void removeElementAt(int pos) 649 { 650 CHECK_EXCEPTIONS(pos); 651 652 v.removeElementAt(pos); 653 654 if (pos < cursor) cursor--; 655 656 if (maxCursor != -1) maxCursor--; 657 658 MODIFIED(); 659 } 660 661 /** 662 * Convenience Method. 663 * <BR />Invokes: {@link #removeRange(int, int)} 664 * <BR /><BR /><B CLASS=JDDescLabel>Off-By-One Mistake:</B> 665 * <BR />{@code ePos} is decremented by 1, since {@code DotPair.end} is always an 666 * <I>inclusive</I> value, while {@code ePos} is always <I>exclusive</I>. 667 */ 668 public void removeRange(int sPos, int ePos) 669 { removeRange(new DotPair(sPos, ePos-1)); } 670 671 /** 672 * This removes a specified sub-range of nodes in the underlying vectorized-html. 673 * 674 * @param range This is the sub-range or "sub-section" of the underlying vectorized-html page; 675 * 676 * @throws CursorException <EMBED CLASS='external-html' DATA-FILE-ID=CURSOR_EX> 677 * @throws SecondModificationException <EMBED CLASS='external-html' DATA-FILE-ID=SEC_MOD_EX> 678 * @throws IllegalStateException <EMBED CLASS='external-html' DATA-FILE-ID=HNLI_ILST_EX> 679 * @throws IteratorOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=IOOB_EX> 680 * 681 * @throws ConcurrentModificationException 682 * <EMBED CLASS='external-html' DATA-FILE-ID=CONC_MOD_EX> 683 * 684 * @see Util.Remove.range(Vector, DotPair) 685 * @see DotPair#isInside(int) 686 * @see DotPair#size() 687 * @see #CHECK_EXCEPTIONS(DotPair) 688 * @see #MODIFIED() 689 */ 690 public void removeRange(DotPair range) 691 { 692 CHECK_EXCEPTIONS(range); 693 694 Util.Remove.range(v, range); 695 696 if (range.isInside(cursor)) cursor = range.start; 697 else if(cursor > range.end) cursor -= range.size(); 698 699 if (maxCursor != -1) maxCursor -= range.size(); 700 701 MODIFIED(); 702 } 703 704 /** 705 * This will remove every {@code Vector}-element that is identified by the {@code 'posArr'} 706 * {@code Vector}-position {@code int[]} array. 707 * 708 * @param posArr This is a list of nodes that shall be removed from the underlying 709 * html-{@code Vector}. 710 * 711 * @throws CursorException <EMBED CLASS='external-html' DATA-FILE-ID=CURSOR_EX> 712 * @throws SecondModificationException <EMBED CLASS='external-html' DATA-FILE-ID=SEC_MOD_EX> 713 * @throws IllegalStateException <EMBED CLASS='external-html' DATA-FILE-ID=HNLI_ILST_EX> 714 * @throws IteratorOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=IOOB_EX> 715 * 716 * @throws ConcurrentModificationException 717 * <EMBED CLASS='external-html' DATA-FILE-ID=CONC_MOD_EX> 718 * 719 * @see Util.Remove.nodes(boolean, Vector, int[]) 720 * @see #CHECK_EXCEPTIONS(int[]) 721 * @see #MODIFIED() 722 */ 723 public void removeElements(int... posArr) 724 { 725 CHECK_EXCEPTIONS(posArr); 726 727 Util.Remove.nodes(false, v, posArr); // false --> sorts the input int[] array 728 729 int ORIGINAL_CURSOR = cursor; 730 731 for (int pos : posArr) 732 733 if (pos < ORIGINAL_CURSOR) cursor--; 734 else break; 735 736 if (maxCursor != -1) maxCursor -= posArr.length; 737 738 MODIFIED(); 739 } 740 741 742 // ******************************************************************************************** 743 // ******************************************************************************************** 744 // Exception Checking 745 // ******************************************************************************************** 746 // ******************************************************************************************** 747 748 749 /** 750 * Checks the input position {@code 'pos'} parameter to verify it is not out of the 751 * bounds of the underlying HTML-{@code Vector}, nor out of the bounds of the {@code Cursor 752 * Boundary Window} - <I>if one has been set.</I> 753 * 754 * <BR /><BR />This shall throw exceptions if the passed {@code 'range'} is out of either of 755 * these bounds. 756 * 757 * <BR /><BR />Upon completion of this test, the rest of the standard Exception check-throws 758 * are performed. 759 * 760 * @throws IteratorOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=IOOB_EX> 761 * @throws CursorException <EMBED CLASS='external-html' DATA-FILE-ID=CURSOR_EX> 762 * 763 * @see #CHECK_EXCEPTIONS() 764 */ 765 protected void CHECK_EXCEPTIONS(int pos) 766 { 767 IteratorOutOfBoundsException.check(v, pos); 768 CursorException.check(minCursor, maxCursor, pos); 769 770 CHECK_EXCEPTIONS(); 771 } 772 773 /** 774 * Checks the input position {@code 'range'} parameter to verify the provided {@code range} 775 * values are not out of the bounds of the underlying HTML-{@code Vector}, nor out of the 776 * bounds of the {@code Cursor Boundary Window} - <I>if one has been set.</I> 777 * 778 * <BR /><BR />This shall throw exceptions if the passed {@code 'range'} is out of either of 779 * these bounds. 780 * 781 * <BR /><BR />Upon completion of this test, the rest of the standard Exception check-throws 782 * are performed. 783 * 784 * @throws IteratorOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=IOOB_EX> 785 * @throws CursorException <EMBED CLASS='external-html' DATA-FILE-ID=CURSOR_EX> 786 * 787 * @see #CHECK_EXCEPTIONS() 788 */ 789 protected void CHECK_EXCEPTIONS(DotPair range) 790 { 791 IteratorOutOfBoundsException.check(v, range); 792 CursorException.check(minCursor, maxCursor, range); 793 794 CHECK_EXCEPTIONS(); 795 } 796 797 /** 798 * Checks the input position-array {@code 'posArr'} parameter to verify that none of the 799 * indices listed in this position-array are out of the bounds of the underlying 800 * HTML-{@code Vector}, nor out of the bounds of the {@code Cursor Boundary Window} - <I>if 801 * one has been set.</I> 802 * 803 * <BR /><BR />This shall throw exceptions if the indices in this input array extend past 804 * either of these boundaries. 805 * 806 * <BR /><BR />Upon completion of this test, the rest of the standard Exception check-throws 807 * are performed. 808 * 809 * @throws IteratorOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=IOOB_EX> 810 * @throws CursorException <EMBED CLASS='external-html' DATA-FILE-ID=CURSOR_EX> 811 * 812 * @see #CHECK_EXCEPTIONS() 813 */ 814 protected void CHECK_EXCEPTIONS(int[] posArr) 815 { 816 IteratorOutOfBoundsException.check(v, posArr); 817 CursorException.check(minCursor, maxCursor, posArr); 818 819 CHECK_EXCEPTIONS(); 820 } 821 822 /** 823 * Does a check regarding whether any exceptions should throw. 824 * 825 * @throws IllegalStateException <EMBED CLASS='external-html' DATA-FILE-ID=HNLI_ILST_EX> 826 * @throws SecondModificationException <EMBED CLASS='external-html' DATA-FILE-ID=SEC_MOD_EX> 827 * 828 * @throws ConcurrentModificationException 829 * <EMBED CLASS='external-html' DATA-FILE-ID=CONC_MOD_EX> 830 * 831 * @see #CHECK_CME() 832 */ 833 protected void CHECK_EXCEPTIONS() 834 { 835 CHECK_CME(); 836 837 if (cursor == -1) throw new IllegalStateException( 838 "Neither next, nor previous have been called since initializing the iterator with a " + 839 "constructor." 840 ); 841 842 if (modifiedSince) throw new SecondModificationException( 843 "One of the remove, add, or set methods - which are this Iterator's Update (Modifier) " + 844 "Operations - has already been called since the prior call to a next, previous, first, " + 845 "or last (Inspection) method. The Modifier and Inspection methods / API of this " + 846 "Iterator may only be used ONCE PER CALL (or, rather, on A ONE-TO-ONE BASIS) with " + 847 "each-other. In other words, after an invocation of an 'Inspection Method' (such as " + 848 "'next'), only one invocation of a 'Modifier Method' (such as 'set') will be allowed " + 849 "until another inspection is invoked." 850 ); 851 } 852 853 /** 854 * Does a check regarding whether an exception should throw. 855 * 856 * @throws ConcurrentModificationException Checks for, and throws if necessary, Java's 857 * {@code ConcurrentModificationException}. 858 */ 859 protected void CHECK_CME() // Because HNLI<E> is an interface, this is actually 'protected' 860 { 861 if (expectedSize != v.size()) throw new ConcurrentModificationException( 862 "The expected size of the underlying vector was: [" + expectedSize + "], but the " + 863 "encountered size was: [" + v.size() + "]. This implies that the Vector was modified " + 864 "outside of this HNLI Iterator's provided update & modify API. This is not allowed, " + 865 "unless followed by a call to: first, last, firstIndex, or lastIndex - all of which " + 866 "'reset' the outside-modification monitor-logic (as do the cursor-movement and cursor " + 867 "bounds methods)." 868 ); 869 } 870}