This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 43484
Collapse All | Expand All

(-)src/org/openide/text/DocumentLine.java (-9 / +14 lines)
Lines 781-788 Link Here
781
    * NetBeans conventions.
781
    * NetBeans conventions.
782
    */
782
    */
783
    public static abstract class Set extends Line.Set {
783
    public static abstract class Set extends Line.Set {
784
        /** listener on document changes */
784
        /** listener on document changes, accessed from LazyLines */
785
        private final LineListener listener;
785
        final LineListener listener;
786
        /** all lines in the set or null */
786
        /** all lines in the set or null */
787
        private java.util.List list;
787
        private java.util.List list;
788
788
Lines 859-872 Link Here
859
        *
859
        *
860
        * @return list of Line objects
860
        * @return list of Line objects
861
        */
861
        */
862
        public java.util.List getLines () {
862
        public synchronized java.util.List getLines () {
863
            if (list == null) {
863
            if (list == null) {
864
                int cnt = listener.getOriginalLineCount ();
864
                list = new LazyLines (this);
865
                java.util.List l = new java.util.LinkedList ();
866
                for (int i = 0; i < cnt; i++) {
867
                    l.add (getOriginal (i));
868
                }
869
                list = l;
870
            }
865
            }
871
            return list;
866
            return list;
872
        }
867
        }
Lines 885-890 Link Here
885
            return safelyRegisterLine(createLine(offset));
880
            return safelyRegisterLine(createLine(offset));
886
        }
881
        }
887
882
883
        
884
        public int getOriginal (Line line) {
885
            Line find = findLine (line);
886
            if (find != null) {
887
                return listener.getOld (find.getLineNumber ());
888
            } else {
889
                return -1;
890
            }
891
        }
892
        
888
        /* Creates current line.
893
        /* Creates current line.
889
        *
894
        *
890
        * @param line is a number of the line (text line) we want to acquire
895
        * @param line is a number of the line (text line) we want to acquire
(-)src/org/openide/text/LazyLines.java (+160 lines)
Added Link Here
1
/*
2
 *                 Sun Public License Notice
3
 *
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 *
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.openide.text;
15
16
/** Lazy List that delegates to another instance of itself.
17
 */
