Copyright (c) 2000, 2016 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation
/******************************************************************************* * Copyright (c) 2000, 2016 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/
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;
Abstract default implementation of IDocument and its extension interfaces IDocumentExtension, IDocumentExtension2, IDocumentExtension3, IDocumentExtension4, as well as IRepairableDocument.

An AbstractDocument supports the following implementation plug-ins:

  • a text store implementing ITextStore for storing and managing the document's content,
  • a line tracker implementing ILineTracker to map character positions to line numbers and vice versa
The document can dynamically change the text store when switching between sequential rewrite mode and normal mode.

This class must be subclassed. Subclasses must configure which implementation plug-ins the document instance should use. Subclasses are not intended to overwrite existing methods.

See Also:
/** * Abstract default implementation of <code>IDocument</code> and its extension * interfaces {@link org.eclipse.jface.text.IDocumentExtension}, * {@link org.eclipse.jface.text.IDocumentExtension2}, * {@link org.eclipse.jface.text.IDocumentExtension3}, * {@link org.eclipse.jface.text.IDocumentExtension4}, as well as * {@link org.eclipse.jface.text.IRepairableDocument}. * <p> * * An <code>AbstractDocument</code> supports the following implementation * plug-ins: * <ul> * <li>a text store implementing {@link org.eclipse.jface.text.ITextStore} for * storing and managing the document's content,</li> * <li>a line tracker implementing {@link org.eclipse.jface.text.ILineTracker} * to map character positions to line numbers and vice versa</li> * </ul> * The document can dynamically change the text store when switching between * sequential rewrite mode and normal mode. * <p> * * This class must be subclassed. Subclasses must configure which implementation * plug-ins the document instance should use. Subclasses are not intended to * overwrite existing methods. * * @see org.eclipse.jface.text.ITextStore * @see org.eclipse.jface.text.ILineTracker */
public abstract class AbstractDocument implements IDocument, IDocumentExtension, IDocumentExtension2, IDocumentExtension3, IDocumentExtension4, IRepairableDocument, IRepairableDocumentExtension {
Tells whether this class is in debug mode.
Since:3.1
/** * Tells whether this class is in debug mode. * @since 3.1 */
private static final boolean DEBUG= false;
Inner class to bundle a registered post notification replace operation together with its owner.
Since:2.0
/** * Inner class to bundle a registered post notification replace operation together with its * owner. * * @since 2.0 */
static private class RegisteredReplace {
The owner of this replace operation.
/** The owner of this replace operation. */
IDocumentListener fOwner;
The replace operation
/** The replace operation */
IDocumentExtension.IReplace fReplace;
Creates a new bundle object.
Params:
  • owner – the document listener owning the replace operation
  • replace – the replace operation
/** * Creates a new bundle object. * @param owner the document listener owning the replace operation * @param replace the replace operation */
RegisteredReplace(IDocumentListener owner, IDocumentExtension.IReplace replace) { fOwner= owner; fReplace= replace; } }
The document's text store
/** The document's text store */
private ITextStore fStore;
The document's line tracker
/** The document's line tracker */
private ILineTracker fTracker;
The registered document listeners
/** The registered document listeners */
private ListenerList<IDocumentListener> fDocumentListeners;
The registered pre-notified document listeners
/** The registered pre-notified document listeners */
private ListenerList<IDocumentListener> fPrenotifiedDocumentListeners;
The registered document partitioning listeners
/** The registered document partitioning listeners */
private ListenerList<IDocumentPartitioningListener> fDocumentPartitioningListeners;
All positions managed by the document ordered by their start positions.
/** All positions managed by the document ordered by their start positions. */
private Map<String, List<Position>> fPositions;
All positions managed by the document ordered by their end positions.
Since:3.4
/** * All positions managed by the document ordered by their end positions. * @since 3.4 */
private Map<String, List<Position>> fEndPositions;
All registered document position updaters
/** All registered document position updaters */
private List<IPositionUpdater> fPositionUpdaters;
The list of post notification changes
Since:2.0
/** * The list of post notification changes * @since 2.0 */
private List<RegisteredReplace> fPostNotificationChanges;
The reentrance count for post notification changes.
Since:2.0
/** * The reentrance count for post notification changes. * @since 2.0 */
private int fReentranceCount= 0;
Indicates whether post notification change processing has been stopped.
Since:2.0
/** * Indicates whether post notification change processing has been stopped. * @since 2.0 */
private int fStoppedCount= 0;
Indicates whether the registration of post notification changes should be ignored.
Since:2.1
/** * Indicates whether the registration of post notification changes should be ignored. * @since 2.1 */
private boolean fAcceptPostNotificationReplaces= true;
Indicates whether the notification of listeners has been stopped.
Since:2.1
/** * Indicates whether the notification of listeners has been stopped. * @since 2.1 */
private int fStoppedListenerNotification= 0;
The document event to be sent after listener notification has been resumed.
Since:2.1
/** * The document event to be sent after listener notification has been resumed. * @since 2.1 */
private DocumentEvent fDeferredDocumentEvent;
The registered document partitioners.
Since:3.0
/** * The registered document partitioners. * @since 3.0 */
private Map<String, IDocumentPartitioner> fDocumentPartitioners;
The partitioning changed event.
Since:3.0
/** * The partitioning changed event. * @since 3.0 */
private DocumentPartitioningChangedEvent fDocumentPartitioningChangedEvent;
The find/replace document adapter.
Since:3.0
/** * The find/replace document adapter. * @since 3.0 */
private FindReplaceDocumentAdapter fFindReplaceDocumentAdapter;
The active document rewrite session.
Since:3.1
/** * The active document rewrite session. * @since 3.1 */
private DocumentRewriteSession fDocumentRewriteSession;
The registered document rewrite session listeners.
Since:3.1
/** * The registered document rewrite session listeners. * @since 3.1 */
private List<IDocumentRewriteSessionListener> fDocumentRewriteSessionListeners;
The current modification stamp.
Since:3.1
/** * The current modification stamp. * @since 3.1 */
private long fModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP;
Keeps track of next modification stamp.
Since:3.1.1
/** * Keeps track of next modification stamp. * @since 3.1.1 */
private long fNextModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP;
This document's default line delimiter.
Since:3.1
/** * This document's default line delimiter. * @since 3.1 */
private String fInitialLineDelimiter;
The default constructor does not perform any configuration but leaves it to the clients who must first initialize the implementation plug-ins and then call completeInitialization. Results in the construction of an empty document.
/** * The default constructor does not perform any configuration * but leaves it to the clients who must first initialize the * implementation plug-ins and then call <code>completeInitialization</code>. * Results in the construction of an empty document. */
protected AbstractDocument() { fModificationStamp= getNextModificationStamp(); }
Returns the document's text store. Assumes that the document has been initialized with a text store.
Returns:the document's text store
/** * Returns the document's text store. Assumes that the * document has been initialized with a text store. * * @return the document's text store */
protected ITextStore getStore() { Assert.isNotNull(fStore); return fStore; }
Returns the document's line tracker. Assumes that the document has been initialized with a line tracker.
Returns:the document's line tracker
/** * Returns the document's line tracker. Assumes that the * document has been initialized with a line tracker. * * @return the document's line tracker */
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; }
Returns the document's document listeners.
Returns:the document's document listeners
/** * Returns the document's document listeners. * * @return the document's document listeners */
protected List<IDocumentListener> getDocumentListeners() { return asList(fDocumentListeners); }
Returns the document's partitioning listeners.
Returns:the document's partitioning listeners
/** * Returns the document's partitioning listeners. * * @return the document's partitioning listeners */
protected List<IDocumentPartitioningListener> getDocumentPartitioningListeners() { return asList(fDocumentPartitioningListeners); }
Returns all positions managed by the document grouped by category.
Returns:the document's positions
/** * Returns all positions managed by the document grouped by category. * * @return the document's positions */
protected Map<String, List<Position>> getDocumentManagedPositions() { return fPositions; } @Override public IDocumentPartitioner getDocumentPartitioner() { return getDocumentPartitioner(DEFAULT_PARTITIONING); } //--- implementation configuration interface ------------
Sets the document's text store. Must be called at the beginning of the constructor.
Params:
  • store – the document's text store
