KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > text > LineStruct


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.openide.text;
20
21 import org.openide.util.RequestProcessor;
22
23 import java.io.*;
24
25 import java.util.*;
26
27
28 /** Class that holds line information about one document.
29 * Defines operations that can be executed on the objects, the implementation
30 * can change when we find that it is too slow.
31 *
32 * @author Jaroslav Tulach
33 */

34 final class LineStruct extends Object JavaDoc {
35     /** max number of lines to work with */
36     private static final int MAX = Integer.MAX_VALUE / 2;
37
38     /** processor for all requests */
39     private static final RequestProcessor PROCESSOR = new RequestProcessor("LineStruct Processor"); // NOI18N
40

41     /** list of Info objects that represents the whole document */
42     private List<Info> list;
43
44     /** Constructor.
45     */

46     public LineStruct() {
47         list = new LinkedList<Info>();
48         list.add(new Info(MAX, MAX));
49     }
50
51     /** Converts original numbering to the new one.
52     * @param line the line number in the original
53     * @return line number in the new numbering
54     */

55     public int convert(int line, final boolean currentToOriginal) {
56         // class to compute in the request processor thread
57
class Compute extends Object JavaDoc implements Runnable JavaDoc {
58             public int result;
59
60             public Compute(int i) {
61                 result = i;
62             }
63
64             public void run() {
65                 if (currentToOriginal) {
66                     result = originalToCurrentImpl(result);
67                 } else {
68                     result = currentToOriginalImpl(result);
69                 }
70             }
71         }
72
73         Compute c = new Compute(line);
74
75         // post the computation and wait till it is finished
76
PROCESSOR.post(c).waitFinished();
77
78         // return result
79
return c.result;
80     }
81
82     /** Inserts line(s) at given position.
83     * @param line the line number in current numbering
84     * @param count number of lines inserted
85     */

86     public void insertLines(final int line, final int count) {
87         PROCESSOR.post(
88             new Runnable JavaDoc() {
89                 public void run() {
90                     insertLinesImpl(line, count);
91                 }
92             }
93         );
94     }
95
96     /** Method that deletes some lines in the current state of
97     * the document.
98     *
99     * @param line the line number in current numbering
100     * @param
101     */

102     public void deleteLines(final int line, final int count) {
103         PROCESSOR.post(
104             new Runnable JavaDoc() {
105                 public void run() {
106                     deleteLinesImpl(line, count);
107                 }
108             }
109         );
110     }
111
112     /** Converts original numbering to the new one.
113     * @param line the line number in the original
114     * @return line number in the new numbering
115     */

116     private int originalToCurrentImpl(int line) {
117         Iterator it = list.iterator();
118         int cur = 0;
119
120         for (;;) {
121             Info i = (Info) it.next();
122
123             if (i.original > line) {
124                 // ok we found the segment that contained this line
125
return (line > i.current) ? (cur + i.current) : (cur + line);
126             }
127
128             cur += i.current;
129             line -= i.original;
130         }
131     }
132
133     /** Converts the current numbering to original
134     * @param line the line number now
135     * @return line number in the original numbering
136     */

137     private int currentToOriginalImpl(int line) {
138         Iterator it = list.iterator();
139         int cur = 0;
140
141         for (;;) {
142             Info i = (Info) it.next();
143
144             if (i.current > line) {
145                 // ok we found the segment that contained this line
146
return (line > i.original) ? (cur + i.original) : (cur + line);
147             }
148
149             cur += i.original;
150             line -= i.current;
151         }
152     }
153
154     /** Inserts line(s) at given position.
155     * @param line the line number in current numbering
156     * @param count number of lines inserted
157     */

158     private void insertLinesImpl(int line, int count) {
159         ListIterator<Info> it = list.listIterator();
160
161         for (;;) {
162             Info i = it.next();
163
164             if (i.current >= line) {
165                 for (;;) {
166                     count = i.insert(line, count, it);
167
168                     if (count == 0) {
169                         return;
170                     }
171
172                     i = it.next();
173                     line = 0;
174                 }
175             }
176
177             line -= i.current;
178         }
179     }
180
181     /** Method that deletes some lines in the current state of
182     * the document.
183     *
184     * @param line the line number in current numbering
185     * @param
186     */

187     private void deleteLinesImpl(int line, int count) {
188         ListIterator<Info> it = list.listIterator();
189
190         for (;;) {
191             Info i = it.next();
192
193             if (i.current >= line) {
194                 // information to hold both the number of lines to delete (original)
195
// and the number of lines to mark as delete at the end (current)
196
Info stat = new Info(count, 0);
197
198                 for (;;) {
199                     stat = i.delete(line, stat, it);
200
201                     if (stat.original == 0) {
202                         break;
203                     }
204
205                     i = it.next();
206                     line = 0;
207                 }
208
209                 // insert the amount of lines to mark deleted before current position
210
if ((stat.current > 0) && it.hasPrevious()) {
211                     Info prev = it.previous();
212                     boolean hasPrev = it.hasPrevious();
213
214                     if (hasPrev) {
215                         prev = it.previous();
216                     }
217
218                     if (prev.current == 0) {
219                         prev.original += stat.current;
220                     } else {
221                         if (hasPrev) {
222                             it.next();
223                         }
224
225                         it.add(new Info(stat.current, 0));
226                     }
227                 }
228
229                 return;
230             }
231
232             line -= i.current;
233         }
234     }
235
236     /** Holding the original and current number of lines.
237     */

238     private static final class Info extends Object JavaDoc {
239         /** constants for distintion of the type of info */
240         public static final int AREA_ORIGINAL = 0;
241         public static final int AREA_INSERT = 1;
242         public static final int AREA_REMOVE = -1;
243
244         /** original number */
245         public int original;
246
247         /** current number */
248         public int current;
249
250         public Info(int o, int c) {
251             original = o;
252             current = c;
253         }
254
255         /** Finds the type.
256         */

257         public int type() {
258             if (current == original) {
259                 return AREA_ORIGINAL;
260             }
261
262             if (current == 0) {
263                 return AREA_REMOVE;
264             }
265
266             if (original == 0) {
267                 return AREA_INSERT;
268             }
269
270             throw new IllegalStateException JavaDoc("Original: " + original + " current: " + current); // NOI18N
271
}
272
273         /** Performs insert on this Info object.
274         * @param pos position to insert to
275         * @param count how much objects to insert
276         * @param it iterator that just returned this object
277         * @return how much lines to insert after this object
278         */

279         public int insert(int pos, int count, ListIterator<Info> it) {
280             switch (type()) {
281             case AREA_INSERT:
282
283                 // insert area, add to it all
284
current += count;
285
286                 return 0;
287
288             case AREA_ORIGINAL:
289
290                 if (pos == current) {
291                     // if the insert position is at the end,
292
// then let all the characters be added by next
293
// item
294
return count;
295                 }
296
297                 if (pos == 0) {
298                     // prepend the insert area before the current
299
// Info in the chain
300
Info ni = new Info(original, original);
301                     original = 0;
302                     current = count;
303                     it.add(ni);
304
305                     // everything has been prepended
306
return 0;
307                 }
308
309                 // we have to devided the interval to two parts
310
// and insert insert block between them
311
Info ni = new Info(original - pos, original - pos);
312
313                 // the area from 0 to pos
314
original = current = pos;
315
316                 // insert the insert area
317
it.add(new Info(0, count));
318
319                 // the rest of the area
320
it.add(ni);
321
322                 return 0;
323
324             case AREA_REMOVE:
325
326                 // supposing that pos == 0
327
if (pos != 0) {
328                     throw new IllegalStateException JavaDoc("Pos: " + pos); // NOI18N
329
}
330
331                 // check the previous Info if it cannot be merged
332
Info prev = it.previous(); // current item
333

334                 if (it.hasPrevious()) {
335                     prev = it.previous(); // previous
336
it.next(); // previous
337
}
338
339                 it.next(); // current
340

341                 if (count < original) {
342                     if (prev.type() == AREA_ORIGINAL) {
343                         prev.original += count;
344                         prev.current += count;
345
346                         // modify this remove object
347
original -= count;
348                     } else {
349                         ni = new Info(original - count, 0);
350
351                         // turn this to regular part
352
original = current = count;
353
354                         // insert the new delete part
355
it.add(ni);
356                     }
357
358                     // everything processed
359
return 0;
360                 } else {
361                     if (prev.type() == AREA_ORIGINAL) {
362                         prev.current += original;
363                         prev.original += original;
364                         it.remove();
365
366                         return count - original;
367                     } else {
368                         // turn whole delete part to regular one
369
current = original;
370
371                         // the rest of characters to proceed
372
return count - current;
373                     }
374                 }
375
376             default:
377                 throw new IllegalStateException JavaDoc("Type: " + type()); // NOI18N
378
}
379         }
380
381         /** A method that handles the delete operation.
382         * @param pos position in the Info block where delete started
383         * @param info
384         * info.original the amount of lines to be deleted
385         * info.current the amount of lines that should be later marked as deleted
386         * @param it the iterator that previously returned this instance
387         * @return
388         * info.original the amount of lines to be yet deleted
389         * info.current the amount of lines that needs to be later marked as deleted
390         * this will be put before the
391         */

392         public Info delete(int pos, Info info, ListIterator<Info> it) {
393             switch (type()) {
394             case AREA_ORIGINAL:
395
396                 if (pos != 0) {
397                     // specials
398
int size = current - pos;
399                     current = original = pos;
400
401                     if (size >= info.original) {
402                         // delete is whole only in this block
403
Info ni = new Info(size, size);
404                         it.add(ni);
405                         info.current += info.original;
406                         info.original = 0;
407
408                         return info;
409                     } else {
410                         // something is resting after this block
411
info.original -= size;
412                         info.current += size;
413
414                         return info;
415                     }
416                 } else {
417                     // deleting from first position
418
if (current >= info.original) {
419                         // something is resting from me (at the end)
420
// number of lines to mark as deleted
421
info.current += info.original;
422
423                         // number of lines in this block is decreased
424
current -= info.original;
425                         original = current;
426
427                         // number of lines to be yet deleted
428
info.original = 0;
429
430                         return info;
431                     } else {
432                         // I am completelly deleted
433
it.remove();
434
435                         // number of lines to mark as deleted
436
info.current += current;
437                         info.original -= current;
438
439                         return info;
440                     }
441                 }
442
443             case AREA_INSERT:
444
445                 if (pos != 0) {
446                     // specials
447
int size = current - pos;
448
449                     if (size >= info.original) {
450                         // delete is whole only in this block
451
current -= info.original;
452
453                         info.original = 0;
454
455                         return info;
456                     } else {
457                         // something is resting after this block
458
current = pos;
459
460                         info.original -= size;
461
462                         return info;
463                     }
464                 } else {
465                     // deleting from first position
466
if (current >= info.original) {
467                         // something is resting from me (at the end)
468
// number of lines in this block is decreased
469
current -= info.original;
470
471                         // number of lines to be yet deleted
472
info.original = 0;
473
474                         it.remove();
475
476                         return info;
477                     } else {
478                         // I am completelly deleted
479
it.remove();
480
481                         // how much lines to be deleted yet
482
info.original -= current;
483
484                         return info;
485                     }
486                 }
487
488             case AREA_REMOVE:
489
490                 // only derease the number of lines that needs to be deleted
491
// because this area can absorb some
492
original += info.current;
493                 info.current = 0;
494
495                 return info;
496
497             default:
498                 throw new IllegalStateException JavaDoc("Type: " + type()); // NOI18N
499
}
500         }
501     }
502 }
503
Popular Tags