18
final class LazyLines extends Object implements java.util.List {
19
    private java.util.List delegate;
20
    private DocumentLine.Set set;
21
    
22
    public LazyLines (DocumentLine.Set set) {
23
        this.set = set;
24
    }
25
    
26
    /** Override this to create the delegate 
27
     */
28
    private java.util.List createDelegate () {
29
        int cnt = set.listener.getOriginalLineCount ();
30
        java.util.List l = new java.util.ArrayList (cnt);
31
        for (int i = 0; i < cnt; i++) {
32
            l.add (set.getOriginal (i));
33
        }
34
        return l;
35
    }
36
    
37
    
38
    private synchronized java.util.List getDelegate () {
39
        if (delegate == null) {
40
            delegate = createDelegate ();
41
        }
42
        return delegate;
43
    }
44
    
45
    public int indexOf (Object o) {
46
        if (o instanceof DocumentLine) {
47
            Line find = set.findLine ((DocumentLine)o);
48
            if (find != null) {
49
                int indx = set.listener.getOld (find.getLineNumber ());
50
                if (set.getOriginal (indx).equals (o)) {
51
                    // just to verify that the index really exists
52
                    return indx;
53
                }
54
            }
55
        }
56
        return -1;
57
    }
58
59
    public int lastIndexOf (Object o) {
60
        return indexOf (o);
61
    }
62
    
63
    
64
    //
65
    // Pure delegate methods
66
    //
67
    
68
    public int hashCode () {
69
        return getDelegate ().hashCode ();
70
    }
71
    
72
    public boolean addAll (java.util.Collection c) {
73
        throw new UnsupportedOperationException ();
74
    }
75
    
76
    public boolean removeAll (java.util.Collection c) {
77
        throw new UnsupportedOperationException ();
78
    }
79
    
80
    public java.util.ListIterator listIterator () {
81
        return getDelegate ().listIterator ();
82
    }
83
    
84
    public Object[] toArray () {
85
        return getDelegate ().toArray ();
86
    }
87
    
88
    public Object[] toArray (Object[] a) {
89
        return getDelegate ().toArray (a);
90
    }
91
    
92
    public java.util.ListIterator listIterator (int index) {
93
        return getDelegate ().listIterator (index);
94
    }
95
    
96
    public boolean remove (Object o) {
97
        throw new UnsupportedOperationException ();
98
    }
99
    
100
    public boolean equals (Object obj) {
101
        return getDelegate ().equals (obj);
102
    }
103
    
104
    public boolean contains (Object o) {
105
        return getDelegate ().contains (o);
106
    }
107
    
108
    public void add (int index, Object element) {
109
        throw new UnsupportedOperationException ();
110
    }
111
    
112
    public void clear () {
113
        getDelegate ().clear ();
114
    }
115
    
116
    public Object set (int index, Object element) {
117
        throw new UnsupportedOperationException ();
118
    }
119
    
120
    public int size () {
121
        return getDelegate ().size ();
122
    }
123
    
124
    public Object get (int index) {
125
        return getDelegate ().get (index);
126
    }
127
    
128
    public boolean containsAll (java.util.Collection c) {
129
        return getDelegate ().containsAll (c);
130
    }
131
    
132
    public boolean add (Object o) {
133
        throw new UnsupportedOperationException ();
134
    }
135
    
136
    public boolean isEmpty () {
137
        return getDelegate ().isEmpty ();
138
    }
139
    
140
    public boolean retainAll (java.util.Collection c) {
141
        throw new UnsupportedOperationException ();
142
    }
143
    
144
    public java.util.List subList (int fromIndex, int toIndex) {
145
        return getDelegate ().subList (fromIndex, toIndex);
146
    }
147
    
148
    public Object remove (int index) {
149
        return getDelegate ().remove (index);
150
    }
151
    
152
    public java.util.Iterator iterator () {
153
        return getDelegate ().iterator ();
154
    }
155
    
156
    public boolean addAll (int index, java.util.Collection c) {
157
        throw new UnsupportedOperationException ();
158
    }
159
    
160
}
(-)src/org/openide/text/Line.java (-2 / +112 lines)
Lines 325-337 Link Here
325
        * @exception IndexOutOfBoundsException if <code>line</code> is an invalid index for the original set of lines
325
        * @exception IndexOutOfBoundsException if <code>line</code> is an invalid index for the original set of lines
326
        */
326
        */
327
        public abstract Line getCurrent (int line) throws IndexOutOfBoundsException;
327
        public abstract Line getCurrent (int line) throws IndexOutOfBoundsException;
328
328
        
329
        /** Finds an original line number for given line in this line set.
330
         * @param line the line to look for
331
         * @return the number that best matches the line number of the line or -1 
332
         *    if the line does seem to be produced by this line set
333
         * @since JST-PENDING
334
         */
335
        public int getOriginal (Line line) {
336
            return computeOriginal (this, line);
337
        }
338
        
329
        /** Registers the line to this <code>Line.Set</code>.
339
        /** Registers the line to this <code>Line.Set</code>.
330
         * @param line <code>Line</code> to register
340
         * @param line <code>Line</code> to register
331
         * @return registered <code>Line</code>. <em>Note:</em> the retruned
341
         * @return registered <code>Line</code>. <em>Note:</em> the retruned
332
         * <code>Line</code> could be different (identityHashCode not equal)
342
         * <code>Line</code> could be different (identityHashCode not equal)
333
         * from the one passed in */
343
         * from the one passed in */
