alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 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 javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Position;

/**
* Support class for chain of MarkBlocks
*
* @author Miloslav Metelka
* @version 1.00
*/

public class MarkChain {

    /** Chain of all marks */
    protected MarkFactory.ChainDrawMark chain;

    /** Current mark to make checks faster */
    protected MarkFactory.ChainDrawMark curMark;

    /** Document for this mark */
    protected BaseDocument doc;

    /** If this chain uses draw marks, then this is the name for the draw layer
    * that will be used for the marks
    */
    protected String layerName;

    /** The mark created by addMark() method is stored in this variable. In case
     * the mark was not created, because there already was some on this position,
     * the already existing mark is returned. */
    private MarkFactory.ChainDrawMark recentlyAddedMark;
    
    /** Construct chain using draw marks */
    public MarkChain(BaseDocument doc, String layerName) {
        this.doc = doc;
        this.layerName = layerName;
    }

    public final MarkFactory.ChainDrawMark getChain() {
        return chain;
    }

    public final MarkFactory.ChainDrawMark getCurMark() {
        return curMark;
    }

    /** Tests whether the position range is partly or fully inside
    * some mark block from the chain.
    * @param pos compared position
    * @return relation of curMark to the given position
    */
    public int compareMark(int pos) {
        try {
            if (curMark == null) {
                curMark = chain;
                if (curMark == null) {
                    return -1; // no marks yet
                }
            }

            int rel;
            boolean after = false;
            boolean before = false;
            while ((rel = curMark.compare(pos)) != 0) { // just match
                if (rel > 0) { // this mark after pos
                    if (before) {
                        return rel;
                    }
                    if (curMark.prev != null) {
                        after = true;
                        curMark = curMark.prev;
                    } else { // end of chain
                        return rel;
                    }
                } else { // this mark before pos
                    if (after) {
                        return rel;
                    }
                    if (curMark.next != null) {
                        before = true;
                        curMark = curMark.next;
                    } else { // start of chain
                        return rel;
                    }
                }
            }
            return 0; // match
        } catch (InvalidMarkException e) {
            Utilities.annotateLoggable(e);
            return -1; // don't match, but what to return?
        }
    }

    protected MarkFactory.ChainDrawMark createAndInsertNewMark(int pos)
    throws BadLocationException {
        MarkFactory.ChainDrawMark mark = createMark();
        try {
            mark.insert(doc, pos);
        } catch (InvalidMarkException e) {
            Utilities.annotateLoggable(e);
        }
        return mark;
    }

    protected MarkFactory.ChainDrawMark createMark() {
        MarkFactory.ChainDrawMark mark = new MarkFactory.ChainDrawMark(layerName, null, Position.Bias.Backward);
        mark.activateLayer = true;
        return mark;
    }

    public boolean addMark(int pos) throws BadLocationException {
        return addMark(pos, false);
    }

    /** Add mark to the chain
     * @param pos position at which the mark should be added
     * @param forceAdd force adding of a fresh mark
     *  even if the mark at the same position already exists
     * @return true if the mark was added
     *         false if there's already mark at that pos
     */
    public boolean addMark(int pos, boolean forceAdd) throws BadLocationException {
        int rel = compareMark(pos);
        if (rel == 0) {
            if (forceAdd) { // create fresh
                MarkFactory.ChainDrawMark mark = createAndInsertNewMark(pos);
                recentlyAddedMark = mark;
                if (curMark == chain) { // curMark is first mark
                    chain = curMark.insertChain(mark);
                } else { // curMark is not first mark
                    curMark.insertChain(mark);
                }
                
            } else { // return existing
                recentlyAddedMark = curMark;
                return false; // already exists
            }

        } else if (rel > 0) { // curMark after pos
            MarkFactory.ChainDrawMark mark = createAndInsertNewMark(pos);
            recentlyAddedMark = mark;
            if (curMark != null) {
                if (curMark == chain) { // curMark is first mark
                    chain = curMark.insertChain(mark);
                } else { // curMark is not first mark
                    curMark.insertChain(mark);
                }
            } else { // no marks in chain
                chain = mark;
            }
        } else { // curMark before pos
            MarkFactory.ChainDrawMark mark = createAndInsertNewMark(pos);
            recentlyAddedMark = mark;
            if (curMark != null) {
                if (curMark.next != null) {
                    curMark.next.insertChain(mark);
                } else { // last mark in chain
                    curMark.setNextChain(mark);
                }
            } else { // no marks in chain
                chain = mark;
            }
        }
        return true;
    }

    /** The mark created by addMark() method is returned by this method. In case
     * the mark was not created, because there already was some on requested position,
     * the already existing mark is returned. */
    public MarkFactory.ChainDrawMark getAddedMark() {
        return recentlyAddedMark;
    }
    
    /** Remove non-empty block from area covered by blocks from chain */
    public boolean removeMark(int pos) {
        int rel = compareMark(pos);
        if (rel == 0) {
            boolean first = (curMark == chain);
            curMark = curMark.removeChain();
            if (first) {
                chain = curMark;
            }
            return true;
        } else { // not found
            return false;
        }
    }
    
    public boolean removeMark(MarkFactory.ChainDrawMark mark) {
        if (mark == null) {
            throw new NullPointerException();
        }
        
        if (curMark != mark) {
            // dumb impl
            curMark = chain;
            while (curMark != null) {
                if (curMark == mark) {
                    break;
                }
                curMark = curMark.next;
            }
        }
        
        if (curMark != null) {
            boolean first = (curMark == chain);
            curMark = curMark.removeChain();
            if (first) {
                chain = curMark;
            }
            return true;
        } else {
            return false;
        }
    }

    /** Is there mark at given position? */
    public boolean isMark(int pos) {
        return (compareMark(pos) == 0);
    }

    /** Toggle the mark so that if it didn't exist it is created
    * and if it existed it's removed
    * @return true if the new mark was added
    *         false if the existing mark was removed
    */
    public boolean toggleMark(int pos) throws BadLocationException {
        int rel = compareMark(pos);
        if (rel == 0) { // exists
            removeMark(pos);
            return false;
        } else { // didn't exist
            addMark(pos);
            return true;
        }
    }


    public String toString() {
        return "MarkChain: curMark=" + curMark + ", mark chain: " // NOI18N
               + (chain != null ? ("\n" + chain.toStringChain()) : "Empty"); // NOI18N
    }

}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.