/** * Sets the document's text store. * Must be called at the beginning of the constructor. * * @param store the document's text store */
protected void setTextStore(ITextStore store) { fStore= store; }
Sets the document's line tracker. Must be called at the beginning of the constructor.
Params:
  • tracker – the document's line tracker
/** * Sets the document's line tracker. * Must be called at the beginning of the constructor. * * @param tracker the document's line tracker */
protected void setLineTracker(ILineTracker tracker) { fTracker= tracker; } @Override public void setDocumentPartitioner(IDocumentPartitioner partitioner) { setDocumentPartitioner(DEFAULT_PARTITIONING, partitioner); }
Initializes document listeners, positions, and position updaters. Must be called inside the constructor after the implementation plug-ins have been set.
/** * Initializes document listeners, positions, and position updaters. * Must be called inside the constructor after the implementation plug-ins * have been set. */
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; }
Computes the index in the list of positions at which a position with the given offset would be inserted. The position is supposed to become the first in this list of all positions with the same offset.
Params:
  • positions – the list in which the index is computed
  • offset – the offset for which the index is computed
See Also:
Returns:the computed index
Deprecated:As of 3.4, replaced by computeIndexInPositionList(List<? extends Position>, int, boolean)
/** * Computes the index in the list of positions at which a position with the given * offset would be inserted. The position is supposed to become the first in this list * of all positions with the same offset. * * @param positions the list in which the index is computed * @param offset the offset for which the index is computed * @return the computed index * * @see IDocument#computeIndexInCategory(String, int) * @deprecated As of 3.4, replaced by {@link #computeIndexInPositionList(List, int, boolean)} */
@Deprecated protected int computeIndexInPositionList(List<? extends Position> positions, int offset) { return computeIndexInPositionList(positions, offset, true); }
Computes the index in the list of positions at which a position with the given position would be inserted. The position to insert is supposed to become the first in this list of all positions with the same position.
Params:
  • positions – the list in which the index is computed
  • offset – the offset for which the index is computed
  • orderedByOffset – true if ordered by offset, false if ordered by end position
