All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openide.text.Line Maven / Gradle / Ivy

Go to download

The NetBeans Platform is a generic base for desktop applications. It provides the services common to almost all large desktop applications: window management, menus, settings and storage, an update manager, and file access. Get a head start by reusing these standard components, allowing you to concentrate fully on your application's business logic.

The newest version!
/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.openide.text;

import java.io.*;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.Date;
import java.util.WeakHashMap;
import org.openide.util.Lookup;

import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;

/** Represents one line in a text document.
 * The line number may change
* when the text is modified, but the identity of the line is retained. It is designed to allow line-dependent
* modules of the IDE (such as the compiler and debugger) to make use of a line consistently even as the text is modified.
*
* @author Ales Novak, Petr Hamernik, Jan Jancura, Jaroslav Tulach, David Konecny
*/
public abstract class Line extends Annotatable implements java.io.Serializable {
    /** generated Serialized Version UID */
    static final long serialVersionUID = 9113186289600795476L;

    /** Property name of the line number */
    public static final String PROP_LINE_NUMBER = "lineNumber"; // NOI18N

    /** context of this line */
    private org.openide.util.Lookup dataObject;

    /** Create a new line object based on a given data object.
     * This implementation is abstract, so the specific line number is not used here.
     * Subclasses should somehow specify the position.
     * 

* The context argument shall contain information about the * producer of the Line, that can be then extracted by {@link Line#getLookup} call. * * @param context the context for this line */ public Line(Lookup context) { if (context == null) throw new NullPointerException(); dataObject = context; } /** * Create a new line object based on a given data object. * This implementation is abstract, so the specific line number is not used here. Subclasses should somehow specify the position. * @param source the object that is producing the Line */ public Line(Object source) { this(source instanceof Lookup ? (Lookup)source : Lookups.singleton(source)); if (source == null) throw new NullPointerException(); } /** Shows the line only if the editor is open. * @see #show(int) show */ public final static int SHOW_TRY_SHOW = 0; /** Opens the editor if necessary and shows the line. * @see #show(int) show */ public final static int SHOW_SHOW = 1; /** Opens the editor if necessary, shows the line, and takes the focus. * @see #show(int) show */ public final static int SHOW_GOTO = 2; /** Instance of null implementation of Line.Part */ static final private Line.Part nullPart = new Line.NullPart(); /** Composes a human presentable name for the line. The default * implementation uses the name of data object and the line number * to create the display name. * * @return human presentable name that should identify the line */ public String getDisplayName () { return getClass().getName() + ":" + getLineNumber(); // NOI18N } /** Provides access to the context passed into the line constructor. * For example lines produced by DataEditorSupport * provide DataObject as the content of the lookup. * One can use: *

     *   dataObjectOrNull = (DataObject)line.getLookup ().lookup (DataObject.class);
     * 
* to get the access. * * @return context associated with the line * @since 4.3 */ public final org.openide.util.Lookup getLookup () { return dataObject; } /** Get the line number. The last condition in following should * always be true: *
    *   Line.Set lineSet = 
    *   Line l = 
    *   
    *   l.equals (lineSet.getCurrent (l.getLineNumber ())) 
    * 
* * @return current line number (may change as text is edited) */ public abstract int getLineNumber (); /** Show the line. * @param kind one of {@link #SHOW_TRY_SHOW}, {@link #SHOW_SHOW}, or {@link #SHOW_GOTO} * @param column the column of this line which should be selected */ public abstract void show(int kind, int column); /** Shows the line (at the first column). * @param kind one of {@link #SHOW_TRY_SHOW}, {@link #SHOW_SHOW}, or {@link #SHOW_GOTO} * @see #show(int, int) */ public void show(int kind) { show(kind, 0); } /** Set or clear a (debugger) breakpoint at this line. * @param b true to turn on * @deprecated Deprecated since 1.20. Use {@link Annotation#attach} instead. */ public abstract void setBreakpoint(boolean b); /** Test if there is a breakpoint set at this line. * @return true is there is * @deprecated Deprecated since 1.20. Use {@link Annotation} instead. */ public abstract boolean isBreakpoint(); /** Mark an error at this line. * @deprecated Deprecated since 1.20. Use {@link Annotation#attach} instead. */ public abstract void markError(); /** Unmark error at this line. * @deprecated Deprecated since 1.20. Use {@link Annotation#detach} instead. */ public abstract void unmarkError(); /** Mark this line as current. * @deprecated Deprecated since 1.20. Use {@link Annotation#attach} instead. */ public abstract void markCurrentLine(); /** Unmark this line as current. * @deprecated Deprecated since 1.20. Use {@link Annotation#detach} instead. */ public abstract void unmarkCurrentLine(); /** Method that should allow the debugger to communicate with lines that * wants to have a control over the current line of debugger. It allows the * line to refuse the current status and force the debugger to continue * over this line. *

* The default implementation simply returns true. * * @param action type of action that is trying to mark this line as current * one of constants (Debugger.ACTION_BREAKPOINT_HIT, * Debugger.ACTION_TRACE_OVER, etc.) * @param previousLine previous line (if any) or null * * @return true if this line accepts the "current" state or false if the * line wants the debugger to proceed with next instruction * * @deprecated Deprecated since 1.20, as {@link #markCurrentLine} is deprecated by {@link Annotation#attach}. */ public boolean canBeMarkedCurrent (int action, Line previousLine) { return true; } /** Create object which represent part of the text on the line. This part * of the line can be used for attaching of annotations. * @param column starting column of the part of the text * @param length length of the part of the text * @return instance of the Line.Part which represent the part of the text * @since 1.20 */ public Line.Part createPart( int column, int length ) { return nullPart; } public String getText() { return null; } /** Representation of the part of the Line's text. The part of the text is defined by * the starting column, length of the part and reference to Line. The length of the * part never cross the end of the line. * @since 1.20 */ public static abstract class Part extends Annotatable { /** Property name for the line attribute */ public static final String PROP_LINE = "line"; // NOI18N /** Property name for the column attribute */ public static final String PROP_COLUMN = "column"; // NOI18N /** Property name for the length attribute */ public static final String PROP_LENGTH = "length"; // NOI18N /** Start column of annotation * @return column at which this part begining */ public abstract int getColumn(); /** Length of the annotated text. The length does not cross line end. If the annotated text is * split during the editing, the annotation is shorten till the end of the line. Modules can listen on * changes of this value * @return length of the part */ public abstract int getLength(); /** Line can change during editting * @return reference to the Line to which this part belongs */ public abstract Line getLine(); } /** Implementation of Line.Part which is presenting empty part */ static final private class NullPart extends Part { NullPart() {} public int getColumn() { return 0; } public int getLength() { return 0; } public Line getLine() { return null; } public String getText() { return null; } } /** Object that represents a snapshot of lines at the time it was created. * It is used to create a mapping from line * numbers to line objects, for example when the file is saved. * Such a mapping can then be used by the compiler, e.g., to find * the correct {@link Line} object, assuming it has a line number. *

* Mappings of line numbers to line objects will survive modifications * of the text, and continue to represent the original lines as close as possible. * For example: if a new line is inserted at the 10th line of a document * 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 * of the current document will be marked as being in error. */ public static abstract class Set extends Object { /** date when the object has been created */ private Date date; /** Map which contains all lines as keys and * values weakReferences on itself. There woudl be better use * set but there is missing get method, returning equal object. * belonging to this Line.Set. * @see DocumentLine#hashCode * @see DocumentLine#equals * @see #registerLine */ private WeakHashMap whm; /** Create a new snapshot. Remembers the date when it was created. */ public Set () { date = new Date (); } /** Returns a set of line objects sorted by their * line numbers. This immutable list will contains all lines held by this * line set. * * @return list of element type {@link Line} */ public abstract java.util.List getLines (); /** Get creation time for this line set. * @return time */ public final Date getDate() { return date; } /** Find line object in the line set corresponding to original line number. * That is, finds the line in the current document which originally had the indicated line number. * If there have been modifications of that line, find one as close as possible. * * @param line number of the line * @return line object * @exception IndexOutOfBoundsException if line is an invalid index for the original set of lines */ public abstract Line getOriginal (int line) throws IndexOutOfBoundsException; /** Find line object representing the line in current document. * * * @param line number of the line in current state of the document * @return line object * @exception IndexOutOfBoundsException if line is an invalid index for the original set of lines */ public abstract Line getCurrent (int line) throws IndexOutOfBoundsException; /** Finds an original line number for given line in this line set. * @param line the line to look for * @return the number that best matches the line number of the line or -1 * if the line does seem to be produced by this line set * @since 4.38 */ public int getOriginalLineNumber (Line line) { return computeOriginal (this, line); } /** Lazyly creates or finds already created map for internal use. */ WeakHashMap findWeakHashMap () { synchronized (date) { if (whm != null) return whm; whm = new WeakHashMap (); return whm; } } /** Registers the line to this Line.Set. * @param line Line to register * @return registered Line. Note: the retruned * Line could be different (identityHashCode not equal) * from the one passed in */ final Line registerLine(Line line) { // beware of null argument if (line == null) throw new NullPointerException(); WeakHashMap lines = findWeakHashMap (); synchronized(lines) { Reference r = (Reference)lines.get(line); Line in = (r != null ? (Line)r.get() : null); if(in == null) { if(line instanceof DocumentLine) { ((DocumentLine)line).init(); } lines.put(line, new WeakReference(line)); in = line; } return in; } } /** Finds whether a line equal to provided is already registered. * @param line the line to register * @return the registered line equal to line or null */ final Line findLine (Line line) { WeakHashMap lines = findWeakHashMap (); synchronized (lines) { Reference r = (Reference)lines.get(line); Line in = (r != null ? (Line)r.get() : null); return in; } } /** A method that for a given Line.Set and a line computes the best * original line number based on the querying the set. This is called * in default implementation of getOriginal (Line) to provide * inefficient (but better then most people would write) way to * compute the number. It is static so it can be tested from * tests working on DocumentLine objects that override the * getOriginal (Line) method. * * @param set the set to search in * @param line the line to look for * @return closest possible line number for given line */ static int computeOriginal (Line.Set set, Line line) { int n = line.getLineNumber (); Line current = null; try { current = set.getOriginal (n); if (line.equals (current)) { return n; } } catch (IndexOutOfBoundsException ex) { // ok, few lines have been added and this one is now // bellow the end of the document } if (current == null) { return binarySearch (set, n, 0, findMaxLine (set)); } if (n < current.getLineNumber ()) { return binarySearch (set, n, 0, current.getLineNumber ()); } else { return binarySearch (set, n, current.getLineNumber (), findMaxLine (set)); } } /** Does a search for a given line number in a given Line.Set. */ private static int binarySearch (Line.Set set, int number, int from, int to) { while (from < to) { int middle = (from + to) / 2; Line l = set.getOriginal (middle); int ln = l.getLineNumber (); if (ln == number) { return middle; } if (ln < number) { // try after the middle from = middle + 1; } else { // try before the middle to = middle - 1; } } return from; } private static int findMaxLine (Line.Set set) { int from = 0; int to = 32000; // probably larger than any existing document for (;;) { try { set.getOriginal (to); // if the line exists, double the max number, but keep // for reference that it exists from = to; to *= 2; } catch (IndexOutOfBoundsException ex) { break; } } while (from < to) { int middle = (from + to + 1) / 2; try { set.getOriginal (middle); // line exists from = middle; } catch (IndexOutOfBoundsException ex) { // line does not exists, we have to search lower to = middle - 1; } } return from; } } // End of class Line.Set. }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy