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

org.netbeans.editor.Mark Maven / Gradle / Ivy

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

package org.netbeans.editor;

import java.util.Comparator;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.Position;

/**
* Marks hold the relative position in the document.
*
* @author Miloslav Metelka
* @version 1.00
*/


/** Class defining basic type of mark. This is a mark used most frequently.
* It's instances are inserted into the leaf plane of the tree.
*/
public class Mark {
    
    private static final MarkComparator MARK_COMPARATOR = new MarkComparator();

    /** Document to which this mark belongs. */
    private BaseDocument doc;
    
    /** MultiMark to which this mark delegates. */
    private MultiMark multiMark;
    
    /** Bias of the mark. It is either
     * {@link javax.swing.text.Position.Bias.Forward}
     * or {@link javax.swing.text.Position.Bias.Backward}
     */
    private Position.Bias bias;
    
    /** Construct new mark with forward bias. */
    public Mark() {
        this(Position.Bias.Forward);
    }

    public Mark(Position.Bias bias) {
        this.bias = bias;
    }
    
    /** Construct new mark.
    * @param backwardBias whether the inserts performed right at the position
    *   of this mark will go after this mark i.e. this mark will not move
    *   forward when inserting right at its position. This flag corresponds
    *   to Position.Bias.Backward.
    */
    public Mark(boolean backwardBias) {
        this(backwardBias ? Position.Bias.Backward : Position.Bias.Forward);
    }
    
    void insert(BaseDocument doc, int offset) throws InvalidMarkException, BadLocationException {
        BaseDocument ldoc = this.doc;
        if (ldoc != null) {
            throw new InvalidMarkException("Mark already inserted: mark=" + this // NOI18N
                + ", class=" + this.getClass()); // NOI18N
        }

        this.doc = doc;
        ldoc = this.doc;
        Map docMarks = ldoc.marks;
        synchronized (docMarks) {
            if (multiMark != null) {
                throw new IllegalStateException("Mark already inserted: mark=" + this // NOI18N
                + ", class=" + this.getClass()); // NOI18N
            }

            if (offset < 0 || offset > ldoc.getLength() + 1) { // doc.getEndPosition() is valid
                throw new BadLocationException("Invalid offset", offset); // NOI18N
            }

            multiMark = doc.marksStorage.createBiasMark(offset, bias);
            doc.marksStorage.insert(multiMark);
            docMarks.put(multiMark, this);
//            checkMarks(docMarks);
        }
    }
    
    private void checkMarks(Map docMarks) {
        for (Iterator it = docMarks.entrySet().iterator(); it.hasNext();) {
            Map.Entry me = (Map.Entry)it.next();
            MultiMark mm = (MultiMark)me.getKey();
            Mark m = (Mark)me.getValue();
            
            if (m.multiMark != mm) {
                throw new IllegalStateException("m.class" + m.getClass() + " mapped to wrong mark=" + mm); // NOI18N
            }
        }            
    }
    
    void move(BaseDocument doc, int newOffset) throws InvalidMarkException, BadLocationException {
        dispose();
        insert(doc, newOffset);
    }
    
    /** Get the position of this mark */
    public final int getOffset() throws InvalidMarkException {
        BaseDocument ldoc = doc;
        if (ldoc != null) {
            Map docMarks = ldoc.marks;
            synchronized (docMarks) {
                if (multiMark != null) {
                    return multiMark.getOffset();
                } else {
                    throw new InvalidMarkException();
                }
            }
        } else {
            throw new InvalidMarkException();
        }
    }

    /** Get the line number of this mark */
    public final int getLine() throws InvalidMarkException {
        BaseDocument ldoc = doc;
        if (ldoc != null) {
            Map docMarks = ldoc.marks;
            synchronized (docMarks) {
                if (multiMark != null) {
                    int offset = multiMark.getOffset();
                    Element lineRoot = ldoc.getParagraphElement(0).getParentElement();
                    return lineRoot.getElementIndex(offset);

                } else {
                    throw new InvalidMarkException();
                }
            }
        } else {
            throw new InvalidMarkException();
        }
    }

    /** Get the insertAfter flag.
     * Replaced by {@link #getBackwardBias()}
     * @deprecated
     */
    public final boolean getInsertAfter() {
        return (bias == Position.Bias.Backward);
    }
    
    /** @return true if the mark has backward bias or false if it has forward bias.
     */
    public final boolean getBackwardBias() {
        return getInsertAfter();
    }
    
    /** @return the bias of this mark. It will be either
     * {@link javax.swing.text.Position.Bias.Forward}
     * or {@link javax.swing.text.Position.Bias.Backward}.
     */
    public final Position.Bias getBias() {
        return bias;
    }
    
    int getBiasAsInt() {
        return (bias == Position.Bias.Backward) ? -1 : +1;
    }
    
    /** Mark will no longer represent a valid place in the document.
     * Although it will not be removed from the structure that holds
     * the marks it will be done later automatically.
     */
    public final void dispose() {
        BaseDocument ldoc = doc;
        if (ldoc != null) {
            Map docMarks = ldoc.marks;
            synchronized (docMarks) {
                if (multiMark != null) {
                    if (docMarks.remove(multiMark) != this) {
                        throw new IllegalStateException("Mark cannot be disposed mark=" + this + ", class=" + getClass()); // NOI18N
                    }

                    multiMark.dispose();
                    multiMark = null;

//                    checkMarks(docMarks);

                    this.doc = null;
                    
                    return;
                }
            }
        }

        throw new IllegalStateException("Mark already disposed: mark=" + this // NOI18N
                + ", class=" + this.getClass()); // NOI18N
    }
        
    /** Remove mark from the structure holding the marks. The mark can
    * be inserted again into some document.
    */
    public final void remove() throws InvalidMarkException {
        dispose();
    }


    /** Compare this mark to some position.
     * @param pos tested position
     * @return zero - if the marks have the same position
     *         less than zero - if this mark is before the position
     *         greater than zero - if this mark is after the position
     */
    public final int compare(int pos) throws InvalidMarkException {
        return getOffset() - pos;
    }

    /** This function is called from removeUpdater when mark occupies
     * the removal area. The mark can decide what to do next.
     * If it doesn't redefine this method it will be simply moved to
     * the begining of removal area. It is valid to add or remove other mark 
     * from this method. It is even possible (but not very useful)
     * to add the mark to the removal area. However that mark will not be
     * notified about current removal.
     * @deprecated It will not be supported in the future.
     */
    protected void removeUpdateAction(int pos, int len) {
    }


    /** @return true if this mark is currently inserted in the document
     * or false otherwise.
     */
    public final boolean isValid() {
        BaseDocument ldoc = doc;
        if (ldoc != null) {
            Map docMarks = ldoc.marks;
            synchronized (docMarks) {
                return (multiMark != null && multiMark.isValid());
            }
        }
        
        return false;
    }

    /** Get info about Mark. */
    public String toString() {
        return "offset=" + (isValid() ? Integer.toString(multiMark.getOffset()) : "") // NOI18N
               + ", bias=" + bias; // NOI18N
    }

    private static final class MarkComparator implements Comparator {
        
        public int compare(Object o1, Object o2) {
            Mark m1 = ((Mark)o1);
            Mark m2 = ((Mark)o2);
            try {
                int offDiff = m1.getOffset() - m2.getOffset();
                if (offDiff != 0) {
                    return offDiff;
                } else {
                    return m1.getBiasAsInt() - m2.getBiasAsInt();
                }
            } catch (InvalidMarkException e) {
                throw new IllegalStateException(e.toString());
            }
        }

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy