[hg] main-silver: #225451 - IndexOutOfBoundsException: Invalid l...

  • From: Miloslav Metelka < >
  • To: ,
  • Subject: [hg] main-silver: #225451 - IndexOutOfBoundsException: Invalid l...
  • Date: Sun, 03 Feb 2013 12:35:23 -0800

changeset f77dd1c30480 in main-silver ((none))
details: http://hg.netbeans.org/main-silver/rev/f77dd1c30480
description:
        #225451 - IndexOutOfBoundsException: Invalid line index=1 >= 
lineCount=1.

diffstat:

 editor.lib2/src/org/netbeans/modules/editor/lib2/view/DocumentView.java      
                       |   8 +
 
editor.lib2/src/org/netbeans/modules/editor/lib2/view/HighlightsViewFactory.java
                    |  18 +
 editor.lib2/src/org/netbeans/modules/editor/lib2/view/ViewBuilder.java       
                       |  70 +++---
 editor.lib2/src/org/netbeans/modules/editor/lib2/view/ViewReplace.java       
                       |  14 +-
 
editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/TestOffsetsHighlightsContainer.java
 |  96 +++++++++
 
editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/ViewUpdatesExtraFactoryTest.java
    |  36 +++
 
editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/ViewUpdatesTest.java
                |  98 +++++++++-
 
editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/ViewUpdatesTesting.java
             |  39 +++-
 8 files changed, 329 insertions(+), 50 deletions(-)

diffs (613 lines):

diff --git 
a/editor.lib2/src/org/netbeans/modules/editor/lib2/view/DocumentView.java 
b/editor.lib2/src/org/netbeans/modules/editor/lib2/view/DocumentView.java
--- a/editor.lib2/src/org/netbeans/modules/editor/lib2/view/DocumentView.java
+++ b/editor.lib2/src/org/netbeans/modules/editor/lib2/view/DocumentView.java
@@ -318,6 +318,14 @@
         this.endOffset = endOffset;
     }
     
+    void updateEndOffset() {
+        int viewCount = getViewCount();
+        int endOffset = (viewCount > 0)
+                ? getParagraphView(viewCount - 1).getEndOffset()
+                : getStartOffset();
+        setEndOffset(endOffset);
+    }
+    
     @Override
     public int getViewCount() {
         return children.size();
diff --git 
a/editor.lib2/src/org/netbeans/modules/editor/lib2/view/HighlightsViewFactory.java
 
b/editor.lib2/src/org/netbeans/modules/editor/lib2/view/HighlightsViewFactory.java
--- 
a/editor.lib2/src/org/netbeans/modules/editor/lib2/view/HighlightsViewFactory.java
+++ 
b/editor.lib2/src/org/netbeans/modules/editor/lib2/view/HighlightsViewFactory.java
@@ -408,6 +408,24 @@
         });
     }
 
+    @Override
+    public String toString() {
+        return toString(Integer.MIN_VALUE);
+    }
+    
+    public String toString(int offset) {
+        StringBuilder sb = new StringBuilder(100);
+        if (offset != Integer.MIN_VALUE) {
+            sb.append("offset=").append(offset).append(", "); // NOI18N
+        }
+        sb.append("lineIndex=").append(lineIndex). // NOI18N
+                append(", lineEndOffset=").append(lineEndOffset). // NOI18N
+                append(", charType=").append(charType). // NOI18N
+                append(", nextTabOrRTLOffset=").append(nextTabOrRTLOffset). 
// NOI18N
+                append(", nextCharType=").append(nextCharType); // NOI18N
+        return sb.toString();
+    }
+
     public static final class HighlightsFactory implements 