Returns:the computed index
Since:3.4
/** * Computes the index in the list of positions at which a position with the given * position would be inserted. The position to insert is supposed to become the first * in this list of all positions with the same position. * * @param positions the list in which the index is computed * @param offset the offset for which the index is computed * @param orderedByOffset <code>true</code> if ordered by offset, false if ordered by end position * @return the computed index * @since 3.4 */
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) { // append to the end pos++; } else { // entry will become the first of all entries with the same offset 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; } /* * @since 3.4 */ 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); }
Fires the document partitioning changed notification to all registered document partitioning listeners. Uses a robust iterator.
Deprecated:as of 2.0. Use fireDocumentPartitioningChanged(IRegion) instead.
/** * Fires the document partitioning changed notification to all registered * document partitioning listeners. Uses a robust iterator. * * @deprecated as of 2.0. Use <code>fireDocumentPartitioningChanged(IRegion)</code> instead. */
@Deprecated protected void fireDocumentPartitioningChanged() { if (fDocumentPartitioningListeners == null) return; for (IDocumentPartitioningListener listener : fDocumentPartitioningListeners) { listener.documentPartitioningChanged(this); } }
Fires the document partitioning changed notification to all registered document partitioning listeners. Uses a robust iterator.
Params:
  • region – the region in which partitioning has changed
See Also:
Since:2.0
Deprecated:as of 3.0. Use fireDocumentPartitioningChanged(DocumentPartitioningChangedEvent) instead.
/** * Fires the document partitioning changed notification to all registered * document partitioning listeners. Uses a robust iterator. * * @param region the region in which partitioning has changed * * @see IDocumentPartitioningListenerExtension * @since 2.0 * @deprecated as of 3.0. Use * <code>fireDocumentPartitioningChanged(DocumentPartitioningChangedEvent)</code> * instead. */
@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); } } }
Fires the document partitioning changed notification to all registered document partitioning listeners. Uses a robust iterator.
Params:
  • event – the document partitioning changed event
