use of gate.Annotation in project gate-core by GateNLP.
the class AnnotationSetImpl method edit.
// addToStartOffsetIndex(a)
/**
* Propagate document content changes to this AnnotationSet.
*
* This method is called for all annotation sets of a document from
* DocumentImpl.edit to adapt the annotations to the text changes made through
* the edit. The behaviour of this method is influenced by the configuration
* setting {@link gate.GateConstants#DOCEDIT_INSERT_PREPEND GateConstants.DOCEDIT_INSERT_PREPEND }:
* annotations immediately
* ending before or starting after the point of insertion will either become
* part of the inserted text or not. Currently it works like this:
* <ul>
* <li>PREPEND=true: annotation before will become part, annotation after not
* <li>PREPEND=false: annotation before will not become part, annotation after
* will become part
* </UL>
* NOTE 1 (JP): There is another setting
* {@link gate.GateConstants#DOCEDIT_INSERT_APPEND GateConstants.DOCEDIT_INSERT_APPEND }
* but
* this setting does currently not influence the behaviour of this method.
* The behaviour of this method may change in the future so that
* DOCEDIT_INSERT_APPEND is considered separately and in addition to
* DOCEDIT_INSERT_PREPEND so that it can be controlled independently if
* the annotation before and/or after an insertion point gets expanded or not.
* <p>
* NOTE 2: This method has, unfortunately, to be
* public, to allow DocumentImpls to get at it. Oh for a "friend" declaration.
* Doesn't throw InvalidOffsetException as DocumentImpl is the only client,
* and that checks the offsets before calling this method.
*/
public void edit(Long start, Long end, DocumentContent replacement) {
// make sure we have the indices computed
indexByStartOffset();
if (end.compareTo(start) > 0) {
// get the nodes that need to be processed (the nodes internal to
// the
// removed section plus the marginal ones
List<Node> affectedNodes = new ArrayList<Node>(nodesByOffset.subMap(start, end.longValue() + 1).values());
// if we have more than 1 node we need to delete all apart from
// the first
// and move the annotations so that they refer to the one we keep
// (the
// first)
NodeImpl firstNode = null;
if (!affectedNodes.isEmpty()) {
firstNode = (NodeImpl) affectedNodes.get(0);
List<Annotation> startingAnnotations = new ArrayList<Annotation>();
List<Annotation> endingAnnotations = new ArrayList<Annotation>();
// now we need to find all the annotations
// ending in the zone
List<Node> beforeNodes = new ArrayList<Node>(nodesByOffset.subMap(0L, end.longValue() + 1).values());
Iterator<Node> beforeNodesIter = beforeNodes.iterator();
while (beforeNodesIter.hasNext()) {
Node currentNode = beforeNodesIter.next();
Collection<Annotation> annotations = getAnnotsByStartNode(currentNode.getId());
if (annotations == null)
continue;
// iterates on the annotations in this set
Iterator<Annotation> localIterator = annotations.iterator();
while (localIterator.hasNext()) {
Annotation annotation = localIterator.next();
long offsetEndAnnotation = annotation.getEndNode().getOffset().longValue();
// inside the zone
if (offsetEndAnnotation >= start.longValue() && offsetEndAnnotation <= end.longValue())
endingAnnotations.add(annotation);
}
}
for (int i = 1; i < affectedNodes.size(); i++) {
Node aNode = affectedNodes.get(i);
Collection<Annotation> annSet = getAnnotsByStartNode(aNode.getId());
if (annSet != null) {
startingAnnotations.addAll(annSet);
}
// remove the node
// nodesByOffset.remove(aNode.getOffset());
// annotsByStartNode.remove(aNode);
}
// modify the annotations so they point to the saved node
Iterator<Annotation> annIter = startingAnnotations.iterator();
while (annIter.hasNext()) {
AnnotationImpl anAnnot = (AnnotationImpl) annIter.next();
anAnnot.start = firstNode;
// zero-length
if (anAnnot.start == anAnnot.end) {
remove(anAnnot);
} else {
addToStartOffsetIndex(anAnnot);
}
}
annIter = endingAnnotations.iterator();
while (annIter.hasNext()) {
AnnotationImpl anAnnot = (AnnotationImpl) annIter.next();
anAnnot.end = firstNode;
// zero-length
if (anAnnot.start == anAnnot.end) {
remove(anAnnot);
}
}
// remove the unused nodes inside the area
for (int i = 1; i < affectedNodes.size(); i++) {
Node aNode = affectedNodes.get(i);
nodesByOffset.remove(aNode.getOffset());
annotsByStartNode.remove(aNode.getId());
}
// repair the first node
// remove from offset index
nodesByOffset.remove(firstNode.getOffset());
// change the offset for the saved node
firstNode.setOffset(start);
// add back to the offset index
nodesByOffset.put(firstNode.getOffset(), firstNode);
}
}
// now handle the insert and/or update the rest of the nodes'
// position
// get the user selected behaviour (defaults to append)
boolean shouldPrepend = Gate.getUserConfig().getBoolean(GateConstants.DOCEDIT_INSERT_PREPEND).booleanValue();
long s = start.longValue(), e = end.longValue();
// length of the replacement value
long rlen = ((replacement == null) ? 0 : replacement.size().longValue());
// update the offsets and the index by offset for the rest of the
// nodes
List<Node> nodesAfterReplacement = new ArrayList<Node>(nodesByOffset.tailMap(start).values());
// remove from the index by offset
Iterator<Node> nodesAfterReplacementIter = nodesAfterReplacement.iterator();
while (nodesAfterReplacementIter.hasNext()) {
NodeImpl n = (NodeImpl) nodesAfterReplacementIter.next();
nodesByOffset.remove(n.getOffset());
}
// change the offsets
nodesAfterReplacementIter = nodesAfterReplacement.iterator();
while (nodesAfterReplacementIter.hasNext()) {
NodeImpl n = (NodeImpl) nodesAfterReplacementIter.next();
long oldOffset = n.getOffset().longValue();
// by default we move all nodes back
long newOffset = oldOffset - (e - s) + rlen;
// for the first node we need behave differently
if (oldOffset == s) {
// the first offset never moves back
if (newOffset < s)
newOffset = s;
// if we're prepending we don't move forward
if (shouldPrepend)
newOffset = s;
}
n.setOffset(newOffset);
}
// add back to the index by offset with the new offsets
nodesAfterReplacementIter = nodesAfterReplacement.iterator();
while (nodesAfterReplacementIter.hasNext()) {
NodeImpl n = (NodeImpl) nodesAfterReplacementIter.next();
nodesByOffset.put(n.getOffset(), n);
}
// //rebuild the indices with the new offsets
// nodesByOffset = null;
// annotsByStartNode = null;
// annotsByEndNode = null;
// indexByStartOffset();
// indexByEndOffset();
}
use of gate.Annotation in project gate-core by GateNLP.
the class AnnotationSetImpl method get.
// get(type, featureNames)
/**
* Select annotations by offset. This returns the set of annotations whose
* start node is the least such that it is less than or equal to offset. If a
* positional index doesn't exist it is created. If there are no nodes at or
* beyond the offset param then it will return an empty annotationset.
*/
@Override
public AnnotationSet get(Long offset) {
if (annotsByStartNode == null)
indexByStartOffset();
// find the next node at or after offset; get the annots starting
// there
Node nextNode = nodesByOffset.getNextOf(offset);
if (// no nodes at or beyond this offset
nextNode == null)
return emptyAS();
Collection<Annotation> annotationsToAdd = getAnnotsByStartNode(nextNode.getId());
// skip all the nodes that have no starting annotations
while (annotationsToAdd == null) {
nextNode = nodesByOffset.getNextOf(nextNode.getOffset().longValue() + 1);
if (nextNode == null)
return emptyAS();
annotationsToAdd = getAnnotsByStartNode(nextNode.getId());
}
return new ImmutableAnnotationSetImpl(doc, annotationsToAdd);
}
use of gate.Annotation in project gate-core by GateNLP.
the class AnnotationSetImpl method getCovering.
// get(type, startOfset, endOffset)
/**
* Select annotations of the given type that completely span the range.
* Formally, for any annotation a, a will be included in the return
* set if:
* <ul>
* <li>a.getStartNode().getOffset() <= startOffset</li>
* <li>and</li>
* <li>a.getEndNode().getOffset() >= endOffset</li>
*
* @param neededType Type of annotation to return. If empty, all
* annotation types will be returned.
* @return annotations of the given type that completely span the range.
*/
@Override
public AnnotationSet getCovering(String neededType, Long startOffset, Long endOffset) {
// check the range
if (endOffset < startOffset)
return emptyAS();
// ensure index
if (annotsByStartNode == null)
indexByStartOffset();
// so we return an empty set.
if (endOffset - startOffset > longestAnnot)
return emptyAS();
List<Annotation> annotationsToAdd = new ArrayList<Annotation>();
Iterator<Node> nodesIter;
Iterator<Annotation> annotsIter;
Node currentNode;
Annotation currentAnnot;
boolean checkType = StringUtils.isNotBlank(neededType);
// find all the annots with startNode <= startOffset. Need the + 1 because
// headMap returns strictly less than.
// the length of the longest annot from the endOffset since we know that nothing
// that starts earlier will be long enough to cover the entire span.
Long searchStart = ((endOffset - 1) - longestAnnot);
if (searchStart < 0)
searchStart = 0l;
// nodesIter = nodesByOffset.headMap(startOffset + 1).values().iterator();
nodesIter = nodesByOffset.subMap(searchStart, startOffset + 1).values().iterator();
while (nodesIter.hasNext()) {
currentNode = nodesIter.next();
Collection<Annotation> objFromPoint = getAnnotsByStartNode(currentNode.getId());
if (objFromPoint == null)
continue;
annotsIter = objFromPoint.iterator();
while (annotsIter.hasNext()) {
currentAnnot = annotsIter.next();
// if neededType is set, make sure this is the right type
if (checkType && !currentAnnot.getType().equals(neededType))
continue;
// check that the annot ends at or after the endOffset
if (currentAnnot.getEndNode().getOffset().compareTo(endOffset) >= 0)
annotationsToAdd.add(currentAnnot);
}
// while
}
return new ImmutableAnnotationSetImpl(doc, annotationsToAdd);
}
use of gate.Annotation in project gate-core by GateNLP.
the class AnnotationSetImpl method remove.
/**
* Remove an element from this set.
*/
@Override
public boolean remove(Object o) throws ClassCastException {
Annotation a = (Annotation) o;
boolean wasPresent = removeFromIdIndex(a);
if (wasPresent) {
removeFromTypeIndex(a);
removeFromOffsetIndex(a);
}
// fire the event
fireAnnotationRemoved(new AnnotationSetEvent(AnnotationSetImpl.this, AnnotationSetEvent.ANNOTATION_REMOVED, getDocument(), a));
return wasPresent;
}
use of gate.Annotation in project gate-core by GateNLP.
the class AnnotationSetImpl method get.
// getStrict(startOfset, endOffset)
/**
* Select annotations by offset. This returns the set of annotations of the
* given type that overlap totaly or partially with the interval defined by
* the two provided offsets.The result will include all the annotations that
* either:
* <ul>
* <li>start before the start offset and end strictly after it</li>
* <li>OR</li>
* <li>start at a position between the start and the end offsets</li>
*/
@Override
public AnnotationSet get(String neededType, Long startOffset, Long endOffset) {
if (annotsByStartNode == null)
indexByStartOffset();
List<Annotation> annotationsToAdd = new ArrayList<Annotation>();
Iterator<Node> nodesIter;
Iterator<Annotation> annotsIter;
Node currentNode;
Annotation currentAnnot;
boolean checkType = StringUtils.isNotBlank(neededType);
// find all the annots that start strictly before the start offset
// and end
// strictly after it
Long searchStart = (startOffset - longestAnnot);
if (searchStart < 0)
searchStart = 0l;
// nodesIter = nodesByOffset.headMap(startOffset).values().iterator();
nodesIter = nodesByOffset.subMap(searchStart, startOffset).values().iterator();
while (nodesIter.hasNext()) {
currentNode = nodesIter.next();
Collection<Annotation> objFromPoint = getAnnotsByStartNode(currentNode.getId());
if (objFromPoint == null)
continue;
annotsIter = objFromPoint.iterator();
while (annotsIter.hasNext()) {
currentAnnot = annotsIter.next();
// if neededType is set, make sure this is the right type
if (checkType && !currentAnnot.getType().equals(neededType))
continue;
if (currentAnnot.getEndNode().getOffset().compareTo(startOffset) > 0) {
annotationsToAdd.add(currentAnnot);
}
// if
}
// while
}
// find all the annots that start at or after the start offset but
// before the end offset
nodesIter = nodesByOffset.subMap(startOffset, endOffset).values().iterator();
while (nodesIter.hasNext()) {
currentNode = nodesIter.next();
Collection<Annotation> objFromPoint = getAnnotsByStartNode(currentNode.getId());
if (objFromPoint == null)
continue;
// if no specific type requested, add all of the annots
if (!checkType)
annotationsToAdd.addAll(objFromPoint);
else {
// check the type of each annot
annotsIter = objFromPoint.iterator();
while (annotsIter.hasNext()) {
currentAnnot = annotsIter.next();
if (currentAnnot.getType().equals(neededType))
annotationsToAdd.add(currentAnnot);
}
// while
}
}
return new ImmutableAnnotationSetImpl(doc, annotationsToAdd);
}
Aggregations