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

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

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.openide.text;

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

import java.io.*;

import java.lang.ref.Reference;
import java.lang.ref.WeakReference;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;


/** 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 Serializable {
    /** generated Serialized Version UID */
    private static final long serialVersionUID = 9113186289600795476L;

    static final Logger LOG = Logger.getLogger(Line.class.getName());

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

    /** Shows the line only if the editor is open.
     * @see #show(int) show
     * @deprecated Deprecated since 6.21. Use {@link ShowOpenType#NONE}
     * and {@link ShowVisibilityType#NONE} instead.
     */
    @Deprecated
    public static final int SHOW_TRY_SHOW = 0;

    /** Opens the editor if necessary and shows the line.
     * @see #show(int) show
     * @deprecated Deprecated since 6.21. Use {@link ShowOpenType#OPEN}
     * and {@link ShowVisibilityType#NONE} instead.
     */
    @Deprecated
    public static final int SHOW_SHOW = 1;

    /** Opens the editor if necessary, shows the line, and takes the focus.
     * @see #show(int) show
     * @deprecated Deprecated since 6.21. Use {@link ShowOpenType#OPEN}
     * and {@link ShowVisibilityType#FOCUS} instead.
     */
    @Deprecated
    public static final int SHOW_GOTO = 2;

    /** Same as SHOW_GOTO except that the Window Manager attempts to front the
     * editor window (i.e. make it the top most window).
     * @see #show(int) show
     * @see org.openide.windows.TopComponent#toFront()
     * @since 5.8
     * @deprecated Deprecated since 6.21. Use {@link ShowOpenType#OPEN}
     * and {@link ShowVisibilityType#FRONT} instead.
     */
    @Deprecated
    public static final int SHOW_TOFRONT = 3;

    /** Takes the focus in case the editor is already opened and shows the line.
     * Replaces (closes) the last editor opened using SHOW_REUSE in case 
     * the user haven't interacted with it much (e.g. haven't modified it).
     * Opens a new editor in case there is no such reusable editor
     * and marks it for editor reusal. 
     * @see #show(int) show
     * @since org.openide.text 6.14
     * @deprecated Deprecated since 6.21. Use {@link ShowOpenType#REUSE}
     * and {@link ShowVisibilityType#FOCUS} instead.
     */
    @Deprecated
    public static final int SHOW_REUSE = 4;

    /** Focuses or opens given editor, marking it as reusable editor if it
     * was not opened before. Similar to {@link #SHOW_REUSE} but ignores
     * currently reusable editor.
     * @see #show(int) show
     * @since org.openide.text 6.14
     * @deprecated Deprecated since 6.21. Use {@link ShowOpenType#REUSE_NEW}
     * and {@link ShowVisibilityType#FOCUS} instead.
     */
    @Deprecated
    public static final int SHOW_REUSE_NEW = 5;

    /** ShowOpenType and ShowVisibilityType is replacement for constants SHOW_TRY_SHOW, SHOW_SHOW,
     * SHOW_GOTO, SHOW_TOFRONT, SHOW_REUSE, SHOW_REUSE_NEW. It is to provide full control
     * over show method behavior without need to add new constant for missing flag combination.
     *
     * 

Note: Any modification of editor marked for reuse resets reuse flag. There is one global static reference * so only one or none editor can be marked for reuse. * * @see #show(ShowOpenType, ShowVisibilityType) show * @see ShowVisibilityType ShowVisibilityType * @since org.openide.text 6.21 * */ public enum ShowOpenType { /** shows the line only if the editor is open */ NONE, /** opens editor if necessary (editor was not opened) and shows the line */ OPEN, /** replaces editor marked for reuse (last editor opened using {@link ShowOpenType#REUSE} * or {@link ShowOpenType#REUSE_NEW} and opens editor if necessary, if editor is being opened (editor was not opened) * marks it for reuse, shows the line */ REUSE, /** ignores editor marked for reuse (resets reference to editor marked for reuse), * opens editor if necessary, if editor is being opened (editor was not opened) * marks it for reuse, shows the line */ REUSE_NEW }; /** ShowOpenType and ShowVisibilityType is replacement for constants SHOW_TRY_SHOW, SHOW_SHOW, * SHOW_GOTO, SHOW_TOFRONT, SHOW_REUSE, SHOW_REUSE_NEW. It is to provide full control * over show method behavior without need to add new constant for missing flag combination. * * @since org.openide.text 6.21 * @see #show(ShowOpenType, ShowVisibilityType) show * @see ShowOpenType ShowOpenType */ public enum ShowVisibilityType { /** no action */ NONE, /** fronts editor component to become visible */ FRONT, /** front editor component to become visible and activates/focuses it. It does * the same as {@link ShowVisibilityType#FRONT} plus activates/focuses editor */ FOCUS }; /** Instance of null implementation of Line.Part */ private static final Line.Part nullPart = new Line.NullPart(); /** 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(); } } /** 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: *
{@code 
    *   Line.Set lineSet = 
    *   Line l = 
    *
    *   l.equals (lineSet.getCurrent (l.getLineNumber ()))
    * }
* * @return current line number (may change as text is edited) (starting at 0) */ 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 (starting at 0), * value -1 does not change previously selected column * @deprecated Deprecated since 6.21. Use {@link #show(ShowOpenType, ShowVisibilityType, int)} instead. */ @Deprecated 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}, {@link #SHOW_GOTO}, * {@link #SHOW_REUSE} or {@link #SHOW_REUSE_NEW} * @see #show(int, int) * @deprecated Deprecated since 6.21. Use {@link #show(ShowOpenType, ShowVisibilityType)} instead. */ @Deprecated public void show(int kind) { show(kind, 0); } /** Show the line. * @param openType one of {@link ShowOpenType#NONE}, {@link ShowOpenType#OPEN}, * {@link ShowOpenType#REUSE} or {@link ShowOpenType#REUSE_NEW} * @param visibilityType one of {@link ShowVisibilityType#NONE}, * {@link ShowVisibilityType#FRONT} or {@link ShowVisibilityType#FOCUS} * @param column the column of this line which should be selected (starting at 0), * value -1 does not change previously selected column * @since org.openide.text 6.21 */ public void show(ShowOpenType openType, ShowVisibilityType visibilityType, int column) { if (openType == ShowOpenType.NONE) { if (visibilityType == ShowVisibilityType.NONE) { show(SHOW_TRY_SHOW, column); } else { LOG.warning("Line.show(ShowOpenType, ShowVisibilityType, int) uses unsupported combination of parameters"); show(SHOW_TRY_SHOW, column); } } else if (openType == ShowOpenType.OPEN) { if (visibilityType == ShowVisibilityType.NONE) { show(SHOW_SHOW, column); } else if (visibilityType == ShowVisibilityType.FOCUS) { show(SHOW_GOTO, column); } else if (visibilityType == ShowVisibilityType.FRONT) { show(SHOW_TOFRONT, column); } } else if (openType == ShowOpenType.REUSE) { if (visibilityType == ShowVisibilityType.FOCUS) { show(SHOW_REUSE, column); } else { LOG.warning("Line.show(ShowOpenType, ShowVisibilityType, int) uses unsupported combination of parameters"); show(SHOW_REUSE, column); } } else if (openType == ShowOpenType.REUSE_NEW) { if (visibilityType == ShowVisibilityType.FOCUS) { show(SHOW_REUSE_NEW, column); } else { LOG.warning("Line.show(ShowOpenType, ShowVisibilityType, int) uses unsupported combination of parameters"); show(SHOW_REUSE_NEW, column); } } } /** Shows the line (at the first column). * @param openType one of {@link ShowOpenType#NONE}, {@link ShowOpenType#OPEN}, * {@link ShowOpenType#REUSE} or {@link ShowOpenType#REUSE_NEW} * @param visibilityType one of {@link ShowVisibilityType#NONE}, * {@link ShowVisibilityType#FRONT} or {@link ShowVisibilityType#FOCUS} * @see #show(ShowOpenType, ShowVisibilityType, int) * @since org.openide.text 6.21 */ public void show(ShowOpenType openType, ShowVisibilityType visibilityType) { show(openType, visibilityType, 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. */ @Deprecated 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. */ @Deprecated public abstract boolean isBreakpoint(); /** Mark an error at this line. * @deprecated Deprecated since 1.20. Use {@link Annotation#attach} instead. */ @Deprecated public abstract void markError(); /** Unmark error at this line. * @deprecated Deprecated since 1.20. Use {@link Annotation#detach} instead. */ @Deprecated public abstract void unmarkError(); /** Mark this line as current. * @deprecated Deprecated since 1.20. Use {@link Annotation#attach} instead. */ @Deprecated public abstract void markCurrentLine(); /** Unmark this line as current. * @deprecated Deprecated since 1.20. Use {@link Annotation#detach} instead. */ @Deprecated 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}. */ @Deprecated 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 (starting at 0) * @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 abstract static 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 (starting at 0) */ 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 */ private static final 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 abstract static class Set extends Object { /** date when the object has been created */ private Date date; /** * Binary-searchable vector of lines. */ private LineVector lineVector; /** 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 lines */ public abstract 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 (starting at 0) * @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 (starting at 0) * @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 (starting at 0) 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); } /** * Lazily creates or finds binary-searchable vector of registered lines. */ LineVector findLineVector() { synchronized (date) { if (lineVector != null) { return lineVector; } lineVector = new LineVector(); return lineVector; } } /** Registers the line to this Line.Set. * @param lineIndex line index * @param lineCreator Line to register * @return registered Line. Note: the retruned * Line could be different (identityHashCode not equal) * from the one passed in */ final Line findOrCreateLine(int lineIndex, LineVector.LineCreator lineCreator) { // beware of null argument if (lineCreator == null) { throw new NullPointerException(); } LineVector lineVector = findLineVector(); return lineVector.findOrCreateLine(lineIndex, lineCreator); } /** 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) { LineVector lineVector = findLineVector(); return lineVector.findOrCreateLine(line.getLineNumber(), null); } /** 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 - 2025 Weber Informatics LLC | Privacy Policy