334
        Line registerLine(Line line) {
344
        final Line registerLine(Line line) {
335
            synchronized(lines) {
345
            synchronized(lines) {
336
                Reference r = (Reference)lines.get(line);
346
                Reference r = (Reference)lines.get(line);
337
                Line in = (r != null ? (Line)r.get() : null);
347
                Line in = (r != null ? (Line)r.get() : null);
Lines 347-352 Link Here
347
                
357
                
348
                return in;
358
                return in;
349
            }
359
            }
360
        }
361
        
362
        /** Finds whether a line equal to provided is already registered.
363
         * @param line the line to register
364
         * @return the registered line equal to line or null
365
         */
366
        final Line findLine (Line line) {
367
            synchronized (lines) {
368
                Reference r = (Reference)lines.get(line);
369
                Line in = (r != null ? (Line)r.get() : null);
370
                return in;
371
            }
372
        }
373
        
374
        /** A method that for a given Line.Set and a line computes the best
375
         * original line number based on the querying the set. This is called 
376
         * in default implementation of getOriginal (Line) to provide 
377
         * inefficient (but better then most people would write) way to
378
         * compute the number. It is static so it can be tested from 
379
         * tests working on DocumentLine objects that override the
380
         * getOriginal (Line) method.
381
         * 
382
         * @param set the set to search in
383
         * @param line the line to look for
384
         * @return closest possible line number for given line
385
         */
386
        static int computeOriginal (Line.Set set, Line line) {
387
            int n = line.getLineNumber ();
388
            Line current = null;
389
            try {
390
                current = set.getOriginal (n);
391
                if (line.equals (current)) {
392
                    return n;
393
                }
394
            } catch (IndexOutOfBoundsException ex) {
395
                // ok, few lines have been added and this one is now
396
                // bellow the end of the document
397
            }
398
            
399
            if (current == null) {
400
                return binarySearch (set, n, 0, findMaxLine (set));
401
            }
402
            
403
            if (n < current.getLineNumber ()) {
404
                return binarySearch (set, n, 0, current.getLineNumber ());
405
            } else {
406
                return binarySearch (set, n, current.getLineNumber (), findMaxLine (set));
407
            }
408
        }
409
        
410
        /** Does a search for a given line number in a given Line.Set.
411
         */
412
        private static int binarySearch (Line.Set set, int number, int from, int to) {
413
            while (from < to) {
414
                int middle = (from + to) / 2;
415
                
416
                Line l = set.getOriginal (middle);
417
                if (l.getLineNumber () < number) {
418
                    // try after the middle
419
                    from = middle + 1;
420
                } else {
421
                    // try before the middle
422
                    to = middle - 1;
423
                }
424
            }
425
            
426
            return from;
427
        }
428
        
429
        private static int findMaxLine (Line.Set set) {
430
            int from = 0;
431
            int to = 32000; 
432
            
433
            // probably larger than any existing document
434
            for (;;) {
435
                try {
436
                    set.getOriginal (to);
437
                    // if the line exists, double the max number, but keep
438
                    // for reference that it exists
439
                    from = to;
440
                    to *= 2;
441
                } catch (IndexOutOfBoundsException ex) {
442
                    break;
443
                }
444
            }
445
            
446
            while (from < to) {
447
                int middle = (from + to + 1) / 2;
448
                
449
                try {
450
                    set.getOriginal (middle);
451
                    // line exists
452
                    from = middle;
453
                } catch (IndexOutOfBoundsException ex) {
454
                    // line does not exists, we have to search lower
455
                    to = middle - 1;
456
                }
457
            }
458
            
459
            return from;
350
        }
460
        }
351
461
352
    } // End of class Line.Set.
462
    } // End of class Line.Set.
(-)src/org/openide/text/LineListener.java (-1 / +5 lines)
Lines 55-61 Link Here
55
55
56
    /** Convertor between old and new line sets */
56
    /** Convertor between old and new line sets */
57
    public int getLine (int i) {
57
    public int getLine (int i) {
58
        return struct.originalToCurrent (i);
58
        return struct.convert (i, true/*originalToCurrent*/);
59
    }
60
    /** Convertor between old and new line sets */
61
    public int getOld (int i) {
62
        return struct.convert (i, false/*currentToOriginal*/);
59
    }
63
    }
