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

com.globalmentor.swing.text.Bookmark Maven / Gradle / Ivy

The newest version!
/*
 * Copyright © 1996-2009 GlobalMentor, Inc. 
 *
 * Licensed 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 com.globalmentor.swing.text;

import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Position;

import com.globalmentor.java.Java;
import com.globalmentor.log.Log;

/**
 * Represents a bookmark in a document that can survive edits and can be stored.
 * 

* A bookmark may or may not be attached to a document. If the bookmark is attached, its offset is continually updated through edits. If a bookmark is not * attached to a document, it retains a constant offset. *

*

* A bookmark may or may not have an ending offset attached. If it has an ending offset, it will be updated as will be the starting offset. If there is no * ending offset attached, the ending offset will always reflect the beginning offset. *

* @author Garret Wilson */ public class Bookmark implements Comparable, Position { /** The optional name of the bookmark. */ private String name = null; /** * @return The name of the bookmark, or null if this bookmark has no name. */ public String getName() { return name; } /** * Sets the name of the bookmark. * @param newName The name of the bookmark, or null if there should be no name. */ public void setName(final String newName) { name = newName; } /** The offset used if the bookmark is not attached to a document. */ private int offset = 0; /** * Sets the offset of the bookmark. If the document is attached to a document, it is detached. * @param newOffset The offset of the bookmark. */ public void setOffset(final int newOffset) { detach(); //make sure the bookmark isn't attached to a document offset = newOffset; //update the offset } /** The ending offset used if the bookmark is not attached to a document. */ private int endOffset = 0; /** * Sets the ending offset of the bookmark. If the document is attached to a document, it is detached. * @param newEndOffset The ending offset of the bookmark. */ public void setEndOffset(final int newEndOffset) { detach(); //make sure the bookmark isn't attached to a document endOffset = newEndOffset; //update the ending offset } /** The position within the document the bookmark represents. */ private Position position = null; /** * @return The position within the document the bookmark represents, or null if the bookmark is not attached to a document. */ private Position getPosition() { return position; } /** * Sets the position of the bookmark in the document. * @param newPosition The new position in the document. */ private void setPosition(final Position newPosition) { position = newPosition; } /** The ending position within the document the bookmark represents. */ private Position endPosition = null; /** * @return The ending position within the document the bookmark represents, or null if the bookmark is not attached to a document. */ private Position getEndPosition() { return endPosition; } /** * Sets the ending position of the bookmark in the document. * @param newEndPosition The new ending position in the document. */ private void setEndPosition(final Position newEndPosition) { endPosition = newEndPosition; } /** * Determines whether the bookmark contains a given offset, meaning that the the offset is equal to or greater than the start offset and less than the ending * offset. For the special condition for which the bookmark has no ending offset (that is, the ending offset is equal to the beginning offset), this method * returns true if the given offset equals the beginning offset. * @param An offset in a document. * @return true if the bookmark contains the given offset, or if the bookmark has no ending position and the bookmark's beginning offset matching * the given offset. */ public boolean contains(final int offset) { return getEndOffset() != getStartOffset() ? //if there is an ending offset offset >= getStartOffset() && offset < getEndOffset() : //return whether the offset falls within the bookmark range offset == getStartOffset(); //if there is no ending offset, see if the starting offset matches the given offset } /** * Attaches the bookmark to a document at a particular location in a document. If the bookmark is already attached to a document at a different location, it * is detached and reattached to the specified location. * @param document The document to which the bookmark should be attached. * @param offset The offset in the document at which the bookmark should be attached. * @throws BadLocationException Thrown if the given position does not represent a valid location in the document. */ public void attach(final Document document, final int offset) throws BadLocationException { if(!isAttached() || (isAttached() && getOffset() != offset)) { //only reattach if we're not attached already, or we're attached but at a different offset detach(); //make sure the bookmark is not attached to a document if(document != null) //if a valid document was passed setPosition(document.createPosition(offset)); //create a position in the document and store the position } } /** * Attaches the bookmark to a document at particular starting and ending locations in a document. If the bookmark is already attached to a document at a * different location, it is detached and reattached to the specified location. * @param document The document to which the bookmark should be attached. * @param startOffset The starting offset in the document at which the bookmark should be attached. * @param endOffset The ending offset in the document at which the bookmark should be attached. * @throws BadLocationException Thrown if one of the given positions does not represent a valid location in the document. */ public void attach(final Document document, final int startOffset, final int endOffset) throws BadLocationException { if(!isAttached() || //only reattach if we're not attached already... (isAttached() && (getStartOffset() != startOffset || getEndOffset() != endOffset))) { //...or we're attached but at a different offset detach(); //make sure the bookmark is not attached to a document if(document != null) { //if a valid document was passed setPosition(document.createPosition(startOffset)); //create a position in the document and store it as the starting position setEndPosition(document.createPosition(endOffset)); //create a position in the document and store it as the ending position } } } /** * Attaches the bookmark to a document at the location at which the document was last attached. If the bookmark is already attached to a document, it is * detached and reattached to another location. * @param document The document to which the bookmark should be attached. * @throws BadLocationException Thrown if that last attached position is no longer valid. */ /*TODO del public void attach(final Document document) throws BadLocationException { attach(document, getOffset()); //attach ourselves to the document at our last recorded position } */ /** * Attaches the bookmark to a document at the location at which the document was last attached. If the bookmark had an ending offset greater than its starting * offset, that position is attached as well. If the bookmark is already attached to a document, it is detached and reattached to another location. * @param document The document to which the bookmark should be attached. * @throws BadLocationException Thrown if that last attached position is no longer valid. */ public void attach(final Document document) throws BadLocationException { if(getEndOffset() > getStartOffset()) //if we had a valid ending offset attach(document, getStartOffset(), getEndOffset()); //attach ourselves to the document at our last recorded staring and ending position else //if we only were attached at the beginning offset attach(document, getOffset()); //attach ourselves to the document at our last recorded position } /** * Detaches the bookmark from the document. After this point, the offset will reflect the last attached position in the document. If the bookmark did not have * an ending position attached, its ending offset will be set equal to theh starting offset. */ public void detach() { final Position position = getPosition(); //get the current position, if we have one if(position != null) { //if we have a position offset = position.getOffset(); //update our local offset so that it will reflect our last document position setPosition(null); //throw away any position we had final Position endPosition = getEndPosition(); //get the current ending position, if we have one (we should only ever have one when we have a starting position as well) if(endPosition != null) { //if we have an ending position endOffset = endPosition.getOffset(); //update our local ending offset so that it will reflect our last document ending position setEndPosition(null); //throw away any position we had } else { //if the end offset was not attached endOffset = offset; //make sure the ending offset is equal to the beginning offset } } } /** Default constructor that does not link the bookmark to a document. */ public Bookmark() { } /** * Constructor that links the bookmark to a position that already exists in the document. It is assumed that the position argument will be automatically * updated. If not, this class will function as if it were not attached to a document. * @param position The position in the document. */ /*TODO del if we don't need public Bookmark(final Position position) { setPosition(position); //set the position } */ /** * Constructs a bookmark attached to a document at a particular offset. * @param document The document to which the bookmark should be attached. * @param offset The offset in the document at which the bookmark should be attached. * @throws BadLocationException Thrown if the given position does not represent a valid location in the document. */ public Bookmark(final Document document, final int offset) throws BadLocationException { attach(document, offset); //attach the bookmark to the document } /** * Constructs a bookmark attached to a document at particular starting and ending offsets. * @param document The document to which the bookmark should be attached. * @param startOffset The staring offset in the document at which the bookmark should be attached. * @param endOffset The ending offset in the document at which the bookmark should be attached. * @throws BadLocationException Thrown if the given position does not represent a valid location in the document. */ public Bookmark(final Document document, final int startOffset, final int endOffset) throws BadLocationException { attach(document, startOffset, endOffset); //attach the bookmark to the document } /** * Constructs a named bookmark attached to a document at a particular offset. * @param newName The new name of the bookmark. * @param document The document to which the bookmark should be attached. * @param offset The offset in the document at which the bookmark should be attached. * @throws BadLocationException Thrown if the given position does not represent a valid location in the document. */ public Bookmark(final String newName, final Document document, final int offset) throws BadLocationException { setName(newName); //set the name of the bookmark attach(document, offset); //attach the bookmark to the document } /** * Constructs a bookmark at a particular offset, but not attached to a document. * @param offset The offset in the document at which the bookmark should be attached. */ public Bookmark(final int offset) throws BadLocationException { setOffset(offset); //set our local offset } /** * Constructs a named bookmark at a particular offset, but not attached to a document. * @param newName The new name of the bookmark. * @param offset The offset in the document at which the bookmark should be attached. */ public Bookmark(final String newName, final int offset) throws BadLocationException { setName(newName); //set the name of the bookmark setOffset(offset); //set our local offset } /** * @return The current offset (>=0) within the document. This allows this class to fulfill the requirements of the Position interface. */ public int getOffset() { final Position position = getPosition(); //get the position return position != null ? position.getOffset() : offset; //return the position's offset or, if there is no position, the last offset we know about } /** * @return The current offset (>=0) within the document. This is a convenience method equivalent to getStartOffset() to provide the converse to * getEndOffset(). * @see #getOffset */ public final int getStartOffset() { return getOffset(); //return the offset as the starting offset } /** * @return The current ending offset (>=0) within the document, which will be equal to getStartOffset() if the bookmark is attached but no ending * offset is defined. */ public int getEndOffset() { if(isAttached()) { //if the bookmark is attached final Position endPosition = getEndPosition(); //get the ending position return endPosition != null ? endPosition.getOffset() : getStartOffset(); //return the position's offset or, if there is no ending position, the starting position } else { //if the bookmark is not attached return endOffset; //return the last ending offset we know about } } /** @return Whether the bookmark is attached to a document. */ public boolean isAttached() { return getPosition() != null; } /** * If object is a Bookmark, compares the name, start, and ending offsets. Otherwise, compares the objects using the superclass * functionality. * @param object The object with which to compare this bookmark; should be a Bookmark * @return true if this bookmark equals that specified in object. * @see #getStartOffset * @see #getEndOffset * @see #getName */ public boolean equals(Object object) { Log.trace("Comparing bookmark " + this + " to object: ", object); //TODO del if(object instanceof Bookmark) { //if we're being compared with another bookmark final Bookmark otherBookmark = (Bookmark)object; //cast the other object to a bookmark if(getStartOffset() != otherBookmark.getStartOffset() //if the offsets don't match || getEndOffset() != otherBookmark.getEndOffset()) return false; if(getName() != null) //if we have a name return getName().equals(otherBookmark.getName()); //compare this name with the other else //if we don't have a name return otherBookmark.getName() == null; //see if the other bookmark also doesn't have a name } else //if we're being compared with anything else return super.equals(object); //use the default compare } /** * Compares this bookmark to another bookmark. This method determines order based upon the offset and, if two offsets are the same, the ending offsets and * then the order of the names, with no name considered lower. * @param object The object with which to compare the component. This must be another Bookmark object. * @return A negative integer, zero, or a positive integer as this bookmark is less than, equal to, or greater than the specified bookmark, respectively. If * the bookmarks represent the same beginning and ending offsets, their names are compared. * @throws ClassCastException Thrown if the specified object's type is not an Bookmark. * @see #Offset */ public int compareTo(Object object) throws ClassCastException { final Bookmark bookmark = (Bookmark)object; //cast the object to a bookmark final int offsetDifference = getOffset() - bookmark.getOffset(); //get the difference in offsets if(offsetDifference != 0) //if the offsets aren't the same return offsetDifference; //return the difference in offsets else { //if the offsets are the same, compare the ending offsets final int endOffsetDifference = getEndOffset() - bookmark.getEndOffset(); //get the difference in ending offsets if(endOffsetDifference != 0) //if the ending offsets aren't the same return endOffsetDifference; //return the difference in ending offsets else { //if the ending offsets are the same, compare the names return Java.compareTo(getName(), bookmark.getName()); //compare the names /*TODO del if(getName()!=null && bookmark.getName()!=null) //if both bookmarks have names return getName().compareTo(bookmark.getName()); //compare the names else if(getName()==bookmark.getName()) //if neither bookmark has a name (we know at this point that one does not have a name, so if the names are equal then neither name exists) return 0; //the bookmarks are equal (but not necessarily identical) else //if one bookmark has a name and the other doesn't return getName()==null ? -1 : 1; //the missing name is lower */ } } } /** @return A string representation of the bookmark. */ /*TODO fix or del public String toString() { } */ }