package org.eclipse.jface.text;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.PatternSyntaxException;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.SafeRunner;
public abstract class AbstractDocument implements IDocument, IDocumentExtension, IDocumentExtension2, IDocumentExtension3, IDocumentExtension4, IRepairableDocument, IRepairableDocumentExtension {
private static final boolean DEBUG= false;
static private class RegisteredReplace {
IDocumentListener fOwner;
IDocumentExtension.IReplace fReplace;
RegisteredReplace(IDocumentListener owner, IDocumentExtension.IReplace replace) {
fOwner= owner;
fReplace= replace;
}
}
private ITextStore fStore;
private ILineTracker fTracker;
private ListenerList<IDocumentListener> fDocumentListeners;
private ListenerList<IDocumentListener> fPrenotifiedDocumentListeners;
private ListenerList<IDocumentPartitioningListener> fDocumentPartitioningListeners;
private Map<String, List<Position>> fPositions;
private Map<String, List<Position>> fEndPositions;
private List<IPositionUpdater> fPositionUpdaters;
private List<RegisteredReplace> fPostNotificationChanges;
private int fReentranceCount= 0;
private int fStoppedCount= 0;
private boolean fAcceptPostNotificationReplaces= true;
private int fStoppedListenerNotification= 0;
private DocumentEvent fDeferredDocumentEvent;
private Map<String, IDocumentPartitioner> fDocumentPartitioners;
private DocumentPartitioningChangedEvent fDocumentPartitioningChangedEvent;
private FindReplaceDocumentAdapter fFindReplaceDocumentAdapter;
private DocumentRewriteSession fDocumentRewriteSession;
private List<IDocumentRewriteSessionListener> fDocumentRewriteSessionListeners;
private long fModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP;
private long fNextModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP;
private String fInitialLineDelimiter;
protected AbstractDocument() {
fModificationStamp= getNextModificationStamp();
}
protected ITextStore getStore() {
Assert.isNotNull(fStore);
return fStore;
}
protected ILineTracker getTracker() {
Assert.isNotNull(fTracker);
return fTracker;
}
private static <T> List<T> asList(ListenerList<T> listenerList) {
List<?> list= Arrays.asList(listenerList.getListeners());
@SuppressWarnings("unchecked")
List<T> castList= (List<T>) list;
return castList;
}
protected List<IDocumentListener> getDocumentListeners() {
return asList(fDocumentListeners);
}
protected List<IDocumentPartitioningListener> getDocumentPartitioningListeners() {
return asList(fDocumentPartitioningListeners);
}
protected Map<String, List<Position>> getDocumentManagedPositions() {
return fPositions;
}
@Override
public IDocumentPartitioner getDocumentPartitioner() {
return getDocumentPartitioner(DEFAULT_PARTITIONING);
}
protected void setTextStore(ITextStore store) {
fStore= store;
}
protected void setLineTracker(ILineTracker tracker) {
fTracker= tracker;
}
@Override
public void setDocumentPartitioner(IDocumentPartitioner partitioner) {
setDocumentPartitioner(DEFAULT_PARTITIONING, partitioner);
}
protected void completeInitialization() {
fPositions= new HashMap<>();
fEndPositions= new HashMap<>();
fPositionUpdaters= new ArrayList<>();
fDocumentListeners= new ListenerList<>(ListenerList.IDENTITY);
fPrenotifiedDocumentListeners= new ListenerList<>(ListenerList.IDENTITY);
fDocumentPartitioningListeners= new ListenerList<>(ListenerList.IDENTITY);
fDocumentRewriteSessionListeners= new ArrayList<>();
addPositionCategory(DEFAULT_CATEGORY);
addPositionUpdater(new DefaultPositionUpdater(DEFAULT_CATEGORY));
}
@Override
public void addDocumentListener(IDocumentListener listener) {
Assert.isNotNull(listener);
fDocumentListeners.add(listener);
}
@Override
public void removeDocumentListener(IDocumentListener listener) {
Assert.isNotNull(listener);
fDocumentListeners.remove(listener);
}
@Override
public void addPrenotifiedDocumentListener(IDocumentListener listener) {
Assert.isNotNull(listener);
fPrenotifiedDocumentListeners.add(listener);
}
@Override
public void removePrenotifiedDocumentListener(IDocumentListener listener) {
Assert.isNotNull(listener);
fPrenotifiedDocumentListeners.remove(listener);
}
@Override
public void addDocumentPartitioningListener(IDocumentPartitioningListener listener) {
Assert.isNotNull(listener);
fDocumentPartitioningListeners.add(listener);
}
@Override
public void removeDocumentPartitioningListener(IDocumentPartitioningListener listener) {
Assert.isNotNull(listener);
fDocumentPartitioningListeners.remove(listener);
}
@Override
public void addPosition(String category, Position position) throws BadLocationException, BadPositionCategoryException {
if ((0 > position.offset) || (0 > position.length) || (position.offset + position.length > getLength()))
throw new BadLocationException();
if (category == null)
throw new BadPositionCategoryException();
List<Position> list= fPositions.get(category);
if (list == null)
throw new BadPositionCategoryException();
list.add(computeIndexInPositionList(list, position.offset), position);
List<Position> endPositions= fEndPositions.get(category);
if (endPositions == null)
throw new BadPositionCategoryException();
endPositions.add(computeIndexInPositionList(endPositions, position.offset + position.length - 1, false), position);
}
@Override
public void addPosition(Position position) throws BadLocationException {
try {
addPosition(DEFAULT_CATEGORY, position);
} catch (BadPositionCategoryException e) {
}
}
@Override
public void addPositionCategory(String category) {
if (category == null)
return;
if (!containsPositionCategory(category)) {
fPositions.put(category, new ArrayList<>());
fEndPositions.put(category, new ArrayList<>());
}
}
@Override
public void addPositionUpdater(IPositionUpdater updater) {
insertPositionUpdater(updater, fPositionUpdaters.size());
}
@Override
public boolean containsPosition(String category, int offset, int length) {
if (category == null)
return false;
List<Position> list= fPositions.get(category);
if (list == null)
return false;
int size= list.size();
if (size == 0)
return false;
int index= computeIndexInPositionList(list, offset);
if (index < size) {
Position p= list.get(index);
while (p != null && p.offset == offset) {
if (p.length == length)
return true;
++ index;
p= (index < size) ? list.get(index) : null;
}
}
return false;
}
@Override
public boolean containsPositionCategory(String category) {
if (category != null)
return fPositions.containsKey(category);
return false;
}
@Deprecated
protected int computeIndexInPositionList(List<? extends Position> positions, int offset) {
return computeIndexInPositionList(positions, offset, true);
}
protected int computeIndexInPositionList(List<? extends Position> positions, int offset, boolean orderedByOffset) {
if (positions.isEmpty())
return 0;
int left= 0;
int right= positions.size() -1;
int mid= 0;
Position p= null;
while (left < right) {
mid= (left + right) / 2;
p= positions.get(mid);
int pOffset= getOffset(orderedByOffset, p);
if (offset < pOffset) {
if (left == mid)
right= left;
else
right= mid -1;
} else if (offset > pOffset) {
if (right == mid)
left= right;
else
left= mid +1;
} else if (offset == pOffset) {
left= right= mid;
}
}
int pos= left;
p= positions.get(pos);
int pPosition= getOffset(orderedByOffset, p);
if (offset > pPosition) {
pos++;
} else {
do {
--pos;
if (pos < 0)
break;
p= positions.get(pos);
pPosition= getOffset(orderedByOffset, p);
} while (offset == pPosition);
++pos;
}
Assert.isTrue(0 <= pos && pos <= positions.size());
return pos;
}
private int getOffset(boolean orderedByOffset, Position position) {
if (orderedByOffset || position.getLength() == 0)
return position.getOffset();
return position.getOffset() + position.getLength() - 1;
}
@Override
public int computeIndexInCategory(String category, int offset) throws BadLocationException, BadPositionCategoryException {
if (0 > offset || offset > getLength())
throw new BadLocationException();
List<Position> c= fPositions.get(category);
if (c == null)
throw new BadPositionCategoryException();
return computeIndexInPositionList(c, offset);
}
@Deprecated
protected void fireDocumentPartitioningChanged() {
if (fDocumentPartitioningListeners == null)
return;
for (IDocumentPartitioningListener listener : fDocumentPartitioningListeners) {
listener.documentPartitioningChanged(this);
}
}
@Deprecated
protected void fireDocumentPartitioningChanged(IRegion region) {
if (fDocumentPartitioningListeners == null)
return;
for (IDocumentPartitioningListener l : fDocumentPartitioningListeners) {
try {
if (l instanceof IDocumentPartitioningListenerExtension)
((IDocumentPartitioningListenerExtension)l).documentPartitioningChanged(this, region);
else
l.documentPartitioningChanged(this);
} catch (Exception ex) {
log(ex);
}
}
}
protected void fireDocumentPartitioningChanged(DocumentPartitioningChangedEvent event) {
if (fDocumentPartitioningListeners == null)
return;
for (IDocumentPartitioningListener l : fDocumentPartitioningListeners) {
try {
if (l instanceof IDocumentPartitioningListenerExtension2) {
IDocumentPartitioningListenerExtension2 extension2= (IDocumentPartitioningListenerExtension2)l;
extension2.documentPartitioningChanged(event);
} else if (l instanceof IDocumentPartitioningListenerExtension) {
IDocumentPartitioningListenerExtension extension= (IDocumentPartitioningListenerExtension)l;
extension.documentPartitioningChanged(this, event.getCoverage());
} else {
l.documentPartitioningChanged(this);
}
} catch (Exception ex) {
log(ex);
}
}
}
protected void fireDocumentAboutToBeChanged(DocumentEvent event) {
if (fReentranceCount == 0)
flushPostNotificationChanges();
if (fDocumentPartitioners != null) {
Iterator<IDocumentPartitioner> e= fDocumentPartitioners.values().iterator();
while (e.hasNext()) {
IDocumentPartitioner p= e.next();
if (p instanceof IDocumentPartitionerExtension3) {
IDocumentPartitionerExtension3 extension= (IDocumentPartitionerExtension3) p;
if (extension.getActiveRewriteSession() != null)
continue;
}
try {
p.documentAboutToBeChanged(event);
} catch (Exception ex) {
log(ex);
}
}
}
for (IDocumentListener listener : fPrenotifiedDocumentListeners) {
try {
listener.documentAboutToBeChanged(event);
} catch (Exception ex) {
log(ex);
}
}
for (IDocumentListener listener : fDocumentListeners) {
try {
listener.documentAboutToBeChanged(event);
} catch (Exception ex) {
log(ex);
}
}
}
protected void updateDocumentStructures(DocumentEvent event) {
if (fDocumentPartitioners != null) {
fDocumentPartitioningChangedEvent= new DocumentPartitioningChangedEvent(this);
for (Entry<String, IDocumentPartitioner> entry : fDocumentPartitioners.entrySet()) {
String partitioning= entry.getKey();
IDocumentPartitioner partitioner= entry.getValue();
if (partitioner instanceof IDocumentPartitionerExtension3) {
IDocumentPartitionerExtension3 extension= (IDocumentPartitionerExtension3) partitioner;
if (extension.getActiveRewriteSession() != null)
continue;
}
if (partitioner instanceof IDocumentPartitionerExtension) {
IDocumentPartitionerExtension extension= (IDocumentPartitionerExtension) partitioner;
IRegion r= extension.documentChanged2(event);
if (r != null)
fDocumentPartitioningChangedEvent.setPartitionChange(partitioning, r.getOffset(), r.getLength());
} else {
if (partitioner.documentChanged(event))
fDocumentPartitioningChangedEvent.setPartitionChange(partitioning, 0, event.getDocument().getLength());
}
}
}
if (!fPositions.isEmpty())
updatePositions(event);
}
protected void doFireDocumentChanged(DocumentEvent event) {
boolean changed= fDocumentPartitioningChangedEvent != null && !fDocumentPartitioningChangedEvent.isEmpty();
IRegion change= changed ? fDocumentPartitioningChangedEvent.getCoverage() : null;
doFireDocumentChanged(event, changed, change);
}
@Deprecated
protected void doFireDocumentChanged(DocumentEvent event, boolean firePartitionChange, IRegion partitionChange) {
doFireDocumentChanged2(event);
}
protected void doFireDocumentChanged2(DocumentEvent event) {
DocumentPartitioningChangedEvent p= fDocumentPartitioningChangedEvent;
fDocumentPartitioningChangedEvent= null;
if (p != null && !p.isEmpty())
fireDocumentPartitioningChanged(p);
for (IDocumentListener listener : fPrenotifiedDocumentListeners) {
try {
listener.documentChanged(event);
} catch (Exception ex) {
log(ex);
}
}
for (IDocumentListener listener : fDocumentListeners) {
try {
listener.documentChanged(event);
} catch (Exception ex) {
log(ex);
}
}
++ fReentranceCount;
try {
if (fReentranceCount == 1)
executePostNotificationChanges();
} finally {
-- fReentranceCount;
}
}
protected void fireDocumentChanged(DocumentEvent event) {
updateDocumentStructures(event);
if (fStoppedListenerNotification == 0)
doFireDocumentChanged(event);
else
fDeferredDocumentEvent= event;
}
@Override
public char getChar(int pos) throws BadLocationException {
if ((0 > pos) || (pos >= getLength()))
throw new BadLocationException();
return getStore().get(pos);
}
@Override
public String getContentType(int offset) throws BadLocationException {
String contentType= null;
try {
contentType= getContentType(DEFAULT_PARTITIONING, offset, false);
Assert.isNotNull(contentType);
} catch (BadPartitioningException e) {
Assert.isTrue(false);
}
return contentType;
}
@Override
public String[] getLegalContentTypes() {
String[] contentTypes= null;
try {
contentTypes= getLegalContentTypes(DEFAULT_PARTITIONING);
Assert.isNotNull(contentTypes);
} catch (BadPartitioningException e) {
Assert.isTrue(false);
}
return contentTypes;
}
@Override
public int getLength() {
return getStore().getLength();
}
@Override
public String getLineDelimiter(int line) throws BadLocationException {
return getTracker().getLineDelimiter(line);
}
@Override
public String[] getLegalLineDelimiters() {
return getTracker().getLegalLineDelimiters();
}
@Override
public String getDefaultLineDelimiter() {
String lineDelimiter= null;
try {
lineDelimiter= getLineDelimiter(0);
} catch (BadLocationException x) {
}
if (lineDelimiter != null)
return lineDelimiter;
if (fInitialLineDelimiter != null)
return fInitialLineDelimiter;
String sysLineDelimiter= System.getProperty("line.separator");
String[] delimiters= getLegalLineDelimiters();
Assert.isTrue(delimiters.length > 0);
for (String delimiter : delimiters) {
if (delimiter.equals(sysLineDelimiter)) {
lineDelimiter= sysLineDelimiter;
break;
}
}
if (lineDelimiter == null)
lineDelimiter= delimiters[0];
return lineDelimiter;
}
@Override
public void setInitialLineDelimiter(String lineDelimiter) {
Assert.isNotNull(lineDelimiter);
fInitialLineDelimiter= lineDelimiter;
}
@Override
public int getLineLength(int line) throws BadLocationException {
return getTracker().getLineLength(line);
}
@Override
public int getLineOfOffset(int pos) throws BadLocationException {
return getTracker().getLineNumberOfOffset(pos);
}
@Override
public int getLineOffset(int line) throws BadLocationException {
return getTracker().getLineOffset(line);
}
@Override
public IRegion getLineInformation(int line) throws BadLocationException {
return getTracker().getLineInformation(line);
}
@Override
public IRegion getLineInformationOfOffset(int offset) throws BadLocationException {
return getTracker().getLineInformationOfOffset(offset);
}
@Override
public int getNumberOfLines() {
return getTracker().getNumberOfLines();
}
@Override
public int getNumberOfLines(int offset, int length) throws BadLocationException {
return getTracker().getNumberOfLines(offset, length);
}
@Override
public int computeNumberOfLines(String text) {
return getTracker().computeNumberOfLines(text);
}
@Override
public ITypedRegion getPartition(int offset) throws BadLocationException {
ITypedRegion partition= null;
try {
partition= getPartition(DEFAULT_PARTITIONING, offset, false);
Assert.isNotNull(partition);
} catch (BadPartitioningException e) {
Assert.isTrue(false);
}
return partition;
}
@Override
public ITypedRegion[] computePartitioning(int offset, int length) throws BadLocationException {
ITypedRegion[] partitioning= null;
try {
partitioning= computePartitioning(DEFAULT_PARTITIONING, offset, length, false);
Assert.isNotNull(partitioning);
} catch (BadPartitioningException e) {
Assert.isTrue(false);
}
return partitioning;
}
@Override
public Position[] getPositions(String category) throws BadPositionCategoryException {
if (category == null)
throw new BadPositionCategoryException();
List<Position> c= fPositions.get(category);
if (c == null)
throw new BadPositionCategoryException();
Position[] positions= new Position[c.size()];
c.toArray(positions);
return positions;
}
@Override
public String[] getPositionCategories() {
String[] categories= new String[fPositions.size()];
Iterator<String> keys= fPositions.keySet().iterator();
for (int i= 0; i < categories.length; i++)
categories[i]= keys.next();
return categories;
}
@Override
public IPositionUpdater[] getPositionUpdaters() {
IPositionUpdater[] updaters= new IPositionUpdater[fPositionUpdaters.size()];
fPositionUpdaters.toArray(updaters);
return updaters;
}
@Override
public String get() {
return getStore().get(0, getLength());
}
@Override
public String get(int pos, int length) throws BadLocationException {
int myLength= getLength();
if ((0 > pos) || (0 > length) || (pos + length > myLength))
throw new BadLocationException();
return getStore().get(pos, length);
}
@Override
public void insertPositionUpdater(IPositionUpdater updater, int index) {
for (int i= fPositionUpdaters.size() - 1; i >= 0; i--) {
if (fPositionUpdaters.get(i) == updater)
return;
}
if (index == fPositionUpdaters.size())
fPositionUpdaters.add(updater);
else
fPositionUpdaters.add(index, updater);
}
@Override
public void removePosition(String category, Position position) throws BadPositionCategoryException {
if (position == null)
return;
if (category == null)
throw new BadPositionCategoryException();
List<Position> c= fPositions.get(category);
if (c == null)
throw new BadPositionCategoryException();
removeFromPositionsList(c, position, true);
List<Position> endPositions= fEndPositions.get(category);
if (endPositions == null)
throw new BadPositionCategoryException();
removeFromPositionsList(endPositions, position, false);
}
private void removeFromPositionsList(List<Position> positions, Position position, boolean orderedByOffset) {
int size= positions.size();
int index= computeIndexInPositionList(positions, orderedByOffset ? position.offset : position.offset + position.length - 1, orderedByOffset);
if (index < size && positions.get(index) == position) {
positions.remove(index);
return;
}
int back= index - 1;
int forth= index + 1;
while (back >= 0 || forth < size) {
if (back >= 0) {
if (position == positions.get(back)) {
positions.remove(back);
return;
}
back--;
}
if (forth < size) {
if (position == positions.get(forth)) {
positions.remove(forth);
return;
}
forth++;
}
}
}
@Override
public void removePosition(Position position) {
try {
removePosition(DEFAULT_CATEGORY, position);
} catch (BadPositionCategoryException e) {
}
}
@Override
public void removePositionCategory(String category) throws BadPositionCategoryException {
if (category == null)
return;
if ( !containsPositionCategory(category))
throw new BadPositionCategoryException();
fPositions.remove(category);
fEndPositions.remove(category);
}
@Override
public void removePositionUpdater(IPositionUpdater updater) {
for (int i= fPositionUpdaters.size() - 1; i >= 0; i--) {
if (fPositionUpdaters.get(i) == updater) {
fPositionUpdaters.remove(i);
return;
}
}
}
private long getNextModificationStamp() {
if (fNextModificationStamp == Long.MAX_VALUE || fNextModificationStamp == IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP)
fNextModificationStamp= 0;
else
fNextModificationStamp= fNextModificationStamp + 1;
return fNextModificationStamp;
}
@Override
public long getModificationStamp() {
return fModificationStamp;
}
@Override
public void replace(int pos, int length, String text, long modificationStamp) throws BadLocationException {
if ((0 > pos) || (0 > length) || (pos + length > getLength()))
throw new BadLocationException();
DocumentEvent e= new DocumentEvent(this, pos, length, text);
fireDocumentAboutToBeChanged(e);
getStore().replace(pos, length, text);
getTracker().replace(pos, length, text);
fModificationStamp= modificationStamp;
fNextModificationStamp= Math.max(fModificationStamp, fNextModificationStamp);
e.fModificationStamp= fModificationStamp;
fireDocumentChanged(e);
}
@Override
public boolean isLineInformationRepairNeeded(int offset, int length, String text) throws BadLocationException {
return false;
}
@Override
public void replace(int pos, int length, String text) throws BadLocationException {
if (length == 0 && (text == null || text.isEmpty()))
replace(pos, length, text, getModificationStamp());
else
replace(pos, length, text, getNextModificationStamp());
}
@Override
public void set(String text) {
set(text, getNextModificationStamp());
}
@Override
public void set(String text, long modificationStamp) {
int length= getStore().getLength();
DocumentEvent e= new DocumentEvent(this, 0, length, text);
fireDocumentAboutToBeChanged(e);
getStore().set(text);
getTracker().set(text);
fModificationStamp= modificationStamp;
fNextModificationStamp= Math.max(fModificationStamp, fNextModificationStamp);
e.fModificationStamp= fModificationStamp;
fireDocumentChanged(e);
}
protected void updatePositions(DocumentEvent event) {
List<IPositionUpdater> list= new ArrayList<>(fPositionUpdaters);
Iterator<IPositionUpdater> e= list.iterator();
while (e.hasNext()) {
IPositionUpdater u= e.next();
u.update(event);
}
}
@Deprecated
@Override
public int search(int startPosition, String findString, boolean forwardSearch, boolean caseSensitive, boolean wholeWord) throws BadLocationException {
try {
IRegion region= getFindReplaceDocumentAdapter().find(startPosition, findString, forwardSearch, caseSensitive, wholeWord, false);
return region == null ? -1 : region.getOffset();
} catch (IllegalStateException ex) {
return -1;
} catch (PatternSyntaxException ex) {
return -1;
}
}
private FindReplaceDocumentAdapter getFindReplaceDocumentAdapter() {
if (fFindReplaceDocumentAdapter == null)
fFindReplaceDocumentAdapter= new FindReplaceDocumentAdapter(this);
return fFindReplaceDocumentAdapter;
}
private void flushPostNotificationChanges() {
if (fPostNotificationChanges != null)
fPostNotificationChanges.clear();
}
private void executePostNotificationChanges() {
if (fStoppedCount > 0)
return;
while (fPostNotificationChanges != null) {
List<RegisteredReplace> changes= fPostNotificationChanges;
fPostNotificationChanges= null;
Iterator<RegisteredReplace> e= changes.iterator();
while (e.hasNext()) {
RegisteredReplace replace= e.next();
replace.fReplace.perform(this, replace.fOwner);
}
}
}
@Override
public void acceptPostNotificationReplaces() {
fAcceptPostNotificationReplaces= true;
}
@Override
public void ignorePostNotificationReplaces() {
fAcceptPostNotificationReplaces= false;
}
@Override
public void registerPostNotificationReplace(IDocumentListener owner, IDocumentExtension.IReplace replace) {
if (fAcceptPostNotificationReplaces) {
if (fPostNotificationChanges == null)
fPostNotificationChanges= new ArrayList<>(1);
fPostNotificationChanges.add(new RegisteredReplace(owner, replace));
}
}
@Override
public void stopPostNotificationProcessing() {
++ fStoppedCount;
}
@Override
public void resumePostNotificationProcessing() {
-- fStoppedCount;
if (fStoppedCount == 0 && fReentranceCount == 0)
executePostNotificationChanges();
}
@Deprecated
@Override
public void startSequentialRewrite(boolean normalized) {
}
@Deprecated
@Override
public void stopSequentialRewrite() {
}
@Override
public void resumeListenerNotification() {
-- fStoppedListenerNotification;
if (fStoppedListenerNotification == 0) {
resumeDocumentListenerNotification();
}
}
@Override
public void stopListenerNotification() {
++ fStoppedListenerNotification;
}
private void resumeDocumentListenerNotification() {
if (fDeferredDocumentEvent != null) {
DocumentEvent event= fDeferredDocumentEvent;
fDeferredDocumentEvent= null;
doFireDocumentChanged(event);
}
}
@Override
public ITypedRegion[] computePartitioning(String partitioning, int offset, int length, boolean includeZeroLengthPartitions) throws BadLocationException, BadPartitioningException {
if ((0 > offset) || (0 > length) || (offset + length > getLength()))
throw new BadLocationException();
IDocumentPartitioner partitioner= getDocumentPartitioner(partitioning);
if (partitioner instanceof IDocumentPartitionerExtension2) {
checkStateOfPartitioner(partitioner, partitioning);
return ((IDocumentPartitionerExtension2) partitioner).computePartitioning(offset, length, includeZeroLengthPartitions);
} else if (partitioner != null) {
checkStateOfPartitioner(partitioner, partitioning);
return partitioner.computePartitioning(offset, length);
} else if (DEFAULT_PARTITIONING.equals(partitioning))
return new TypedRegion[] { new TypedRegion(offset, length, DEFAULT_CONTENT_TYPE) };
else
throw new BadPartitioningException();
}
@Override
public String getContentType(String partitioning, int offset, boolean preferOpenPartitions) throws BadLocationException, BadPartitioningException {
if ((0 > offset) || (offset > getLength()))
throw new BadLocationException();
IDocumentPartitioner partitioner= getDocumentPartitioner(partitioning);
if (partitioner instanceof IDocumentPartitionerExtension2) {
checkStateOfPartitioner(partitioner, partitioning);
return ((IDocumentPartitionerExtension2) partitioner).getContentType(offset, preferOpenPartitions);
} else if (partitioner != null) {
checkStateOfPartitioner(partitioner, partitioning);
return partitioner.getContentType(offset);
} else if (DEFAULT_PARTITIONING.equals(partitioning))
return DEFAULT_CONTENT_TYPE;
else
throw new BadPartitioningException();
}
@Override
public IDocumentPartitioner getDocumentPartitioner(String partitioning) {
return fDocumentPartitioners != null ? fDocumentPartitioners.get(partitioning) : null;
}
@Override
public String[] getLegalContentTypes(String partitioning) throws BadPartitioningException {
IDocumentPartitioner partitioner= getDocumentPartitioner(partitioning);
if (partitioner != null)
return partitioner.getLegalContentTypes();
if (DEFAULT_PARTITIONING.equals(partitioning))
return new String[] { DEFAULT_CONTENT_TYPE };
throw new BadPartitioningException();
}
@Override
public ITypedRegion getPartition(String partitioning, int offset, boolean preferOpenPartitions) throws BadLocationException, BadPartitioningException {
if ((0 > offset) || (offset > getLength()))
throw new BadLocationException();
IDocumentPartitioner partitioner= getDocumentPartitioner(partitioning);
if (partitioner instanceof IDocumentPartitionerExtension2) {
checkStateOfPartitioner(partitioner, partitioning);
return ((IDocumentPartitionerExtension2) partitioner).getPartition(offset, preferOpenPartitions);
} else if (partitioner != null) {
checkStateOfPartitioner(partitioner, partitioning);
return partitioner.getPartition(offset);
} else if (DEFAULT_PARTITIONING.equals(partitioning))
return new TypedRegion(0, getLength(), DEFAULT_CONTENT_TYPE);
else
throw new BadPartitioningException();
}
@Override
public String[] getPartitionings() {
if (fDocumentPartitioners == null)
return new String[0];
String[] partitionings= new String[fDocumentPartitioners.size()];
fDocumentPartitioners.keySet().toArray(partitionings);
return partitionings;
}
@Override
public void setDocumentPartitioner(String partitioning, IDocumentPartitioner partitioner) {
if (partitioner == null) {
if (fDocumentPartitioners != null) {
fDocumentPartitioners.remove(partitioning);
if (fDocumentPartitioners.isEmpty())
fDocumentPartitioners= null;
}
} else {
if (fDocumentPartitioners == null)
fDocumentPartitioners= new HashMap<>();
fDocumentPartitioners.put(partitioning, partitioner);
}
DocumentPartitioningChangedEvent event= new DocumentPartitioningChangedEvent(this);
event.setPartitionChange(partitioning, 0, getLength());
fireDocumentPartitioningChanged(event);
}
@Override
public void repairLineInformation() {
getTracker().set(get());
}
protected void fireRewriteSessionChanged(DocumentRewriteSessionEvent event) {
if (!fDocumentRewriteSessionListeners.isEmpty()) {
List<IDocumentRewriteSessionListener> list= new ArrayList<>(fDocumentRewriteSessionListeners);
Iterator<IDocumentRewriteSessionListener> e= list.iterator();
while (e.hasNext()) {
try {
IDocumentRewriteSessionListener l= e.next();
l.documentRewriteSessionChanged(event);
} catch (Exception ex) {
log(ex);
}
}
}
}
@Override
public final DocumentRewriteSession getActiveRewriteSession() {
return fDocumentRewriteSession;
}
@Override
public DocumentRewriteSession startRewriteSession(DocumentRewriteSessionType sessionType) {
if (getActiveRewriteSession() != null)
throw new IllegalStateException();
fDocumentRewriteSession= new DocumentRewriteSession(sessionType);
if (DEBUG)
System.out.println("AbstractDocument: Starting rewrite session: " + fDocumentRewriteSession);
fireRewriteSessionChanged(new DocumentRewriteSessionEvent(this, fDocumentRewriteSession, DocumentRewriteSessionEvent.SESSION_START));
startRewriteSessionOnPartitioners(fDocumentRewriteSession);
ILineTracker tracker= getTracker();
if (tracker instanceof ILineTrackerExtension) {
ILineTrackerExtension extension= (ILineTrackerExtension) tracker;
extension.startRewriteSession(fDocumentRewriteSession);
}
if (DocumentRewriteSessionType.SEQUENTIAL == sessionType)
startSequentialRewrite(false);
else if (DocumentRewriteSessionType.STRICTLY_SEQUENTIAL == sessionType)
startSequentialRewrite(true);
return fDocumentRewriteSession;
}
protected final void startRewriteSessionOnPartitioners(DocumentRewriteSession session) {
if (fDocumentPartitioners != null) {
Iterator<IDocumentPartitioner> e= fDocumentPartitioners.values().iterator();
while (e.hasNext()) {
Object partitioner= e.next();
if (partitioner instanceof IDocumentPartitionerExtension3) {
IDocumentPartitionerExtension3 extension= (IDocumentPartitionerExtension3) partitioner;
extension.startRewriteSession(session);
}
}
}
}
@Override
public void stopRewriteSession(DocumentRewriteSession session) {
if (fDocumentRewriteSession != null && fDocumentRewriteSession == session) {
if (DEBUG)
System.out.println("AbstractDocument: Stopping rewrite session: " + session);
DocumentRewriteSessionType sessionType= session.getSessionType();
if (DocumentRewriteSessionType.SEQUENTIAL == sessionType || DocumentRewriteSessionType.STRICTLY_SEQUENTIAL == sessionType)
stopSequentialRewrite();
ILineTracker tracker= getTracker();
if (tracker instanceof ILineTrackerExtension) {
ILineTrackerExtension extension= (ILineTrackerExtension) tracker;
extension.stopRewriteSession(session, get());
}
stopRewriteSessionOnPartitioners(fDocumentRewriteSession);
fDocumentRewriteSession= null;
fireRewriteSessionChanged(new DocumentRewriteSessionEvent(this, session, DocumentRewriteSessionEvent.SESSION_STOP));
}
}
protected final void stopRewriteSessionOnPartitioners(DocumentRewriteSession session) {
if (fDocumentPartitioners != null) {
DocumentPartitioningChangedEvent event= new DocumentPartitioningChangedEvent(this);
for (Entry<String, IDocumentPartitioner> entry : fDocumentPartitioners.entrySet()) {
String partitioning = entry.getKey();
IDocumentPartitioner partitioner= entry.getValue();
if (partitioner instanceof IDocumentPartitionerExtension3) {
IDocumentPartitionerExtension3 extension= (IDocumentPartitionerExtension3) partitioner;
extension.stopRewriteSession(session);
event.setPartitionChange(partitioning, 0, getLength());
}
}
if (!event.isEmpty())
fireDocumentPartitioningChanged(event);
}
}
@Override
public void addDocumentRewriteSessionListener(IDocumentRewriteSessionListener listener) {
Assert.isNotNull(listener);
if (! fDocumentRewriteSessionListeners.contains(listener))
fDocumentRewriteSessionListeners.add(listener);
}
@Override
public void removeDocumentRewriteSessionListener(IDocumentRewriteSessionListener listener) {
Assert.isNotNull(listener);
fDocumentRewriteSessionListeners.remove(listener);
}
protected final void checkStateOfPartitioner(IDocumentPartitioner partitioner, String partitioning) {
if (!(partitioner instanceof IDocumentPartitionerExtension3))
return;
IDocumentPartitionerExtension3 extension= (IDocumentPartitionerExtension3) partitioner;
DocumentRewriteSession session= extension.getActiveRewriteSession();
if (session != null) {
extension.stopRewriteSession(session);
if (DEBUG)
System.out.println("AbstractDocument: Flushing rewrite session for partition type: " + partitioning);
DocumentPartitioningChangedEvent event= new DocumentPartitioningChangedEvent(this);
event.setPartitionChange(partitioning, 0, getLength());
fireDocumentPartitioningChanged(event);
}
}
public Position[] getPositions(String category, int offset, int length, boolean canStartBefore, boolean canEndAfter) throws BadPositionCategoryException {
if (canStartBefore && canEndAfter || (!canStartBefore && !canEndAfter)) {
List<Position> documentPositions;
if (canStartBefore && canEndAfter) {
if (offset < getLength() / 2) {
documentPositions= getStartingPositions(category, 0, offset + length);
} else {
documentPositions= getEndingPositions(category, offset, getLength() - offset + 1);
}
} else {
documentPositions= getStartingPositions(category, offset, length);
}
ArrayList<Position> list= new ArrayList<>(documentPositions.size());
Position region= new Position(offset, length);
for (Position position : documentPositions) {
if (isWithinRegion(region, position, canStartBefore, canEndAfter)) {
list.add(position);
}
}
Position[] positions= new Position[list.size()];
list.toArray(positions);
return positions;
} else if (canStartBefore) {
List<Position> list= getEndingPositions(category, offset, length);
Position[] positions= new Position[list.size()];
list.toArray(positions);
return positions;
} else {
Assert.isLegal(canEndAfter && !canStartBefore);
List<Position> list= getStartingPositions(category, offset, length);
Position[] positions= new Position[list.size()];
list.toArray(positions);
return positions;
}
}
private boolean isWithinRegion(Position region, Position position, boolean canStartBefore, boolean canEndAfter) {
if (canStartBefore && canEndAfter) {
return region.overlapsWith(position.getOffset(), position.getLength());
} else if (canStartBefore) {
return region.includes(position.getOffset() + position.getLength() - 1);
} else if (canEndAfter) {
return region.includes(position.getOffset());
} else {
int start= position.getOffset();
return region.includes(start) && region.includes(start + position.getLength() - 1);
}
}
private List<Position> getStartingPositions(String category, int offset, int length) throws BadPositionCategoryException {
List<Position> positions= fPositions.get(category);
if (positions == null)
throw new BadPositionCategoryException();
int indexStart= computeIndexInPositionList(positions, offset, true);
int indexEnd= computeIndexInPositionList(positions, offset + length, true);
return positions.subList(indexStart, indexEnd);
}
private List<Position> getEndingPositions(String category, int offset, int length) throws BadPositionCategoryException {
List<Position> positions= fEndPositions.get(category);
if (positions == null)
throw new BadPositionCategoryException();
int indexStart= computeIndexInPositionList(positions, offset, false);
int indexEnd= computeIndexInPositionList(positions, offset + length, false);
return positions.subList(indexStart, indexEnd);
}
private static void log(final Exception ex) {
SafeRunner.run(new ISafeRunnable() {
@Override
public void run() throws Exception {
throw ex;
}
@Override
public void handleException(Throwable exception) {
}
});
}
}