EditorViewFactory.Factory {
 
         @Override
diff --git 
a/editor.lib2/src/org/netbeans/modules/editor/lib2/view/ViewBuilder.java 
b/editor.lib2/src/org/netbeans/modules/editor/lib2/view/ViewBuilder.java
--- a/editor.lib2/src/org/netbeans/modules/editor/lib2/view/ViewBuilder.java
+++ b/editor.lib2/src/org/netbeans/modules/editor/lib2/view/ViewBuilder.java
@@ -310,13 +310,8 @@
             // Either endAffectedOffset points to begining of paragraph or 
inside it
             endCreationOffset = endPView.getStartOffset();
             if (endCreationOffset < endAffectedOffset) { // Inside paragraph
+                endCreationOffset += endPView.getLength();
                 endCreationIndex++;
-                if (endCreationIndex < docView.getViewCount()) {
-                    endPView = docView.getParagraphView(endCreationIndex);
-                    endCreationOffset = endPView.getStartOffset();
-                } else {
-                    endCreationOffset = docView.getDocument().getLength();
-                }
             }
             modOffset = endModOffset = Integer.MIN_VALUE; // No mod
             matchOffset = endCreationOffset;
@@ -458,9 +453,9 @@
                     startCreationPIndex = -1;
                 } else { // inside or past docView's end
                     // docView.startOffset stays at current value
-                    if (modOffset == startOffset) {
+                    if (modOffset == startOffset) { // Removal right at 
docView's start offset
                         startCreationPIndex = 0;
-                    } else {
+                    } else { // Removal starts inside docView
                         // Search for modOffset - 1 since (multiple) 
positions might get moved to modOffset
                         // due to removal and bin-search would find first 
one of them for modOffset
                         startCreationPIndex = docView.getViewIndex(modOffset 
- 1);
@@ -487,15 +482,16 @@
                 lastAffectedPView = startCreationPView;
                 int lastAffectedPViewOffset = startCreationPViewOffset;
                 // If local offset not within view then goto next pView if 
it exists
-                int pViewLen;
-                while ((lastAffectedLocalOffset = Math.min(endRemoveOffset, 
endOffset) - lastAffectedPViewOffset) >
-                            (pViewLen = lastAffectedPView.getLength()) &&
-                        (lastAffectedPIndex + 1 < pViewCount))
-                {
+                int pViewLen = lastAffectedPView.getLength();
+                lastAffectedLocalOffset = endRemoveOffset - 
lastAffectedPViewOffset;
+                while (lastAffectedLocalOffset > pViewLen && 
lastAffectedPIndex + 1 < pViewCount) {
                     lastAffectedPViewOffset += pViewLen;
                     lastAffectedPIndex++;
                     lastAffectedPView = 
docView.getParagraphView(lastAffectedPIndex);
+                    pViewLen = lastAffectedPView.getLength();
+                    lastAffectedLocalOffset = endRemoveOffset - 
lastAffectedPViewOffset;
                 }
+                lastAffectedLocalOffset = Math.min(lastAffectedLocalOffset, 
pViewLen);
             }
         } // END-of-REMOVAL handling
         
@@ -933,26 +929,23 @@
                 // If firstReplace is not active then remove full paragraph 
views
                 // (again to avoid re-parenting of local views to new 
paragraph views).
                 if (eolView && inFirstReplace) { // Rest of views on first 
pagaraph view will be thrown away
-                    // Remove local views till end of first paragraph view
-                    
firstReplace.setRemoveCount(firstReplace.view.getViewCount() - 
firstReplace.index);
-                    int index = docReplace.removeEndIndex();
-                    if (index < docView.getViewCount()) {
-                        matchOffset = 
docView.getParagraphView(index).getStartOffset();
-                    } else {
-                        matchOffset = docView.getEndOffset();
+                    // Ensure that local views till end of first paragraph 
view will be thrown away
+                    if (!firstReplace.isRemovedTillEnd()) {
+                        // Increase matchOffset by remaining views on 
firstReplace's view
+                        int remainingLenOnParagraph = 
firstReplace.view.getLength() - 
+                                
firstReplace.view.getLocalOffset(firstReplace.removeEndIndex());
+                        matchOffset += remainingLenOnParagraph;
+                        firstReplace.removeTillEnd();
                     }
                 }
                 if (createdViewEndOffset > matchOffset) {
                     boolean matchOffsetValid = false;
                     if (inFirstReplace) { // Replacing in firstReplace
-                        int index = firstReplace.removeEndIndex();
-                        int localViewCount = 
firstReplace.view.getViewCount();
-                        while (index < localViewCount) {
+                        while (!firstReplace.isRemovedTillEnd()) {
                             // Use getLength() instead of getEndOffset() 
since for intra-line mods
                             // with modLength != 0 the views do not have 
updated offsets
-                            matchOffset += 
localReplace.view.getEditorView(index).getLength();
+                            matchOffset += 
localReplace.view.getEditorView(firstReplace.removeEndIndex()).getLength();
                             
localReplace.setRemoveCount(localReplace.getRemoveCount() + 1);
-                            index++;
                             // For eolView remove all till end; otherwise 
only until matchOffset is ok
                             if (createdViewEndOffset <= matchOffset) {
                                 matchOffsetValid = true;
@@ -961,12 +954,9 @@
                         }
                     }
                     if (!matchOffsetValid) {
-                        int pViewCount = docView.getViewCount();
-                        int index = docReplace.removeEndIndex();
-                        while (index < pViewCount) {
-                            matchOffset += 
docView.getParagraphView(index).getLength();
+                        while (!docReplace.isRemovedTillEnd()) {
+                            matchOffset += 
docView.getParagraphView(docReplace.removeEndIndex()).getLength();
                             
docReplace.setRemoveCount(docReplace.getRemoveCount() + 1);
-                            index++;
                             if (createdViewEndOffset <= matchOffset) {
                                 break;
                             }
@@ -977,13 +967,10 @@
                     // Check for condition in 
ViewUpdatesTest.testInsertAndRemoveNewline()
                     // when backspace pressed on begining of an empty line 
then rebuilding
                     // could end up with a line not ended by NewlineView.
-                    if (inFirstReplace && !eolView && 
localReplace.removeEndIndex() ==
-                            localReplace.view.getViewCount()) // Would end 
up without NewlineView
-                    {
+                    if (inFirstReplace && !eolView && 
localReplace.isRemovedTillEnd()) {
                         // Rebuild next paragraph
-                        int index = docReplace.removeEndIndex();
-                        if (index < docView.getViewCount()) {
-                            matchOffset += 
docView.getParagraphView(index).getLength();
+                        if (!docReplace.isRemovedTillEnd()) {
+                            matchOffset += 
docView.getParagraphView(docReplace.removeEndIndex()).getLength();
                             
docReplace.setRemoveCount(docReplace.getRemoveCount() + 1);
                         }
                     }
@@ -1232,6 +1219,9 @@
             endY = docView.getY(docReplace.index);
             deltaY = 0d;
         }
+        // Update end offset of the docView since it might extend beyond 
boundary computed
+        // before view building process.
+        docView.updateEndOffset();
         
         // For accurate span force computation of text layouts
         Rectangle2D.Double docViewRect = docView.getAllocationCopy();
@@ -1244,7 +1234,12 @@
             for (; pIndex < endIndex; pIndex++) {
                 ParagraphView pView = docView.getParagraphView(pIndex);
                 Shape pAlloc = docView.getChildAllocation(pIndex, 
docViewRect);
-                assert (!pView.isChildrenNull()) : "Null children for 
accurate span"; // NOI18N
+                if (!pView.isChildrenNull()) {
+                    LOG.info("Null children for accurate span at pIndex=" + 
// NOI18N
+                        pIndex + "\nviewBuilder:\n" + this); // NOI18N
+//                        "\n\ndocView:\n" + 
docView.toStringDetailNeedsLock()); // NOI18N
+                    break;
+                }
                 pView.checkLayoutUpdate(pIndex, 
ViewUtils.shapeAsRect(pAlloc));
             }
         }
@@ -1292,6 +1287,7 @@
     public String toString() {
         StringBuilder sb = new StringBuilder(200);
         sb.append("-------- ViewBuilder dump -------\n"). // NOI18N
+                
append("docLen=").append(docReplace.view.getDocument().getLength()).append('\n').
 // NOI18N
                 
append("start/endCreationOffset:<").append(startCreationOffset). // NOI18N
                 append(",").append(endCreationOffset).append(">\n").
                 
append("creationOffset=").append(creationOffset).append('\n').
diff --git 
a/editor.lib2/src/org/netbeans/modules/editor/lib2/view/ViewReplace.java 
b/editor.lib2/src/org/netbeans/modules/editor/lib2/view/ViewReplace.java
--- a/editor.lib2/src/org/netbeans/modules/editor/lib2/view/ViewReplace.java
+++ b/editor.lib2/src/org/netbeans/modules/editor/lib2/view/ViewReplace.java
@@ -63,9 +63,13 @@
 
     private List<CV> added; // 20 + 4 = 24 bytes
 
+    private final int childViewCount; // 24 + 4 = 28 bytes
+
     ViewReplace(V view) {
         assert (view != null);
         this.view = view;
+        // Cache child view count since the view is not going to change 
during views rebuild.
+        this.childViewCount = view.getViewCount();
     }
     
     void add(CV childView) {
@@ -99,7 +103,7 @@
     }
 
     void setRemoveCount(int removeCount) {
-        if (index + removeCount > view.getViewCount()) {
+        if (index + removeCount > childViewCount) {
             throw new IllegalStateException("removeCount=" + removeCount + 
", this:\n" + this);
         }
         this.removeCount = removeCount;
@@ -114,7 +118,11 @@
     }
     
     void removeTillEnd() {
-        setRemoveCount(view.getViewCount() - index);
+        setRemoveCount(childViewCount - index);
+    }
+    
+    boolean isRemovedTillEnd() {
+        return (index + removeCount == childViewCount);
     }
 
     boolean isChanged() {
@@ -122,7 +130,7 @@
     }
     
     boolean isMakingViewEmpty() {
-        return index == 0 && getRemoveCount() == view.getViewCount() && 
addedSize() == 0;
+        return index == 0 && getRemoveCount() == childViewCount && 
addedSize() == 0;
     }
 
     @Override
diff --git 
a/editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/TestOffsetsHighlightsContainer.java
 
b/editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/TestOffsetsHighlightsContainer.java
new file mode 100644
--- /dev/null
+++ 
b/editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/TestOffsetsHighlightsContainer.java
@@ -0,0 +1,96 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2013 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.editor.lib2.view;
+
+import javax.swing.text.AttributeSet;
+import org.netbeans.spi.editor.highlighting.HighlightsSequence;
+import 
org.netbeans.spi.editor.highlighting.support.AbstractHighlightsContainer;
+
+/**
+ *
+ * @author Miloslav Metelka
+ */
+public class TestOffsetsHighlightsContainer extends 
AbstractHighlightsContainer {
+    
+    int[] offsetPairs = new int[0];
+    
+    public void setOffsetPairs(int[] offsetPairs) {
+        this.offsetPairs = offsetPairs;
+        fireHighlightsChange(0, Integer.MAX_VALUE);
+    }
+
+    @Override
+    public HighlightsSequence getHighlights(int startOffset, int endOffset) {
+        return new HiSeq();
+    }
+
+    private final class HiSeq implements HighlightsSequence {
+        
+        int index;
+
+        @Override
+        public boolean moveNext() {
+            if (index < offsetPairs.length) {
+                index += 2;
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public int getStartOffset() {
+            return offsetPairs[index - 2];
+        }
+
+        @Override
+        public int getEndOffset() {
+            return offsetPairs[index - 1];
+        }
+
+        @Override
+        public AttributeSet getAttributes() {
+            return ViewUpdatesTesting.FONT_ATTRS[0];
+        }
+        
+    }
+    
+}
diff --git 
a/editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/ViewUpdatesExtraFactoryTest.java
 
b/editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/ViewUpdatesExtraFactoryTest.java
--- 
a/editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/ViewUpdatesExtraFactoryTest.java
+++ 
b/editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/ViewUpdatesExtraFactoryTest.java
@@ -59,6 +59,7 @@
 import static 
org.netbeans.modules.editor.lib2.view.ViewUpdatesTesting.NL_VIEW;
 import static 
org.netbeans.modules.editor.lib2.view.ViewUpdatesTesting.P_VIEW;
 import static 
org.netbeans.modules.editor.lib2.view.ViewUpdatesTesting.VIEW_BUILDER_TEST_VALUE_NAMES;
+import org.netbeans.spi.editor.highlighting.support.OffsetsBag;
 
 /**
  *
@@ -264,4 +265,39 @@
         ViewUpdatesTesting.setTestValues();
     }
 
+    public void testHighlightBeyondDocEnd() throws Exception {
+        loggingOn();
+        
ViewUpdatesTesting.setTestValues(ViewUpdatesTesting.NO_OP_TEST_VALUE);
+        JEditorPane pane = ViewUpdatesTesting.createPane();
+        Document doc = pane.getDocument();
+        final DocumentView docView = DocumentView.get(pane);
+        final OffsetsBag highlights = 
ViewUpdatesTesting.getSingleHighlightingLayerOffsets(pane);
+        String text = "abcd\nefgh";
+        doc.insertString(0, text, null);
+        highlights.addHighlight(0, 5, ViewUpdatesTesting.FONT_ATTRS[0]);
+        highlights.addHighlight(7, doc.getLength() + 2, 
ViewUpdatesTesting.FONT_ATTRS[1]); // Beyond doc's end
+
+        docView.op.viewsRebuildOrMarkInvalid(); // Manually mark affected 
children as invalid
+        docView.ensureAllParagraphsChildrenAndLayoutValid();
+
 }
+
+    public void testCustomHighlightBeyondDocEnd() throws Exception {
+        loggingOn();
+        
ViewUpdatesTesting.setTestValues(ViewUpdatesTesting.NO_OP_TEST_VALUE);
+        JEditorPane pane = ViewUpdatesTesting.createPane();
+        Document doc = pane.getDocument();
+        final DocumentView docView = DocumentView.get(pane);
+        final TestOffsetsHighlightsContainer highlights = new 
TestOffsetsHighlightsContainer();
+        ViewUpdatesTesting.getSingleHighlightingLayerCustom(pane, 
highlights);
+        highlights.setOffsetPairs(new int[] { 0, 5 });
+        String text = "abcd\nefgh";
+        doc.insertString(0, text, null);
+
+        docView.op.viewsRebuildOrMarkInvalid(); // Manually mark affected 
children as invalid
+        docView.ensureAllParagraphsChildrenAndLayoutValid();
+        highlights.setOffsetPairs(new int[] { 3, 9 });
+        doc.remove(0, doc.getLength());
+    }
+
+}
diff --git 
a/editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/ViewUpdatesTest.java
 
b/editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/ViewUpdatesTest.java
--- 
a/editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/ViewUpdatesTest.java
+++ 
b/editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/ViewUpdatesTest.java
@@ -76,8 +76,9 @@
 //        includes.add("testModsWithHighlights");
 //        includes.add("testLongHighlightedLine");
 //        includes.add("testRemoveAtBeginning");
-        includes.add("testRemoveTrailingWhitespace");
-        filterTests(includes);
+//        includes.add("testRemoveTrailingWhitespace");
+        includes.add("testRemoveSpanningEndOfPartial");
+//        filterTests(includes);
     }
 
     private void filterTests(List<String> includeTestNames) {
@@ -1753,4 +1754,97 @@
         ViewUpdatesTesting.setTestValues();
     }
 
+    public void testRemoveSpanningEndOfPartial() throws Exception {
+        loggingOn();
+        
ViewUpdatesTesting.setTestValues(ViewUpdatesTesting.NO_OP_TEST_VALUE);
+        JEditorPane pane = ViewUpdatesTesting.createPane();
+        Document doc = pane.getDocument();
+        final DocumentView docView = DocumentView.get(pane);
+        final PositionsBag highlights = 
ViewUpdatesTesting.getSingleHighlightingLayer(pane);
+        int offset;
+        String text;
+        int cRegionStartOffset;
+        int cRegionEndOffset;
+        
+        offset = 0;
+        //      0123 456789 0123 456789 0123 4567 890
+        text = "abc\ndefgh\nijk\nlmnop\nrst\nuvw\nxyz";
+        ViewUpdatesTesting.setTestValues(
+/*rebuildCause*/        ViewBuilder.RebuildCause.MOD_UPDATE,
+/*createLocalViews*/    true,
+/*startCreationOffset*/ 0,
+/*matchOffset*/         offset + text.length(),
+/*endCreationOffset*/   offset + text.length() + 1, // includes '\n'
+/*bmReuseOffset*/       0,
+/*bmReusePView*/        docView.getParagraphView(0),
+/*bmReuseLocalIndex*/   0,
+/*amReuseOffset*/       offset + text.length(),
+/*amReusePIndex*/       0,
+/*amReusePView*/        docView.getParagraphView(0),
+/*amReuseLocalIndex*/   0 // Could reuse NewlineView
+        );
+        doc.insertString(offset, text, null);
+        ViewUpdatesTesting.checkViews(docView, 0, -1,
+            3, HI_VIEW,
+            1, NL_VIEW /* e:4 */,
+            5, HI_VIEW,
+            1, NL_VIEW /* e:10 */,
+            3, HI_VIEW,
+            1, NL_VIEW /* e:14 */,
+            5, HI_VIEW,
+            1, NL_VIEW /* e:20 */,
+            3, HI_VIEW,
+            1, NL_VIEW /* e:24 */,
+            3, HI_VIEW,
+            1, NL_VIEW /* e:28 */,
+            3, HI_VIEW,
+            1, NL_VIEW /* e:32 */
+        );
+
+        
ViewUpdatesTesting.setTestValues(ViewUpdatesTesting.NO_OP_TEST_VALUE);
+        ViewUpdatesTesting.setViewBounds(pane, 6, 19);
+        pane.modelToView(7); // Init
+        docView.ensureAllParagraphsChildrenAndLayoutValid();
+        ViewUpdatesTesting.checkIntegrity(pane);
+        ViewUpdatesTesting.checkViews(docView, 6, -1,
+            3, HI_VIEW,
+            1, NL_VIEW /* e:10 */,
+            3, HI_VIEW,
+            1, NL_VIEW /* e:14 */,
+            5, HI_VIEW
+        );
+
+        ParagraphView pView1 = docView.getParagraphView(1);
+        ParagraphView pView2 = docView.getParagraphView(2);
+        int removeLength = 12;
+        offset = pView1.getStartOffset() + 3; // Remove before NL
+        assert (offset == 13) : "offset=" + offset;
+//        cRegionStartOffset = offset;
+//        cRegionEndOffset = offset + removeLength;
+//        
docView.op.viewUpdates.extendCharRebuildRegion(OffsetRegion.create(doc, 
cRegionStartOffset, cRegionEndOffset));
+        ViewUpdatesTesting.setTestValues(
+/*rebuildCause*/        ViewBuilder.RebuildCause.MOD_UPDATE,
+/*createLocalViews*/    true,
+/*startCreationOffset*/ pView1.getStartOffset(),
+/*matchOffset*/         pView1.getEndOffset() - 1,
+/*endCreationOffset*/   pView1.getEndOffset() - 1,
+/*bmReuseOffset*/       pView1.getStartOffset(),
+/*bmReusePView*/        pView1,
+/*bmReuseLocalIndex*/   0,
+/*amReuseOffset*/       Integer.MAX_VALUE,
+/*amReusePIndex*/       3,
+/*amReusePView*/        null,
+/*amReuseLocalIndex*/   0 // Could reuse NewlineView
+        );
+        doc.remove(offset, removeLength);
+        ViewUpdatesTesting.checkViews(docView, 6, -1,
+            3, HI_VIEW,
+            1, NL_VIEW /* e:4 */,
+            3, HI_VIEW
+        );
+
+        ViewUpdatesTesting.checkIntegrity(pane);
+        ViewUpdatesTesting.setTestValues();
 }
+
+}
diff --git 
a/editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/ViewUpdatesTesting.java
 
b/editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/ViewUpdatesTesting.java
--- 
a/editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/ViewUpdatesTesting.java
+++ 
b/editor.lib2/test/unit/src/org/netbeans/modules/editor/lib2/view/ViewUpdatesTesting.java
@@ -41,23 +41,20 @@
  */
 package org.netbeans.modules.editor.lib2.view;
 
-import java.awt.Font;
 import java.awt.Graphics;
 import java.awt.image.BufferedImage;
 import java.lang.reflect.InvocationTargetException;
 import java.util.List;
-import javax.swing.JComponent;
 import javax.swing.JEditorPane;
 import javax.swing.SwingUtilities;
-import javax.swing.plaf.basic.BasicTextUI;
 import javax.swing.text.*;
 import javax.swing.undo.UndoManager;
-import junit.framework.Assert;
 import junit.framework.TestCase;
 import org.netbeans.api.editor.settings.AttributesUtilities;
 import org.netbeans.lib.editor.util.GapList;
 import org.netbeans.modules.editor.lib2.highlighting.HighlightingManager;
 import org.netbeans.spi.editor.highlighting.HighlightsContainer;
+import org.netbeans.spi.editor.highlighting.support.OffsetsBag;
 import org.netbeans.spi.editor.highlighting.support.PositionsBag;
 
 /**
@@ -179,12 +176,28 @@
         c.putClientProperty(DocumentView.END_POSITION_PROPERTY, endPos);
     }
     
+    public static OffsetsBag getSingleHighlightingLayerOffsets(final 
JEditorPane pane) {
+        return (OffsetsBag) getSingleHighlightingLayerImpl(pane, null, true);
+    }
+
     public static PositionsBag getSingleHighlightingLayer(final JEditorPane 
pane) {
+        return (PositionsBag) getSingleHighlightingLayerImpl(pane, null, 
false);
+    }
+
+    public static HighlightsContainer getSingleHighlightingLayerCustom(final 
JEditorPane pane, HighlightsContainer container) {
+        return getSingleHighlightingLayerImpl(pane, container, false);
+    }
+
+    private static HighlightsContainer getSingleHighlightingLayerImpl(
+            final JEditorPane pane, HighlightsContainer container, boolean 
offsets)
+    {
         String propName = "test-single-highlighting-container";
         HighlightsContainer tshc = (HighlightsContainer) 
pane.getClientProperty(propName);
         if (tshc == null) {
             final Document doc = pane.getDocument();
-            final PositionsBag bag = new PositionsBag(doc);
+            final HighlightsContainer bag = (container != null)
+                    ? container
+                    : (offsets ? new OffsetsBag(doc) : new 
PositionsBag(doc));
             doc.render(new Runnable() {
                 @Override
                 public void run() {
@@ -202,7 +215,7 @@
             tshc = bag;
             pane.putClientProperty(propName, tshc);
         }
-        return (PositionsBag) tshc;
+        return tshc;
     }
     
     private static String[] testValueNames;
@@ -234,7 +247,8 @@
             @Override
             public void run() {
                 if (processed) {
-                    throw new IllegalStateException("Already processed");
+                    throw new IllegalStateException("Test values were 
already processed. " + 
+                            "New call to setTestValues() needed before the 
code that checks them gets called.");
                 }
                 processed = true;
                 Object[] testValues = DocumentView.testValues;
@@ -319,6 +333,15 @@
         return highlights;
     }
     
+    public static void checkIntegrity(JTextComponent component) {
+        DocumentView docView = DocumentView.get(component);
+        String err = docView.findTreeIntegrityError();
+        if (err != null) {
+            throw new IllegalStateException("Integrity ERROR:\n" +
+                    err + "\n" + docView.toStringDetailNeedsLock());
+        }
+    }
+
     /**
      * Ensure a part of view hierarchy has local views of certain length and 
class
      * 
@@ -387,7 +410,7 @@
                 sbCall.append("            
").append(view.getLength()).append(", ").append(viewType).append(",\n");
             }
             if (argIndex < argCount && errorMsg == null) {
-                errorMsg = "Ending argIndex=" + argIndex + " != argCount=" + 
argCount;
+                errorMsg = "checkViews() called with " + argCount + " 
arguments but only " + argIndex + " used.";
             }
         } else { // No pViews
             if (argCount == 0) { // No pViews => Ok

[hg] main-silver: #225451 - IndexOutOfBoundsException: Invalid l...

Miloslav Metelka 02/03/2013

Project Features

About this Project

Editor was started in November 2009, is owned by Martin Ryzl, and has 147 members.
By use of this website, you agree to the NetBeans Policies and Terms of Use (revision 20140418.2d69abc). © 2013, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo
 
 
Close
loading
Please Confirm
Close