60
64
61
    public void removeUpdate(javax.swing.event.DocumentEvent p0) {
65
    public void removeUpdate(javax.swing.event.DocumentEvent p0) {
(-)src/org/openide/text/LineStruct.java (-2 / +24 lines)
Lines 279-285 Link Here
279
    * @param line the line number in the original
279
    * @param line the line number in the original
280
    * @return line number in the new numbering
280
    * @return line number in the new numbering
281
    */
281
    */
282
    public int originalToCurrent (int line) {
282
    public int convert (int line, final boolean currentToOriginal) {
283
        // class to compute in the request processor thread
283
        // class to compute in the request processor thread
284
        class Compute extends Object implements Runnable {
284
        class Compute extends Object implements Runnable {
285
            public int result;
285
            public int result;
Lines 289-295 Link Here
289
            }
289
            }
290
290
291
            public void run () {
291
            public void run () {
292
                result = originalToCurrentImpl (result);
292
                if (currentToOriginal) {
293
                    result = originalToCurrentImpl (result);
294
                } else {
295
                    result = currentToOriginalImpl (result);
296
                }
293
            }
297
            }
294
        }
298
        }
295
299
Lines 343-348 Link Here
343
            }
347
            }
344
            cur += i.current;
348
            cur += i.current;
345
            line -= i.original;
349
            line -= i.original;
350
        }
351
    }
352
    
353
    /** Converts the current numbering to original
354
    * @param line the line number now
355
    * @return line number in the original numbering
356
    */
357
    private int currentToOriginalImpl (int line) {
358
        Iterator it = list.iterator ();
359
        int cur = 0;
360
        for (;;) {
361
            Info i = (Info)it.next ();
362
            if (i.current > line) {
363
                // ok we found the segment that contained this line
364
                return line > i.original ? cur + i.original : cur + line;
365
            }
366
            cur += i.original;
367
            line -= i.current;
346
        }
368
        }
347
    }
369
    }
348
370
(-)test/unit/src/org/openide/text/LineSetTest.java (+211 lines)
Lines 50-55 Link Here
50
    }
50
    }
51
    
51
    
52
    public static void main(java.lang.String[] args) {
52
    public static void main(java.lang.String[] args) {
53
        if (args.length == 1) {
54
            junit.textui.TestRunner.run (new LineSetTest (args[0]));
55
        }
53
        junit.textui.TestRunner.run(suite());
56
        junit.textui.TestRunner.run(suite());
54
    }
57
    }
55
    
58
    
Lines 63-68 Link Here
63
    protected void setUp () {
66
    protected void setUp () {
64
        ic = new InstanceContent ();
67
        ic = new InstanceContent ();
65
        support = new CES (this, new AbstractLookup (ic));
68
        support = new CES (this, new AbstractLookup (ic));
69
        ic.add (this);
66
    }
70
    }
