blob: 77f9d15811d3408aea83798b8e9c0635dab0aae7 [file] [log] [blame]
/*
* 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.netbeans.editor;
import java.util.Comparator;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.Position;
import javax.swing.text.Position.Bias;
/**
* Marks hold the relative position in the document.
*
* @author Miloslav Metelka
* @version 1.00
* @deprecated Use {@link Position} instead.
*/
public class Mark {
private static final MarkComparator MARK_COMPARATOR = new MarkComparator();
/** Document to which this mark belongs. */
private BaseDocument doc;
/** Position to which this mark delegates. */
private Position pos;
/** 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 <tt>Position.Bias.Backward</tt>.
*/
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;
synchronized (ldoc) {
if (pos != 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
}
// Deal with supplementary characters #164820
if (offset <= ldoc.getLength() && Character.isLowSurrogate(org.netbeans.lib.editor.util.swing.DocumentUtilities.getText(ldoc).charAt(offset))) {
if (bias == Bias.Forward && offset < ldoc.getLength()) {
offset++;
} else if (bias == Bias.Backward && offset > 0) {
offset--;
}
// If there is still a low surrogate after recalculating,
// treat it as an invalid document, just ignore and pass through.
// Since there should be a surrogate pair in Java and Unicode to
// represent a supplementary character.
}
pos = doc.createPosition(offset, bias);
}
}
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) {
synchronized (ldoc) {
if (pos != null) {
return pos.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) {
synchronized (ldoc) {
if (pos != null) {
int offset = pos.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) {
synchronized (ldoc) {
if (pos != null) {
pos = null;
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) {
synchronized (ldoc) {
return (pos != null);
}
}
return false;
}
/** Get info about <CODE>Mark</CODE>. */
public @Override String toString() {
return "offset=" + (isValid() ? Integer.toString(pos.getOffset()) : "<invalid>") // 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());
}
}
}
}