KickJava   Java API By Example, From Geeks To Geeks.

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


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-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.openide.text;
20
21 import org.openide.util.Lookup;
22 import org.openide.util.lookup.Lookups;
23
24 import java.io.*;
25
26 import java.lang.ref.Reference JavaDoc;
27 import java.lang.ref.WeakReference JavaDoc;
28
29 import java.util.Date JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.Map JavaDoc;
32 import java.util.WeakHashMap JavaDoc;
33
34
35 /** Represents one line in a text document.
36  * The line number may change
37 * when the text is modified, but the identity of the line is retained. It is designed to allow line-dependent
38 * modules of the IDE (such as the compiler and debugger) to make use of a line consistently even as the text is modified.
39 *
40 * @author Ales Novak, Petr Hamernik, Jan Jancura, Jaroslav Tulach, David Konecny
41 */

42 public abstract class Line extends Annotatable implements Serializable {
43     /** generated Serialized Version UID */
44     static final long serialVersionUID = 9113186289600795476L;
45
46     /** Property name of the line number */
47     public static final String JavaDoc PROP_LINE_NUMBER = "lineNumber"; // NOI18N
48

49     /** Shows the line only if the editor is open.
50      * @see #show(int) <code>show</code>
51      */

52     public final static int SHOW_TRY_SHOW = 0;
53
54     /** Opens the editor if necessary and shows the line.
55      * @see #show(int) <code>show</code>
56      */

57     public final static int SHOW_SHOW = 1;
58
59     /** Opens the editor if necessary, shows the line, and takes the focus.
60      * @see #show(int) <code>show</code>
61      */

62     public final static int SHOW_GOTO = 2;
63
64     /** Same as SHOW_GOTO except that the Window Manager attempts to front the
65      * editor window (i.e. make it the top most window).
66      * @see #show(int) <code>show</code>
67      * @see org.openide.windows.TopComponent#toFront()
68      * @since 5.8
69      */

70     public final static int SHOW_TOFRONT = 3;
71
72     /** Takes the focus in case the editor is already opened and shows the line.
73      * Replaces (closes) the last editor opened using SHOW_REUSE in case
74      * the user haven't interacted with it much (e.g. haven't modified it).
75      * Opens a new editor in case there is no such reusable editor
76      * and marks it for editor reusal.
77      * @see #show(int) <code>show</code>
78      */

79     public final static int SHOW_REUSE = 4;
80
81     /** Focuses or opens given editor, marking it as reusable editor if it
82      * was not opened before. Similar to {@link #SHOW_REUSE) but ignores
83      * currently reusable editor.
84      * @see #show(int) <code>show</code>
85      */

86     public final static int SHOW_REUSE_NEW = 5;
87
88     /** Instance of null implementation of Line.Part */
89     static final private Line.Part nullPart = new Line.NullPart();
90
91     /** context of this line */
92     private org.openide.util.Lookup dataObject;
93
94     /** Create a new line object based on a given data object.
95      * This implementation is abstract, so the specific line number is not used here.
96      * Subclasses should somehow specify the position.
97      * <P>
98      * The context argument shall contain information about the
99      * producer of the Line, that can be then extracted by {@link Line#getLookup} call.
100      *
101      * @param context the context for this line
102      */

103     public Line(Lookup context) {
104         if (context == null) {
105             throw new NullPointerException JavaDoc();
106         }
107
108         dataObject = context;
109     }
110
111     /**
112      * Create a new line object based on a given data object.
113      * This implementation is abstract, so the specific line number is not used here. Subclasses should somehow specify the position.
114      * @param source the object that is producing the Line
115      */

116     public Line(Object JavaDoc source) {
117         this((source instanceof Lookup) ? (Lookup) source : Lookups.singleton(source));
118
119         if (source == null) {
120             throw new NullPointerException JavaDoc();
121         }
122     }
123
124     /** Composes a human presentable name for the line. The default
125     * implementation uses the name of data object and the line number
126     * to create the display name.
127     *
128     * @return human presentable name that should identify the line
129     */

130     public String JavaDoc getDisplayName() {
131         return getClass().getName() + ":" + getLineNumber(); // NOI18N
132
}
133
134     /** Provides access to the context passed into the line constructor.
135      * For example lines produced by <code>DataEditorSupport</code>
136      * provide <code>DataObject</code> as the content of the lookup.
137      * One can use:
138      * <PRE>
139      * dataObjectOrNull = (DataObject)line.getLookup ().lookup (DataObject.class);
140      * </PRE>
141      * to get the access.
142      *
143      * @return context associated with the line
144      * @since 4.3
145      */

146     public final org.openide.util.Lookup getLookup() {
147         return dataObject;
148     }
149
150     /** Get the line number. The last condition in following should
151     * always be true:
152     * <PRE>
153     * Line.Set lineSet = <line set>
154     * Line l = <some line from line set lineSet>
155     *
156     * l.equals (lineSet.getCurrent (l.getLineNumber ()))
157     * </PRE>
158     *
159     * @return current line number (may change as text is edited) (starting at 0)
160     */

161     public abstract int getLineNumber();
162
163     /** Show the line.
164     * @param kind one of {@link #SHOW_TRY_SHOW}, {@link #SHOW_SHOW}, or {@link #SHOW_GOTO}
165     * @param column the column of this line which should be selected (starting at 0)
166     */

167     public abstract void show(int kind, int column);
168
169     /** Shows the line (at the first column).
170     * @param kind one of {@link #SHOW_TRY_SHOW}, {@link #SHOW_SHOW}, {@link #SHOW_GOTO},
171     * {@link #SHOW_REUSE} or {@link #SHOW_REUSE_NEW}
172     * @see #show(int, int)
173     */

174     public void show(int kind) {
175         show(kind, 0);
176     }
177
178     /** Set or clear a (debugger) breakpoint at this line.
179      * @param b <code>true</code> to turn on
180      * @deprecated Deprecated since 1.20. Use {@link Annotation#attach} instead.
181      */

182     @Deprecated JavaDoc
183     public abstract void setBreakpoint(boolean b);
184
185     /** Test if there is a breakpoint set at this line.
186      * @return <code>true</code> is there is
187      * @deprecated Deprecated since 1.20. Use {@link Annotation} instead.
188      */

189     @Deprecated JavaDoc
190     public abstract boolean isBreakpoint();
191
192     /** Mark an error at this line.
193      * @deprecated Deprecated since 1.20. Use {@link Annotation#attach} instead.
194      */

195     @Deprecated JavaDoc
196     public abstract void markError();
197
198     /** Unmark error at this line.
199      * @deprecated Deprecated since 1.20. Use {@link Annotation#detach} instead.
200      */

201     @Deprecated JavaDoc
202     public abstract void unmarkError();
203
204     /** Mark this line as current.
205      * @deprecated Deprecated since 1.20. Use {@link Annotation#attach} instead.
206      */

207     @Deprecated JavaDoc
208     public abstract void markCurrentLine();
209
210     /** Unmark this line as current.
211      * @deprecated Deprecated since 1.20. Use {@link Annotation#detach} instead.
212      */

213     @Deprecated JavaDoc
214     public abstract void unmarkCurrentLine();
215
216     /** Method that should allow the debugger to communicate with lines that
217     * wants to have a control over the current line of debugger. It allows the
218     * line to refuse the current status and force the debugger to continue
219     * over this line.
220     * <P>
221     * The default implementation simply returns true.
222     *
223     * @param action type of action that is trying to mark this line as current
224     * one of constants (Debugger.ACTION_BREAKPOINT_HIT,
225     * Debugger.ACTION_TRACE_OVER, etc.)
226     * @param previousLine previous line (if any) or null
227     *
228     * @return true if this line accepts the "current" state or false if the
229     * line wants the debugger to proceed with next instruction
230     *
231     * @deprecated Deprecated since 1.20, as {@link #markCurrentLine} is deprecated by {@link Annotation#attach}.
232     */

233     @Deprecated JavaDoc
234     public boolean canBeMarkedCurrent(int action, Line previousLine) {
235         return true;
236     }
237
238     /** Create object which represent part of the text on the line. This part
239      * of the line can be used for attaching of annotations.
240      * @param column starting column of the part of the text (starting at 0)
241      * @param length length of the part of the text
242      * @return instance of the Line.Part which represent the part of the text
243      * @since 1.20
244      */

245     public Line.Part createPart(int column, int length) {
246         return nullPart;
247     }
248
249     public String JavaDoc getText() {
250         return null;
251     }
252
253     /** Representation of the part of the Line's text. The part of the text is defined by
254      * the starting column, length of the part and reference to Line. The length of the
255      * part never cross the end of the line.
256      * @since 1.20
257      */

258     public static abstract class Part extends Annotatable {
259         /** Property name for the line attribute */
260         public static final String JavaDoc PROP_LINE = "line"; // NOI18N
261

262         /** Property name for the column attribute */
263         public static final String JavaDoc PROP_COLUMN = "column"; // NOI18N
264

265         /** Property name for the length attribute */
266         public static final String JavaDoc PROP_LENGTH = "length"; // NOI18N
267

268         /** Start column of annotation
269          * @return column at which this part begining (starting at 0)
270          */

271         public abstract int getColumn();
272
273         /** Length of the annotated text. The length does not cross line end. If the annotated text is
274          * split during the editing, the annotation is shorten till the end of the line. Modules can listen on
275          * changes of this value
276          * @return length of the part
277          */

278         public abstract int getLength();
279
280         /** Line can change during editting
281          * @return reference to the Line to which this part belongs
282          */

283         public abstract Line getLine();
284     }
285
286     /** Implementation of Line.Part which is presenting empty part */
287     static final private class NullPart extends Part {
288         NullPart() {
289         }
290
291         public int getColumn() {
292             return 0;
293         }
294
295         public int getLength() {
296             return 0;
297         }
298
299         public Line getLine() {
300             return null;
301         }
302
303         public String JavaDoc getText() {
304             return null;
305         }
306     }
307
308     /** Object that represents a snapshot of lines at the time it was created.
309     * It is used to create a mapping from line
310     * numbers to line objects, for example when the file is saved.
311     * Such a mapping can then be used by the compiler, e.g., to find
312     * the correct {@link Line} object, assuming it has a line number.
313     * <P>
314     * Mappings of line numbers to line objects will survive modifications
315     * of the text, and continue to represent the original lines as close as possible.
316     * For example: if a new line is inserted at the 10th line of a document
317     * and the compiler module asks for the 25th line (because the compiler reports an error at line 25 in the saved file) via the line set, the 26th line
318     * of the current document will be marked as being in error.
319     */

320     public static abstract class Set extends Object JavaDoc {
321         /** date when the object has been created */
322         private Date JavaDoc date;
323
324         /** <code>Map</code> which contains all lines as keys and
325          * values weakReferences on itself. There woudl be better use
326          * set but there is missing get method, returning equal object.
327          * belonging to this <code>Line.Set</code>.
328          * @see DocumentLine#hashCode
329          * @see DocumentLine#equals
330          * @see #registerLine */

331         private Map JavaDoc<Line,Reference JavaDoc<Line>> whm;
332
333         /** Create a new snapshot. Remembers the date when it was created. */
334         public Set() {
335             date = new Date JavaDoc();
336         }
337
338         /** Returns a set of line objects sorted by their
339         * line numbers. This immutable list will contains all lines held by this
340         * line set.
341         *
342         * @return list of lines
343         */

344         public abstract List JavaDoc<? extends Line> getLines();
345
346         /** Get creation time for this line set.
347          * @return time
348         */

349         public final Date JavaDoc getDate() {
350             return date;
351         }
352
353         /** Find line object in the line set corresponding to original line number.
354          * That is, finds the line in the current document which originally had the indicated line number.
355          * If there have been modifications of that line, find one as close as possible.
356         *
357         * @param line number of the line (starting at 0)
358         * @return line object
359         * @exception IndexOutOfBoundsException if <code>line</code> is an invalid index for the original set of lines
360         */

361         public abstract Line getOriginal(int line) throws IndexOutOfBoundsException JavaDoc;
362
363         /** Find line object representing the line in current document.
364         *
365         *
366         * @param line number of the line in current state of the document (starting at 0)
367         * @return line object
368         * @exception IndexOutOfBoundsException if <code>line</code> is an invalid index for the original set of lines
369         */

370         public abstract Line getCurrent(int line) throws IndexOutOfBoundsException JavaDoc;
371
372         /** Finds an original line number for given line in this line set.
373          * @param line the line to look for
374          * @return the number (starting at 0) that best matches the line number of the line or -1
375          * if the line does seem to be produced by this line set
376          * @since 4.38
377          */

378         public int getOriginalLineNumber(Line line) {
379             return computeOriginal(this, line);
380         }
381
382         /** Lazyly creates or finds already created map for internal use.
383          */

384         Map JavaDoc<Line,Reference JavaDoc<Line>> findWeakHashMap() {
385             synchronized (date) {
386                 if (whm != null) {
387                     return whm;
388                 }
389
390                 whm = new WeakHashMap JavaDoc<Line,Reference JavaDoc<Line>>();
391
392                 return whm;
393             }
394         }
395
396         /** Registers the line to this <code>Line.Set</code>.
397          * @param line <code>Line</code> to register
398          * @return registered <code>Line</code>. <em>Note:</em> the retruned
399          * <code>Line</code> could be different (identityHashCode not equal)
400          * from the one passed in */

401         final Line registerLine(Line line) {
402             // beware of null argument
403
if (line == null) {
404                 throw new NullPointerException JavaDoc();
405             }
406
407             Map JavaDoc<Line,Reference JavaDoc<Line>> lines = findWeakHashMap();
408
409             synchronized (lines) {
410                 Reference JavaDoc<Line> r = lines.get(line);
411                 Line in = r != null ? r.get() : null;
412
413                 if (in == null) {
414                     if (line instanceof DocumentLine) {
415                         ((DocumentLine) line).init();
416                     }
417
418                     lines.put(line, new WeakReference JavaDoc<Line>(line));
419                     in = line;
420                 }
421
422                 return in;
423             }
424         }
425
426         /** Finds whether a line equal to provided is already registered.
427          * @param line the line to register
428          * @return the registered line equal to line or null
429          */

430         final Line findLine(Line line) {
431             Map JavaDoc<Line,Reference JavaDoc<Line>> lines = findWeakHashMap();
432
433             synchronized (lines) {
434                 Reference JavaDoc<Line> r = lines.get(line);
435                 Line in = r != null ? r.get() : null;
436
437                 return in;
438             }
439         }
440
441         /** A method that for a given Line.Set and a line computes the best
442          * original line number based on the querying the set. This is called
443          * in default implementation of getOriginal (Line) to provide
444          * inefficient (but better then most people would write) way to
445          * compute the number. It is static so it can be tested from
446          * tests working on DocumentLine objects that override the
447          * getOriginal (Line) method.
448          *
449          * @param set the set to search in
450          * @param line the line to look for
451          * @return closest possible line number for given line
452          */

453         static int computeOriginal(Line.Set set, Line line) {
454             int n = line.getLineNumber();
455             Line current = null;
456
457             try {
458                 current = set.getOriginal(n);
459
460                 if (line.equals(current)) {
461                     return n;
462                 }
463             } catch (IndexOutOfBoundsException JavaDoc ex) {
464                 // ok, few lines have been added and this one is now
465
// bellow the end of the document
466
}
467
468             if (current == null) {
469                 return binarySearch(set, n, 0, findMaxLine(set));
470             }
471
472             if (n < current.getLineNumber()) {
473                 return binarySearch(set, n, 0, current.getLineNumber());
474             } else {
475                 return binarySearch(set, n, current.getLineNumber(), findMaxLine(set));
476             }
477         }
478
479         /** Does a search for a given line number in a given Line.Set.
480          */

481         private static int binarySearch(Line.Set set, int number, int from, int to) {
482             while (from < to) {
483                 int middle = (from + to) / 2;
484
485                 Line l = set.getOriginal(middle);
486                 int ln = l.getLineNumber();
487
488                 if (ln == number) {
489                     return middle;
490                 }
491
492                 if (ln < number) {
493                     // try after the middle
494
from = middle + 1;
495                 } else {
496                     // try before the middle
497
to = middle - 1;
498                 }
499             }
500
501             return from;
502         }
503
504         private static int findMaxLine(Line.Set set) {
505             int from = 0;
506             int to = 32000;
507
508             // probably larger than any existing document
509
for (;;) {
510                 try {
511                     set.getOriginal(to);
512
513                     // if the line exists, double the max number, but keep
514
// for reference that it exists
515
from = to;
516                     to *= 2;
517                 } catch (IndexOutOfBoundsException JavaDoc ex) {
518                     break;
519                 }
520             }
521
522             while (from < to) {
523                 int middle = (from + to + 1) / 2;
524
525                 try {
526                     set.getOriginal(middle);
527
528                     // line exists
529
from = middle;
530                 } catch (IndexOutOfBoundsException JavaDoc ex) {
531                     // line does not exists, we have to search lower
532
to = middle - 1;
533                 }
534             }
535
536             return from;
537         }
538     }
539      // End of class Line.Set.
540
}
541
Popular Tags