See Also:
Since:3.0
/** * Fires the document partitioning changed notification to all registered * document partitioning listeners. Uses a robust iterator. * * @param event the document partitioning changed event * * @see IDocumentPartitioningListenerExtension2 * @since 3.0 */
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); } } }
Fires the given document event to all registers document listeners informing them about the forthcoming document manipulation. Uses a robust iterator.
Params:
  • event – the event to be sent out
/** * Fires the given document event to all registers document listeners informing them * about the forthcoming document manipulation. Uses a robust iterator. * * @param event the event to be sent out */
protected void fireDocumentAboutToBeChanged(DocumentEvent event) { // IDocumentExtension 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); } } }
Updates document partitioning and document positions according to the specification given by the document event.
Params:
  • event – the document event describing the change to which structures must be adapted
/** * Updates document partitioning and document positions according to the * specification given by the document event. * * @param event the document event describing the change to which structures must be adapted */
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); }
Notifies all listeners about the given document change. Uses a robust iterator.

Executes all registered post notification replace operation.

Params:
  • event – the event to be sent out.
/** * Notifies all listeners about the given document change. Uses a robust * iterator. * <p> * Executes all registered post notification replace operation. * * @param event the event to be sent out. */
protected void doFireDocumentChanged(DocumentEvent event) { boolean changed= fDocumentPartitioningChangedEvent != null && !fDocumentPartitioningChangedEvent.isEmpty(); IRegion change= changed ? fDocumentPartitioningChangedEvent.getCoverage() : null; doFireDocumentChanged(event, changed, change); }
Notifies all listeners about the given document change. Uses a robust iterator.

Executes all registered post notification replace operation.

Params:
  • event – the event to be sent out
  • firePartitionChange – true if a partition change notification should be sent
  • partitionChange – the region whose partitioning changed
Since:2.0
Deprecated:as of 3.0. Use doFireDocumentChanged2(DocumentEvent) instead; this method will be removed.
/** * Notifies all listeners about the given document change. * Uses a robust iterator. <p> * Executes all registered post notification replace operation. * * @param event the event to be sent out * @param firePartitionChange <code>true</code> if a partition change notification should be sent * @param partitionChange the region whose partitioning changed * @since 2.0 * @deprecated as of 3.0. Use <code>doFireDocumentChanged2(DocumentEvent)</code> instead; this method will be removed. */
@Deprecated protected void doFireDocumentChanged(DocumentEvent event, boolean firePartitionChange, IRegion partitionChange) { doFireDocumentChanged2(event); }
Notifies all listeners about the given document change. Uses a robust iterator.

Executes all registered post notification replace operation.

This method will be renamed to doFireDocumentChanged.

Params:
  • event – the event to be sent out
Since:3.0
/** * Notifies all listeners about the given document change. Uses a robust * iterator. * <p> * Executes all registered post notification replace operation. * <p> * This method will be renamed to <code>doFireDocumentChanged</code>. * * @param event the event to be sent out * @since 3.0 */
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); } } // IDocumentExtension ++ fReentranceCount; try { if (fReentranceCount == 1) executePostNotificationChanges(); } finally { -- fReentranceCount; } }
Updates the internal document structures and informs all document listeners if listener notification has been enabled. Otherwise it remembers the event to be sent to the listeners on resume.
Params:
  • event – the document event to be sent out