67
71
68
    public void testLineSetIsEmpty () throws Exception {
72
    public void testLineSetIsEmpty () throws Exception {
Lines 90-95 Link Here
90
        
94
        
91
        Line line = set.getCurrent (1);
95
        Line line = set.getCurrent (1);
92
        assertEquals ("Line number is one", 1, line.getLineNumber ());
96
        assertEquals ("Line number is one", 1, line.getLineNumber ());
97
        assertGetOriginal ("Original number is of course 1", set, line, 1);
93
        
98
        
94
        doc.insertString (0, "New line\n", null);
99
        doc.insertString (0, "New line\n", null);
95
        
100
        
Lines 107-112 Link Here
107
        
112
        
108
        Line currentLineTwo = support.getLineSet ().getOriginal (2);
113
        Line currentLineTwo = support.getLineSet ().getOriginal (2);
109
        assertEquals ("This is our original line", line, currentLineTwo);
114
        assertEquals ("This is our original line", line, currentLineTwo);
115
        assertGetOriginal ("Original number of the line was 1", set, line, 1);
110
        
116
        
111
        assertEquals ("Original set still has two lines", 2, set.getLines ().size ());
117
        assertEquals ("Original set still has two lines", 2, set.getLines ().size ());
112
        assertEquals ("Index of current line 1 is 0 in old set", 1, set.getLines ().indexOf (line));
118
        assertEquals ("Index of current line 1 is 0 in old set", 1, set.getLines ().indexOf (line));
Lines 165-170 Link Here
165
        assertEquals ("They will not part", one, two);
171
        assertEquals ("They will not part", one, two);
166
        
172
        
167
        assertEquals ("Line number is 0", 0, one.getLineNumber ());
173
        assertEquals ("Line number is 0", 0, one.getLineNumber ());
174
    }
175
    
176
    public void testGetLinesIndexOfDoesNotCreateAllLines () throws Exception {
177
        content = "0\n1\n2\n3\n4\n";
178
        javax.swing.text.Document doc = support.openDocument ();
179
        
180
        Line.Set set = support.getLineSet ();
181
        Line two = set.getOriginal (2);
182
        
183
        assertEquals ("Line index is two", 2, set.getLines ().indexOf (two));
184
        assertNumberOfLines (1, set);
185
        
186
        assertEquals ("Really two", 2, new java.util.ArrayList (set.getLines ()).indexOf (two));
187
    }
188
    
189
    public void testLinesAreNonMutable () throws Exception {
190
        content = "0\n1\n2\n3\n4\n";
191
        javax.swing.text.Document doc = support.openDocument ();
192
        
193
        assertNonmutable (support.getLineSet ().getLines ());
194
    }
195
196
    public void testGetLinesIndexWorksAfterModifications () throws Exception {
197
        content = "0\n1\n2\n3\n4\n";
198
        javax.swing.text.Document doc = support.openDocument ();
199
        
200
        Line.Set set = support.getLineSet ();
201
        
202
        int offset = 4;
203
        assertEquals ("2 is on the second line", "2", doc.getText (4, 1));
204
        doc.insertString (offset, "x\n", null);
205
        assertEquals ("x\n is on the second line", "x\n", doc.getText (4, 2));
206
        
207
        
208
        Line two = set.getOriginal (2);
209
        assertEquals ("2\n is the line text", "2\n", two.getText ());
210
        
211
        assertEquals ("Line index is two", 2, set.getLines ().indexOf (two));
212
        assertNumberOfLines (1, set);
213
        
214
        assertEquals ("Really two", 2, new java.util.ArrayList (set.getLines ()).indexOf (two));
215
    }
216
    
217
    public void testWhatHappensWhenAskingForLineOutOfBounds () throws Exception {
218
        content = "0";
219
        javax.swing.text.Document doc = support.openDocument ();
220
        
221
        Line.Set set = support.getLineSet ();
222
223
        try {
224
            Line l = set.getCurrent (1);
225
            fail ("Should thrown IndexOutOfBoundsException");
226
        } catch (IndexOutOfBoundsException ex) {
227
            // ok
228
        }
229
        
230
        try {
231
            Line n = set.getOriginal (1);
232
            fail ("Should thrown IndexOutOfBoundsException");
233
        } catch (IndexOutOfBoundsException ex) {
234
            // ok
235
        }
236
        try {
237
            Line l = set.getCurrent (-1);
238
            fail ("Should thrown IndexOutOfBoundsException");
239
        } catch (IndexOutOfBoundsException ex) {
240
            // ok
241
        }
242
        
243
        try {
244
            Line n = set.getOriginal (-1);
245
            fail ("Should thrown IndexOutOfBoundsException");
246
        } catch (IndexOutOfBoundsException ex) {
247
            // ok
248
        }
249
        
250
        Line l = set.getCurrent (0);
251
        Line n = set.getOriginal (0);
252
        
253
        assertNotNull (l);
254
        assertNotNull (n);
255
        
256
        assertEquals ("Lines are the same", l, n);
257
        assertEquals ("Text is", "0", l.getText ());
258
    }
259
260
    
261
    public void testGetLinesIndexWorksForNewlyAddedLines () throws Exception {
262
        content = "0\n1\n2\n3\n4\n";
263
        javax.swing.text.Document doc = support.openDocument ();
264
        
265
        Line.Set set = support.getLineSet ();
266
        
267
        int offset = 4;
268
        assertEquals ("2 is on the second line", "2", doc.getText (4, 1));
269
        doc.insertString (offset, "x\n", null);
270
        assertEquals ("x\n is on the second line", "x\n", doc.getText (4, 2));
271
        
272
        
273
        Line two = set.getCurrent (2);
274
        assertEquals ("x\n is the line text", "x\n", two.getText ());
275
        
276
        assertEquals ("Line index is -1 as it is not present", -1, set.getLines ().indexOf (two));
277
        // two lines created as we need to verify that the current two line is not 
278
        // in the original set
279
        // of course that it can be one if somebody implements this query 
280
        // in better way
281
        assertNumberOfLines (2, set);
282
        assertEquals ("Query on set works and does not produce new lines", 2, set.getOriginal (two));
283
        assertNumberOfLines (2, set);
284
285
        // now few additinal checks 
286
        assertGetOriginal ("However if one asks the line set it works", set, two, 2);
287
        assertEquals ("Really missing from the list", -1, new java.util.ArrayList (set.getLines ()).indexOf (two));
288
    }
289
    
290
    private void assertNumberOfLines (int cnt, Line.Set set) throws Exception {
291
        class MF implements org.netbeans.junit.MemoryFilter {
292
            private java.util.HashSet counted = new java.util.HashSet ();
293
            public int cnt;
294
            public boolean reject(Object obj) {
295
                if (obj instanceof Line) {
296
                    Line l = (Line)obj;
297
                    if (counted.add (obj)) {
298
                        if (l.getLookup ().lookup (LineSetTest.class) == LineSetTest.this) {
299
                            cnt++;
300
                        }
301
                    }
302
                }
303
                return false;
304
            }
305
        }
306
        
307
        MF mf = new MF ();
308
        
309
        // just travel thru the memory
310
        assertSize (
311
            "Just one line",
312
            java.util.Collections.singleton (set), 
313
            Integer.MAX_VALUE,
314
            mf
315
        );
316
317
        if (mf.cnt > cnt) {
318
            fail ("Only given number of instance of line created (" + cnt + ") but was: " + mf.cnt);
319
        }
320
    }
321
322
    private static void assertGetOriginal (String s, Line.Set set, Line line, int expected) {
323
        assertEquals (s + " - Overriden DocumentLine.Set.getOriginal as well", expected, set.getOriginal (line));
324
        assertEquals (s + " - The default Line.Set.computeOriginal method works", expected, Line.Set.computeOriginal (set, line));
325
    }
326
    
327
    private static void assertNonmutable (java.util.List l) throws Exception {
328
        try {
329
            l.add (new Object ());
330
            fail ("add should fail"); 
331
        } catch (java.lang.UnsupportedOperationException ex) {
332
            // ok
333
        }
334
        try {
335
            l.add (0, new Object ());
336
            fail ("add should fail"); 
337
        } catch (java.lang.UnsupportedOperationException ex) {
338
            // ok
339
        }
340
        
341
        try {
342
            l.remove (new Object ());
343
            fail ("remove should fail"); 
344
        } catch (java.lang.UnsupportedOperationException ex) {
345
            // ok
346
        }
347
348
        try {
349
            l.addAll (java.util.Collections.EMPTY_LIST);
350
            fail ("addAll should fail"); 
351
        } catch (java.lang.UnsupportedOperationException ex) {
352
            // ok
353
        }
354
        try {
355
            l.addAll (0, java.util.Collections.EMPTY_LIST);
356
            fail ("addAll should fail"); 
357
        } catch (java.lang.UnsupportedOperationException ex) {
358
            // ok
359
        }
360
        try {
361
            l.removeAll (java.util.Collections.EMPTY_LIST);
362
            fail ("removeAll should fail"); 
363
        } catch (java.lang.UnsupportedOperationException ex) {
364
            // ok
365
        }
366
        
367
        try {
368
            l.retainAll (java.util.Collections.EMPTY_LIST);
369
            fail ("retainAll should fail"); 
370
        } catch (java.lang.UnsupportedOperationException ex) {
371
            // ok
372
        }
373
        try {
374
            l.set (0, null);
375
            fail ("set should fail"); 
376
        } catch (java.lang.UnsupportedOperationException ex) {
377
            // ok
378
        }
168
    }
379
    }
169
    
380
    
170
    //
381
    //

Return to bug 43484