/** * Updates the internal document structures and informs all document listeners * if listener notification has been enabled. Otherwise it remembers the event * to be sent to the listeners on resume. * * @param event the document event to be sent out */
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"); //$NON-NLS-1$ 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); }
Remove the given position form the given list of positions based on identity not equality.
Params:
  • positions – a list of positions
  • position – the position to remove
  • orderedByOffset – true if positions is ordered by offset, false if ordered by end position
Since:3.4
/** * Remove the given position form the given list of positions based on identity not equality. * * @param positions a list of positions * @param position the position to remove * @param orderedByOffset true if <code>positions</code> is ordered by offset, false if ordered by end position * @since 3.4 */
private void removeFromPositionsList(List<Position> positions, Position position, boolean orderedByOffset) { int size= positions.size(); //Assume position is somewhere near it was before 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); }
{@inheritDoc}
Since:3.4
/** * {@inheritDoc} * * @since 3.4 */
@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); }
Updates all positions of all categories to the change described by the document event. All registered document updaters are called in the sequence they have been arranged. Uses a robust iterator.
Params:
  • event – the document event describing the change to which to adapt the positions
/** * Updates all positions of all categories to the change described by the * document event. All registered document updaters are called in the * sequence they have been arranged. Uses a robust iterator. * * @param event the document event describing the change to which to adapt * the positions */
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); } }
{@inheritDoc}
Deprecated:as of 3.0 search is provided by FindReplaceDocumentAdapter
/** * {@inheritDoc} * * @deprecated as of 3.0 search is provided by {@link FindReplaceDocumentAdapter} */
@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; } }
Returns the find/replace adapter for this document.
Returns:this document's find/replace document adapter
Since:3.0
/** * Returns the find/replace adapter for this document. * * @return this document's find/replace document adapter * @since 3.0 */
private FindReplaceDocumentAdapter getFindReplaceDocumentAdapter() { if (fFindReplaceDocumentAdapter == null) fFindReplaceDocumentAdapter= new FindReplaceDocumentAdapter(this); return fFindReplaceDocumentAdapter; }
Flushes all registered post notification changes.
Since:2.0
/** * Flushes all registered post notification changes. * * @since 2.0 */
private void flushPostNotificationChanges() { if (fPostNotificationChanges != null) fPostNotificationChanges.clear(); }
Executes all registered post notification changes. The process is repeated until no new post notification changes are added.
Since:2.0
/** * Executes all registered post notification changes. The process is * repeated until no new post notification changes are added. * * @since 2.0 */
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(); }
{@inheritDoc}
Since:2.0
Deprecated:since 3.1. Use IDocumentExtension4.startRewriteSession(DocumentRewriteSessionType) instead.
/** * {@inheritDoc} * * @since 2.0 * @deprecated since 3.1. Use * {@link IDocumentExtension4#startRewriteSession(DocumentRewriteSessionType)} * instead. */
@Deprecated @Override public void startSequentialRewrite(boolean normalized) { }
{@inheritDoc}
Since:2.0
Deprecated:As of 3.1, replaced by IDocumentExtension4.stopRewriteSession(DocumentRewriteSession)
/** * {@inheritDoc} * * @since 2.0 * @deprecated As of 3.1, replaced by {@link IDocumentExtension4#stopRewriteSession(DocumentRewriteSession)} */
@Deprecated @Override public void stopSequentialRewrite() { } @Override public void resumeListenerNotification() { -- fStoppedListenerNotification; if (fStoppedListenerNotification == 0) { resumeDocumentListenerNotification(); } } @Override public void stopListenerNotification() { ++ fStoppedListenerNotification; }
Resumes the document listener notification by sending out the remembered partition changed and document event.
Since:2.1
/** * Resumes the document listener notification by sending out the remembered * partition changed and document event. * * @since 2.1 */
private void resumeDocumentListenerNotification() { if (fDeferredDocumentEvent != null) { DocumentEvent event= fDeferredDocumentEvent; fDeferredDocumentEvent= null; doFireDocumentChanged(event); } } /* * @see org.eclipse.jface.text.IDocumentExtension3#computeZeroLengthPartitioning(java.lang.String, int, int) * @since 3.0 */ @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(); } /* * @see org.eclipse.jface.text.IDocumentExtension3#getZeroLengthContentType(java.lang.String, int) * @since 3.0 */ @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(); } /* * @see org.eclipse.jface.text.IDocumentExtension3#getZeroLengthPartition(java.lang.String, int) * @since 3.0 */ @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()); }
Fires the given event to all registered rewrite session listeners. Uses robust iterators.
Params:
  • event – the event to be fired
Since:3.1
/** * Fires the given event to all registered rewrite session listeners. Uses robust iterators. * * @param event the event to be fired * @since 3.1 */
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); //$NON-NLS-1$ 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; }
Starts the given rewrite session.
Params:
  • session – the rewrite session
Since:3.1
/** * Starts the given rewrite session. * * @param session the rewrite session * @since 3.1 */
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); //$NON-NLS-1$ 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)); } }
Stops the given rewrite session.
Params:
  • session – the rewrite session
Since:3.1
/** * Stops the given rewrite session. * * @param session the rewrite session * @since 3.1 */
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); }
Checks the state for the given partitioner and stops the active rewrite session.
Params:
  • partitioner – the document partitioner to be checked
  • partitioning – the document partitioning the partitioner is registered for
Since:3.1
/** * Checks the state for the given partitioner and stops the * active rewrite session. * * @param partitioner the document partitioner to be checked * @param partitioning the document partitioning the partitioner is registered for * @since 3.1 */
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); //$NON-NLS-1$ DocumentPartitioningChangedEvent event= new DocumentPartitioningChangedEvent(this); event.setPartitionChange(partitioning, 0, getLength()); fireDocumentPartitioningChanged(event); } }
Returns all positions of the given category that are inside the given region.
Params:
  • category – the position category
  • offset – the start position of the region, must be >= 0
  • length – the length of the region, must be >= 0
  • canStartBefore – if true then positions are included which start before the region if they end at or after the regions start
  • canEndAfter – if true then positions are included which end after the region if they start at or before the regions end
Throws:
Returns:all positions inside the region of the given category
Since:3.4
/** * Returns all positions of the given category that are inside the given region. * * @param category the position category * @param offset the start position of the region, must be &gt;= 0 * @param length the length of the region, must be &gt;= 0 * @param canStartBefore if <code>true</code> then positions are included * which start before the region if they end at or after the regions start * @param canEndAfter if <code>true</code> then positions are included * which end after the region if they start at or before the regions end * @return all positions inside the region of the given category * @throws BadPositionCategoryException if category is undefined in this document * @since 3.4 */
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; } } /* * @since 3.4 */ 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); } }
A list of positions in the given category with an offset inside the given region. The order of the positions is arbitrary.
Params:
  • category – the position category
  • offset – the offset of the region
  • length – the length of the region
Throws:
Returns:a list of the positions in the region
Since:3.4
/** * A list of positions in the given category with an offset inside the given * region. The order of the positions is arbitrary. * * @param category the position category * @param offset the offset of the region * @param length the length of the region * @return a list of the positions in the region * @throws BadPositionCategoryException if category is undefined in this document * @since 3.4 */
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); }
A list of positions in the given category with an end position inside the given region. The order of the positions is arbitrary.
Params:
  • category – the position category
  • offset – the offset of the region
  • length – the length of the region
Throws:
Returns:a list of the positions in the region
Since:3.4
/** * A list of positions in the given category with an end position inside * the given region. The order of the positions is arbitrary. * * @param category the position category * @param offset the offset of the region * @param length the length of the region * @return a list of the positions in the region * @throws BadPositionCategoryException if category is undefined in this document * @since 3.4 */
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); }
Logs the given exception by reusing the code in SafeRunner.
Params:
  • ex – the exception
Since:3.6
/** * Logs the given exception by reusing the code in {@link SafeRunner}. * * @param ex the exception * @since 3.6 */
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) { // NOTE: Logging is done by SafeRunner } }); } }